Browse Source

Implicit Selector Expressions: `.A`

gingerBill 6 years ago
parent
commit
ad3b6ab718
6 changed files with 89 additions and 3 deletions
  1. 4 0
      core/odin/ast/ast.odin
  2. 7 0
      core/odin/parser/parser.odin
  3. 47 2
      src/check_expr.cpp
  4. 7 0
      src/ir.cpp
  5. 23 1
      src/parser.cpp
  6. 1 0
      src/parser.hpp

+ 4 - 0
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,

+ 7 - 0
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);
 }

+ 47 - 2
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, ".(");

+ 7 - 0
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"));
 

+ 23 - 1
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<Ast *> 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);

+ 1 - 0
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 { \