Browse Source

auto_cast

gingerBill 7 years ago
parent
commit
4c339360e9
6 changed files with 102 additions and 42 deletions
  1. 1 0
      src/check_decl.cpp
  2. 48 13
      src/check_expr.cpp
  3. 8 0
      src/ir.cpp
  4. 43 29
      src/parser.cpp
  5. 1 0
      src/parser.hpp
  6. 1 0
      src/tokenizer.cpp

+ 1 - 0
src/check_decl.cpp

@@ -243,6 +243,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
 	named->Named.base = base_type(bt);
 	if (!is_distinct) {
 		e->type = bt;
+		named->Named.base = bt;
 		e->TypeName.is_type_alias = true;
 	}
 	// if (is_alias) {

+ 48 - 13
src/check_expr.cpp

@@ -394,7 +394,7 @@ bool find_or_generate_polymorphic_procedure_from_parameters(Checker *c, Entity *
 
 bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type);
 bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type);
-
+bool check_cast_internal(Checker *c, Operand *x, Type *type);
 
 i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 	if (operand->mode == Addressing_Invalid ||
@@ -571,7 +571,15 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 		}
 	}
 
-
+	AstNode *expr = unparen_expr(operand->expr);
+	if (expr != nullptr && expr->kind == AstNode_AutoCast) {
+		Operand x = *operand;
+		x.expr = expr->AutoCast.expr;
+		bool ok = check_cast_internal(c, &x, type);
+		if (ok) {
+			return 10;
+		}
+	}
 
 	return -1;
 }
@@ -1797,13 +1805,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
 	return false;
 }
 
-void check_cast(Checker *c, Operand *x, Type *type) {
-	if (!is_operand_value(*x)) {
-		error(x->expr, "'cast' can only be applied to values");
-		x->mode = Addressing_Invalid;
-		return;
-	}
-
+bool check_cast_internal(Checker *c, Operand *x, Type *type) {
 	bool is_const_expr = x->mode == Addressing_Constant;
 	bool can_convert = false;
 
@@ -1811,9 +1813,9 @@ void check_cast(Checker *c, Operand *x, Type *type) {
 	if (is_const_expr && is_type_constant_type(bt)) {
 		if (core_type(bt)->kind == Type_Basic) {
 			if (check_representable_as_constant(c, x->value, bt, &x->value)) {
-				can_convert = true;
+				return true;
 			} else if (is_type_pointer(type) && check_is_castable_to(c, x, type)) {
-				can_convert = true;
+				return true;
 			}
 		}
 	} else if (check_is_castable_to(c, x, type)) {
@@ -1822,8 +1824,21 @@ void check_cast(Checker *c, Operand *x, Type *type) {
 		} else if (is_type_slice(type) && is_type_string(x->type)) {
 			x->mode = Addressing_Value;
 		}
-		can_convert = true;
+		return true;
 	}
+	return false;
+
+}
+
+void check_cast(Checker *c, Operand *x, Type *type) {
+	if (!is_operand_value(*x)) {
+		error(x->expr, "Only values can be casted");
+		x->mode = Addressing_Invalid;
+		return;
+	}
+
+	bool is_const_expr = x->mode == Addressing_Constant;
+	bool can_convert = check_cast_internal(c, x, type);
 
 	if (!can_convert) {
 		gbString expr_str = expr_to_string(x->expr);
@@ -5767,6 +5782,19 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 		return Expr_Expr;
 	case_end;
 
+	case_ast_node(ac, AutoCast, node);
+		check_expr_base(c, o, ac->expr, type_hint);
+		if (o->mode == Addressing_Invalid) {
+			o->expr = node;
+			return kind;
+		}
+		if (type_hint) {
+			check_cast(c, o, type_hint);
+		}
+		o->expr = node;
+		return Expr_Expr;
+	case_end;
+
 	case_ast_node(ue, UnaryExpr, node);
 		check_expr_base(c, o, ue->expr, type_hint);
 		if (o->mode == Addressing_Invalid) {
@@ -6215,7 +6243,8 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = write_expr_to_string(str, ta->type);
 		str = gb_string_append_rune(str, ')');
 	case_end;
-		case_ast_node(tc, TypeCast, node);
+
+	case_ast_node(tc, TypeCast, node);
 		str = string_append_token(str, tc->token);
 		str = gb_string_append_rune(str, '(');
 		str = write_expr_to_string(str, tc->type);
@@ -6223,6 +6252,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = write_expr_to_string(str, tc->expr);
 	case_end;
 
+	case_ast_node(ac, AutoCast, node);
+		str = string_append_token(str, ac->token);
+		str = gb_string_append_rune(str, ' ');
+		str = write_expr_to_string(str, ac->expr);
+	case_end;
+
 	case_ast_node(ie, IndexExpr, node);
 		str = write_expr_to_string(str, ie->expr);
 		str = gb_string_append_rune(str, '[');

+ 8 - 0
src/ir.cpp

@@ -4979,6 +4979,10 @@ irValue *ir_build_expr_internal(irProcedure *proc, AstNode *expr) {
 		GB_PANIC("Invalid AST TypeCast");
 	case_end;
 
+	case_ast_node(ac, AutoCast, expr);
+		return ir_build_expr(proc, ac->expr);
+	case_end;
+
 	case_ast_node(ue, UnaryExpr, expr);
 		switch (ue->op.kind) {
 		case Token_And: {
@@ -6052,6 +6056,10 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 		ir_emit_store(proc, v, e);
 		return ir_addr(v);
 	case_end;
+
+	case_ast_node(ac, AutoCast, expr);
+		return ir_build_addr(proc, ac->expr);
+	case_end;
 	}
 
 	TokenPos token_pos = ast_node_token(expr).pos;

+ 43 - 29
src/parser.cpp

@@ -25,35 +25,36 @@ Token ast_node_token(AstNode *node) {
 			return ast_node_token(node->SelectorExpr.selector);
 		}
 		return node->SelectorExpr.token;
-	case AstNode_IndexExpr:     return node->IndexExpr.open;
-	case AstNode_SliceExpr:     return node->SliceExpr.open;
-	case AstNode_Ellipsis:      return node->Ellipsis.token;
-	case AstNode_FieldValue:    return node->FieldValue.eq;
-	case AstNode_DerefExpr:     return node->DerefExpr.op;
-	case AstNode_TernaryExpr:   return ast_node_token(node->TernaryExpr.cond);
-	case AstNode_TypeAssertion: return ast_node_token(node->TypeAssertion.expr);
-	case AstNode_TypeCast:      return node->TypeCast.token;
-
-	case AstNode_BadStmt:       return node->BadStmt.begin;
-	case AstNode_EmptyStmt:     return node->EmptyStmt.token;
-	case AstNode_ExprStmt:      return ast_node_token(node->ExprStmt.expr);
-	case AstNode_TagStmt:       return node->TagStmt.token;
-	case AstNode_AssignStmt:    return node->AssignStmt.op;
-	case AstNode_IncDecStmt:    return ast_node_token(node->IncDecStmt.expr);
-	case AstNode_BlockStmt:     return node->BlockStmt.open;
-	case AstNode_IfStmt:        return node->IfStmt.token;
-	case AstNode_WhenStmt:      return node->WhenStmt.token;
-	case AstNode_ReturnStmt:    return node->ReturnStmt.token;
-	case AstNode_ForStmt:       return node->ForStmt.token;
-	case AstNode_RangeStmt:     return node->RangeStmt.token;
-	case AstNode_CaseClause:    return node->CaseClause.token;
-	case AstNode_SwitchStmt:     return node->SwitchStmt.token;
-	case AstNode_TypeSwitchStmt: return node->TypeSwitchStmt.token;
-	case AstNode_DeferStmt:     return node->DeferStmt.token;
-	case AstNode_BranchStmt:    return node->BranchStmt.token;
-	case AstNode_UsingStmt:     return node->UsingStmt.token;
-	case AstNode_UsingInStmt:   return node->UsingInStmt.using_token;
-	case AstNode_PushContext:   return node->PushContext.token;
+	case AstNode_IndexExpr:          return node->IndexExpr.open;
+	case AstNode_SliceExpr:          return node->SliceExpr.open;
+	case AstNode_Ellipsis:           return node->Ellipsis.token;
+	case AstNode_FieldValue:         return node->FieldValue.eq;
+	case AstNode_DerefExpr:          return node->DerefExpr.op;
+	case AstNode_TernaryExpr:        return ast_node_token(node->TernaryExpr.cond);
+	case AstNode_TypeAssertion:      return ast_node_token(node->TypeAssertion.expr);
+	case AstNode_TypeCast:           return node->TypeCast.token;
+	case AstNode_AutoCast:           return node->AutoCast.token;
+
+	case AstNode_BadStmt:            return node->BadStmt.begin;
+	case AstNode_EmptyStmt:          return node->EmptyStmt.token;
+	case AstNode_ExprStmt:           return ast_node_token(node->ExprStmt.expr);
+	case AstNode_TagStmt:            return node->TagStmt.token;
+	case AstNode_AssignStmt:         return node->AssignStmt.op;
+	case AstNode_IncDecStmt:         return ast_node_token(node->IncDecStmt.expr);
+	case AstNode_BlockStmt:          return node->BlockStmt.open;
+	case AstNode_IfStmt:             return node->IfStmt.token;
+	case AstNode_WhenStmt:           return node->WhenStmt.token;
+	case AstNode_ReturnStmt:         return node->ReturnStmt.token;
+	case AstNode_ForStmt:            return node->ForStmt.token;
+	case AstNode_RangeStmt:          return node->RangeStmt.token;
+	case AstNode_CaseClause:         return node->CaseClause.token;
+	case AstNode_SwitchStmt:         return node->SwitchStmt.token;
+	case AstNode_TypeSwitchStmt:     return node->TypeSwitchStmt.token;
+	case AstNode_DeferStmt:          return node->DeferStmt.token;
+	case AstNode_BranchStmt:         return node->BranchStmt.token;
+	case AstNode_UsingStmt:          return node->UsingStmt.token;
+	case AstNode_UsingInStmt:        return node->UsingInStmt.using_token;
+	case AstNode_PushContext:        return node->PushContext.token;
 
 	case AstNode_BadDecl:            return node->BadDecl.begin;
 	case AstNode_Label:              return node->Label.token;
@@ -633,6 +634,12 @@ AstNode *ast_type_cast(AstFile *f, Token token, AstNode *type, AstNode *expr) {
 	result->TypeCast.expr  = expr;
 	return result;
 }
+AstNode *ast_auto_cast(AstFile *f, Token token, AstNode *expr) {
+	AstNode *result = make_ast_node(f, AstNode_AutoCast);
+	result->AutoCast.token = token;
+	result->AutoCast.expr  = expr;
+	return result;
+}
 
 
 
@@ -2195,6 +2202,13 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
 		AstNode *expr = parse_unary_expr(f, lhs);
 		return ast_type_cast(f, token, type, expr);
 	}
+
+	case Token_auto_cast: {
+		Token token = advance_token(f);
+		AstNode *expr = parse_unary_expr(f, lhs);
+		return ast_auto_cast(f, token, expr);
+	}
+
 	case Token_Add:
 	case Token_Sub:
 	case Token_Not:

+ 1 - 0
src/parser.hpp

@@ -220,6 +220,7 @@ AST_NODE_KIND(_ExprBegin,  "",  struct {}) \
 	AST_NODE_KIND(TernaryExpr,   "ternary expression",  struct { AstNode *cond, *x, *y; }) \
 	AST_NODE_KIND(TypeAssertion, "type assertion",      struct { AstNode *expr; Token dot; AstNode *type; }) \
 	AST_NODE_KIND(TypeCast,      "type cast",           struct { Token token; AstNode *type, *expr; }) \
+	AST_NODE_KIND(AutoCast,      "auto_cast",           struct { Token token; AstNode *expr; }) \
 AST_NODE_KIND(_ExprEnd,       "", struct {}) \
 AST_NODE_KIND(_StmtBegin,     "", struct {}) \
 	AST_NODE_KIND(BadStmt,    "bad statement",                 struct { Token begin, end; }) \

+ 1 - 0
src/tokenizer.cpp

@@ -108,6 +108,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_map,                    "map"),                    \
 	TOKEN_KIND(Token_static,                 "static"),                 \
 	TOKEN_KIND(Token_dynamic,                "dynamic"),                \
+	TOKEN_KIND(Token_auto_cast,              "auto_cast"),              \
 	TOKEN_KIND(Token_cast,                   "cast"),                   \
 	TOKEN_KIND(Token_transmute,              "transmute"),              \
 	TOKEN_KIND(Token_distinct,               "distinct"),               \