mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
Amend allocation procedures with caller location; Compound literals missing type can determine type in certain cases.
This commit is contained in:
+39
-28
@@ -290,32 +290,32 @@ __check_context :: proc() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr {
|
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr {
|
||||||
a := context.allocator;
|
a := context.allocator;
|
||||||
return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0);
|
return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr) {
|
free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, location := #caller_location) {
|
||||||
if ptr == nil do return;
|
if ptr == nil do return;
|
||||||
if a.procedure == nil do return;
|
if a.procedure == nil do return;
|
||||||
a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0);
|
a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_ptr :: inline proc(ptr: rawptr) do free_ptr_with_allocator(context.allocator, ptr);
|
free_ptr :: inline proc(ptr: rawptr, location := #caller_location) do free_ptr_with_allocator(context.allocator, ptr);
|
||||||
|
|
||||||
free_all :: inline proc() {
|
free_all :: inline proc(location := #caller_location) {
|
||||||
a := context.allocator;
|
a := context.allocator;
|
||||||
a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0);
|
a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr {
|
resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr {
|
||||||
a := context.allocator;
|
a := context.allocator;
|
||||||
return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0);
|
return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
copy :: proc(dst, src: $T/[]$E) -> int {
|
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||||
n := max(0, min(len(dst), len(src)));
|
n := max(0, min(len(dst), len(src)));
|
||||||
if n > 0 do __mem_copy(&dst[0], &src[0], n*size_of(E));
|
if n > 0 do __mem_copy(&dst[0], &src[0], n*size_of(E));
|
||||||
return n;
|
return n;
|
||||||
@@ -406,7 +406,7 @@ clear :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
|||||||
entries.len = 0;
|
entries.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
reserve :: proc(array: ^$T/[dynamic]$E, capacity: int) -> bool {
|
reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, location := #caller_location) -> bool {
|
||||||
if array == nil do return false;
|
if array == nil do return false;
|
||||||
a := cast(^raw.Dynamic_Array)array;
|
a := cast(^raw.Dynamic_Array)array;
|
||||||
|
|
||||||
@@ -421,7 +421,10 @@ reserve :: proc(array: ^$T/[dynamic]$E, capacity: int) -> bool {
|
|||||||
new_size := capacity * size_of(E);
|
new_size := capacity * size_of(E);
|
||||||
allocator := a.allocator;
|
allocator := a.allocator;
|
||||||
|
|
||||||
new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, align_of(E), a.data, old_size, 0);
|
new_data := allocator.procedure(
|
||||||
|
allocator.data, Allocator_Mode.Resize, new_size, align_of(E),
|
||||||
|
a.data, old_size, 0, location,
|
||||||
|
);
|
||||||
if new_data == nil do return false;
|
if new_data == nil do return false;
|
||||||
|
|
||||||
a.data = new_data;
|
a.data = new_data;
|
||||||
@@ -490,25 +493,33 @@ delete :: proc(m: ^$T/map[$K]$V, key: K) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
new :: inline proc(T: type) -> ^T {
|
new :: inline proc(T: type, location := #caller_location) -> ^T {
|
||||||
ptr := cast(^T)alloc(size_of(T), align_of(T));
|
ptr := cast(^T)alloc(size_of(T), align_of(T), location);
|
||||||
ptr^ = T{};
|
ptr^ = T{};
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
new_clone :: inline proc(data: $T) -> ^T {
|
new_clone :: inline proc(data: $T, location := #caller_location) -> ^T {
|
||||||
ptr := cast(^T)alloc(size_of(T), align_of(T));
|
ptr := cast(^T)alloc(size_of(T), align_of(T), location);
|
||||||
ptr^ = data;
|
ptr^ = data;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
free :: proc(ptr: rawptr) do free_ptr(ptr);
|
free :: proc(ptr: rawptr, location := #caller_location) {
|
||||||
free :: proc(str: $T/string) do free_ptr((^raw.String )(&str).data);
|
free_ptr(ptr, location);
|
||||||
free :: proc(array: $T/[dynamic]$E) do free_ptr((^raw.Dynamic_Array)(&array).data);
|
}
|
||||||
free :: proc(slice: $T/[]$E) do free_ptr((^raw.Slice )(&slice).data);
|
free :: proc(str: $T/string, location := #caller_location) {
|
||||||
free :: proc(m: $T/map[$K]$V) {
|
free_ptr((^raw.String)(&str).data, location);
|
||||||
|
}
|
||||||
|
free :: proc(array: $T/[dynamic]$E, location := #caller_location) {
|
||||||
|
free_ptr((^raw.Dynamic_Array)(&array).data, location);
|
||||||
|
}
|
||||||
|
free :: proc(slice: $T/[]$E, location := #caller_location) {
|
||||||
|
free_ptr((^raw.Slice)(&slice).data, location);
|
||||||
|
}
|
||||||
|
free :: proc(m: $T/map[$K]$V, location := #caller_location) {
|
||||||
raw := cast(^raw.Map)&m;
|
raw := cast(^raw.Map)&m;
|
||||||
free(raw.hashes);
|
free(raw.hashes, location);
|
||||||
free(raw.entries.data);
|
free(raw.entries.data, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): This code works but I will prefer having `make` a built-in procedure
|
// NOTE(bill): This code works but I will prefer having `make` a built-in procedure
|
||||||
@@ -557,21 +568,21 @@ make :: proc(T: type/map[$K]$V, cap: int = 16, using location := #caller_locatio
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, location := #caller_location) -> rawptr {
|
||||||
if old_memory == nil do return alloc(new_size, alignment);
|
if old_memory == nil do return alloc(new_size, alignment, location);
|
||||||
|
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
free(old_memory);
|
free(old_memory, location);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == old_size do return old_memory;
|
if new_size == old_size do return old_memory;
|
||||||
|
|
||||||
new_memory := alloc(new_size, alignment);
|
new_memory := alloc(new_size, alignment, location);
|
||||||
if new_memory == nil do return nil;
|
if new_memory == nil do return nil;
|
||||||
|
|
||||||
__mem_copy(new_memory, old_memory, min(old_size, new_size));;
|
__mem_copy(new_memory, old_memory, min(old_size, new_size));;
|
||||||
free(old_memory);
|
free(old_memory, location);
|
||||||
return new_memory;
|
return new_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-9
@@ -4082,13 +4082,17 @@ void check_unpack_arguments(Checker *c, Entity **lhs, isize lhs_count, Array<Ope
|
|||||||
|
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
|
|
||||||
|
Type *type_hint = nullptr;
|
||||||
|
|
||||||
if (lhs != nullptr && tuple_index < lhs_count) {
|
if (lhs != nullptr && tuple_index < lhs_count) {
|
||||||
// NOTE(bill): override DeclInfo for dependency
|
// NOTE(bill): override DeclInfo for dependency
|
||||||
DeclInfo *decl = decl_info_of_entity(&c->info, lhs[tuple_index]);
|
Entity *e = lhs[tuple_index];
|
||||||
|
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||||
if (decl) c->context.decl = decl;
|
if (decl) c->context.decl = decl;
|
||||||
|
type_hint = e->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_expr_base(c, &o, rhs[i], nullptr);
|
check_expr_base(c, &o, rhs[i], type_hint);
|
||||||
if (o.mode == Addressing_NoValue) {
|
if (o.mode == Addressing_NoValue) {
|
||||||
error_operand_no_value(&o);
|
error_operand_no_value(&o);
|
||||||
o.mode = Addressing_Invalid;
|
o.mode = Addressing_Invalid;
|
||||||
@@ -5508,7 +5512,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
fields_visited[sel.index[0]] = true;
|
fields_visited[sel.index[0]] = true;
|
||||||
check_expr(c, o, fv->value);
|
check_expr_with_type_hint(c, o, fv->value, field->type);
|
||||||
|
|
||||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) {
|
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) {
|
||||||
is_constant = false;
|
is_constant = false;
|
||||||
@@ -5530,7 +5534,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isize field_index = 0;
|
||||||
for_array(index, cl->elems) {
|
for_array(index, cl->elems) {
|
||||||
|
Entity *field = t->Struct.fields_in_src_order[field_index++];
|
||||||
|
if (!all_fields_are_blank && is_blank_ident(field->token)) {
|
||||||
|
// NOTE(bill): Ignore blank identifiers
|
||||||
|
continue;
|
||||||
|
}
|
||||||
AstNode *elem = cl->elems[index];
|
AstNode *elem = cl->elems[index];
|
||||||
if (elem->kind == AstNode_FieldValue) {
|
if (elem->kind == AstNode_FieldValue) {
|
||||||
error(elem, "Mixture of `field = value` and value elements in a literal is not allowed");
|
error(elem, "Mixture of `field = value` and value elements in a literal is not allowed");
|
||||||
@@ -5541,12 +5551,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *field = t->Struct.fields_in_src_order[index];
|
check_expr_with_type_hint(c, o, elem, field->type);
|
||||||
if (!all_fields_are_blank && is_blank_ident(field->token)) {
|
|
||||||
// NOTE(bill): Ignore blank identifiers
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_expr(c, o, elem);
|
|
||||||
|
|
||||||
if (!check_is_field_exported(c, field)) {
|
if (!check_is_field_exported(c, field)) {
|
||||||
gbString t = type_to_string(type);
|
gbString t = type_to_string(type);
|
||||||
|
|||||||
+41
-37
@@ -181,13 +181,13 @@ bool check_is_terminating(AstNode *node) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
|
||||||
if (rhs->mode == Addressing_Invalid ||
|
if (rhs->mode == Addressing_Invalid ||
|
||||||
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
|
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *node = unparen_expr(lhs_node);
|
AstNode *node = unparen_expr(lhs->expr);
|
||||||
|
|
||||||
// NOTE(bill): Ignore assignments to `_`
|
// NOTE(bill): Ignore assignments to `_`
|
||||||
if (is_blank_ident(node)) {
|
if (is_blank_ident(node)) {
|
||||||
@@ -201,12 +201,9 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
|
|
||||||
Entity *e = nullptr;
|
Entity *e = nullptr;
|
||||||
bool used = false;
|
bool used = false;
|
||||||
Operand lhs = {Addressing_Invalid};
|
|
||||||
|
|
||||||
|
if (lhs->mode == Addressing_Invalid ||
|
||||||
check_expr(c, &lhs, lhs_node);
|
(lhs->type == t_invalid && lhs->mode != Addressing_Overload)) {
|
||||||
if (lhs.mode == Addressing_Invalid ||
|
|
||||||
(lhs.type == t_invalid && lhs.mode != Addressing_Overload)) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +221,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
Operand x = {};
|
Operand x = {};
|
||||||
x.mode = Addressing_Value;
|
x.mode = Addressing_Value;
|
||||||
x.type = t;
|
x.type = t;
|
||||||
if (check_is_assignable_to(c, &x, lhs.type)) {
|
if (check_is_assignable_to(c, &x, lhs->type)) {
|
||||||
e = procs[i];
|
e = procs[i];
|
||||||
add_entity_use(c, rhs->expr, e);
|
add_entity_use(c, rhs->expr, e);
|
||||||
break;
|
break;
|
||||||
@@ -253,14 +250,14 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
e->flags |= EntityFlag_Used;
|
e->flags |= EntityFlag_Used;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *assignment_type = lhs.type;
|
Type *assignment_type = lhs->type;
|
||||||
switch (lhs.mode) {
|
switch (lhs->mode) {
|
||||||
case Addressing_Invalid:
|
case Addressing_Invalid:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
case Addressing_Variable: {
|
case Addressing_Variable: {
|
||||||
if (is_type_bit_field_value(lhs.type)) {
|
if (is_type_bit_field_value(lhs->type)) {
|
||||||
Type *lt = base_type(lhs.type);
|
Type *lt = base_type(lhs->type);
|
||||||
i64 lhs_bits = lt->BitFieldValue.bits;
|
i64 lhs_bits = lt->BitFieldValue.bits;
|
||||||
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);
|
||||||
@@ -284,7 +281,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
// TODO(bill): Any other checks?
|
// TODO(bill): Any other checks?
|
||||||
return rhs->type;
|
return rhs->type;
|
||||||
}
|
}
|
||||||
gbString lhs_expr = expr_to_string(lhs.expr);
|
gbString lhs_expr = expr_to_string(lhs->expr);
|
||||||
gbString rhs_expr = expr_to_string(rhs->expr);
|
gbString rhs_expr = expr_to_string(rhs->expr);
|
||||||
error(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr);
|
error(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr);
|
||||||
gb_string_free(rhs_expr);
|
gb_string_free(rhs_expr);
|
||||||
@@ -295,15 +292,15 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Addressing_MapIndex: {
|
case Addressing_MapIndex: {
|
||||||
AstNode *ln = unparen_expr(lhs_node);
|
AstNode *ln = unparen_expr(lhs->expr);
|
||||||
if (ln->kind == AstNode_IndexExpr) {
|
if (ln->kind == AstNode_IndexExpr) {
|
||||||
AstNode *x = ln->IndexExpr.expr;
|
AstNode *x = ln->IndexExpr.expr;
|
||||||
TypeAndValue tav = type_and_value_of_expr(&c->info, x);
|
TypeAndValue tav = type_and_value_of_expr(&c->info, x);
|
||||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||||
if (tav.mode != Addressing_Variable) {
|
if (tav.mode != Addressing_Variable) {
|
||||||
if (!is_type_pointer(tav.type)) {
|
if (!is_type_pointer(tav.type)) {
|
||||||
gbString str = expr_to_string(lhs.expr);
|
gbString str = expr_to_string(lhs->expr);
|
||||||
error(lhs.expr, "Cannot assign to the value of a map `%s`", str);
|
error(lhs->expr, "Cannot assign to the value of a map `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -314,24 +311,24 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
if (lhs.expr->kind == AstNode_SelectorExpr) {
|
if (lhs->expr->kind == AstNode_SelectorExpr) {
|
||||||
// NOTE(bill): Extra error checks
|
// NOTE(bill): Extra error checks
|
||||||
Operand op_c = {Addressing_Invalid};
|
Operand op_c = {Addressing_Invalid};
|
||||||
ast_node(se, SelectorExpr, lhs.expr);
|
ast_node(se, SelectorExpr, lhs->expr);
|
||||||
check_expr(c, &op_c, se->expr);
|
check_expr(c, &op_c, se->expr);
|
||||||
if (op_c.mode == Addressing_MapIndex) {
|
if (op_c.mode == Addressing_MapIndex) {
|
||||||
gbString str = expr_to_string(lhs.expr);
|
gbString str = expr_to_string(lhs->expr);
|
||||||
error(lhs.expr, "Cannot assign to struct field `%s` in map", str);
|
error(lhs->expr, "Cannot assign to struct field `%s` in map", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gbString str = expr_to_string(lhs.expr);
|
gbString str = expr_to_string(lhs->expr);
|
||||||
if (lhs.mode == Addressing_Immutable) {
|
if (lhs->mode == Addressing_Immutable) {
|
||||||
error(lhs.expr, "Cannot assign to an immutable: `%s`", str);
|
error(lhs->expr, "Cannot assign to an immutable: `%s`", str);
|
||||||
} else {
|
} else {
|
||||||
error(lhs.expr, "Cannot assign to `%s`", str);
|
error(lhs->expr, "Cannot assign to `%s`", str);
|
||||||
}
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
|
|
||||||
@@ -694,26 +691,31 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||||
// an extra allocation
|
// an extra allocation
|
||||||
Array<Operand> operands = {};
|
Array<Operand> lhs_operands = {};
|
||||||
array_init(&operands, c->tmp_allocator, 2 * lhs_count);
|
Array<Operand> rhs_operands = {};
|
||||||
check_unpack_arguments(c, nullptr, lhs_count, &operands, as->rhs, true);
|
array_init_count(&lhs_operands, c->tmp_allocator, lhs_count);
|
||||||
|
array_init(&rhs_operands, c->tmp_allocator, 2 * lhs_count);
|
||||||
|
|
||||||
isize rhs_count = operands.count;
|
for_array(i, as->lhs) {
|
||||||
for_array(i, operands) {
|
check_expr(c, &lhs_operands[i], as->lhs[i]);
|
||||||
if (operands[i].mode == Addressing_Invalid) {
|
}
|
||||||
|
|
||||||
|
check_unpack_arguments(c, nullptr, lhs_operands.count, &rhs_operands, as->rhs, true);
|
||||||
|
|
||||||
|
isize rhs_count = rhs_operands.count;
|
||||||
|
for_array(i, rhs_operands) {
|
||||||
|
if (rhs_operands[i].mode == Addressing_Invalid) {
|
||||||
rhs_count--;
|
rhs_count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isize max = gb_min(lhs_count, rhs_count);
|
isize max = gb_min(lhs_count, rhs_count);
|
||||||
for (isize i = 0; i < max; i++) {
|
for (isize i = 0; i < max; i++) {
|
||||||
check_assignment_variable(c, &operands[i], as->lhs[i]);
|
check_assignment_variable(c, &lhs_operands[i], &rhs_operands[i]);
|
||||||
}
|
}
|
||||||
if (lhs_count != rhs_count) {
|
if (lhs_count != rhs_count) {
|
||||||
error(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
error(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,7 +730,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
error(op, "Unknown Assignment operation `%.*s`", LIT(op.string));
|
error(op, "Unknown Assignment operation `%.*s`", LIT(op.string));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Operand operand = {Addressing_Invalid};
|
Operand lhs = {Addressing_Invalid};
|
||||||
|
Operand rhs = {Addressing_Invalid};
|
||||||
AstNode binary_expr = {AstNode_BinaryExpr};
|
AstNode binary_expr = {AstNode_BinaryExpr};
|
||||||
ast_node(be, BinaryExpr, &binary_expr);
|
ast_node(be, BinaryExpr, &binary_expr);
|
||||||
be->op = op;
|
be->op = op;
|
||||||
@@ -737,12 +740,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
be->left = as->lhs[0];
|
be->left = as->lhs[0];
|
||||||
be->right = as->rhs[0];
|
be->right = as->rhs[0];
|
||||||
|
|
||||||
check_binary_expr(c, &operand, &binary_expr);
|
check_expr(c, &lhs, as->lhs[0]);
|
||||||
if (operand.mode == Addressing_Invalid) {
|
check_binary_expr(c, &rhs, &binary_expr);
|
||||||
|
if (rhs.mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// NOTE(bill): Only use the first one will be used
|
// NOTE(bill): Only use the first one will be used
|
||||||
check_assignment_variable(c, &operand, as->lhs[0]);
|
check_assignment_variable(c, &lhs, &rhs);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2223,6 +2223,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
return ast_basic_lit(f, token);
|
return ast_basic_lit(f, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Token_OpenBrace:
|
||||||
|
if (!lhs) return parse_literal_value(f, nullptr);
|
||||||
|
break;
|
||||||
|
|
||||||
case Token_OpenParen: {
|
case Token_OpenParen: {
|
||||||
Token open, close;
|
Token open, close;
|
||||||
|
|||||||
Reference in New Issue
Block a user