Browse Source

Demaybe operator ?

Ginger Bill 8 years ago
parent
commit
c5d20d2eef
7 changed files with 107 additions and 70 deletions
  1. 2 1
      code/demo.odin
  2. 0 3
      core/_preload.odin
  3. 12 7
      src/checker/checker.cpp
  4. 37 25
      src/checker/expr.cpp
  5. 3 6
      src/codegen/codegen.cpp
  6. 23 18
      src/codegen/ssa.cpp
  7. 30 10
      src/parser.cpp

+ 2 - 1
code/demo.odin

@@ -1,8 +1,9 @@
 #import "fmt.odin"
 #import "fmt.odin"
 
 
+
 main :: proc() {
 main :: proc() {
 	maybe_print :: proc(x: ?int) {
 	maybe_print :: proc(x: ?int) {
-		if v, ok := maybe_value(x); ok {
+		if v, ok := x?; ok {
 			fmt.println(v)
 			fmt.println(v)
 		} else {
 		} else {
 			fmt.println("nowt")
 			fmt.println("nowt")

+ 0 - 3
core/_preload.odin

@@ -327,6 +327,3 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
 	}
 	}
 	return ""
 	return ""
 }
 }
-
-
-

+ 12 - 7
src/checker/checker.cpp

@@ -168,8 +168,6 @@ enum BuiltinProcId {
 
 
 	BuiltinProc_enum_to_string,
 	BuiltinProc_enum_to_string,
 
 
-	BuiltinProc_maybe_value,
-
 	BuiltinProc_Count,
 	BuiltinProc_Count,
 };
 };
 struct BuiltinProc {
 struct BuiltinProc {
@@ -213,9 +211,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{STR_LIT("abs"),              1, false, Expr_Expr},
 	{STR_LIT("abs"),              1, false, Expr_Expr},
 
 
 	{STR_LIT("enum_to_string"),   1, false, Expr_Expr},
 	{STR_LIT("enum_to_string"),   1, false, Expr_Expr},
-
-	{STR_LIT("maybe_value"),      1, false, Expr_Expr},
-
 };
 };
 
 
 struct CheckerContext {
 struct CheckerContext {
@@ -874,8 +869,6 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start)
 	Map<Entity *> map = {}; // Key: Entity *
 	Map<Entity *> map = {}; // Key: Entity *
 	map_init(&map, gb_heap_allocator());
 	map_init(&map, gb_heap_allocator());
 
 
-	add_dependency_to_map(&map, info, start);
-
 	gb_for_array(i, info->entities.entries) {
 	gb_for_array(i, info->entities.entries) {
 		auto *entry = &info->entities.entries[i];
 		auto *entry = &info->entities.entries[i];
 		Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
 		Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
@@ -885,6 +878,8 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start)
 		}
 		}
 	}
 	}
 
 
+	add_dependency_to_map(&map, info, start);
+
 	return map;
 	return map;
 }
 }
 
 
@@ -1200,6 +1195,16 @@ void check_parsed_files(Checker *c) {
 				add_curr_ast_file(c, d->scope->file);
 				add_curr_ast_file(c, d->scope->file);
 
 
 				if (d->scope == e->scope) {
 				if (d->scope == e->scope) {
+					if (kind != Entity_Procedure && e->token.string == "main") {
+						if (e->scope->is_init) {
+							error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
+							continue;
+						}
+					} else if (e->scope->is_global && e->token.string == "main") {
+						error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
+						continue;
+					}
+
 					Scope *prev_scope = c->context.scope;
 					Scope *prev_scope = c->context.scope;
 					c->context.scope = d->scope;
 					c->context.scope = d->scope;
 					check_entity_decl(c, e, d, NULL);
 					check_entity_decl(c, e, d, NULL);

+ 37 - 25
src/checker/expr.cpp

@@ -3028,31 +3028,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 		operand->mode = Addressing_Value;
 		operand->mode = Addressing_Value;
 		operand->type = t_string;
 		operand->type = t_string;
 	} break;
 	} break;
-
-	case BuiltinProc_maybe_value: {
-		Type *type = operand->type;
-		if (!is_type_maybe(type)) {
-			gbString type_str = type_to_string(operand->type);
-			defer (gb_string_free(type_str));
-			error(ast_node_token(call),
-			      "Expected a maybe to `maybe_value`, got `%s`",
-			      type_str);
-			return false;
-		}
-
-		operand->mode = Addressing_Value;
-
-		Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
-		Type *elem = base_type(type)->Maybe.elem;
-		Token t = make_token_ident(make_string(""));
-		variables[0] = make_entity_param(c->allocator, NULL, t, elem, false);
-		variables[1] = make_entity_param(c->allocator, NULL, t, t_bool, false);
-
-		Type *tuple = make_type_tuple(c->allocator);
-		tuple->Tuple.variables = variables;
-		tuple->Tuple.variable_count = 2;
-		operand->type = tuple;
-	} break;
 	}
 	}
 
 
 	return true;
 	return true;
@@ -3270,6 +3245,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	o->type = t_invalid;
 	o->type = t_invalid;
 
 
 	switch (node->kind) {
 	switch (node->kind) {
+	default:
+		goto error;
+		break;
+
 	case_ast_node(be, BadExpr, node)
 	case_ast_node(be, BadExpr, node)
 		goto error;
 		goto error;
 	case_end;
 	case_end;
@@ -3731,6 +3710,34 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 		}
 		}
 	case_end;
 	case_end;
 
 
+	case_ast_node(de, DemaybeExpr, node);
+		check_expr_or_type(c, o, de->expr);
+		if (o->mode == Addressing_Invalid) {
+			goto error;
+		} else {
+			Type *t = base_type(o->type);
+			if (t->kind == Type_Maybe) {
+				Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
+				Type *elem = t->Maybe.elem;
+				Token tok = make_token_ident(make_string(""));
+				variables[0] = make_entity_param(c->allocator, NULL, tok, elem, false);
+				variables[1] = make_entity_param(c->allocator, NULL, tok, t_bool, false);
+
+				Type *tuple = make_type_tuple(c->allocator);
+				tuple->Tuple.variables = variables;
+				tuple->Tuple.variable_count = 2;
+
+				o->type = tuple;
+				o->mode = Addressing_Variable;
+ 			} else {
+ 				gbString str = expr_to_string(o->expr);
+ 				error(ast_node_token(o->expr), "Cannot demaybe `%s`", str);
+ 				gb_string_free(str);
+ 				goto error;
+ 			}
+		}
+	case_end;
+
 	case AstNode_ProcType:
 	case AstNode_ProcType:
 	case AstNode_PointerType:
 	case AstNode_PointerType:
 	case AstNode_MaybeType:
 	case AstNode_MaybeType:
@@ -3910,6 +3917,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "^");
 		str = gb_string_appendc(str, "^");
 	case_end;
 	case_end;
 
 
+	case_ast_node(de, DemaybeExpr, node);
+		str = write_expr_to_string(str, de->expr);
+		str = gb_string_appendc(str, "?");
+	case_end;
+
 	case_ast_node(be, BinaryExpr, node);
 	case_ast_node(be, BinaryExpr, node);
 		str = write_expr_to_string(str, be->left);
 		str = write_expr_to_string(str, be->left);
 		str = gb_string_appendc(str, " ");
 		str = gb_string_appendc(str, " ");

+ 3 - 6
src/codegen/codegen.cpp

@@ -121,12 +121,9 @@ void ssa_gen_tree(ssaGen *s) {
 			continue;
 			continue;
 		}
 		}
 
 
-		if (entry_point != NULL) {
-			auto found = map_get(&min_dep_map, hash_pointer(e));
-			if (found == NULL) {
-				// NOTE(bill): Nothing depends upon it so doesn't need to be built
-				continue;
-			}
+		if (map_get(&min_dep_map, hash_pointer(e)) == NULL) {
+			// NOTE(bill): Nothing depends upon it so doesn't need to be built
+			continue;
 		}
 		}
 
 
 		if (!scope->is_global && !scope->is_init) {
 		if (!scope->is_global && !scope->is_init) {

+ 23 - 18
src/codegen/ssa.cpp

@@ -2689,24 +2689,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					args[1] = ssa_emit_conv(proc, x, t_i64);
 					args[1] = ssa_emit_conv(proc, x, t_i64);
 					return ssa_emit_global_call(proc, "__enum_to_string", args, 2);
 					return ssa_emit_global_call(proc, "__enum_to_string", args, 2);
 				} break;
 				} break;
-
-				case BuiltinProc_maybe_value: {
-					ssa_emit_comment(proc, make_string("maybe_value"));
-					ssaValue *maybe = ssa_build_expr(proc, ce->args[0]);
-					Type *t = default_type(type_of_expr(proc->module->info, expr));
-					GB_ASSERT(is_type_tuple(t));
-
-					Type *elem = ssa_type(maybe);
-					GB_ASSERT(is_type_maybe(elem));
-					elem = base_type(elem)->Maybe.elem;
-
-					ssaValue *result = ssa_add_local_generated(proc, t);
-					ssaValue *gep0 = ssa_emit_struct_gep(proc, result, v_zero32, make_type_pointer(proc->module->allocator, elem));
-					ssaValue *gep1 = ssa_emit_struct_gep(proc, result, v_one32,  make_type_pointer(proc->module->allocator, t_bool));
-					ssa_emit_store(proc, gep0, ssa_emit_struct_ev(proc, maybe, 0, elem));
-					ssa_emit_store(proc, gep1, ssa_emit_struct_ev(proc, maybe, 1, t_bool));
-					return ssa_emit_load(proc, result);
-				} break;
 				}
 				}
 			}
 			}
 		}
 		}
@@ -2803,6 +2785,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		return ssa_emit_call(proc, value, args, arg_count);
 		return ssa_emit_call(proc, value, args, arg_count);
 	case_end;
 	case_end;
 
 
+	case_ast_node(de, DemaybeExpr, expr);
+		return ssa_emit_load(proc, ssa_build_addr(proc, expr).addr);
+	case_end;
+
 	case_ast_node(se, SliceExpr, expr);
 	case_ast_node(se, SliceExpr, expr);
 		return ssa_emit_load(proc, ssa_build_addr(proc, expr).addr);
 		return ssa_emit_load(proc, ssa_build_addr(proc, expr).addr);
 	case_end;
 	case_end;
@@ -3191,6 +3177,25 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		return ssa_make_addr(gep, expr);
 		return ssa_make_addr(gep, expr);
 	case_end;
 	case_end;
 
 
+	case_ast_node(de, DemaybeExpr, expr);
+		ssa_emit_comment(proc, make_string("DemaybeExpr"));
+		ssaValue *maybe = ssa_build_expr(proc, de->expr);
+		Type *t = default_type(type_of_expr(proc->module->info, expr));
+		GB_ASSERT(is_type_tuple(t));
+
+		Type *elem = ssa_type(maybe);
+		GB_ASSERT(is_type_maybe(elem));
+		elem = base_type(elem)->Maybe.elem;
+
+		ssaValue *result = ssa_add_local_generated(proc, t);
+		ssaValue *gep0 = ssa_emit_struct_gep(proc, result, v_zero32, make_type_pointer(proc->module->allocator, elem));
+		ssaValue *gep1 = ssa_emit_struct_gep(proc, result, v_one32,  make_type_pointer(proc->module->allocator, t_bool));
+		ssa_emit_store(proc, gep0, ssa_emit_struct_ev(proc, maybe, 0, elem));
+		ssa_emit_store(proc, gep1, ssa_emit_struct_ev(proc, maybe, 1, t_bool));
+
+		return ssa_make_addr(result, expr);
+	case_end;
+
 	case_ast_node(ce, CallExpr, expr);
 	case_ast_node(ce, CallExpr, expr);
 		ssaValue *e = ssa_build_expr(proc, expr);
 		ssaValue *e = ssa_build_expr(proc, expr);
 		ssaValue *v = ssa_add_local_generated(proc, ssa_type(e));
 		ssaValue *v = ssa_add_local_generated(proc, ssa_type(e));

+ 30 - 10
src/parser.cpp

@@ -129,6 +129,7 @@ AST_NODE_KIND(_ExprBegin,  "",  struct{}) \
 	AST_NODE_KIND(SelectorExpr, "selector expression",    struct { Token token; AstNode *expr, *selector; }) \
 	AST_NODE_KIND(SelectorExpr, "selector expression",    struct { Token token; AstNode *expr, *selector; }) \
 	AST_NODE_KIND(IndexExpr,    "index expression",       struct { AstNode *expr, *index; Token open, close; }) \
 	AST_NODE_KIND(IndexExpr,    "index expression",       struct { AstNode *expr, *index; Token open, close; }) \
 	AST_NODE_KIND(DerefExpr,    "dereference expression", struct { Token op; AstNode *expr; }) \
 	AST_NODE_KIND(DerefExpr,    "dereference expression", struct { Token op; AstNode *expr; }) \
+	AST_NODE_KIND(DemaybeExpr,  "demaybe expression",     struct { Token op; AstNode *expr; }) \
 	AST_NODE_KIND(CallExpr,     "call expression", struct { \
 	AST_NODE_KIND(CallExpr,     "call expression", struct { \
 		AstNode *proc; \
 		AstNode *proc; \
 		AstNodeArray args; \
 		AstNodeArray args; \
@@ -398,6 +399,8 @@ Token ast_node_token(AstNode *node) {
 		return node->FieldValue.eq;
 		return node->FieldValue.eq;
 	case AstNode_DerefExpr:
 	case AstNode_DerefExpr:
 		return node->DerefExpr.op;
 		return node->DerefExpr.op;
+	case AstNode_DemaybeExpr:
+		return node->DemaybeExpr.op;
 	case AstNode_BadStmt:
 	case AstNode_BadStmt:
 		return node->BadStmt.begin;
 		return node->BadStmt.begin;
 	case AstNode_EmptyStmt:
 	case AstNode_EmptyStmt:
@@ -597,6 +600,13 @@ AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) {
 	return result;
 	return result;
 }
 }
 
 
+AstNode *make_demaybe_expr(AstFile *f, AstNode *expr, Token op) {
+	AstNode *result = make_node(f, AstNode_DemaybeExpr);
+	result->DemaybeExpr.expr = expr;
+	result->DemaybeExpr.op = op;
+	return result;
+}
+
 
 
 AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
 AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
 	AstNode *result = make_node(f, AstNode_BasicLit);
 	AstNode *result = make_node(f, AstNode_BasicLit);
@@ -1453,7 +1463,8 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
 			next_token(f);
 			next_token(f);
 		}
 		}
 
 
-		gb_array_append(args, parse_expr(f, false));
+		AstNode *arg = parse_expr(f, false);
+		gb_array_append(args, arg);
 
 
 		if (f->curr_token.kind != Token_Comma) {
 		if (f->curr_token.kind != Token_Comma) {
 			if (f->curr_token.kind == Token_CloseParen)
 			if (f->curr_token.kind == Token_CloseParen)
@@ -1564,6 +1575,10 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) {
 			operand = make_deref_expr(f, operand, expect_token(f, Token_Pointer));
 			operand = make_deref_expr(f, operand, expect_token(f, Token_Pointer));
 			break;
 			break;
 
 
+		case Token_Maybe: // Demaybe
+			operand = make_demaybe_expr(f, operand, expect_token(f, Token_Maybe));
+			break;
+
 		case Token_OpenBrace: {
 		case Token_OpenBrace: {
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
 				if (f->curr_token.pos.line == f->prev_token.pos.line) {
 				if (f->curr_token.pos.line == f->prev_token.pos.line) {
@@ -2715,12 +2730,12 @@ AstNode *parse_stmt(AstFile *f) {
 				f->is_global_scope = true;
 				f->is_global_scope = true;
 				return make_empty_stmt(f, f->curr_token);
 				return make_empty_stmt(f, f->curr_token);
 			}
 			}
-			syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope.");
+			syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope");
 			return make_bad_decl(f, token, f->curr_token);
 			return make_bad_decl(f, token, f->curr_token);
 		} else if (tag == "import") {
 		} else if (tag == "import") {
 			// TODO(bill): better error messages
 			// TODO(bill): better error messages
 			Token import_name = {};
 			Token import_name = {};
-			Token file_path = expect_token(f, Token_String);
+			Token file_path = expect_token_after(f, Token_String, "#import");
 			if (allow_token(f, Token_as)) {
 			if (allow_token(f, Token_as)) {
 				// NOTE(bill): Custom import name
 				// NOTE(bill): Custom import name
 				if (f->curr_token.kind == Token_Period) {
 				if (f->curr_token.kind == Token_Period) {
@@ -2728,14 +2743,19 @@ AstNode *parse_stmt(AstFile *f) {
 					import_name.kind = Token_Identifier;
 					import_name.kind = Token_Identifier;
 					next_token(f);
 					next_token(f);
 				} else {
 				} else {
-					import_name = expect_token(f, Token_Identifier);
+					import_name = expect_token_after(f, Token_Identifier, "`as` for import declaration");
+				}
+
+				if (import_name.string == "_") {
+					syntax_error(token, "Illegal import name: `_`");
+					return make_bad_decl(f, token, f->curr_token);
 				}
 				}
 			}
 			}
 
 
 			if (f->curr_proc == NULL) {
 			if (f->curr_proc == NULL) {
 				return make_import_decl(f, s->TagStmt.token, file_path, import_name, false);
 				return make_import_decl(f, s->TagStmt.token, file_path, import_name, false);
 			}
 			}
-			syntax_error(token, "You cannot use #import within a procedure. This must be done at the file scope.");
+			syntax_error(token, "You cannot use #import within a procedure. This must be done at the file scope");
 			return make_bad_decl(f, token, file_path);
 			return make_bad_decl(f, token, file_path);
 		} else if (tag == "load") {
 		} else if (tag == "load") {
 			// TODO(bill): better error messages
 			// TODO(bill): better error messages
@@ -2746,14 +2766,14 @@ AstNode *parse_stmt(AstFile *f) {
 			if (f->curr_proc == NULL) {
 			if (f->curr_proc == NULL) {
 				return make_import_decl(f, s->TagStmt.token, file_path, import_name, true);
 				return make_import_decl(f, s->TagStmt.token, file_path, import_name, true);
 			}
 			}
-			syntax_error(token, "You cannot use #load within a procedure. This must be done at the file scope.");
+			syntax_error(token, "You cannot use #load within a procedure. This must be done at the file scope");
 			return make_bad_decl(f, token, file_path);
 			return make_bad_decl(f, token, file_path);
 		} else if (tag == "foreign_system_library") {
 		} else if (tag == "foreign_system_library") {
 			Token file_path = expect_token(f, Token_String);
 			Token file_path = expect_token(f, Token_String);
 			if (f->curr_proc == NULL) {
 			if (f->curr_proc == NULL) {
 				return make_foreign_system_library(f, s->TagStmt.token, file_path);
 				return make_foreign_system_library(f, s->TagStmt.token, file_path);
 			}
 			}
-			syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope.");
+			syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope");
 			return make_bad_decl(f, token, file_path);
 			return make_bad_decl(f, token, file_path);
 		} else if (tag == "thread_local") {
 		} else if (tag == "thread_local") {
 			AstNode *var_decl = parse_simple_stmt(f);
 			AstNode *var_decl = parse_simple_stmt(f);
@@ -2762,7 +2782,7 @@ AstNode *parse_stmt(AstFile *f) {
 				return make_bad_decl(f, token, ast_node_token(var_decl));
 				return make_bad_decl(f, token, ast_node_token(var_decl));
 			}
 			}
 			if (f->curr_proc != NULL) {
 			if (f->curr_proc != NULL) {
-				syntax_error(token, "#thread_local is only allowed at the file scope.");
+				syntax_error(token, "#thread_local is only allowed at the file scope");
 				return make_bad_decl(f, token, ast_node_token(var_decl));
 				return make_bad_decl(f, token, ast_node_token(var_decl));
 			}
 			}
 			var_decl->VarDecl.tags |= VarDeclTag_thread_local;
 			var_decl->VarDecl.tags |= VarDeclTag_thread_local;
@@ -2783,12 +2803,12 @@ AstNode *parse_stmt(AstFile *f) {
 			return s;
 			return s;
 		}
 		}
 
 
-
 		s->TagStmt.stmt = parse_stmt(f); // TODO(bill): Find out why this doesn't work as an argument
 		s->TagStmt.stmt = parse_stmt(f); // TODO(bill): Find out why this doesn't work as an argument
 		return s;
 		return s;
 	} break;
 	} break;
 
 
-	case Token_OpenBrace: return parse_block_stmt(f);
+	case Token_OpenBrace:
+		return parse_block_stmt(f);
 
 
 	case Token_Semicolon:
 	case Token_Semicolon:
 		s = make_empty_stmt(f, token);
 		s = make_empty_stmt(f, token);