mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-08 19:44:20 +00:00
@@ -1,8 +1,8 @@
|
||||
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 == nil && b != nil) ||
|
||||
@@ -17,47 +17,47 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
||||
}
|
||||
|
||||
switch x in a.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
y, ok := b.variant.(runtime.Type_Info_Named);
|
||||
case rt.Type_Info_Named:
|
||||
y, ok := b.variant.(rt.Type_Info_Named);
|
||||
if !ok do return false;
|
||||
return x.base == y.base;
|
||||
|
||||
case runtime.Type_Info_Integer:
|
||||
y, ok := b.variant.(runtime.Type_Info_Integer);
|
||||
case rt.Type_Info_Integer:
|
||||
y, ok := b.variant.(rt.Type_Info_Integer);
|
||||
if !ok do return false;
|
||||
return x.signed == y.signed;
|
||||
|
||||
case runtime.Type_Info_Rune:
|
||||
_, ok := b.variant.(runtime.Type_Info_Rune);
|
||||
case rt.Type_Info_Rune:
|
||||
_, ok := b.variant.(rt.Type_Info_Rune);
|
||||
return ok;
|
||||
|
||||
case runtime.Type_Info_Float:
|
||||
_, ok := b.variant.(runtime.Type_Info_Float);
|
||||
case rt.Type_Info_Float:
|
||||
_, ok := b.variant.(rt.Type_Info_Float);
|
||||
return ok;
|
||||
|
||||
case runtime.Type_Info_Complex:
|
||||
_, ok := b.variant.(runtime.Type_Info_Complex);
|
||||
case rt.Type_Info_Complex:
|
||||
_, ok := b.variant.(rt.Type_Info_Complex);
|
||||
return ok;
|
||||
|
||||
case runtime.Type_Info_String:
|
||||
_, ok := b.variant.(runtime.Type_Info_String);
|
||||
case rt.Type_Info_String:
|
||||
_, ok := b.variant.(rt.Type_Info_String);
|
||||
return ok;
|
||||
|
||||
case runtime.Type_Info_Boolean:
|
||||
_, ok := b.variant.(runtime.Type_Info_Boolean);
|
||||
case rt.Type_Info_Boolean:
|
||||
_, ok := b.variant.(rt.Type_Info_Boolean);
|
||||
return ok;
|
||||
|
||||
case runtime.Type_Info_Any:
|
||||
_, ok := b.variant.(runtime.Type_Info_Any);
|
||||
case rt.Type_Info_Any:
|
||||
_, ok := b.variant.(rt.Type_Info_Any);
|
||||
return ok;
|
||||
|
||||
case runtime.Type_Info_Pointer:
|
||||
y, ok := b.variant.(runtime.Type_Info_Pointer);
|
||||
case rt.Type_Info_Pointer:
|
||||
y, ok := b.variant.(rt.Type_Info_Pointer);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case runtime.Type_Info_Procedure:
|
||||
y, ok := b.variant.(runtime.Type_Info_Procedure);
|
||||
case rt.Type_Info_Procedure:
|
||||
y, ok := b.variant.(rt.Type_Info_Procedure);
|
||||
if !ok do return false;
|
||||
switch {
|
||||
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);
|
||||
|
||||
case runtime.Type_Info_Array:
|
||||
y, ok := b.variant.(runtime.Type_Info_Array);
|
||||
case rt.Type_Info_Array:
|
||||
y, ok := b.variant.(rt.Type_Info_Array);
|
||||
if !ok do return false;
|
||||
if x.count != y.count do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
y, ok := b.variant.(runtime.Type_Info_Dynamic_Array);
|
||||
case rt.Type_Info_Dynamic_Array:
|
||||
y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
y, ok := b.variant.(runtime.Type_Info_Slice);
|
||||
case rt.Type_Info_Slice:
|
||||
y, ok := b.variant.(rt.Type_Info_Slice);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case runtime.Type_Info_Tuple:
|
||||
y, ok := b.variant.(runtime.Type_Info_Tuple);
|
||||
case rt.Type_Info_Tuple:
|
||||
y, ok := b.variant.(rt.Type_Info_Tuple);
|
||||
if !ok do return false;
|
||||
if len(x.types) != len(y.types) do return false;
|
||||
for _, i in x.types {
|
||||
@@ -95,8 +95,8 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
||||
}
|
||||
return true;
|
||||
|
||||
case runtime.Type_Info_Struct:
|
||||
y, ok := b.variant.(runtime.Type_Info_Struct);
|
||||
case rt.Type_Info_Struct:
|
||||
y, ok := b.variant.(rt.Type_Info_Struct);
|
||||
if !ok do return false;
|
||||
switch {
|
||||
case len(x.types) != len(y.types),
|
||||
@@ -114,8 +114,8 @@ are_types_identical :: proc(a, b: ^runtime.Type_Info) -> bool {
|
||||
}
|
||||
return true;
|
||||
|
||||
case runtime.Type_Info_Union:
|
||||
y, ok := b.variant.(runtime.Type_Info_Union);
|
||||
case rt.Type_Info_Union:
|
||||
y, ok := b.variant.(rt.Type_Info_Union);
|
||||
if !ok 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;
|
||||
|
||||
case runtime.Type_Info_Enum:
|
||||
case rt.Type_Info_Enum:
|
||||
// NOTE(bill): Should be handled above
|
||||
return false;
|
||||
|
||||
case runtime.Type_Info_Map:
|
||||
y, ok := b.variant.(runtime.Type_Info_Map);
|
||||
case rt.Type_Info_Map:
|
||||
y, ok := b.variant.(rt.Type_Info_Map);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
|
||||
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
y, ok := b.variant.(runtime.Type_Info_Bit_Field);
|
||||
case rt.Type_Info_Bit_Field:
|
||||
y, ok := b.variant.(rt.Type_Info_Bit_Field);
|
||||
if !ok 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;
|
||||
switch i in runtime.type_info_base(info).variant {
|
||||
case runtime.Type_Info_Integer: return i.signed;
|
||||
case runtime.Type_Info_Float: return true;
|
||||
switch i in rt.type_info_base(info).variant {
|
||||
case rt.Type_Info_Integer: return i.signed;
|
||||
case rt.Type_Info_Float: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_integer :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_integer :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_rune :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_rune :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_float :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_float :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_complex :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_complex :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_any :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_any :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_string :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_string :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_boolean :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_boolean :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_pointer :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_pointer :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_procedure :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_procedure :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_array :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_array :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_dynamic_array :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_dynamic_map :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_slice :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_slice :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_tuple :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_tuple :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_struct :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_struct :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_raw_union :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_raw_union :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_union :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_union :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
is_enum :: proc(info: ^runtime.Type_Info) -> bool {
|
||||
is_enum :: proc(info: ^rt.Type_Info) -> bool {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package utf16
|
||||
|
||||
REPLACEMENT_CHAR :: '\uFFFD';
|
||||
MAX_RUNE :: '\U0010FFFF';
|
||||
REPLACEMENT_CHAR :: '\ufffd';
|
||||
MAX_RUNE :: '\U0010ffff';
|
||||
|
||||
_surr1 :: 0xd800;
|
||||
_surr2 :: 0xdc00;
|
||||
|
||||
1408
src/big_int.cpp
Normal file
1408
src/big_int.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -813,7 +813,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
if (e->Constant.value.kind != ExactValue_Integer) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
@@ -1257,33 +1257,44 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
|
||||
return true;
|
||||
}
|
||||
|
||||
i64 i = v.value_integer;
|
||||
u64 u = bit_cast<u64>(i);
|
||||
BigInt i = v.value_integer;
|
||||
|
||||
i64 bit_size = type_size_of(type);
|
||||
u64 umax = unsigned_integer_maxs[bit_size];
|
||||
i64 imin = signed_integer_mins[bit_size];
|
||||
i64 imax = signed_integer_maxs[bit_size];
|
||||
BigInt umax = {};
|
||||
BigInt imin = {};
|
||||
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) {
|
||||
case Basic_rune:
|
||||
case Basic_i8:
|
||||
case Basic_i16:
|
||||
case Basic_i32:
|
||||
case Basic_i64:
|
||||
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_u16:
|
||||
case Basic_u32:
|
||||
case Basic_u64:
|
||||
case Basic_uint:
|
||||
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:
|
||||
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)) {
|
||||
error(o->expr, "'%s' truncated to '%s'", a, b);
|
||||
} else {
|
||||
char buf[127] = {};
|
||||
String str = {};
|
||||
i64 i = o->value.value_integer;
|
||||
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));
|
||||
}
|
||||
gbAllocator ha = heap_allocator();
|
||||
String str = big_int_to_string(ha, &o->value.value_integer);
|
||||
defer (gb_free(ha, str.text));
|
||||
error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b);
|
||||
}
|
||||
} 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)) {
|
||||
gbString err_str = expr_to_string(node);
|
||||
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;
|
||||
}
|
||||
|
||||
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 (node != nullptr) {
|
||||
@@ -1638,8 +1651,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
|
||||
return;
|
||||
}
|
||||
|
||||
i64 amount = y_val.value_integer;
|
||||
if (amount > 128) {
|
||||
BigInt max_shift = {};
|
||||
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);
|
||||
error(node, "Shift amount too large: '%s'", 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->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)) {
|
||||
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);
|
||||
error(node, "Shift amount cannot be negative: '%s'", 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) {
|
||||
GB_ASSERT(node->kind == Ast_BinaryExpr);
|
||||
ast_node(be, BinaryExpr, node);
|
||||
GB_ASSERT(is_type_pointer(ptr->type));
|
||||
GB_ASSERT(is_type_integer(offset->type));
|
||||
GB_ASSERT(op == Token_Add || op == Token_Sub);
|
||||
// Operand check_ptr_addition(CheckerContext *c, TokenKind op, Operand *ptr, Operand *offset, Ast *node) {
|
||||
// GB_ASSERT(node->kind == Ast_BinaryExpr);
|
||||
// ast_node(be, BinaryExpr, node);
|
||||
// GB_ASSERT(is_type_pointer(ptr->type));
|
||||
// GB_ASSERT(is_type_integer(offset->type));
|
||||
// GB_ASSERT(op == Token_Add || op == Token_Sub);
|
||||
|
||||
Operand operand = {};
|
||||
operand.mode = Addressing_Value;
|
||||
operand.type = ptr->type;
|
||||
operand.expr = node;
|
||||
// Operand operand = {};
|
||||
// operand.mode = Addressing_Value;
|
||||
// operand.type = ptr->type;
|
||||
// operand.expr = node;
|
||||
|
||||
if (base_type(ptr->type) == t_rawptr) {
|
||||
gbString str = type_to_string(ptr->type);
|
||||
error(node, "Invalid pointer type for pointer arithmetic: '%s'", str);
|
||||
gb_string_free(str);
|
||||
operand.mode = Addressing_Invalid;
|
||||
return operand;
|
||||
}
|
||||
// if (base_type(ptr->type) == t_rawptr) {
|
||||
// gbString str = type_to_string(ptr->type);
|
||||
// error(node, "Invalid pointer type for pointer arithmetic: '%s'", str);
|
||||
// gb_string_free(str);
|
||||
// operand.mode = Addressing_Invalid;
|
||||
// return operand;
|
||||
// }
|
||||
|
||||
#if defined(NO_POINTER_ARITHMETIC)
|
||||
operand.mode = Addressing_Invalid;
|
||||
error(operand.expr, "Pointer arithmetic is not supported");
|
||||
return operand;
|
||||
#else
|
||||
// #if defined(NO_POINTER_ARITHMETIC)
|
||||
// operand.mode = Addressing_Invalid;
|
||||
// error(operand.expr, "Pointer arithmetic is not supported");
|
||||
// return operand;
|
||||
// #else
|
||||
|
||||
Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
|
||||
Type *elem = base_ptr->Pointer.elem;
|
||||
i64 elem_size = type_size_of(elem);
|
||||
// Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
|
||||
// Type *elem = base_ptr->Pointer.elem;
|
||||
// i64 elem_size = type_size_of(elem);
|
||||
|
||||
if (elem_size <= 0) {
|
||||
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);
|
||||
gb_string_free(str);
|
||||
operand.mode = Addressing_Invalid;
|
||||
return operand;
|
||||
}
|
||||
// if (elem_size <= 0) {
|
||||
// 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);
|
||||
// gb_string_free(str);
|
||||
// operand.mode = Addressing_Invalid;
|
||||
// return operand;
|
||||
// }
|
||||
|
||||
if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
|
||||
i64 ptr_val = ptr->value.value_pointer;
|
||||
i64 offset_val = exact_value_to_integer(offset->value).value_integer;
|
||||
i64 new_ptr_val = ptr_val;
|
||||
if (op == Token_Add) {
|
||||
new_ptr_val += elem_size*offset_val;
|
||||
} else {
|
||||
new_ptr_val -= elem_size*offset_val;
|
||||
}
|
||||
operand.mode = Addressing_Constant;
|
||||
operand.value = exact_value_pointer(new_ptr_val);
|
||||
}
|
||||
// if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
|
||||
// i64 ptr_val = ptr->value.value_pointer;
|
||||
// i64 offset_val = exact_value_to_integer(offset->value).value_integer;
|
||||
// i64 new_ptr_val = ptr_val;
|
||||
// if (op == Token_Add) {
|
||||
// new_ptr_val += elem_size*offset_val;
|
||||
// } else {
|
||||
// new_ptr_val -= elem_size*offset_val;
|
||||
// }
|
||||
// operand.mode = Addressing_Constant;
|
||||
// operand.value = exact_value_pointer(new_ptr_val);
|
||||
// }
|
||||
|
||||
return operand;
|
||||
#endif
|
||||
}
|
||||
// return operand;
|
||||
// #endif
|
||||
// }
|
||||
|
||||
|
||||
|
||||
@@ -2030,24 +2045,24 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (op.kind == Token_Add || op.kind == Token_Sub) {
|
||||
if (is_type_pointer(x->type) && is_type_integer(y->type)) {
|
||||
*x = check_ptr_addition(c, op.kind, x, y, node);
|
||||
return;
|
||||
} else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
|
||||
if (op.kind == Token_Sub) {
|
||||
gbString lhs = expr_to_string(x->expr);
|
||||
gbString rhs = expr_to_string(y->expr);
|
||||
error(node, "Invalid pointer arithmetic, did you mean '%s %.*s %s'?", rhs, LIT(op.string), lhs);
|
||||
gb_string_free(rhs);
|
||||
gb_string_free(lhs);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
*x = check_ptr_addition(c, op.kind, y, x, node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if (op.kind == Token_Add || op.kind == Token_Sub) {
|
||||
// if (is_type_pointer(x->type) && is_type_integer(y->type)) {
|
||||
// *x = check_ptr_addition(c, op.kind, x, y, node);
|
||||
// return;
|
||||
// } else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
|
||||
// if (op.kind == Token_Sub) {
|
||||
// gbString lhs = expr_to_string(x->expr);
|
||||
// gbString rhs = expr_to_string(y->expr);
|
||||
// error(node, "Invalid pointer arithmetic, did you mean '%s %.*s %s'?", rhs, LIT(op.string), lhs);
|
||||
// gb_string_free(rhs);
|
||||
// gb_string_free(lhs);
|
||||
// x->mode = Addressing_Invalid;
|
||||
// return;
|
||||
// }
|
||||
// *x = check_ptr_addition(c, op.kind, y, x, node);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
convert_to_typed(c, x, y->type);
|
||||
if (x->mode == Addressing_Invalid) {
|
||||
@@ -2108,7 +2123,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node) {
|
||||
bool fail = false;
|
||||
switch (y->value.kind) {
|
||||
case ExactValue_Integer:
|
||||
if (y->value.value_integer == 0 ) {
|
||||
if (big_int_is_zero(&y->value.value_integer)) {
|
||||
fail = true;
|
||||
}
|
||||
break;
|
||||
@@ -2246,7 +2261,7 @@ void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_typ
|
||||
char *extra_text = "";
|
||||
|
||||
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
|
||||
// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
|
||||
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 &&
|
||||
(c->stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
|
||||
i64 i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i < 0) {
|
||||
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i.neg) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' cannot be a negative value", 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 (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;
|
||||
if (open_range) {
|
||||
out_of_bounds = i > max_count;
|
||||
out_of_bounds = v > max_count;
|
||||
} else {
|
||||
out_of_bounds = i >= max_count;
|
||||
out_of_bounds = v >= max_count;
|
||||
}
|
||||
if (v < 0) {
|
||||
out_of_bounds = true;
|
||||
}
|
||||
|
||||
if (out_of_bounds) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
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;
|
||||
}
|
||||
|
||||
if (op.value.value_integer < 0) {
|
||||
if (op.value.value_integer.neg) {
|
||||
error(op.expr, "Negative 'swizzle' index");
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
@@ -3804,7 +3829,7 @@ break;
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
switch (operand->value.kind) {
|
||||
case ExactValue_Integer:
|
||||
operand->value.value_integer = gb_abs(operand->value.value_integer);
|
||||
operand->value.value_integer.neg = false;
|
||||
break;
|
||||
case ExactValue_Float:
|
||||
operand->value.value_float = gb_abs(operand->value.value_float);
|
||||
|
||||
@@ -260,18 +260,17 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
||||
if (rhs->mode == Addressing_Constant) {
|
||||
ExactValue v = exact_value_to_integer(rhs->value);
|
||||
if (v.kind == ExactValue_Integer) {
|
||||
i64 i = v.value_integer;
|
||||
u64 u = bit_cast<u64>(i);
|
||||
u64 umax = ~cast(u64)0ull;
|
||||
if (lhs_bits < 64) {
|
||||
umax = (1ull << cast(u64)lhs_bits) - 1ull;
|
||||
}
|
||||
i64 imax = 1ll << (cast(i64)lhs_bits-1ll);
|
||||
BigInt i = v.value_integer;
|
||||
if (!i.neg) {
|
||||
u64 imax_ = ~cast(u64)0ull;
|
||||
if (lhs_bits < 64) {
|
||||
imax_ = (1ull << cast(u64)lhs_bits) - 1ull;
|
||||
}
|
||||
|
||||
bool ok = !(u < 0 || u > umax);
|
||||
|
||||
if (ok) {
|
||||
return rhs->type;
|
||||
BigInt imax = big_int_make_u64(imax_);
|
||||
if (big_int_cmp(&i, &imax) > 0) {
|
||||
return rhs->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (is_type_integer(rhs->type)) {
|
||||
|
||||
@@ -136,7 +136,15 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
Type *type = base_type(o.type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
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)) {
|
||||
error(node, "#align must be a power of 2, got %lld", align);
|
||||
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");
|
||||
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) {
|
||||
error(value, "Bit field's bit size must be within the range 1...64, got %lld", cast(long long)bits_);
|
||||
continue;
|
||||
@@ -1601,11 +1609,22 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
Type *type = base_type(o->type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o->value.kind == ExactValue_Integer) {
|
||||
i64 count = o->value.value_integer;
|
||||
if (count >= 0) {
|
||||
return count;
|
||||
BigInt count = o->value.value_integer;
|
||||
if (o->value.value_integer.neg) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#define GB_IMPLEMENTATION
|
||||
#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) {
|
||||
char buf[200] = {0};
|
||||
char buf[32] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
bool negative = false;
|
||||
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 "ptr_set.cpp"
|
||||
|
||||
@@ -33,7 +33,7 @@ struct ExactValue {
|
||||
union {
|
||||
bool value_bool;
|
||||
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;
|
||||
i64 value_pointer;
|
||||
Complex128 value_complex;
|
||||
@@ -54,8 +54,14 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
return hash_integer(u64(v.value_bool));
|
||||
case ExactValue_String:
|
||||
return hash_string(v.value_string);
|
||||
case ExactValue_Integer:
|
||||
return hash_integer(u64(v.value_integer));
|
||||
case ExactValue_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:
|
||||
return hash_f64(v.value_float);
|
||||
case ExactValue_Pointer:
|
||||
@@ -94,13 +100,13 @@ ExactValue exact_value_string(String string) {
|
||||
|
||||
ExactValue exact_value_i64(i64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
result.value_integer = i;
|
||||
big_int_from_i64(&result.value_integer, i);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_u64(u64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
result.value_integer = i64(i);
|
||||
big_int_from_u64(&result.value_integer, i);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -293,7 +299,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
||||
ExactValue exact_value_to_float(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
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:
|
||||
return v;
|
||||
}
|
||||
@@ -304,7 +310,7 @@ ExactValue exact_value_to_float(ExactValue v) {
|
||||
ExactValue exact_value_to_complex(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
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:
|
||||
return exact_value_complex(v.value_float, 0);
|
||||
case ExactValue_Complex:
|
||||
@@ -371,8 +377,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
||||
case ExactValue_Invalid:
|
||||
return v;
|
||||
case ExactValue_Integer: {
|
||||
ExactValue i = v;
|
||||
i.value_integer = -i.value_integer;
|
||||
ExactValue i = {ExactValue_Integer};
|
||||
big_int_neg(&i.value_integer, &v.value_integer);
|
||||
return i;
|
||||
}
|
||||
case ExactValue_Float: {
|
||||
@@ -390,24 +396,18 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
||||
}
|
||||
|
||||
case Token_Xor: {
|
||||
i64 i = 0;
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid:
|
||||
return v;
|
||||
case ExactValue_Integer:
|
||||
i = ~v.value_integer;
|
||||
break;
|
||||
case ExactValue_Integer: {
|
||||
GB_ASSERT(precision != 0);
|
||||
ExactValue i = {ExactValue_Integer};
|
||||
bit_int_not(&i.value_integer, &v.value_integer, precision, !is_unsigned);
|
||||
return i;
|
||||
}
|
||||
default:
|
||||
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: {
|
||||
@@ -472,10 +472,10 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
return;
|
||||
case ExactValue_Float:
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
@@ -513,28 +513,29 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
break;
|
||||
|
||||
case ExactValue_Integer: {
|
||||
i64 a = x.value_integer;
|
||||
i64 b = y.value_integer;
|
||||
i64 c = 0ll;
|
||||
BigInt const *a = &x.value_integer;
|
||||
BigInt const *b = &y.value_integer;
|
||||
BigInt c = {};
|
||||
switch (op) {
|
||||
case Token_Add: c = a + b; break;
|
||||
case Token_Sub: c = a - b; break;
|
||||
case Token_Mul: c = a * b; break;
|
||||
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
|
||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = a % b; break;
|
||||
case Token_ModMod: c = ((a % b) + b) % b; break;
|
||||
case Token_And: c = a & b; break;
|
||||
case Token_Or: c = a | b; break;
|
||||
case Token_Xor: c = a ^ b; break;
|
||||
case Token_AndNot: c = a & (~b); break;
|
||||
case Token_Shl: c = a << b; break;
|
||||
case Token_Shr: c = a >> b; break;
|
||||
case Token_Add: big_int_add(&c, a, b); break;
|
||||
case Token_Sub: big_int_sub(&c, a, b); break;
|
||||
case Token_Mul: big_int_mul(&c, a, b); break;
|
||||
case Token_Quo: return exact_value_float(fmod(big_int_to_f64(a), big_int_to_f64(b)));
|
||||
case Token_QuoEq: big_int_quo(&c, a, b); break; // NOTE(bill): Integer division
|
||||
case Token_Mod: big_int_rem(&c, a, b); break;
|
||||
case Token_ModMod: big_int_euclidean_mod(&c, a, b); break;
|
||||
case Token_And: big_int_and(&c, a, b); break;
|
||||
case Token_Or: big_int_or(&c, a, b); break;
|
||||
case Token_Xor: big_int_xor(&c, a, b); break;
|
||||
case Token_AndNot: big_int_and_not(&c, a, b); break;
|
||||
case Token_Shl: big_int_shl(&c, a, b); break;
|
||||
case Token_Shr: big_int_shr(&c, a, b); break;
|
||||
default: goto error;
|
||||
}
|
||||
|
||||
return exact_value_i64(c);
|
||||
break;
|
||||
ExactValue res = {ExactValue_Integer};
|
||||
res.value_integer = c;
|
||||
return res;
|
||||
}
|
||||
|
||||
case ExactValue_Float: {
|
||||
@@ -638,15 +639,14 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
break;
|
||||
|
||||
case ExactValue_Integer: {
|
||||
i64 a = x.value_integer;
|
||||
i64 b = y.value_integer;
|
||||
i32 cmp = big_int_cmp(&x.value_integer, &y.value_integer);
|
||||
switch (op) {
|
||||
case Token_CmpEq: return a == b;
|
||||
case Token_NotEq: return a != b;
|
||||
case Token_Lt: return a < b;
|
||||
case Token_LtEq: return a <= b;
|
||||
case Token_Gt: return a > b;
|
||||
case Token_GtEq: return a >= b;
|
||||
case Token_CmpEq: return cmp == 0;
|
||||
case Token_NotEq: return cmp != 0;
|
||||
case Token_Lt: return cmp < 0;
|
||||
case Token_LtEq: return cmp <= 0;
|
||||
case Token_Gt: return cmp > 0;
|
||||
case Token_GtEq: return cmp >= 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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(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;
|
||||
|
||||
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));
|
||||
GB_ASSERT_MSG(is_type_integer(selector_type), "%s", type_to_string(selector_type));
|
||||
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);
|
||||
GB_ASSERT(sel.entity != nullptr);
|
||||
|
||||
@@ -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);
|
||||
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) {
|
||||
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: {
|
||||
if (is_type_pointer(type)) {
|
||||
if (value.value_integer == 0) {
|
||||
if (big_int_is_zero(&value.value_integer)) {
|
||||
ir_write_str_lit(f, "null");
|
||||
} else {
|
||||
ir_write_str_lit(f, "inttoptr (");
|
||||
ir_print_type(f, m, t_int);
|
||||
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_print_type(f, m, t_rawptr);
|
||||
ir_write_str_lit(f, ")");
|
||||
}
|
||||
} else {
|
||||
ir_write_i64(f, value.value_integer);
|
||||
ir_write_big_int(f, value.value_integer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "timings.cpp"
|
||||
#include "build_settings.cpp"
|
||||
#include "tokenizer.cpp"
|
||||
#include "big_int.cpp"
|
||||
#include "exact_value.cpp"
|
||||
|
||||
#include "parser.hpp"
|
||||
@@ -408,7 +409,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
}
|
||||
case BuildFlag_OptimizationLevel:
|
||||
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;
|
||||
case BuildFlag_ShowTimings:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
@@ -416,7 +417,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
break;
|
||||
case BuildFlag_ThreadCount: {
|
||||
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) {
|
||||
gb_printf_err("%.*s expected a positive non-zero number, got %.*s\n", LIT(name), LIT(param));
|
||||
build_context.thread_count = 0;
|
||||
@@ -716,6 +717,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
init_string_buffer_memory();
|
||||
init_global_error_collector();
|
||||
global_big_int_init();
|
||||
arena_init(&global_ast_arena, heap_allocator());
|
||||
|
||||
array_init(&library_collections, heap_allocator());
|
||||
|
||||
107
src/parser.cpp
107
src/parser.cpp
@@ -3470,22 +3470,6 @@ Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
|
||||
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) {
|
||||
CommentGroup *docs = f->lead_comment;
|
||||
Token token = expect_token(f, Token_foreign);
|
||||
@@ -3668,17 +3652,6 @@ Ast *parse_stmt(AstFile *f) {
|
||||
Token name = expect_token(f, Token_Ident);
|
||||
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") {
|
||||
s = parse_stmt(f);
|
||||
s->stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
@@ -3734,9 +3707,7 @@ Ast *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
}
|
||||
|
||||
syntax_error(token,
|
||||
"Expected a statement, got '%.*s'",
|
||||
LIT(token_strings[token.kind]));
|
||||
syntax_error(token, "Expected a statement, got '%.*s'", LIT(token_strings[token.kind]));
|
||||
fix_advance_to_next_stmt(f);
|
||||
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) {
|
||||
if (pos.line != 0) {
|
||||
gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
defer (gb_mutex_unlock(&global_error_collector.mutex));
|
||||
global_error_collector.count++;
|
||||
|
||||
|
||||
switch (rd_err) {
|
||||
case ReadDirectory_InvalidPath:
|
||||
gb_printf_err("Invalid path: %.*s\n", LIT(rel_path));
|
||||
return false;
|
||||
|
||||
case ReadDirectory_NotExists:
|
||||
gb_printf_err("Path does not exist: %.*s\n", LIT(rel_path));
|
||||
return false;
|
||||
|
||||
case ReadDirectory_NotDir:
|
||||
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;
|
||||
}
|
||||
switch (rd_err) {
|
||||
case ReadDirectory_InvalidPath:
|
||||
error(pos, "Invalid path: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
case ReadDirectory_NotExists:
|
||||
error(pos, "Path does not exist: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
case ReadDirectory_Permission:
|
||||
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||
return false;
|
||||
case ReadDirectory_NotDir:
|
||||
error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
case ReadDirectory_Empty:
|
||||
error(pos, "Empty directory: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
case ReadDirectory_Unknown:
|
||||
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
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;
|
||||
case ParseFile_Permission:
|
||||
gb_printf_err("File permissions problem");
|
||||
error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
gb_printf_err("\n");
|
||||
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -292,6 +292,16 @@ void error(Token token, char *fmt, ...) {
|
||||
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, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
Reference in New Issue
Block a user