mirror of
https://github.com/odin-lang/Odin.git
synced 2026-03-02 06:38:21 +00:00
Demaybe operator ?
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -327,6 +327,3 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, " ");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user