aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-10-07 09:41:38 +0100
committerGinger Bill <bill@gingerbill.org>2016-10-07 09:41:38 +0100
commitc5d20d2eef6c25b23c2aa69cdc1dbc7ce7d6753a (patch)
tree23c6a0a5badbf67634a000df4d856f384fc51176
parentf40482aa29f687b4630744457844bad7f45ec614 (diff)
Demaybe operator ?
-rw-r--r--code/demo.odin3
-rw-r--r--core/_preload.odin3
-rw-r--r--src/checker/checker.cpp19
-rw-r--r--src/checker/expr.cpp62
-rw-r--r--src/codegen/codegen.cpp9
-rw-r--r--src/codegen/ssa.cpp41
-rw-r--r--src/parser.cpp40
7 files changed, 107 insertions, 70 deletions
diff --git a/code/demo.odin b/code/demo.odin
index 9b9566faa..786392b77 100644
--- a/code/demo.odin
+++ b/code/demo.odin
@@ -1,8 +1,9 @@
#import "fmt.odin"
+
main :: proc() {
maybe_print :: proc(x: ?int) {
- if v, ok := maybe_value(x); ok {
+ if v, ok := x?; ok {
fmt.println(v)
} else {
fmt.println("nowt")
diff --git a/core/_preload.odin b/core/_preload.odin
index 62b42b8ce..73b8ad358 100644
--- a/core/_preload.odin
+++ b/core/_preload.odin
@@ -327,6 +327,3 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
}
return ""
}
-
-
-
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp
index 19a4807d8..9e1295b9a 100644
--- a/src/checker/checker.cpp
+++ b/src/checker/checker.cpp
@@ -168,8 +168,6 @@ enum BuiltinProcId {
BuiltinProc_enum_to_string,
- BuiltinProc_maybe_value,
-
BuiltinProc_Count,
};
struct BuiltinProc {
@@ -213,9 +211,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("abs"), 1, false, Expr_Expr},
{STR_LIT("enum_to_string"), 1, false, Expr_Expr},
-
- {STR_LIT("maybe_value"), 1, false, Expr_Expr},
-
};
struct CheckerContext {
@@ -874,8 +869,6 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start)
Map<Entity *> map = {}; // Key: Entity *
map_init(&map, gb_heap_allocator());
- add_dependency_to_map(&map, info, start);
-
gb_for_array(i, info->entities.entries) {
auto *entry = &info->entities.entries[i];
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;
}
@@ -1200,6 +1195,16 @@ void check_parsed_files(Checker *c) {
add_curr_ast_file(c, d->scope->file);
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;
c->context.scope = d->scope;
check_entity_decl(c, e, d, NULL);
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index 527b2d92d..26b8399d5 100644
--- a/src/checker/expr.cpp
+++ b/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->type = t_string;
} 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;
@@ -3270,6 +3245,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
o->type = t_invalid;
switch (node->kind) {
+ default:
+ goto error;
+ break;
+
case_ast_node(be, BadExpr, node)
goto error;
case_end;
@@ -3731,6 +3710,34 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
}
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_PointerType:
case AstNode_MaybeType:
@@ -3910,6 +3917,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = gb_string_appendc(str, "^");
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);
str = write_expr_to_string(str, be->left);
str = gb_string_appendc(str, " ");
diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp
index a843da551..cf9e561b1 100644
--- a/src/codegen/codegen.cpp
+++ b/src/codegen/codegen.cpp
@@ -121,12 +121,9 @@ void ssa_gen_tree(ssaGen *s) {
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) {
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index 03879509b..c144d0011 100644
--- a/src/codegen/ssa.cpp
+++ b/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);
return ssa_emit_global_call(proc, "__enum_to_string", args, 2);
} 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);
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);
return ssa_emit_load(proc, ssa_build_addr(proc, expr).addr);
case_end;
@@ -3191,6 +3177,25 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
return ssa_make_addr(gep, expr);
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);
ssaValue *e = ssa_build_expr(proc, expr);
ssaValue *v = ssa_add_local_generated(proc, ssa_type(e));
diff --git a/src/parser.cpp b/src/parser.cpp
index 44b1c62b7..c8559739e 100644
--- a/src/parser.cpp
+++ b/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(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \
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 { \
AstNode *proc; \
AstNodeArray args; \
@@ -398,6 +399,8 @@ Token ast_node_token(AstNode *node) {
return node->FieldValue.eq;
case AstNode_DerefExpr:
return node->DerefExpr.op;
+ case AstNode_DemaybeExpr:
+ return node->DemaybeExpr.op;
case AstNode_BadStmt:
return node->BadStmt.begin;
case AstNode_EmptyStmt:
@@ -597,6 +600,13 @@ AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) {
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 *result = make_node(f, AstNode_BasicLit);
@@ -1453,7 +1463,8 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
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_CloseParen)
@@ -1564,6 +1575,10 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) {
operand = make_deref_expr(f, operand, expect_token(f, Token_Pointer));
break;
+ case Token_Maybe: // Demaybe
+ operand = make_demaybe_expr(f, operand, expect_token(f, Token_Maybe));
+ break;
+
case Token_OpenBrace: {
if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
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;
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);
} else if (tag == "import") {
// TODO(bill): better error messages
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)) {
// NOTE(bill): Custom import name
if (f->curr_token.kind == Token_Period) {
@@ -2728,14 +2743,19 @@ AstNode *parse_stmt(AstFile *f) {
import_name.kind = Token_Identifier;
next_token(f);
} 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) {
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);
} else if (tag == "load") {
// TODO(bill): better error messages
@@ -2746,14 +2766,14 @@ AstNode *parse_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
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);
} else if (tag == "foreign_system_library") {
Token file_path = expect_token(f, Token_String);
if (f->curr_proc == NULL) {
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);
} else if (tag == "thread_local") {
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));
}
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));
}
var_decl->VarDecl.tags |= VarDeclTag_thread_local;
@@ -2783,12 +2803,12 @@ AstNode *parse_stmt(AstFile *f) {
return s;
}
-
s->TagStmt.stmt = parse_stmt(f); // TODO(bill): Find out why this doesn't work as an argument
return s;
} break;
- case Token_OpenBrace: return parse_block_stmt(f);
+ case Token_OpenBrace:
+ return parse_block_stmt(f);
case Token_Semicolon:
s = make_empty_stmt(f, token);