mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-28 17:04:34 +00:00
Fix decimal.odin assignment bug
This commit is contained in:
@@ -29,13 +29,13 @@ decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
|
||||
|
||||
w := 0;
|
||||
if a.decimal_point <= 0 {
|
||||
buf[w] = '0'; w+=1;
|
||||
buf[w] = '.'; w+=1;
|
||||
buf[w] = '0'; w += 1;
|
||||
buf[w] = '.'; w += 1;
|
||||
w += digit_zero(buf[w .. w-a.decimal_point]);
|
||||
w += copy(buf[w..], a.digits[0..a.count]);
|
||||
} else if a.decimal_point < a.count {
|
||||
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
||||
buf[w] = '.'; w+=1;
|
||||
buf[w] = '.'; w += 1;
|
||||
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
||||
} else {
|
||||
w += copy(buf[w..], a.digits[0..a.count]);
|
||||
@@ -63,14 +63,15 @@ assign :: proc(a: ^Decimal, i: u64) {
|
||||
j := i/10;
|
||||
i -= 10*j;
|
||||
buf[n] = u8('0'+i);
|
||||
n+=1;
|
||||
n += 1;
|
||||
i = j;
|
||||
}
|
||||
|
||||
a.count = 0;
|
||||
for n -= 1; n >= 0; n -= 1 {
|
||||
for n >= 0 {
|
||||
a.digits[a.count] = buf[n];
|
||||
a.count+=1;
|
||||
a.count += 1;
|
||||
n -= 1;
|
||||
}
|
||||
a.decimal_point = a.count;
|
||||
trim(a);
|
||||
@@ -83,7 +84,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
w := 0; // write index
|
||||
|
||||
n: uint;
|
||||
for ; n>>k == 0; r+=1 {
|
||||
for ; n>>k == 0; r += 1 {
|
||||
if r >= a.count {
|
||||
if n == 0 {
|
||||
// Just in case
|
||||
@@ -92,7 +93,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
}
|
||||
for n>>k == 0 {
|
||||
n = n * 10;
|
||||
r+=1;
|
||||
r += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -103,12 +104,12 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
|
||||
mask: uint = (1<<k) - 1;
|
||||
|
||||
for ; r < a.count; r+=1 {
|
||||
for ; r < a.count; r += 1 {
|
||||
c := uint(a.digits[r]);
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
a.digits[w] = u8('0' + dig);
|
||||
w+=1;
|
||||
w += 1;
|
||||
n = n*10 + c - '0';
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
n &= mask;
|
||||
if w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + dig);
|
||||
w+=1;
|
||||
w += 1;
|
||||
} else if dig > 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
@@ -215,7 +216,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
|
||||
|
||||
for i := nd-1; i >= 0; i -= 1 {
|
||||
if c := a.digits[i]; c < '9' {
|
||||
a.digits[i]+=1;
|
||||
a.digits[i] += 1;
|
||||
a.count = i+1;
|
||||
return;
|
||||
}
|
||||
@@ -224,7 +225,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
|
||||
// Number is just 9s
|
||||
a.digits[0] = '1';
|
||||
a.count = 1;
|
||||
a.decimal_point+=1;
|
||||
a.decimal_point += 1;
|
||||
}
|
||||
|
||||
round_down :: proc(a: ^Decimal, nd: int) {
|
||||
@@ -249,7 +250,7 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
|
||||
n *= 10;
|
||||
}
|
||||
if can_round_up(a, a.decimal_point) {
|
||||
n+=1;
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice,
|
||||
// integer, padded with zeros when needed
|
||||
if digs.decimal_point > 0 {
|
||||
m := min(digs.count, digs.decimal_point);
|
||||
append(&buf, ...digs.digits[..m]);
|
||||
append(&buf, ...digs.digits[0..m]);
|
||||
for ; m < digs.decimal_point; m += 1 {
|
||||
append(&buf, '0');
|
||||
}
|
||||
@@ -320,7 +320,6 @@ format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice,
|
||||
append(&buf, c);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
case 'e', 'E':
|
||||
|
||||
@@ -3324,7 +3324,6 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
|
||||
}
|
||||
if (out_value) *out_value = v;
|
||||
|
||||
|
||||
switch (type->Basic.kind) {
|
||||
// case Basic_f16:
|
||||
case Basic_f32:
|
||||
@@ -3333,6 +3332,8 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
|
||||
|
||||
case Basic_UntypedFloat:
|
||||
return true;
|
||||
|
||||
default: GB_PANIC("Compiler error: Unknown float type!"); break;
|
||||
}
|
||||
} else if (is_type_complex(type)) {
|
||||
ExactValue v = exact_value_to_complex(in_value);
|
||||
@@ -3353,6 +3354,8 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
|
||||
} break;
|
||||
case Basic_UntypedComplex:
|
||||
return true;
|
||||
|
||||
default: GB_PANIC("Compiler error: Unknown complex type!"); break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
194
src/checker.cpp
194
src/checker.cpp
@@ -327,6 +327,90 @@ void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
|
||||
|
||||
|
||||
|
||||
struct ImportGraphNode;
|
||||
typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
|
||||
|
||||
void import_graph_node_set_destroy(ImportGraphNodeSet *s) {
|
||||
if (s->hashes.data != nullptr) {
|
||||
ptr_set_destroy(s);
|
||||
}
|
||||
}
|
||||
|
||||
void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNode *n) {
|
||||
if (s->hashes.data == nullptr) {
|
||||
ptr_set_init(s, heap_allocator());
|
||||
}
|
||||
ptr_set_add(s, n);
|
||||
}
|
||||
|
||||
bool import_graph_node_set_exists(ImportGraphNodeSet *s, ImportGraphNode *n) {
|
||||
return ptr_set_exists(s, n);
|
||||
}
|
||||
|
||||
void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) {
|
||||
ptr_set_remove(s, n);
|
||||
}
|
||||
|
||||
struct ImportGraphNode {
|
||||
Scope * scope;
|
||||
String path;
|
||||
isize file_id;
|
||||
ImportGraphNodeSet pred;
|
||||
ImportGraphNodeSet succ;
|
||||
isize index; // Index in array/queue
|
||||
isize dep_count;
|
||||
};
|
||||
|
||||
ImportGraphNode *import_graph_node_create(gbAllocator a, Scope *scope) {
|
||||
ImportGraphNode *n = gb_alloc_item(a, ImportGraphNode);
|
||||
n->scope = scope;
|
||||
n->path = scope->file->tokenizer.fullpath;
|
||||
n->file_id = scope->file->id;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void import_graph_node_destroy(ImportGraphNode *n, gbAllocator a) {
|
||||
import_graph_node_set_destroy(&n->pred);
|
||||
import_graph_node_set_destroy(&n->succ);
|
||||
gb_free(a, n);
|
||||
}
|
||||
|
||||
|
||||
int import_graph_node_cmp(ImportGraphNode **data, isize i, isize j) {
|
||||
ImportGraphNode *x = data[i];
|
||||
ImportGraphNode *y = data[j];
|
||||
GB_ASSERT(x != y);
|
||||
|
||||
GB_ASSERT(x->scope != y->scope);
|
||||
|
||||
bool xg = x->scope->is_global;
|
||||
bool yg = y->scope->is_global;
|
||||
if (xg != yg) return xg ? -1 : +1;
|
||||
if (x->dep_count < y->dep_count) return -1;
|
||||
if (x->dep_count > y->dep_count) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void import_graph_node_swap(ImportGraphNode **data, isize i, isize j) {
|
||||
ImportGraphNode *x = data[i];
|
||||
ImportGraphNode *y = data[j];
|
||||
data[i] = y;
|
||||
data[j] = x;
|
||||
x->index = j;
|
||||
y->index = i;
|
||||
}
|
||||
|
||||
GB_COMPARE_PROC(ast_node_cmp) {
|
||||
AstNode *x = *cast(AstNode **)a;
|
||||
AstNode *y = *cast(AstNode **)b;
|
||||
Token i = ast_node_token(x);
|
||||
Token j = ast_node_token(y);
|
||||
return token_pos_cmp(i.pos, j.pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct CheckerContext {
|
||||
Scope * file_scope;
|
||||
Scope * scope;
|
||||
@@ -378,6 +462,7 @@ struct Checker {
|
||||
// NOTE(bill): Procedures to check
|
||||
Map<ProcedureInfo> procs; // Key: DeclInfo *
|
||||
Map<Scope *> file_scopes; // Key: String (fullpath)
|
||||
Array<ImportGraphNode *> file_order;
|
||||
|
||||
Pool pool;
|
||||
gbAllocator allocator;
|
||||
@@ -899,6 +984,8 @@ void init_checker(Checker *c, Parser *parser) {
|
||||
|
||||
map_init(&c->file_scopes, heap_allocator());
|
||||
ptr_set_init(&c->checked_files, heap_allocator());
|
||||
|
||||
array_init(&c->file_order, heap_allocator(), c->parser->files.count);
|
||||
}
|
||||
|
||||
void destroy_checker(Checker *c) {
|
||||
@@ -912,6 +999,7 @@ void destroy_checker(Checker *c) {
|
||||
|
||||
map_destroy(&c->file_scopes);
|
||||
ptr_set_destroy(&c->checked_files);
|
||||
array_free(&c->file_order);
|
||||
}
|
||||
|
||||
|
||||
@@ -2185,88 +2273,6 @@ String path_to_entity_name(String name, String fullpath) {
|
||||
|
||||
|
||||
|
||||
struct ImportGraphNode;
|
||||
typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
|
||||
|
||||
void import_graph_node_set_destroy(ImportGraphNodeSet *s) {
|
||||
if (s->hashes.data != nullptr) {
|
||||
ptr_set_destroy(s);
|
||||
}
|
||||
}
|
||||
|
||||
void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNode *n) {
|
||||
if (s->hashes.data == nullptr) {
|
||||
ptr_set_init(s, heap_allocator());
|
||||
}
|
||||
ptr_set_add(s, n);
|
||||
}
|
||||
|
||||
bool import_graph_node_set_exists(ImportGraphNodeSet *s, ImportGraphNode *n) {
|
||||
return ptr_set_exists(s, n);
|
||||
}
|
||||
|
||||
void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) {
|
||||
ptr_set_remove(s, n);
|
||||
}
|
||||
|
||||
struct ImportGraphNode {
|
||||
Scope * scope;
|
||||
String path;
|
||||
isize file_id;
|
||||
ImportGraphNodeSet pred;
|
||||
ImportGraphNodeSet succ;
|
||||
isize index; // Index in array/queue
|
||||
isize dep_count;
|
||||
};
|
||||
|
||||
ImportGraphNode *import_graph_node_create(gbAllocator a, Scope *scope) {
|
||||
ImportGraphNode *n = gb_alloc_item(a, ImportGraphNode);
|
||||
n->scope = scope;
|
||||
n->path = scope->file->tokenizer.fullpath;
|
||||
n->file_id = scope->file->id;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void import_graph_node_destroy(ImportGraphNode *n, gbAllocator a) {
|
||||
import_graph_node_set_destroy(&n->pred);
|
||||
import_graph_node_set_destroy(&n->succ);
|
||||
gb_free(a, n);
|
||||
}
|
||||
|
||||
|
||||
int import_graph_node_cmp(ImportGraphNode **data, isize i, isize j) {
|
||||
ImportGraphNode *x = data[i];
|
||||
ImportGraphNode *y = data[j];
|
||||
GB_ASSERT(x != y);
|
||||
|
||||
GB_ASSERT(x->scope != y->scope);
|
||||
|
||||
bool xg = x->scope->is_global;
|
||||
bool yg = y->scope->is_global;
|
||||
if (xg != yg) return xg ? -1 : +1;
|
||||
if (x->dep_count < y->dep_count) return -1;
|
||||
if (x->dep_count > y->dep_count) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void import_graph_node_swap(ImportGraphNode **data, isize i, isize j) {
|
||||
ImportGraphNode *x = data[i];
|
||||
ImportGraphNode *y = data[j];
|
||||
data[i] = y;
|
||||
data[j] = x;
|
||||
x->index = j;
|
||||
y->index = i;
|
||||
}
|
||||
|
||||
GB_COMPARE_PROC(ast_node_cmp) {
|
||||
AstNode *x = *cast(AstNode **)a;
|
||||
AstNode *y = *cast(AstNode **)b;
|
||||
Token i = ast_node_token(x);
|
||||
Token j = ast_node_token(y);
|
||||
return token_pos_cmp(i.pos, j.pos);
|
||||
}
|
||||
|
||||
|
||||
void add_import_dependency_node(Checker *c, AstNode *decl, Map<ImportGraphNode *> *M) {
|
||||
Scope *parent_file_scope = decl->file->scope;
|
||||
@@ -2818,10 +2824,6 @@ void check_import_entities(Checker *c) {
|
||||
ptr_set_init(&emitted, heap_allocator());
|
||||
defer (ptr_set_destroy(&emitted));
|
||||
|
||||
Array<ImportGraphNode *> file_order = {};
|
||||
array_init(&file_order, heap_allocator());
|
||||
defer (array_free(&file_order));
|
||||
|
||||
while (pq.queue.count > 0) {
|
||||
ImportGraphNode *n = priority_queue_pop(&pq);
|
||||
|
||||
@@ -2844,12 +2846,10 @@ void check_import_entities(Checker *c) {
|
||||
Token token = mt(s);
|
||||
error(token, "Cyclic importation of `%.*s`", LIT(token.string));
|
||||
for (isize i = path.count-1; i >= 0; i--) {
|
||||
token = mt(s);
|
||||
error(token, "\t`%.*s` refers to", LIT(token.string));
|
||||
gb_printf_err("\t`%.*s` refers to", LIT(token.string));
|
||||
s = path[i];
|
||||
}
|
||||
token = mt(s);
|
||||
error(token, "\t`%.*s`", LIT(token.string));
|
||||
gb_printf_err("\t`%.*s`", LIT(token.string));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2869,7 +2869,7 @@ void check_import_entities(Checker *c) {
|
||||
}
|
||||
ptr_set_add(&emitted, s);
|
||||
|
||||
array_add(&file_order, n);
|
||||
array_add(&c->file_order, n);
|
||||
}
|
||||
|
||||
for_array(file_index, c->parser->files) {
|
||||
@@ -2880,16 +2880,16 @@ void check_import_entities(Checker *c) {
|
||||
}
|
||||
}
|
||||
|
||||
// for_array(file_index, file_order) {
|
||||
// ImportGraphNode *node = file_order[file_index];
|
||||
// for_array(file_index, c->file_order) {
|
||||
// ImportGraphNode *node = c->file_order[file_index];
|
||||
// AstFile *f = node->scope->file;
|
||||
// gb_printf_err("--- %.*s\n", LIT(f->fullpath));
|
||||
// }
|
||||
|
||||
for (;;) {
|
||||
bool new_files = false;
|
||||
for_array(file_index, file_order) {
|
||||
ImportGraphNode *node = file_order[file_index];
|
||||
for_array(file_index, c->file_order) {
|
||||
ImportGraphNode *node = c->file_order[file_index];
|
||||
AstFile *f = node->scope->file;
|
||||
|
||||
if (!ptr_set_exists(&c->checked_files, f)) {
|
||||
@@ -2905,8 +2905,8 @@ void check_import_entities(Checker *c) {
|
||||
if (new_files) break;
|
||||
}
|
||||
|
||||
for (isize file_index = 0; file_index < file_order.count; file_index += 1) {
|
||||
ImportGraphNode *node = file_order[file_index];
|
||||
for (isize file_index = 0; file_index < c->file_order.count; file_index += 1) {
|
||||
ImportGraphNode *node = c->file_order[file_index];
|
||||
AstFile *f = node->scope->file;
|
||||
|
||||
if (!ptr_set_exists(&c->checked_files, f)) {
|
||||
|
||||
Reference in New Issue
Block a user