mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
+79
-79
@@ -1,8 +1,8 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import "core:runtime"
|
import rt "core:runtime"
|
||||||
|
|
||||||
are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||||
if a == b do return true;
|
if a == b do return true;
|
||||||
|
|
||||||
if (a == nil && b != nil) ||
|
if (a == nil && b != nil) ||
|
||||||
@@ -17,47 +17,47 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch x in a.variant {
|
switch x in a.variant {
|
||||||
case runtime.Type_Info_Named:
|
case rt.Type_Info_Named:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Named);
|
y, ok := b.variant.(rt.Type_Info_Named);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
return x.base == y.base;
|
return x.base == y.base;
|
||||||
|
|
||||||
case runtime.Type_Info_Integer:
|
case rt.Type_Info_Integer:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Integer);
|
y, ok := b.variant.(rt.Type_Info_Integer);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
return x.signed == y.signed;
|
return x.signed == y.signed;
|
||||||
|
|
||||||
case runtime.Type_Info_Rune:
|
case rt.Type_Info_Rune:
|
||||||
_, ok := b.variant.(runtime.Type_Info_Rune);
|
_, ok := b.variant.(rt.Type_Info_Rune);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
case runtime.Type_Info_Float:
|
case rt.Type_Info_Float:
|
||||||
_, ok := b.variant.(runtime.Type_Info_Float);
|
_, ok := b.variant.(rt.Type_Info_Float);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
case runtime.Type_Info_Complex:
|
case rt.Type_Info_Complex:
|
||||||
_, ok := b.variant.(runtime.Type_Info_Complex);
|
_, ok := b.variant.(rt.Type_Info_Complex);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
case runtime.Type_Info_String:
|
case rt.Type_Info_String:
|
||||||
_, ok := b.variant.(runtime.Type_Info_String);
|
_, ok := b.variant.(rt.Type_Info_String);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
case runtime.Type_Info_Boolean:
|
case rt.Type_Info_Boolean:
|
||||||
_, ok := b.variant.(runtime.Type_Info_Boolean);
|
_, ok := b.variant.(rt.Type_Info_Boolean);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
case runtime.Type_Info_Any:
|
case rt.Type_Info_Any:
|
||||||
_, ok := b.variant.(runtime.Type_Info_Any);
|
_, ok := b.variant.(rt.Type_Info_Any);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
case runtime.Type_Info_Pointer:
|
case rt.Type_Info_Pointer:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Pointer);
|
y, ok := b.variant.(rt.Type_Info_Pointer);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
return are_types_identical(x.elem, y.elem);
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
case runtime.Type_Info_Procedure:
|
case rt.Type_Info_Procedure:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Procedure);
|
y, ok := b.variant.(rt.Type_Info_Procedure);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
switch {
|
switch {
|
||||||
case x.variadic != y.variadic,
|
case x.variadic != y.variadic,
|
||||||
@@ -67,24 +67,24 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
|||||||
|
|
||||||
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
|
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
|
||||||
|
|
||||||
case runtime.Type_Info_Array:
|
case rt.Type_Info_Array:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Array);
|
y, ok := b.variant.(rt.Type_Info_Array);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
if x.count != y.count do return false;
|
if x.count != y.count do return false;
|
||||||
return are_types_identical(x.elem, y.elem);
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
case runtime.Type_Info_Dynamic_Array:
|
case rt.Type_Info_Dynamic_Array:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Dynamic_Array);
|
y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
return are_types_identical(x.elem, y.elem);
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
case runtime.Type_Info_Slice:
|
case rt.Type_Info_Slice:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Slice);
|
y, ok := b.variant.(rt.Type_Info_Slice);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
return are_types_identical(x.elem, y.elem);
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
case runtime.Type_Info_Tuple:
|
case rt.Type_Info_Tuple:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Tuple);
|
y, ok := b.variant.(rt.Type_Info_Tuple);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
if len(x.types) != len(y.types) do return false;
|
if len(x.types) != len(y.types) do return false;
|
||||||
for _, i in x.types {
|
for _, i in x.types {
|
||||||
@@ -95,8 +95,8 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case runtime.Type_Info_Struct:
|
case rt.Type_Info_Struct:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Struct);
|
y, ok := b.variant.(rt.Type_Info_Struct);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
switch {
|
switch {
|
||||||
case len(x.types) != len(y.types),
|
case len(x.types) != len(y.types),
|
||||||
@@ -114,8 +114,8 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case runtime.Type_Info_Union:
|
case rt.Type_Info_Union:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Union);
|
y, ok := b.variant.(rt.Type_Info_Union);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
if len(x.variants) != len(y.variants) do return false;
|
if len(x.variants) != len(y.variants) do return false;
|
||||||
|
|
||||||
@@ -125,17 +125,17 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case runtime.Type_Info_Enum:
|
case rt.Type_Info_Enum:
|
||||||
// NOTE(bill): Should be handled above
|
// NOTE(bill): Should be handled above
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case runtime.Type_Info_Map:
|
case rt.Type_Info_Map:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Map);
|
y, ok := b.variant.(rt.Type_Info_Map);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
|
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
|
||||||
|
|
||||||
case runtime.Type_Info_Bit_Field:
|
case rt.Type_Info_Bit_Field:
|
||||||
y, ok := b.variant.(runtime.Type_Info_Bit_Field);
|
y, ok := b.variant.(rt.Type_Info_Bit_Field);
|
||||||
if !ok do return false;
|
if !ok do return false;
|
||||||
if len(x.names) != len(y.names) do return false;
|
if len(x.names) != len(y.names) do return false;
|
||||||
|
|
||||||
@@ -156,101 +156,101 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
is_signed :: proc(info: ^runtime.Type_Info) -> bool {
|
is_signed :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
switch i in runtime.type_info_base(info).variant {
|
switch i in rt.type_info_base(info).variant {
|
||||||
case runtime.Type_Info_Integer: return i.signed;
|
case rt.Type_Info_Integer: return i.signed;
|
||||||
case runtime.Type_Info_Float: return true;
|
case rt.Type_Info_Float: return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
is_integer :: proc(info: ^runtime.Type_Info) -> bool {
|
is_integer :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Integer);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Integer);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_rune :: proc(info: ^runtime.Type_Info) -> bool {
|
is_rune :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Rune);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Rune);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_float :: proc(info: ^runtime.Type_Info) -> bool {
|
is_float :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Float);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Float);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_complex :: proc(info: ^runtime.Type_Info) -> bool {
|
is_complex :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Complex);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Complex);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_any :: proc(info: ^runtime.Type_Info) -> bool {
|
is_any :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Any);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Any);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_string :: proc(info: ^runtime.Type_Info) -> bool {
|
is_string :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_String);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_String);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_boolean :: proc(info: ^runtime.Type_Info) -> bool {
|
is_boolean :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Boolean);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Boolean);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_pointer :: proc(info: ^runtime.Type_Info) -> bool {
|
is_pointer :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Pointer);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Pointer);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_procedure :: proc(info: ^runtime.Type_Info) -> bool {
|
is_procedure :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Procedure);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Procedure);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_array :: proc(info: ^runtime.Type_Info) -> bool {
|
is_array :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Array);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Array);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_dynamic_array :: proc(info: ^runtime.Type_Info) -> bool {
|
is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Dynamic_Array);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Dynamic_Array);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_dynamic_map :: proc(info: ^runtime.Type_Info) -> bool {
|
is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Map);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Map);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_slice :: proc(info: ^runtime.Type_Info) -> bool {
|
is_slice :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Slice);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Slice);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_tuple :: proc(info: ^runtime.Type_Info) -> bool {
|
is_tuple :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Tuple);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Tuple);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_struct :: proc(info: ^runtime.Type_Info) -> bool {
|
is_struct :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
s, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Struct);
|
s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
|
||||||
return ok && !s.is_raw_union;
|
return ok && !s.is_raw_union;
|
||||||
}
|
}
|
||||||
is_raw_union :: proc(info: ^runtime.Type_Info) -> bool {
|
is_raw_union :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
s, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Struct);
|
s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
|
||||||
return ok && s.is_raw_union;
|
return ok && s.is_raw_union;
|
||||||
}
|
}
|
||||||
is_union :: proc(info: ^runtime.Type_Info) -> bool {
|
is_union :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Union);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Union);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_enum :: proc(info: ^runtime.Type_Info) -> bool {
|
is_enum :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := runtime.type_info_base(info).variant.(runtime.Type_Info_Enum);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package utf16
|
package utf16
|
||||||
|
|
||||||
REPLACEMENT_CHAR :: '\uFFFD';
|
REPLACEMENT_CHAR :: '\ufffd';
|
||||||
MAX_RUNE :: '\U0010FFFF';
|
MAX_RUNE :: '\U0010ffff';
|
||||||
|
|
||||||
_surr1 :: 0xd800;
|
_surr1 :: 0xd800;
|
||||||
_surr2 :: 0xdc00;
|
_surr2 :: 0xdc00;
|
||||||
|
|||||||
+1408
File diff suppressed because it is too large
Load Diff
+129
-104
@@ -813,7 +813,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
|||||||
if (e->Constant.value.kind != ExactValue_Integer) {
|
if (e->Constant.value.kind != ExactValue_Integer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
i64 count = e->Constant.value.value_integer;
|
i64 count = big_int_to_i64(&e->Constant.value.value_integer);
|
||||||
if (count != source->Array.count) {
|
if (count != source->Array.count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1257,33 +1257,44 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 i = v.value_integer;
|
BigInt i = v.value_integer;
|
||||||
u64 u = bit_cast<u64>(i);
|
|
||||||
i64 bit_size = type_size_of(type);
|
i64 bit_size = type_size_of(type);
|
||||||
u64 umax = unsigned_integer_maxs[bit_size];
|
BigInt umax = {};
|
||||||
i64 imin = signed_integer_mins[bit_size];
|
BigInt imin = {};
|
||||||
i64 imax = signed_integer_maxs[bit_size];
|
BigInt imax = {};
|
||||||
|
|
||||||
|
big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]);
|
||||||
|
big_int_from_i64(&imin, signed_integer_mins[bit_size]);
|
||||||
|
big_int_from_i64(&imax, signed_integer_maxs[bit_size]);
|
||||||
|
|
||||||
switch (type->Basic.kind) {
|
switch (type->Basic.kind) {
|
||||||
case Basic_rune:
|
case Basic_rune:
|
||||||
case Basic_i8:
|
case Basic_i8:
|
||||||
case Basic_i16:
|
case Basic_i16:
|
||||||
case Basic_i32:
|
case Basic_i32:
|
||||||
|
case Basic_i64:
|
||||||
case Basic_int:
|
case Basic_int:
|
||||||
return imin <= i && i <= imax;
|
{
|
||||||
|
// return imin <= i && i <= imax;
|
||||||
|
int a = big_int_cmp(&imin, &i);
|
||||||
|
int b = big_int_cmp(&i, &imax);
|
||||||
|
return (a <= 0) && (b <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
case Basic_u8:
|
case Basic_u8:
|
||||||
case Basic_u16:
|
case Basic_u16:
|
||||||
case Basic_u32:
|
case Basic_u32:
|
||||||
|
case Basic_u64:
|
||||||
case Basic_uint:
|
case Basic_uint:
|
||||||
case Basic_uintptr:
|
case Basic_uintptr:
|
||||||
return 0ull <= u && u <= umax;
|
|
||||||
|
|
||||||
case Basic_u64:
|
{
|
||||||
return 0ull <= i;
|
// return 0ull <= i && i <= umax;
|
||||||
|
int b = big_int_cmp(&i, &umax);
|
||||||
|
return !i.neg && (b <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
case Basic_i64:
|
|
||||||
return true;
|
|
||||||
case Basic_UntypedInteger:
|
case Basic_UntypedInteger:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -1357,14 +1368,9 @@ void check_is_expressible(CheckerContext *c, Operand *o, Type *type) {
|
|||||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||||
error(o->expr, "'%s' truncated to '%s'", a, b);
|
error(o->expr, "'%s' truncated to '%s'", a, b);
|
||||||
} else {
|
} else {
|
||||||
char buf[127] = {};
|
gbAllocator ha = heap_allocator();
|
||||||
String str = {};
|
String str = big_int_to_string(ha, &o->value.value_integer);
|
||||||
i64 i = o->value.value_integer;
|
defer (gb_free(ha, str.text));
|
||||||
if (is_type_unsigned(o->type)) {
|
|
||||||
str = u64_to_string(bit_cast<u64>(i), buf, gb_size_of(buf));
|
|
||||||
} else {
|
|
||||||
str = i64_to_string(i, buf, gb_size_of(buf));
|
|
||||||
}
|
|
||||||
error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b);
|
error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1444,10 +1450,7 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
i32 precision = 0;
|
|
||||||
if (is_type_unsigned(type)) {
|
|
||||||
precision = cast(i32)(8 * type_size_of(type));
|
|
||||||
}
|
|
||||||
if (op.kind == Token_Xor && is_type_untyped(type)) {
|
if (op.kind == Token_Xor && is_type_untyped(type)) {
|
||||||
gbString err_str = expr_to_string(node);
|
gbString err_str = expr_to_string(node);
|
||||||
error(op, "Bitwise not cannot be applied to untyped constants '%s'", err_str);
|
error(op, "Bitwise not cannot be applied to untyped constants '%s'", err_str);
|
||||||
@@ -1463,7 +1466,17 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
o->value = exact_unary_operator_value(op.kind, o->value, precision, is_type_unsigned(type));
|
i32 precision = 0;
|
||||||
|
if (is_type_typed(type)) {
|
||||||
|
precision = cast(i32)(8 * type_size_of(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_unsigned = is_type_unsigned(type);
|
||||||
|
if (is_type_rune(type)) {
|
||||||
|
GB_ASSERT(!is_unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
o->value = exact_unary_operator_value(op.kind, o->value, precision, is_unsigned);
|
||||||
|
|
||||||
if (is_type_typed(type)) {
|
if (is_type_typed(type)) {
|
||||||
if (node != nullptr) {
|
if (node != nullptr) {
|
||||||
@@ -1638,8 +1651,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 amount = y_val.value_integer;
|
BigInt max_shift = {};
|
||||||
if (amount > 128) {
|
big_int_from_u64(&max_shift, 128);
|
||||||
|
|
||||||
|
if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
|
||||||
gbString err_str = expr_to_string(y->expr);
|
gbString err_str = expr_to_string(y->expr);
|
||||||
error(node, "Shift amount too large: '%s'", err_str);
|
error(node, "Shift amount too large: '%s'", err_str);
|
||||||
gb_string_free(err_str);
|
gb_string_free(err_str);
|
||||||
@@ -1653,7 +1668,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
|
|||||||
x->type = t_untyped_integer;
|
x->type = t_untyped_integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
x->value = exact_value_shift(be->op.kind, x_val, exact_value_i64(amount));
|
x->value = exact_value_shift(be->op.kind, x_val, y_val);
|
||||||
|
|
||||||
if (is_type_typed(x->type)) {
|
if (is_type_typed(x->type)) {
|
||||||
check_is_expressible(c, x, base_type(x->type));
|
check_is_expressible(c, x, base_type(x->type));
|
||||||
@@ -1673,7 +1688,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y->mode == Addressing_Constant && y->value.value_integer < 0) {
|
if (y->mode == Addressing_Constant && y->value.value_integer.neg) {
|
||||||
gbString err_str = expr_to_string(y->expr);
|
gbString err_str = expr_to_string(y->expr);
|
||||||
error(node, "Shift amount cannot be negative: '%s'", err_str);
|
error(node, "Shift amount cannot be negative: '%s'", err_str);
|
||||||
gb_string_free(err_str);
|
gb_string_free(err_str);
|
||||||
@@ -1691,60 +1706,60 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Operand check_ptr_addition(CheckerContext *c, TokenKind op, Operand *ptr, Operand *offset, Ast *node) {
|
// Operand check_ptr_addition(CheckerContext *c, TokenKind op, Operand *ptr, Operand *offset, Ast *node) {
|
||||||
GB_ASSERT(node->kind == Ast_BinaryExpr);
|
// GB_ASSERT(node->kind == Ast_BinaryExpr);
|
||||||
ast_node(be, BinaryExpr, node);
|
// ast_node(be, BinaryExpr, node);
|
||||||
GB_ASSERT(is_type_pointer(ptr->type));
|
// GB_ASSERT(is_type_pointer(ptr->type));
|
||||||
GB_ASSERT(is_type_integer(offset->type));
|
// GB_ASSERT(is_type_integer(offset->type));
|
||||||
GB_ASSERT(op == Token_Add || op == Token_Sub);
|
// GB_ASSERT(op == Token_Add || op == Token_Sub);
|
||||||
|
|
||||||
Operand operand = {};
|
// Operand operand = {};
|
||||||
operand.mode = Addressing_Value;
|
// operand.mode = Addressing_Value;
|
||||||
operand.type = ptr->type;
|
// operand.type = ptr->type;
|
||||||
operand.expr = node;
|
// operand.expr = node;
|
||||||
|
|
||||||
if (base_type(ptr->type) == t_rawptr) {
|
// if (base_type(ptr->type) == t_rawptr) {
|
||||||
gbString str = type_to_string(ptr->type);
|
// gbString str = type_to_string(ptr->type);
|
||||||
error(node, "Invalid pointer type for pointer arithmetic: '%s'", str);
|
// error(node, "Invalid pointer type for pointer arithmetic: '%s'", str);
|
||||||
gb_string_free(str);
|
// gb_string_free(str);
|
||||||
operand.mode = Addressing_Invalid;
|
// operand.mode = Addressing_Invalid;
|
||||||
return operand;
|
// return operand;
|
||||||
}
|
// }
|
||||||
|
|
||||||
#if defined(NO_POINTER_ARITHMETIC)
|
// #if defined(NO_POINTER_ARITHMETIC)
|
||||||
operand.mode = Addressing_Invalid;
|
// operand.mode = Addressing_Invalid;
|
||||||
error(operand.expr, "Pointer arithmetic is not supported");
|
// error(operand.expr, "Pointer arithmetic is not supported");
|
||||||
return operand;
|
// return operand;
|
||||||
#else
|
// #else
|
||||||
|
|
||||||
Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
|
// Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
|
||||||
Type *elem = base_ptr->Pointer.elem;
|
// Type *elem = base_ptr->Pointer.elem;
|
||||||
i64 elem_size = type_size_of(elem);
|
// i64 elem_size = type_size_of(elem);
|
||||||
|
|
||||||
if (elem_size <= 0) {
|
// if (elem_size <= 0) {
|
||||||
gbString str = type_to_string(elem);
|
// gbString str = type_to_string(elem);
|
||||||
error(node, "Size of pointer's element type '%s' is zero and cannot be used for pointer arithmetic", str);
|
// error(node, "Size of pointer's element type '%s' is zero and cannot be used for pointer arithmetic", str);
|
||||||
gb_string_free(str);
|
// gb_string_free(str);
|
||||||
operand.mode = Addressing_Invalid;
|
// operand.mode = Addressing_Invalid;
|
||||||
return operand;
|
// return operand;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
|
// if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
|
||||||
i64 ptr_val = ptr->value.value_pointer;
|
// i64 ptr_val = ptr->value.value_pointer;
|
||||||
i64 offset_val = exact_value_to_integer(offset->value).value_integer;
|
// i64 offset_val = exact_value_to_integer(offset->value).value_integer;
|
||||||
i64 new_ptr_val = ptr_val;
|
// i64 new_ptr_val = ptr_val;
|
||||||
if (op == Token_Add) {
|
// if (op == Token_Add) {
|
||||||
new_ptr_val += elem_size*offset_val;
|
// new_ptr_val += elem_size*offset_val;
|
||||||
} else {
|
// } else {
|
||||||
new_ptr_val -= elem_size*offset_val;
|
// new_ptr_val -= elem_size*offset_val;
|
||||||
}
|
// }
|
||||||
operand.mode = Addressing_Constant;
|
// operand.mode = Addressing_Constant;
|
||||||
operand.value = exact_value_pointer(new_ptr_val);
|
// operand.value = exact_value_pointer(new_ptr_val);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return operand;
|
// return operand;
|
||||||
#endif
|
// #endif
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2030,24 +2045,24 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op.kind == Token_Add || op.kind == Token_Sub) {
|
// if (op.kind == Token_Add || op.kind == Token_Sub) {
|
||||||
if (is_type_pointer(x->type) && is_type_integer(y->type)) {
|
// if (is_type_pointer(x->type) && is_type_integer(y->type)) {
|
||||||
*x = check_ptr_addition(c, op.kind, x, y, node);
|
// *x = check_ptr_addition(c, op.kind, x, y, node);
|
||||||
return;
|
// return;
|
||||||
} else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
|
// } else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
|
||||||
if (op.kind == Token_Sub) {
|
// if (op.kind == Token_Sub) {
|
||||||
gbString lhs = expr_to_string(x->expr);
|
// gbString lhs = expr_to_string(x->expr);
|
||||||
gbString rhs = expr_to_string(y->expr);
|
// gbString rhs = expr_to_string(y->expr);
|
||||||
error(node, "Invalid pointer arithmetic, did you mean '%s %.*s %s'?", rhs, LIT(op.string), lhs);
|
// error(node, "Invalid pointer arithmetic, did you mean '%s %.*s %s'?", rhs, LIT(op.string), lhs);
|
||||||
gb_string_free(rhs);
|
// gb_string_free(rhs);
|
||||||
gb_string_free(lhs);
|
// gb_string_free(lhs);
|
||||||
x->mode = Addressing_Invalid;
|
// x->mode = Addressing_Invalid;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
*x = check_ptr_addition(c, op.kind, y, x, node);
|
// *x = check_ptr_addition(c, op.kind, y, x, node);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
convert_to_typed(c, x, y->type);
|
convert_to_typed(c, x, y->type);
|
||||||
if (x->mode == Addressing_Invalid) {
|
if (x->mode == Addressing_Invalid) {
|
||||||
@@ -2108,7 +2123,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node) {
|
|||||||
bool fail = false;
|
bool fail = false;
|
||||||
switch (y->value.kind) {
|
switch (y->value.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
if (y->value.value_integer == 0 ) {
|
if (big_int_is_zero(&y->value.value_integer)) {
|
||||||
fail = true;
|
fail = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2246,7 +2261,7 @@ void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_typ
|
|||||||
char *extra_text = "";
|
char *extra_text = "";
|
||||||
|
|
||||||
if (operand->mode == Addressing_Constant) {
|
if (operand->mode == Addressing_Constant) {
|
||||||
if (operand->value.value_integer == 0) {
|
if (big_int_is_zero(&operand->value.value_integer)) {
|
||||||
if (make_string_c(expr_str) != "nil") { // HACK NOTE(bill): Just in case
|
if (make_string_c(expr_str) != "nil") { // HACK NOTE(bill): Just in case
|
||||||
// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
|
// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
|
||||||
extra_text = " - Did you want 'nil'?";
|
extra_text = " - Did you want 'nil'?";
|
||||||
@@ -2495,8 +2510,8 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
|
|||||||
|
|
||||||
if (operand.mode == Addressing_Constant &&
|
if (operand.mode == Addressing_Constant &&
|
||||||
(c->stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
|
(c->stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
|
||||||
i64 i = exact_value_to_integer(operand.value).value_integer;
|
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
||||||
if (i < 0) {
|
if (i.neg) {
|
||||||
gbString expr_str = expr_to_string(operand.expr);
|
gbString expr_str = expr_to_string(operand.expr);
|
||||||
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
||||||
gb_string_free(expr_str);
|
gb_string_free(expr_str);
|
||||||
@@ -2505,13 +2520,21 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (max_count >= 0) { // NOTE(bill): Do array bound checking
|
if (max_count >= 0) { // NOTE(bill): Do array bound checking
|
||||||
if (value) *value = i;
|
i64 v = -1;
|
||||||
|
if (i.len <= 1) {
|
||||||
|
v = big_int_to_i64(&i);
|
||||||
|
}
|
||||||
|
if (value) *value = v;
|
||||||
bool out_of_bounds = false;
|
bool out_of_bounds = false;
|
||||||
if (open_range) {
|
if (open_range) {
|
||||||
out_of_bounds = i > max_count;
|
out_of_bounds = v > max_count;
|
||||||
} else {
|
} else {
|
||||||
out_of_bounds = i >= max_count;
|
out_of_bounds = v >= max_count;
|
||||||
}
|
}
|
||||||
|
if (v < 0) {
|
||||||
|
out_of_bounds = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (out_of_bounds) {
|
if (out_of_bounds) {
|
||||||
gbString expr_str = expr_to_string(operand.expr);
|
gbString expr_str = expr_to_string(operand.expr);
|
||||||
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
|
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
|
||||||
@@ -3399,12 +3422,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op.value.value_integer < 0) {
|
if (op.value.value_integer.neg) {
|
||||||
error(op.expr, "Negative 'swizzle' index");
|
error(op.expr, "Negative 'swizzle' index");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_count <= op.value.value_integer) {
|
BigInt mc = {};
|
||||||
|
big_int_from_i64(&mc, max_count);
|
||||||
|
if (big_int_cmp(&mc, &op.value.value_integer) <= 0) {
|
||||||
error(op.expr, "'swizzle' index exceeds length");
|
error(op.expr, "'swizzle' index exceeds length");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3804,7 +3829,7 @@ break;
|
|||||||
if (operand->mode == Addressing_Constant) {
|
if (operand->mode == Addressing_Constant) {
|
||||||
switch (operand->value.kind) {
|
switch (operand->value.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
operand->value.value_integer = gb_abs(operand->value.value_integer);
|
operand->value.value_integer.neg = false;
|
||||||
break;
|
break;
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
operand->value.value_float = gb_abs(operand->value.value_float);
|
operand->value.value_float = gb_abs(operand->value.value_float);
|
||||||
|
|||||||
+10
-11
@@ -260,18 +260,17 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
|||||||
if (rhs->mode == Addressing_Constant) {
|
if (rhs->mode == Addressing_Constant) {
|
||||||
ExactValue v = exact_value_to_integer(rhs->value);
|
ExactValue v = exact_value_to_integer(rhs->value);
|
||||||
if (v.kind == ExactValue_Integer) {
|
if (v.kind == ExactValue_Integer) {
|
||||||
i64 i = v.value_integer;
|
BigInt i = v.value_integer;
|
||||||
u64 u = bit_cast<u64>(i);
|
if (!i.neg) {
|
||||||
u64 umax = ~cast(u64)0ull;
|
u64 imax_ = ~cast(u64)0ull;
|
||||||
if (lhs_bits < 64) {
|
if (lhs_bits < 64) {
|
||||||
umax = (1ull << cast(u64)lhs_bits) - 1ull;
|
imax_ = (1ull << cast(u64)lhs_bits) - 1ull;
|
||||||
}
|
}
|
||||||
i64 imax = 1ll << (cast(i64)lhs_bits-1ll);
|
|
||||||
|
|
||||||
bool ok = !(u < 0 || u > umax);
|
BigInt imax = big_int_make_u64(imax_);
|
||||||
|
if (big_int_cmp(&i, &imax) > 0) {
|
||||||
if (ok) {
|
return rhs->type;
|
||||||
return rhs->type;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (is_type_integer(rhs->type)) {
|
} else if (is_type_integer(rhs->type)) {
|
||||||
|
|||||||
+25
-6
@@ -136,7 +136,15 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
|||||||
Type *type = base_type(o.type);
|
Type *type = base_type(o.type);
|
||||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||||
if (o.value.kind == ExactValue_Integer) {
|
if (o.value.kind == ExactValue_Integer) {
|
||||||
i64 align = o.value.value_integer;
|
BigInt v = o.value.value_integer;
|
||||||
|
if (v.len > 1) {
|
||||||
|
gbAllocator a = heap_allocator();
|
||||||
|
String str = big_int_to_string(a, &v);
|
||||||
|
error(node, "#align too large, %.*s", LIT(str));
|
||||||
|
gb_free(a, str.text);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i64 align = big_int_to_i64(&v);
|
||||||
if (align < 1 || !gb_is_power_of_two(cast(isize)align)) {
|
if (align < 1 || !gb_is_power_of_two(cast(isize)align)) {
|
||||||
error(node, "#align must be a power of 2, got %lld", align);
|
error(node, "#align must be a power of 2, got %lld", align);
|
||||||
return false;
|
return false;
|
||||||
@@ -668,7 +676,7 @@ void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Ast *node)
|
|||||||
error(value, "Bit field bit size must be a constant integer");
|
error(value, "Bit field bit size must be a constant integer");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
i64 bits_ = v.value_integer;
|
i64 bits_ = big_int_to_i64(&v.value_integer); // TODO(bill): what if the integer is huge?
|
||||||
if (bits_ < 0 || bits_ > 64) {
|
if (bits_ < 0 || bits_ > 64) {
|
||||||
error(value, "Bit field's bit size must be within the range 1...64, got %lld", cast(long long)bits_);
|
error(value, "Bit field's bit size must be within the range 1...64, got %lld", cast(long long)bits_);
|
||||||
continue;
|
continue;
|
||||||
@@ -1601,11 +1609,22 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
|||||||
Type *type = base_type(o->type);
|
Type *type = base_type(o->type);
|
||||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||||
if (o->value.kind == ExactValue_Integer) {
|
if (o->value.kind == ExactValue_Integer) {
|
||||||
i64 count = o->value.value_integer;
|
BigInt count = o->value.value_integer;
|
||||||
if (count >= 0) {
|
if (o->value.value_integer.neg) {
|
||||||
return count;
|
gbAllocator a = heap_allocator();
|
||||||
|
String str = big_int_to_string(a, &count);
|
||||||
|
error(e, "Invalid negative array count, %.*s", LIT(str));
|
||||||
|
gb_free(a, str.text);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
error(e, "Invalid negative array count %lld", cast(long long)count);
|
switch (count.len) {
|
||||||
|
case 0: return 0;
|
||||||
|
case 1: return count.d.word;
|
||||||
|
}
|
||||||
|
gbAllocator a = heap_allocator();
|
||||||
|
String str = big_int_to_string(a, &count);
|
||||||
|
error(e, "Array count too large, %.*s", LIT(str));
|
||||||
|
gb_free(a, str.text);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-2
@@ -3,6 +3,10 @@
|
|||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(GB_COMPILER_MSVC)
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GB_IMPLEMENTATION
|
#define GB_IMPLEMENTATION
|
||||||
#include "gb/gb.h"
|
#include "gb/gb.h"
|
||||||
|
|
||||||
@@ -200,7 +204,7 @@ u64 u64_from_string(String string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||||
char buf[200] = {0};
|
char buf[32] = {0};
|
||||||
isize i = gb_size_of(buf);
|
isize i = gb_size_of(buf);
|
||||||
|
|
||||||
u64 b = 10;
|
u64 b = 10;
|
||||||
@@ -215,7 +219,7 @@ String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
|||||||
return make_string(cast(u8 *)out_buf, len);
|
return make_string(cast(u8 *)out_buf, len);
|
||||||
}
|
}
|
||||||
String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||||
char buf[200] = {0};
|
char buf[32] = {0};
|
||||||
isize i = gb_size_of(buf);
|
isize i = gb_size_of(buf);
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
@@ -276,6 +280,44 @@ gb_global u64 const unsigned_integer_maxs[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool add_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||||
|
*result = x + y;
|
||||||
|
return *result < x || *result < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||||
|
*result = x - y;
|
||||||
|
return *result > x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
|
||||||
|
#if defined(GB_COMPILER_MSVC)
|
||||||
|
*lo = _umul128(x, y, hi);
|
||||||
|
#else
|
||||||
|
// URL(bill): https://stackoverflow.com/questions/25095741/how-can-i-multiply-64-bit-operands-and-get-128-bit-result-portably#25096197
|
||||||
|
u64 u1, v1, w1, t, w3, k;
|
||||||
|
|
||||||
|
u1 = (x & 0xffffffff);
|
||||||
|
v1 = (y & 0xffffffff);
|
||||||
|
t = (u1 * v1);
|
||||||
|
w3 = (t & 0xffffffff);
|
||||||
|
k = (t >> 32);
|
||||||
|
|
||||||
|
x >>= 32;
|
||||||
|
t = (x * v1) + k;
|
||||||
|
k = (t & 0xffffffff);
|
||||||
|
w1 = (t >> 32);
|
||||||
|
|
||||||
|
y >>= 32;
|
||||||
|
t = (u1 * y) + k;
|
||||||
|
k = (t >> 32);
|
||||||
|
|
||||||
|
*hi = (x * y) + w1 + k;
|
||||||
|
*lo = (t << 32) + w3;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "map.cpp"
|
#include "map.cpp"
|
||||||
#include "ptr_set.cpp"
|
#include "ptr_set.cpp"
|
||||||
|
|||||||
+49
-49
@@ -33,7 +33,7 @@ struct ExactValue {
|
|||||||
union {
|
union {
|
||||||
bool value_bool;
|
bool value_bool;
|
||||||
String value_string;
|
String value_string;
|
||||||
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
|
BigInt value_integer; // NOTE(bill): This must be an integer and not a pointer
|
||||||
f64 value_float;
|
f64 value_float;
|
||||||
i64 value_pointer;
|
i64 value_pointer;
|
||||||
Complex128 value_complex;
|
Complex128 value_complex;
|
||||||
@@ -54,8 +54,14 @@ HashKey hash_exact_value(ExactValue v) {
|
|||||||
return hash_integer(u64(v.value_bool));
|
return hash_integer(u64(v.value_bool));
|
||||||
case ExactValue_String:
|
case ExactValue_String:
|
||||||
return hash_string(v.value_string);
|
return hash_string(v.value_string);
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer: {
|
||||||
return hash_integer(u64(v.value_integer));
|
u64 *d = big_int_ptr(&v.value_integer);
|
||||||
|
u64 x = 0;
|
||||||
|
for (i32 i = 0; i < v.value_integer.len; i++) {
|
||||||
|
x |= d[i];
|
||||||
|
}
|
||||||
|
return hash_integer(x);
|
||||||
|
}
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
return hash_f64(v.value_float);
|
return hash_f64(v.value_float);
|
||||||
case ExactValue_Pointer:
|
case ExactValue_Pointer:
|
||||||
@@ -94,13 +100,13 @@ ExactValue exact_value_string(String string) {
|
|||||||
|
|
||||||
ExactValue exact_value_i64(i64 i) {
|
ExactValue exact_value_i64(i64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
result.value_integer = i;
|
big_int_from_i64(&result.value_integer, i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_u64(u64 i) {
|
ExactValue exact_value_u64(u64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
result.value_integer = i64(i);
|
big_int_from_u64(&result.value_integer, i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +299,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
|||||||
ExactValue exact_value_to_float(ExactValue v) {
|
ExactValue exact_value_to_float(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
return exact_value_float(cast(f64)v.value_integer);
|
return exact_value_float(big_int_to_f64(&v.value_integer));
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -304,7 +310,7 @@ ExactValue exact_value_to_float(ExactValue v) {
|
|||||||
ExactValue exact_value_to_complex(ExactValue v) {
|
ExactValue exact_value_to_complex(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
return exact_value_complex(cast(f64)v.value_integer, 0);
|
return exact_value_complex(big_int_to_f64(&v.value_integer), 0);
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
return exact_value_complex(v.value_float, 0);
|
return exact_value_complex(v.value_float, 0);
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
@@ -371,8 +377,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
|||||||
case ExactValue_Invalid:
|
case ExactValue_Invalid:
|
||||||
return v;
|
return v;
|
||||||
case ExactValue_Integer: {
|
case ExactValue_Integer: {
|
||||||
ExactValue i = v;
|
ExactValue i = {ExactValue_Integer};
|
||||||
i.value_integer = -i.value_integer;
|
big_int_neg(&i.value_integer, &v.value_integer);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
case ExactValue_Float: {
|
case ExactValue_Float: {
|
||||||
@@ -390,24 +396,18 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Token_Xor: {
|
case Token_Xor: {
|
||||||
i64 i = 0;
|
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Invalid:
|
case ExactValue_Invalid:
|
||||||
return v;
|
return v;
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer: {
|
||||||
i = ~v.value_integer;
|
GB_ASSERT(precision != 0);
|
||||||
break;
|
ExactValue i = {ExactValue_Integer};
|
||||||
|
bit_int_not(&i.value_integer, &v.value_integer, precision, !is_unsigned);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): unsigned integers will be negative and will need to be
|
|
||||||
// limited to the types precision
|
|
||||||
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
|
|
||||||
if (is_unsigned) {
|
|
||||||
i = i & unsigned_integer_maxs[precision/8];
|
|
||||||
}
|
|
||||||
return exact_value_i64(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Token_Not: {
|
case Token_Not: {
|
||||||
@@ -472,10 +472,10 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
|||||||
return;
|
return;
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
// TODO(bill): Is this good enough?
|
// TODO(bill): Is this good enough?
|
||||||
*x = exact_value_float(cast(f64)x->value_integer);
|
*x = exact_value_float(big_int_to_f64(&x->value_integer));
|
||||||
return;
|
return;
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
*x = exact_value_complex(cast(f64)x->value_integer, 0);
|
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -513,28 +513,29 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ExactValue_Integer: {
|
case ExactValue_Integer: {
|
||||||
i64 a = x.value_integer;
|
BigInt const *a = &x.value_integer;
|
||||||
i64 b = y.value_integer;
|
BigInt const *b = &y.value_integer;
|
||||||
i64 c = 0ll;
|
BigInt c = {};
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Token_Add: c = a + b; break;
|
case Token_Add: big_int_add(&c, a, b); break;
|
||||||
case Token_Sub: c = a - b; break;
|
case Token_Sub: big_int_sub(&c, a, b); break;
|
||||||
case Token_Mul: c = a * b; break;
|
case Token_Mul: big_int_mul(&c, a, b); break;
|
||||||
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
|
case Token_Quo: return exact_value_float(fmod(big_int_to_f64(a), big_int_to_f64(b)));
|
||||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
case Token_QuoEq: big_int_quo(&c, a, b); break; // NOTE(bill): Integer division
|
||||||
case Token_Mod: c = a % b; break;
|
case Token_Mod: big_int_rem(&c, a, b); break;
|
||||||
case Token_ModMod: c = ((a % b) + b) % b; break;
|
case Token_ModMod: big_int_euclidean_mod(&c, a, b); break;
|
||||||
case Token_And: c = a & b; break;
|
case Token_And: big_int_and(&c, a, b); break;
|
||||||
case Token_Or: c = a | b; break;
|
case Token_Or: big_int_or(&c, a, b); break;
|
||||||
case Token_Xor: c = a ^ b; break;
|
case Token_Xor: big_int_xor(&c, a, b); break;
|
||||||
case Token_AndNot: c = a & (~b); break;
|
case Token_AndNot: big_int_and_not(&c, a, b); break;
|
||||||
case Token_Shl: c = a << b; break;
|
case Token_Shl: big_int_shl(&c, a, b); break;
|
||||||
case Token_Shr: c = a >> b; break;
|
case Token_Shr: big_int_shr(&c, a, b); break;
|
||||||
default: goto error;
|
default: goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exact_value_i64(c);
|
ExactValue res = {ExactValue_Integer};
|
||||||
break;
|
res.value_integer = c;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ExactValue_Float: {
|
case ExactValue_Float: {
|
||||||
@@ -638,15 +639,14 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ExactValue_Integer: {
|
case ExactValue_Integer: {
|
||||||
i64 a = x.value_integer;
|
i32 cmp = big_int_cmp(&x.value_integer, &y.value_integer);
|
||||||
i64 b = y.value_integer;
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Token_CmpEq: return a == b;
|
case Token_CmpEq: return cmp == 0;
|
||||||
case Token_NotEq: return a != b;
|
case Token_NotEq: return cmp != 0;
|
||||||
case Token_Lt: return a < b;
|
case Token_Lt: return cmp < 0;
|
||||||
case Token_LtEq: return a <= b;
|
case Token_LtEq: return cmp <= 0;
|
||||||
case Token_Gt: return a > b;
|
case Token_Gt: return cmp > 0;
|
||||||
case Token_GtEq: return a >= b;
|
case Token_GtEq: return cmp >= 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -4778,7 +4778,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
|
|||||||
GB_ASSERT(is_type_integer(tv.type));
|
GB_ASSERT(is_type_integer(tv.type));
|
||||||
GB_ASSERT(tv.value.kind == ExactValue_Integer);
|
GB_ASSERT(tv.value.kind == ExactValue_Integer);
|
||||||
|
|
||||||
i32 src_index = cast(i32)tv.value.value_integer;
|
i32 src_index = cast(i32)big_int_to_i64(&tv.value.value_integer);
|
||||||
i32 dst_index = i-1;
|
i32 dst_index = i-1;
|
||||||
|
|
||||||
irValue *src_elem = ir_emit_array_epi(proc, src, src_index);
|
irValue *src_elem = ir_emit_array_epi(proc, src, src_index);
|
||||||
@@ -5639,7 +5639,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
Type *selector_type = base_type(type_of_expr(se->selector));
|
Type *selector_type = base_type(type_of_expr(se->selector));
|
||||||
GB_ASSERT_MSG(is_type_integer(selector_type), "%s", type_to_string(selector_type));
|
GB_ASSERT_MSG(is_type_integer(selector_type), "%s", type_to_string(selector_type));
|
||||||
ExactValue val = type_and_value_of_expr(sel).value;
|
ExactValue val = type_and_value_of_expr(sel).value;
|
||||||
i64 index = val.value_integer;
|
i64 index = big_int_to_i64(&val.value_integer);
|
||||||
|
|
||||||
Selection sel = lookup_field_from_index(type, index);
|
Selection sel = lookup_field_from_index(type, index);
|
||||||
GB_ASSERT(sel.entity != nullptr);
|
GB_ASSERT(sel.entity != nullptr);
|
||||||
|
|||||||
+12
-3
@@ -65,6 +65,15 @@ void ir_write_i64(irFileBuffer *f, i64 i) {
|
|||||||
String str = i64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
|
String str = i64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
|
||||||
ir_write_string(f, str);
|
ir_write_string(f, str);
|
||||||
}
|
}
|
||||||
|
void ir_write_big_int(irFileBuffer *f, BigInt const &x) {
|
||||||
|
i64 i = 0;
|
||||||
|
if (x.neg) {
|
||||||
|
i = big_int_to_i64(&x);
|
||||||
|
} else {
|
||||||
|
i = cast(i64)big_int_to_u64(&x);
|
||||||
|
}
|
||||||
|
ir_write_i64(f, i);
|
||||||
|
}
|
||||||
|
|
||||||
void ir_file_write(irFileBuffer *f, void *data, isize len) {
|
void ir_file_write(irFileBuffer *f, void *data, isize len) {
|
||||||
ir_file_buffer_write(f, data, len);
|
ir_file_buffer_write(f, data, len);
|
||||||
@@ -587,19 +596,19 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
}
|
}
|
||||||
case ExactValue_Integer: {
|
case ExactValue_Integer: {
|
||||||
if (is_type_pointer(type)) {
|
if (is_type_pointer(type)) {
|
||||||
if (value.value_integer == 0) {
|
if (big_int_is_zero(&value.value_integer)) {
|
||||||
ir_write_str_lit(f, "null");
|
ir_write_str_lit(f, "null");
|
||||||
} else {
|
} else {
|
||||||
ir_write_str_lit(f, "inttoptr (");
|
ir_write_str_lit(f, "inttoptr (");
|
||||||
ir_print_type(f, m, t_int);
|
ir_print_type(f, m, t_int);
|
||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
ir_write_i64(f, value.value_integer);
|
ir_write_big_int(f, value.value_integer);
|
||||||
ir_write_str_lit(f, " to ");
|
ir_write_str_lit(f, " to ");
|
||||||
ir_print_type(f, m, t_rawptr);
|
ir_print_type(f, m, t_rawptr);
|
||||||
ir_write_str_lit(f, ")");
|
ir_write_str_lit(f, ")");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ir_write_i64(f, value.value_integer);
|
ir_write_big_int(f, value.value_integer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -4,6 +4,7 @@
|
|||||||
#include "timings.cpp"
|
#include "timings.cpp"
|
||||||
#include "build_settings.cpp"
|
#include "build_settings.cpp"
|
||||||
#include "tokenizer.cpp"
|
#include "tokenizer.cpp"
|
||||||
|
#include "big_int.cpp"
|
||||||
#include "exact_value.cpp"
|
#include "exact_value.cpp"
|
||||||
|
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
@@ -408,7 +409,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
}
|
}
|
||||||
case BuildFlag_OptimizationLevel:
|
case BuildFlag_OptimizationLevel:
|
||||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||||
build_context.optimization_level = cast(i32)value.value_integer;
|
build_context.optimization_level = cast(i32)big_int_to_i64(&value.value_integer);
|
||||||
break;
|
break;
|
||||||
case BuildFlag_ShowTimings:
|
case BuildFlag_ShowTimings:
|
||||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||||
@@ -416,7 +417,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
break;
|
break;
|
||||||
case BuildFlag_ThreadCount: {
|
case BuildFlag_ThreadCount: {
|
||||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||||
isize count = cast(isize)value.value_integer;
|
isize count = cast(isize)big_int_to_i64(&value.value_integer);
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
gb_printf_err("%.*s expected a positive non-zero number, got %.*s\n", LIT(name), LIT(param));
|
gb_printf_err("%.*s expected a positive non-zero number, got %.*s\n", LIT(name), LIT(param));
|
||||||
build_context.thread_count = 0;
|
build_context.thread_count = 0;
|
||||||
@@ -716,6 +717,7 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
|
|
||||||
init_string_buffer_memory();
|
init_string_buffer_memory();
|
||||||
init_global_error_collector();
|
init_global_error_collector();
|
||||||
|
global_big_int_init();
|
||||||
arena_init(&global_ast_arena, heap_allocator());
|
arena_init(&global_ast_arena, heap_allocator());
|
||||||
|
|
||||||
array_init(&library_collections, heap_allocator());
|
array_init(&library_collections, heap_allocator());
|
||||||
|
|||||||
+27
-80
@@ -3470,22 +3470,6 @@ Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ast *parse_export_decl(AstFile *f) {
|
|
||||||
// CommentGroup *docs = f->lead_comment;
|
|
||||||
// Token token = expect_token(f, Token_export);
|
|
||||||
// Token file_path = expect_token_after(f, Token_String, "export");
|
|
||||||
// Ast *s = nullptr;
|
|
||||||
// if (f->curr_proc != nullptr) {
|
|
||||||
// syntax_error(token, "You cannot use 'export' within a procedure. This must be done at the file scope");
|
|
||||||
// s = ast_bad_decl(f, token, file_path);
|
|
||||||
// } else {
|
|
||||||
// s = ast_export_decl(f, token, file_path, docs, f->line_comment);
|
|
||||||
// array_add(&f->imports_and_exports, s);
|
|
||||||
// }
|
|
||||||
// expect_semicolon(f, s);
|
|
||||||
// return s;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Ast *parse_foreign_decl(AstFile *f) {
|
Ast *parse_foreign_decl(AstFile *f) {
|
||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
Token token = expect_token(f, Token_foreign);
|
Token token = expect_token(f, Token_foreign);
|
||||||
@@ -3668,17 +3652,6 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
Token name = expect_token(f, Token_Ident);
|
Token name = expect_token(f, Token_Ident);
|
||||||
String tag = name.string;
|
String tag = name.string;
|
||||||
|
|
||||||
// if (tag == "shared_global_scope") {
|
|
||||||
// if (f->curr_proc == nullptr) {
|
|
||||||
// f->is_global_scope = true;
|
|
||||||
// s = ast_empty_stmt(f, f->curr_token);
|
|
||||||
// } else {
|
|
||||||
// syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope");
|
|
||||||
// s = ast_bad_decl(f, token, f->curr_token);
|
|
||||||
// }
|
|
||||||
// expect_semicolon(f, s);
|
|
||||||
// return s;
|
|
||||||
// } else
|
|
||||||
if (tag == "bounds_check") {
|
if (tag == "bounds_check") {
|
||||||
s = parse_stmt(f);
|
s = parse_stmt(f);
|
||||||
s->stmt_state_flags |= StmtStateFlag_bounds_check;
|
s->stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||||
@@ -3734,9 +3707,7 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
syntax_error(token,
|
syntax_error(token, "Expected a statement, got '%.*s'", LIT(token_strings[token.kind]));
|
||||||
"Expected a statement, got '%.*s'",
|
|
||||||
LIT(token_strings[token.kind]));
|
|
||||||
fix_advance_to_next_stmt(f);
|
fix_advance_to_next_stmt(f);
|
||||||
return ast_bad_stmt(f, token, f->curr_token);
|
return ast_bad_stmt(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
@@ -3938,39 +3909,25 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (rd_err != ReadDirectory_None) {
|
switch (rd_err) {
|
||||||
if (pos.line != 0) {
|
case ReadDirectory_InvalidPath:
|
||||||
gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
|
error(pos, "Invalid path: %.*s", LIT(rel_path));
|
||||||
}
|
return false;
|
||||||
gb_mutex_lock(&global_error_collector.mutex);
|
case ReadDirectory_NotExists:
|
||||||
defer (gb_mutex_unlock(&global_error_collector.mutex));
|
error(pos, "Path does not exist: %.*s", LIT(rel_path));
|
||||||
global_error_collector.count++;
|
return false;
|
||||||
|
case ReadDirectory_Permission:
|
||||||
|
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||||
switch (rd_err) {
|
return false;
|
||||||
case ReadDirectory_InvalidPath:
|
case ReadDirectory_NotDir:
|
||||||
gb_printf_err("Invalid path: %.*s\n", LIT(rel_path));
|
error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
|
case ReadDirectory_Empty:
|
||||||
case ReadDirectory_NotExists:
|
error(pos, "Empty directory: %.*s", LIT(rel_path));
|
||||||
gb_printf_err("Path does not exist: %.*s\n", LIT(rel_path));
|
return false;
|
||||||
return false;
|
case ReadDirectory_Unknown:
|
||||||
|
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||||
case ReadDirectory_NotDir:
|
return false;
|
||||||
gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(rel_path));
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case ReadDirectory_Unknown:
|
|
||||||
gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(rel_path));
|
|
||||||
return false;
|
|
||||||
case ReadDirectory_Permission:
|
|
||||||
gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(rel_path));
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case ReadDirectory_Empty:
|
|
||||||
gb_printf_err("Empty directory: %.*s\n", LIT(rel_path));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for_array(list_index, list) {
|
for_array(list_index, list) {
|
||||||
@@ -4353,44 +4310,34 @@ ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) {
|
|||||||
ParseFileError err = init_ast_file(file, fi->fullpath, &err_pos);
|
ParseFileError err = init_ast_file(file, fi->fullpath, &err_pos);
|
||||||
|
|
||||||
if (err != ParseFile_None) {
|
if (err != ParseFile_None) {
|
||||||
gb_mutex_lock(&global_error_collector.mutex);
|
|
||||||
defer (gb_mutex_unlock(&global_error_collector.mutex));
|
|
||||||
global_error_collector.count++;
|
|
||||||
|
|
||||||
if (err == ParseFile_EmptyFile) {
|
if (err == ParseFile_EmptyFile) {
|
||||||
if (fi->fullpath == p->init_fullpath) {
|
if (fi->fullpath == p->init_fullpath) {
|
||||||
gb_printf_err("Initial file is empty - %.*s\n", LIT(p->init_fullpath));
|
error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath));
|
||||||
gb_exit(1);
|
gb_exit(1);
|
||||||
}
|
}
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos.line != 0) {
|
|
||||||
gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
|
|
||||||
}
|
|
||||||
gb_printf_err("Failed to parse file: %.*s\n\t", LIT(fi->name));
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case ParseFile_WrongExtension:
|
case ParseFile_WrongExtension:
|
||||||
gb_printf_err("Invalid file extension: File must have the extension '.odin'");
|
error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_InvalidFile:
|
case ParseFile_InvalidFile:
|
||||||
gb_printf_err("Invalid file or cannot be found");
|
error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_Permission:
|
case ParseFile_Permission:
|
||||||
gb_printf_err("File permissions problem");
|
error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_NotFound:
|
case ParseFile_NotFound:
|
||||||
gb_printf_err("File cannot be found ('%.*s')", LIT(fi->fullpath));
|
error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath));
|
||||||
break;
|
break;
|
||||||
case ParseFile_InvalidToken:
|
case ParseFile_InvalidToken:
|
||||||
gb_printf_err("Invalid token found in file at (%td:%td)", err_pos.line, err_pos.column);
|
error(pos, "Failed to parse file: %.*s; invalid token found in file at (%td:%td)", LIT(fi->name), err_pos.line, err_pos.column);
|
||||||
break;
|
break;
|
||||||
case ParseFile_EmptyFile:
|
case ParseFile_EmptyFile:
|
||||||
gb_printf_err("File contains no tokens");
|
error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gb_printf_err("\n");
|
|
||||||
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,6 +292,16 @@ void error(Token token, char *fmt, ...) {
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void error(TokenPos pos, char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
Token token = {};
|
||||||
|
token.pos = pos;
|
||||||
|
error_va(token, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void syntax_error(Token token, char *fmt, ...) {
|
void syntax_error(Token token, char *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
|
|||||||
Reference in New Issue
Block a user