aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.c50
-rw-r--r--src/ir.c39
-rw-r--r--src/parser.c10
-rw-r--r--src/types.c45
4 files changed, 124 insertions, 20 deletions
diff --git a/src/check_expr.c b/src/check_expr.c
index bd8183069..0096c7566 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -1398,7 +1398,8 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
return true;
}
if (in_value.kind == ExactValue_Integer) {
- return true;
+ return false;
+ // return true;
}
if (out_value) *out_value = in_value;
}
@@ -1727,6 +1728,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
return true;
}
+
if (dst->kind == Type_Array && src->kind == Type_Array) {
if (are_types_identical(dst->Array.elem, src->Array.elem)) {
return dst->Array.count == src->Array.count;
@@ -1868,6 +1870,8 @@ void check_conversion(Checker *c, Operand *x, Type *type) {
if (bt->kind == Type_Basic) {
if (check_representable_as_constant(c, x->value, bt, &x->value)) {
can_convert = true;
+ } else if (is_type_pointer(type) && check_is_castable_to(c, x, type)) {
+ can_convert = true;
}
}
} else if (check_is_castable_to(c, x, type)) {
@@ -2478,8 +2482,10 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
goto error;
}
- if (ast_node_expect(selector, AstNode_Ident)) {
-
+ // if (selector->kind != AstNode_Ident && selector->kind != AstNode_BasicLit) {
+ if (selector->kind != AstNode_Ident) {
+ error_node(selector, "Illegal selector kind: `%.*s`", LIT(ast_node_strings[selector->kind]));
+ goto error;
}
if (op_expr->kind == AstNode_Ident) {
@@ -2577,6 +2583,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
}
}
}
+
if (check_op_expr) {
check_expr_base(c, operand, op_expr, NULL);
if (operand->mode == Addressing_Invalid) {
@@ -2589,6 +2596,43 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type);
entity = sel.entity;
}
+ if (entity == NULL && selector->kind == AstNode_BasicLit) {
+ if (is_type_struct(operand->type) || is_type_tuple(operand->type)) {
+ Type *type = base_type(operand->type);
+ Operand o = {0};
+ check_expr(c, &o, selector);
+ if (o.mode != Addressing_Constant ||
+ !is_type_integer(o.type)) {
+ error_node(op_expr, "Indexed based selectors must be a constant integer %s");
+ goto error;
+ }
+ i64 index = o.value.value_integer;
+ if (index < 0) {
+ error_node(o.expr, "Index %lld cannot be a negative value", index);
+ goto error;
+ }
+
+ i64 max_count = 0;
+ switch (type->kind) {
+ case Type_Record: max_count = type->Record.field_count; break;
+ case Type_Tuple: max_count = type->Tuple.variable_count; break;
+ }
+
+ if (index >= max_count) {
+ error_node(o.expr, "Index %lld is out of bounds range 0..<%lld", index, max_count);
+ goto error;
+ }
+
+ sel = lookup_field_from_index(heap_allocator(), type, index);
+ entity = sel.entity;
+
+ GB_ASSERT(entity != NULL);
+
+ } else {
+ error_node(op_expr, "Indexed based selectors may only be used on structs or tuples");
+ goto error;
+ }
+ }
if (entity == NULL) {
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
diff --git a/src/ir.c b/src/ir.c
index 1888c71e6..4ad0db922 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -1718,7 +1718,10 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec
} else if (type->kind == Type_Record) {
type = type->Record.fields[index]->type;
e = ir_emit_struct_ep(proc, e, index);
- } else if (type->kind == Type_Basic) {
+ } else if (type->kind == Type_Tuple) {
+ type = type->Tuple.variables[index]->type;
+ e = ir_emit_struct_ep(proc, e, index);
+ }else if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
case Basic_any: {
if (index == 0) {
@@ -3351,19 +3354,31 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
case_ast_node(se, SelectorExpr, expr);
ir_emit_comment(proc, str_lit("SelectorExpr"));
AstNode *sel = unparen_expr(se->selector);
- GB_ASSERT(sel->kind == AstNode_Ident);
- String selector = sel->Ident.string;
- Type *type = base_type(type_of_expr(proc->module->info, se->expr));
-
- if (type == t_invalid) {
- // NOTE(bill): Imports
- Entity *imp = entity_of_ident(proc->module->info, se->expr);
- if (imp != NULL) {
- GB_ASSERT(imp->kind == Entity_ImportName);
+ if (sel->kind == AstNode_Ident) {
+ String selector = sel->Ident.string;
+ Type *type = base_type(type_of_expr(proc->module->info, se->expr));
+
+ if (type == t_invalid) {
+ // NOTE(bill): Imports
+ Entity *imp = entity_of_ident(proc->module->info, se->expr);
+ if (imp != NULL) {
+ GB_ASSERT(imp->kind == Entity_ImportName);
+ }
+ return ir_build_addr(proc, unparen_expr(se->selector));
+ } else {
+ Selection sel = lookup_field(proc->module->allocator, type, selector, false);
+ GB_ASSERT(sel.entity != NULL);
+
+ irValue *a = ir_build_addr(proc, se->expr).addr;
+ a = ir_emit_deep_field_gep(proc, type, a, sel);
+ return ir_make_addr(a, expr);
}
- return ir_build_addr(proc, unparen_expr(se->selector));
} else {
- Selection sel = lookup_field(proc->module->allocator, type, selector, false);
+ Type *type = base_type(type_of_expr(proc->module->info, se->expr));
+ ExactValue val = type_and_value_of_expression(proc->module->info, sel)->value;
+ i64 index = val.value_integer;
+
+ Selection sel = lookup_field_from_index(proc->module->allocator, type, index);
GB_ASSERT(sel.entity != NULL);
irValue *a = ir_build_addr(proc, se->expr).addr;
diff --git a/src/parser.c b/src/parser.c
index 3e5486a64..f42e3c94c 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1854,15 +1854,15 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
case Token_Ident:
operand = make_selector_expr(f, token, operand, parse_identifier(f));
break;
- case Token_Integer:
- operand = make_selector_expr(f, token, operand, parse_expr(f, lhs));
- break;
- default: {
+ // case Token_Integer:
+ // operand = make_selector_expr(f, token, operand, parse_expr(f, lhs));
+ // break;
+ default:
syntax_error(f->curr_token, "Expected a selector");
next_token(f);
operand = make_bad_expr(f, ast_node_token(operand), f->curr_token);
// operand = make_selector_expr(f, f->curr_token, operand, NULL);
- } break;
+ break;
}
} break;
diff --git a/src/types.c b/src/types.c
index 9981b197d..c71f162c4 100644
--- a/src/types.c
+++ b/src/types.c
@@ -980,6 +980,51 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_ty
return lookup_field_with_selection(a, type_, field_name, is_type, empty_selection);
}
+Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
+ GB_ASSERT(is_type_struct(type) || is_type_tuple(type));
+ type = base_type(type);
+
+ i64 max_count = 0;
+ switch (type->kind) {
+ case Type_Record: max_count = type->Record.field_count; break;
+ case Type_Tuple: max_count = type->Tuple.variable_count; break;
+ }
+
+ if (index >= max_count) {
+ return empty_selection;
+ }
+
+ switch (type->kind) {
+ case Type_Record:
+ for (isize i = 0; i < max_count; i++) {
+ Entity *f = type->Record.fields[i];
+ if (f->kind == Entity_Variable) {
+ if (f->Variable.field_src_index == index) {
+ Array_isize sel_array = {0};
+ array_init_count(&sel_array, a, 1);
+ sel_array.e[0] = i;
+ return make_selection(f, sel_array, false);
+ }
+ }
+ }
+ break;
+ case Type_Tuple:
+ for (isize i = 0; i < max_count; i++) {
+ Entity *f = type->Tuple.variables[i];
+ if (i == index) {
+ Array_isize sel_array = {0};
+ array_init_count(&sel_array, a, 1);
+ sel_array.e[0] = i;
+ return make_selection(f, sel_array, false);
+ }
+ }
+ break;
+ }
+
+ GB_PANIC("Illegal index");
+ return empty_selection;
+}
+
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
GB_ASSERT(type_ != NULL);