diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 8c43ee8e3..59d18a0c0 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -144,6 +144,10 @@ Selector_Expr :: struct { field: ^Ident, } +Implicit_Selector_Expr :: struct { + using node: Expr, + field: ^Ident, +} Index_Expr :: struct { using node: Expr, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index c10a83e47..90de2ca30 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2581,6 +2581,13 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { ue.expr = expr; return ue; + case token.Period: + op := advance_token(p); + field := parse_ident(p); + ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end); + ise.field = field; + return ise; + } return parse_atom_expr(p, parse_operand(p, lhs), lhs); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ea125a5eb..4c921f484 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -991,7 +991,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ o->expr = n; String name = n->Ident.token.string; - Entity *e = scope_lookup(c->scope, name); if (e == nullptr) { if (is_blank_ident(name)) { @@ -6177,7 +6176,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type continue; } - check_expr(c, o, elem); + check_expr_with_type_hint(c, o, elem, et); if (is_constant) { is_constant = o->mode == Addressing_Constant; @@ -6408,6 +6407,47 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; + case_ast_node(ise, ImplicitSelectorExpr, node); + o->type = t_invalid; + o->expr = node; + o->mode = Addressing_Invalid; + + if (type_hint == nullptr) { + gbString str = expr_to_string(node); + error(node, "Cannot determine type for implicit selector expression '%s'", str); + gb_string_free(str); + return Expr_Expr; + } + o->type = type_hint; + if (!is_type_enum(type_hint)) { + gbString typ = type_to_string(type_hint); + gbString str = expr_to_string(node); + error(node, "Invalid type '%s' for implicit selector expression '%s'", typ, str); + gb_string_free(str); + gb_string_free(typ); + return Expr_Expr; + } + GB_ASSERT(ise->selector->kind == Ast_Ident); + String name = ise->selector->Ident.token.string; + + Type *enum_type = base_type(type_hint); + GB_ASSERT(enum_type->kind == Type_Enum); + Entity *e = scope_lookup_current(enum_type->Enum.scope, name); + if (e == nullptr) { + gbString typ = type_to_string(type_hint); + error(node, "Undeclared name %.*s for type '%s'", LIT(name), typ); + gb_string_free(typ); + return Expr_Expr; + } + GB_ASSERT(are_types_identical(base_type(e->type), base_type(type_hint))); + GB_ASSERT(e->kind == Entity_Constant); + o->value = e->Constant.value; + o->mode = Addressing_Constant; + o->type = e->type; + + return Expr_Expr; + case_end; + case_ast_node(ie, IndexExpr, node); check_expr(c, o, ie->expr); if (o->mode == Addressing_Invalid) { @@ -6832,6 +6872,11 @@ gbString write_expr_to_string(gbString str, Ast *node) { str = write_expr_to_string(str, se->selector); case_end; + case_ast_node(se, ImplicitSelectorExpr, node); + str = gb_string_append_rune(str, '.'); + str = write_expr_to_string(str, se->selector); + case_end; + case_ast_node(ta, TypeAssertion, node); str = write_expr_to_string(str, ta->expr); str = gb_string_appendc(str, ".("); diff --git a/src/ir.cpp b/src/ir.cpp index e3fe83c3b..0d5e3fc36 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6268,6 +6268,13 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; + case_ast_node(ise, ImplicitSelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(expr); + GB_ASSERT(tav.mode == Addressing_Constant); + + return ir_add_module_constant(proc->module, tv.type, tv.value); + case_end; + case_ast_node(te, TernaryExpr, expr); ir_emit_comment(proc, str_lit("TernaryExpr")); diff --git a/src/parser.cpp b/src/parser.cpp index a5526fd73..84c03587d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -25,6 +25,11 @@ Token ast_token(Ast *node) { return ast_token(node->SelectorExpr.selector); } return node->SelectorExpr.token; + case Ast_ImplicitSelectorExpr: + if (node->ImplicitSelectorExpr.selector != nullptr) { + return ast_token(node->ImplicitSelectorExpr.selector); + } + return node->ImplicitSelectorExpr.token; case Ast_IndexExpr: return node->IndexExpr.open; case Ast_SliceExpr: return node->SliceExpr.open; case Ast_Ellipsis: return node->Ellipsis.token; @@ -165,6 +170,9 @@ Ast *clone_ast(Ast *node) { n->SelectorExpr.expr = clone_ast(n->SelectorExpr.expr); n->SelectorExpr.selector = clone_ast(n->SelectorExpr.selector); break; + case Ast_ImplicitSelectorExpr: + n->ImplicitSelectorExpr.selector = clone_ast(n->ImplicitSelectorExpr.selector); + break; case Ast_IndexExpr: n->IndexExpr.expr = clone_ast(n->IndexExpr.expr); n->IndexExpr.index = clone_ast(n->IndexExpr.index); @@ -504,11 +512,20 @@ Ast *ast_call_expr(AstFile *f, Ast *proc, Array args, Token open, Token c Ast *ast_selector_expr(AstFile *f, Token token, Ast *expr, Ast *selector) { Ast *result = alloc_ast_node(f, Ast_SelectorExpr); + result->SelectorExpr.token = token; result->SelectorExpr.expr = expr; result->SelectorExpr.selector = selector; return result; } +Ast *ast_implicit_selector_expr(AstFile *f, Token token, Ast *selector) { + Ast *result = alloc_ast_node(f, Ast_ImplicitSelectorExpr); + result->ImplicitSelectorExpr.token = token; + result->ImplicitSelectorExpr.selector = selector; + return result; +} + + Ast *ast_index_expr(AstFile *f, Ast *expr, Ast *index, Token open, Token close) { Ast *result = alloc_ast_node(f, Ast_IndexExpr); result->IndexExpr.expr = expr; @@ -1612,7 +1629,6 @@ Ast *parse_operand(AstFile *f, bool lhs) { case Token_offset_of: return parse_call_expr(f, ast_implicit(f, advance_token(f))); - case Token_String: return ast_basic_lit(f, advance_token(f)); @@ -2277,6 +2293,12 @@ Ast *parse_unary_expr(AstFile *f, bool lhs) { Ast *expr = parse_unary_expr(f, lhs); return ast_unary_expr(f, token, expr); } + + case Token_Period: { + Token token = expect_token(f, Token_Period); + Ast *ident = parse_ident(f); + return ast_implicit_selector_expr(f, token, ident); + } } return parse_atom_expr(f, parse_operand(f, lhs), lhs); diff --git a/src/parser.hpp b/src/parser.hpp index d685aa1af..816f3f534 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -245,6 +245,7 @@ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BinaryExpr, "binary expression", struct { Token op; Ast *left, *right; } ) \ AST_KIND(ParenExpr, "parentheses expression", struct { Ast *expr; Token open, close; }) \ AST_KIND(SelectorExpr, "selector expression", struct { Token token; Ast *expr, *selector; }) \ + AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \ AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \ AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \ AST_KIND(SliceExpr, "slice expression", struct { \