From f40482aa29f687b4630744457844bad7f45ec614 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 6 Oct 2016 23:30:22 +0100 Subject: [PATCH] Maybe types; value, ok := maybe_value(x) --- code/demo.odin | 16 ++--- core/_preload.odin | 3 + core/fmt.odin | 7 ++ src/checker/checker.cpp | 30 ++++---- src/checker/expr.cpp | 91 +++++++++++++++++++----- src/checker/type.cpp | 62 +++++++++++++--- src/codegen/codegen.cpp | 5 ++ src/codegen/print_llvm.cpp | 16 +++-- src/codegen/ssa.cpp | 39 +++++++++- src/exact_value.cpp | 14 ++-- src/parser.cpp | 142 +++++++++++++++++++++---------------- src/tokenizer.cpp | 2 + 12 files changed, 309 insertions(+), 118 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 0d0ed6735..9b9566faa 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,15 +1,15 @@ #import "fmt.odin" -A :: {2}f32{1, 2} -B :: {2}f32{3, 4} - main :: proc() { - Fruit :: union { - A: int - B: f32 - C: struct { - x: int + maybe_print :: proc(x: ?int) { + if v, ok := maybe_value(x); ok { + fmt.println(v) + } else { + fmt.println("nowt") } } + + maybe_print(123) // 123 + maybe_print(nil) // nowt } diff --git a/core/_preload.odin b/core/_preload.odin index 9f64f2012..62b42b8ce 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -36,6 +36,9 @@ Type_Info :: union { Pointer: struct #ordered { elem: ^Type_Info } + Maybe: struct #ordered { + elem: ^Type_Info + } Procedure: struct #ordered { params: ^Type_Info // Type_Info.Tuple results: ^Type_Info // Type_Info.Tuple diff --git a/core/fmt.odin b/core/fmt.odin index 603f04b21..d2b3a23ae 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -413,6 +413,13 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { print_pointer_to_buffer(buf, nil) } + case Maybe: + if arg.data != nil { + + } else { + print_string_to_buffer(buf, "") + } + case Enum: value: i64 = 0 match type i : info.base { diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 90f04c588..19a4807d8 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -168,6 +168,7 @@ enum BuiltinProcId { BuiltinProc_enum_to_string, + BuiltinProc_maybe_value, BuiltinProc_Count, }; @@ -213,6 +214,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("enum_to_string"), 1, false, Expr_Expr}, + {STR_LIT("maybe_value"), 1, false, Expr_Expr}, + }; struct CheckerContext { @@ -891,7 +894,7 @@ Map generate_minimum_dependency_map(CheckerInfo *info, Entity *start) #include "expr.cpp" #include "stmt.cpp" -void init_runtime_types(Checker *c) { +void init_preload_types(Checker *c) { if (t_type_info == NULL) { Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Type_Info")); if (e == NULL) { @@ -900,13 +903,13 @@ void init_runtime_types(Checker *c) { } t_type_info = e->type; t_type_info_ptr = make_type_pointer(c->allocator, t_type_info); - + GB_ASSERT(is_type_union(e->type)); auto *record = &base_type(e->type)->Record; t_type_info_member = record->other_fields[0]->type; t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member); - if (record->field_count != 16) { + if (record->field_count != 17) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->fields[ 1]->type; @@ -915,15 +918,16 @@ void init_runtime_types(Checker *c) { t_type_info_string = record->fields[ 4]->type; t_type_info_boolean = record->fields[ 5]->type; t_type_info_pointer = record->fields[ 6]->type; - t_type_info_procedure = record->fields[ 7]->type; - t_type_info_array = record->fields[ 8]->type; - t_type_info_slice = record->fields[ 9]->type; - t_type_info_vector = record->fields[10]->type; - t_type_info_tuple = record->fields[11]->type; - t_type_info_struct = record->fields[12]->type; - t_type_info_union = record->fields[13]->type; - t_type_info_raw_union = record->fields[14]->type; - t_type_info_enum = record->fields[15]->type; + t_type_info_maybe = record->fields[ 7]->type; + t_type_info_procedure = record->fields[ 8]->type; + t_type_info_array = record->fields[ 9]->type; + t_type_info_slice = record->fields[10]->type; + t_type_info_vector = record->fields[11]->type; + t_type_info_tuple = record->fields[12]->type; + t_type_info_struct = record->fields[13]->type; + t_type_info_union = record->fields[14]->type; + t_type_info_raw_union = record->fields[15]->type; + t_type_info_enum = record->fields[16]->type; } if (t_allocator == NULL) { @@ -1206,7 +1210,7 @@ void check_parsed_files(Checker *c) { check_global_entity(c, Entity_TypeName); - init_runtime_types(c); + init_preload_types(c); check_global_entity(c, Entity_Constant); check_global_entity(c, Entity_Procedure); diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 3b1881ea0..527b2d92d 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -7,7 +7,7 @@ void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, T Entity * check_selector (Checker *c, Operand *operand, AstNode *node); void check_not_tuple (Checker *c, Operand *operand); b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); -void convert_to_typed (Checker *c, Operand *operand, Type *target_type); +void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level = 0); gbString expr_to_string (AstNode *expression); void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker = NULL); void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); @@ -88,6 +88,11 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu return true; } + if (is_type_maybe(dst)) { + Type *elem = base_type(dst)->Maybe.elem; + return are_types_identical(elem, src); + } + if (is_type_untyped_nil(src)) { return type_has_nil(dst); } @@ -103,6 +108,8 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu return true; } + + if (dst->kind == Type_Array && src->kind == Type_Array) { if (are_types_identical(dst->Array.elem, src->Array.elem)) { return dst->Array.count == src->Array.count; @@ -138,9 +145,7 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu } } - return false; - } @@ -1048,6 +1053,12 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c goto end; case_end; + case_ast_node(mt, MaybeType, e); + Type *elem = check_type(c, mt->type); + type = make_type_maybe(c->allocator, elem); + goto end; + case_end; + case_ast_node(at, ArrayType, e); if (at->count != NULL) { Type *elem = check_type(c, at->elem, NULL, cycle_checker); @@ -1243,8 +1254,10 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { } b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) { - if (in_value.kind == ExactValue_Invalid) + if (in_value.kind == ExactValue_Invalid) { + // NOTE(bill): There's already been an error return true; + } if (is_type_boolean(type)) { return in_value.kind == ExactValue_Bool; @@ -1252,8 +1265,9 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac return in_value.kind == ExactValue_String; } else if (is_type_integer(type)) { ExactValue v = exact_value_to_integer(in_value); - if (v.kind != ExactValue_Integer) + if (v.kind != ExactValue_Integer) { return false; + } if (out_value) *out_value = v; i64 i = v.value_integer; u64 u = *cast(u64 *)&i; @@ -1287,8 +1301,9 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac } } else if (is_type_float(type)) { ExactValue v = exact_value_to_float(in_value); - if (v.kind != ExactValue_Float) + if (v.kind != ExactValue_Float) { return false; + } switch (type->Basic.kind) { case Basic_f32: @@ -1986,7 +2001,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { operand->mode = Addressing_Invalid; } -void convert_to_typed(Checker *c, Operand *operand, Type *target_type) { +void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level) { GB_ASSERT_NOT_NULL(target_type); if (operand->mode == Addressing_Invalid || is_type_typed(operand->type) || @@ -2018,7 +2033,6 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) { } update_expr_value(c, operand->expr, operand->value); } else { - // TODO(bill): Is this really needed? switch (operand->type->Basic.kind) { case Basic_UntypedBool: if (!is_type_boolean(target_type)) { @@ -2045,14 +2059,24 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) { } break; + case Type_Maybe: + if (is_type_untyped_nil(operand->type)) { + // Okay + } else if (level == 0) { + convert_to_typed(c, operand, t->Maybe.elem, level+1); + return; + } + default: - if (!type_has_nil(target_type)) { + if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { convert_untyped_error(c, operand, target_type); return; } break; } + + operand->type = target_type; update_expr_type(c, operand->expr, target_type, true); } @@ -2361,15 +2385,16 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) break; case BuiltinProc_offset_of: { - // offset_val :: proc(Type, field) -> int + // offset_of :: proc(Type, field) -> int Operand op = {}; - Type *type = base_type(check_type(c, ce->args[0])); - if (type != NULL || type == t_invalid) { + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`"); return false; } if (!is_type_struct(type)) { - error(ast_node_token(ce->args[0]), "Expected a structure type for `offset_of`"); + error(ast_node_token(ce->args[0]), "Expected a struct type for `offset_of`"); return false; } @@ -2384,7 +2409,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) ast_node(arg, Ident, field_arg); Selection sel = lookup_field(c->allocator, type, arg->string, operand->mode == Addressing_Type); if (sel.entity == NULL) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string(bt); + defer (gb_string_free(type_str)); error(ast_node_token(ce->args[0]), "`%s` has no field named `%.*s`", type_str, LIT(arg->string)); return false; @@ -2397,7 +2423,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } break; case BuiltinProc_offset_of_val: { - // offset_val :: proc(val: expression) -> int + // offset_of_val :: proc(val: expression) -> int AstNode *arg = unparen_expr(ce->args[0]); if (arg->kind != AstNode_SelectorExpr) { gbString str = expr_to_string(arg); @@ -2418,6 +2444,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } } + if (!is_type_struct(type)) { + error(ast_node_token(ce->args[0]), "Expected a struct type for `offset_of_val`"); + return false; + } + ast_node(i, Ident, s->selector); Selection sel = lookup_field(c->allocator, type, i->string, operand->mode == Addressing_Type); @@ -2677,8 +2708,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (operand->mode == Addressing_Constant && op.mode == Addressing_Constant) { - u8 *ptr = cast(u8 *)operand->value.value_pointer; - isize elem_size = type_size_of(c->sizes, c->allocator, ptr_type->Pointer.elem); + i64 ptr = operand->value.value_pointer; + i64 elem_size = type_size_of(c->sizes, c->allocator, ptr_type->Pointer.elem); ptr += elem_size * op.value.value_integer; operand->value.value_pointer = ptr; } else { @@ -2997,6 +3028,31 @@ 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; @@ -3677,6 +3733,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case AstNode_ProcType: case AstNode_PointerType: + case AstNode_MaybeType: case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 1ebb48c4f..901a467f7 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -58,11 +58,12 @@ struct BasicType { #define TYPE_KINDS \ TYPE_KIND(Invalid), \ TYPE_KIND(Basic), \ + TYPE_KIND(Pointer), \ TYPE_KIND(Array), \ TYPE_KIND(Vector), \ TYPE_KIND(Slice), \ + TYPE_KIND(Maybe), \ TYPE_KIND(Record), \ - TYPE_KIND(Pointer), \ TYPE_KIND(Named), \ TYPE_KIND(Tuple), \ TYPE_KIND(Proc), \ @@ -96,6 +97,7 @@ struct Type { u32 flags; // See parser.cpp `enum TypeFlag` union { BasicType Basic; + struct { Type *elem; } Pointer; struct { Type *elem; i64 count; @@ -107,6 +109,9 @@ struct Type { struct { Type *elem; } Slice; + struct { + Type *elem; + } Maybe; struct { TypeRecordKind kind; @@ -134,7 +139,6 @@ struct Type { Entity **other_fields; isize other_field_count; } Record; - struct { Type *elem; } Pointer; struct { String name; Type * base; @@ -187,6 +191,18 @@ Type *make_type_basic(gbAllocator a, BasicType basic) { return t; } +Type *make_type_pointer(gbAllocator a, Type *elem) { + Type *t = alloc_type(a, Type_Pointer); + t->Pointer.elem = elem; + return t; +} + +Type *make_type_maybe(gbAllocator a, Type *elem) { + Type *t = alloc_type(a, Type_Maybe); + t->Maybe.elem = elem; + return t; +} + Type *make_type_array(gbAllocator a, Type *elem, i64 count) { Type *t = alloc_type(a, Type_Array); t->Array.elem = elem; @@ -207,6 +223,7 @@ Type *make_type_slice(gbAllocator a, Type *elem) { return t; } + Type *make_type_struct(gbAllocator a) { Type *t = alloc_type(a, Type_Record); t->Record.kind = TypeRecord_Struct; @@ -231,11 +248,7 @@ Type *make_type_enum(gbAllocator a) { return t; } -Type *make_type_pointer(gbAllocator a, Type *elem) { - Type *t = alloc_type(a, Type_Pointer); - t->Pointer.elem = elem; - return t; -} + Type *make_type_named(gbAllocator a, String name, Type *base, Entity *type_name) { Type *t = alloc_type(a, Type_Named); @@ -357,6 +370,7 @@ gb_global Type *t_type_info_float = NULL; gb_global Type *t_type_info_string = NULL; gb_global Type *t_type_info_boolean = NULL; gb_global Type *t_type_info_pointer = NULL; +gb_global Type *t_type_info_maybe = NULL; gb_global Type *t_type_info_procedure = NULL; gb_global Type *t_type_info_array = NULL; gb_global Type *t_type_info_slice = NULL; @@ -468,6 +482,15 @@ b32 is_type_pointer(Type *t) { } return t->kind == Type_Pointer; } +b32 is_type_maybe(Type *t) { + t = base_type(t); + return t->kind == Type_Maybe; +} +b32 is_type_tuple(Type *t) { + t = base_type(t); + return t->kind == Type_Tuple; +} + b32 is_type_int_or_uint(Type *t) { if (t->kind == Type_Basic) { @@ -671,6 +694,11 @@ b32 are_types_identical(Type *x, Type *y) { return are_types_identical(x->Pointer.elem, y->Pointer.elem); break; + case Type_Maybe: + if (y->kind == Type_Maybe) + return are_types_identical(x->Maybe.elem, y->Maybe.elem); + break; + case Type_Named: if (y->kind == Type_Named) { return x->Named.base == y->Named.base; @@ -987,6 +1015,9 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { return max; } break; + case Type_Maybe: + return gb_max(type_align_of(s, allocator, t->Maybe.elem), type_align_of(s, allocator, t_bool)); + case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: @@ -1115,6 +1146,9 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { case Type_Slice: // ptr + len + cap return 3 * s.word_size; + case Type_Maybe: // value + bool + return type_size_of(s, allocator, t->Maybe.elem) + type_size_of(s, allocator, t_bool); + case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: { @@ -1199,6 +1233,16 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_append_length(str, type->Basic.name.text, type->Basic.name.len); break; + case Type_Pointer: + str = gb_string_appendc(str, "^"); + str = write_type_to_string(str, type->Pointer.elem); + break; + + case Type_Maybe: + str = gb_string_appendc(str, "?"); + str = write_type_to_string(str, type->Maybe.elem); + break; + case Type_Array: str = gb_string_appendc(str, gb_bprintf("[%td]", type->Array.count)); str = write_type_to_string(str, type->Array.elem); @@ -1266,10 +1310,6 @@ gbString write_type_to_string(gbString str, Type *type) { } } break; - case Type_Pointer: - str = gb_string_appendc(str, "^"); - str = write_type_to_string(str, type->Pointer.elem); - break; case Type_Named: if (type->Named.type_name != NULL) { diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index bb9b999ee..a843da551 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -389,6 +389,11 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Pointer.elem); ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep); } break; + case Type_Maybe: { + tag = ssa_add_local_generated(proc, t_type_info_maybe); + ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Maybe.elem); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep); + } break; case Type_Array: { tag = ssa_add_local_generated(proc, t_type_info_array); ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Array.elem); diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index f565e3570..1abbdb0d1 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -160,6 +160,17 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { case Basic_any: ssa_fprintf(f, "%%..any"); break; } break; + case Type_Pointer: + ssa_print_type(f, m, t->Pointer.elem); + ssa_fprintf(f, "*"); + break; + case Type_Maybe: + ssa_fprintf(f, "{"); + ssa_print_type(f, m, t->Maybe.elem); + ssa_fprintf(f, ", "); + ssa_print_type(f, m, t_bool); + ssa_fprintf(f, "}"); + break; case Type_Array: ssa_fprintf(f, "[%lld x ", t->Array.count); ssa_print_type(f, m, t->Array.elem); @@ -212,10 +223,7 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { } } break; - case Type_Pointer: - ssa_print_type(f, m, t->Pointer.elem); - ssa_fprintf(f, "*"); - break; + case Type_Named: if (is_type_struct(t) || is_type_union(t)) { String *name = map_get(&m->type_names, hash_pointer(t)); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index cb7c8c380..03879509b 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -561,6 +561,10 @@ Type *ssa_type(ssaValue *value) { } ssaDebugInfo *ssa_add_debug_info_file(ssaProcedure *proc, AstFile *file) { + if (!proc->module->generate_debug_info) { + return NULL; + } + GB_ASSERT(file != NULL); ssaDebugInfo *di = ssa_alloc_debug_info(proc->module->allocator, ssaDebugInfo_File); di->File.file = file; @@ -589,6 +593,10 @@ ssaDebugInfo *ssa_add_debug_info_file(ssaProcedure *proc, AstFile *file) { ssaDebugInfo *ssa_add_debug_info_proc(ssaProcedure *proc, Entity *entity, String name, ssaDebugInfo *file) { + if (!proc->module->generate_debug_info) { + return NULL; + } + GB_ASSERT(entity != NULL); ssaDebugInfo *di = ssa_alloc_debug_info(proc->module->allocator, ssaDebugInfo_Proc); di->Proc.entity = entity; @@ -1719,6 +1727,17 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg return value; } + if (is_type_maybe(dst)) { + gbAllocator a = proc->module->allocator; + Type *elem = base_type(dst)->Maybe.elem; + ssaValue *maybe = ssa_add_local_generated(proc, dst); + ssaValue *val = ssa_emit_struct_gep(proc, maybe, v_zero32, make_type_pointer(a, elem)); + ssaValue *set = ssa_emit_struct_gep(proc, maybe, v_one32, make_type_pointer(a, t_bool)); + ssa_emit_store(proc, val, value); + ssa_emit_store(proc, set, v_true); + return ssa_emit_load(proc, maybe); + } + // integer -> integer if (is_type_integer(src) && is_type_integer(dst)) { GB_ASSERT(src->kind == Type_Basic && @@ -2658,7 +2677,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue return ssa_emit_select(proc, cond, neg_x, x); } break; - case BuiltinProc_enum_to_string: { ssa_emit_comment(proc, make_string("enum_to_string")); ssaValue *x = ssa_build_expr(proc, ce->args[0]); @@ -2671,6 +2689,24 @@ 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; } } } @@ -3214,6 +3250,7 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa } ssaValue *expr = ssa_build_expr(proc, cond); + expr = ssa_emit_conv(proc, expr, t_bool); ssa_emit_if(proc, expr, true_block, false_block); } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 6cdc0c033..83e9d5ad6 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -25,7 +25,7 @@ struct ExactValue { String value_string; i64 value_integer; f64 value_float; - void * value_pointer; + i64 value_pointer; AstNode *value_compound; }; }; @@ -93,7 +93,7 @@ ExactValue make_exact_value_float(f64 f) { ExactValue make_exact_value_pointer(void *ptr) { ExactValue result = {ExactValue_Pointer}; - result.value_pointer = ptr; + result.value_pointer = cast(i64)cast(intptr)ptr; return result; } @@ -121,8 +121,14 @@ ExactValue exact_value_to_integer(ExactValue v) { switch (v.kind) { case ExactValue_Integer: return v; - case ExactValue_Float: - return make_exact_value_integer(cast(i64)v.value_float); + case ExactValue_Float: { + i64 i = cast(i64)v.value_float; + f64 f = cast(f64)i; + if (f == v.value_float) { + return make_exact_value_integer(i); + } + } break; + case ExactValue_Pointer: return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer); } diff --git a/src/parser.cpp b/src/parser.cpp index 6b14e375e..44b1c62b7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -270,6 +270,10 @@ AST_NODE_KIND(_TypeBegin, "", struct{}) \ Token token; \ AstNode *type; \ }) \ + AST_NODE_KIND(MaybeType, "maybe type", struct { \ + Token token; \ + AstNode *type; \ + }) \ AST_NODE_KIND(ArrayType, "array type", struct { \ Token token; \ AstNode *count; \ @@ -454,6 +458,8 @@ Token ast_node_token(AstNode *node) { return node->ProcType.token; case AstNode_PointerType: return node->PointerType.token; + case AstNode_MaybeType: + return node->MaybeType.token; case AstNode_ArrayType: return node->ArrayType.token; case AstNode_VectorType: @@ -477,7 +483,7 @@ HashKey hash_token(Token t) { // NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ -gb_inline AstNode *make_node(AstFile *f, AstNodeKind kind) { +AstNode *make_node(AstFile *f, AstNodeKind kind) { gbArena *arena = &f->arena; if (gb_arena_size_remaining(arena, GB_DEFAULT_MEMORY_ALIGNMENT) <= gb_size_of(AstNode)) { // NOTE(bill): If a syntax error is so bad, just quit! @@ -488,14 +494,14 @@ gb_inline AstNode *make_node(AstFile *f, AstNodeKind kind) { return node; } -gb_inline AstNode *make_bad_expr(AstFile *f, Token begin, Token end) { +AstNode *make_bad_expr(AstFile *f, Token begin, Token end) { AstNode *result = make_node(f, AstNode_BadExpr); result->BadExpr.begin = begin; result->BadExpr.end = end; return result; } -gb_inline AstNode *make_tag_expr(AstFile *f, Token token, Token name, AstNode *expr) { +AstNode *make_tag_expr(AstFile *f, Token token, Token name, AstNode *expr) { AstNode *result = make_node(f, AstNode_TagExpr); result->TagExpr.token = token; result->TagExpr.name = name; @@ -503,7 +509,7 @@ gb_inline AstNode *make_tag_expr(AstFile *f, Token token, Token name, AstNode *e return result; } -gb_inline AstNode *make_tag_stmt(AstFile *f, Token token, Token name, AstNode *stmt) { +AstNode *make_tag_stmt(AstFile *f, Token token, Token name, AstNode *stmt) { AstNode *result = make_node(f, AstNode_TagStmt); result->TagStmt.token = token; result->TagStmt.name = name; @@ -511,14 +517,14 @@ gb_inline AstNode *make_tag_stmt(AstFile *f, Token token, Token name, AstNode *s return result; } -gb_inline AstNode *make_unary_expr(AstFile *f, Token op, AstNode *expr) { +AstNode *make_unary_expr(AstFile *f, Token op, AstNode *expr) { AstNode *result = make_node(f, AstNode_UnaryExpr); result->UnaryExpr.op = op; result->UnaryExpr.expr = expr; return result; } -gb_inline AstNode *make_binary_expr(AstFile *f, Token op, AstNode *left, AstNode *right) { +AstNode *make_binary_expr(AstFile *f, Token op, AstNode *left, AstNode *right) { AstNode *result = make_node(f, AstNode_BinaryExpr); if (left == NULL) { @@ -537,7 +543,7 @@ gb_inline AstNode *make_binary_expr(AstFile *f, Token op, AstNode *left, AstNode return result; } -gb_inline AstNode *make_paren_expr(AstFile *f, AstNode *expr, Token open, Token close) { +AstNode *make_paren_expr(AstFile *f, AstNode *expr, Token open, Token close) { AstNode *result = make_node(f, AstNode_ParenExpr); result->ParenExpr.expr = expr; result->ParenExpr.open = open; @@ -545,7 +551,7 @@ gb_inline AstNode *make_paren_expr(AstFile *f, AstNode *expr, Token open, Token return result; } -gb_inline AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, Token close, Token ellipsis) { +AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, Token close, Token ellipsis) { AstNode *result = make_node(f, AstNode_CallExpr); result->CallExpr.proc = proc; result->CallExpr.args = args; @@ -555,14 +561,14 @@ gb_inline AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, return result; } -gb_inline AstNode *make_selector_expr(AstFile *f, Token token, AstNode *expr, AstNode *selector) { +AstNode *make_selector_expr(AstFile *f, Token token, AstNode *expr, AstNode *selector) { AstNode *result = make_node(f, AstNode_SelectorExpr); result->SelectorExpr.expr = expr; result->SelectorExpr.selector = selector; return result; } -gb_inline AstNode *make_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open, Token close) { +AstNode *make_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open, Token close) { AstNode *result = make_node(f, AstNode_IndexExpr); result->IndexExpr.expr = expr; result->IndexExpr.index = index; @@ -572,7 +578,7 @@ gb_inline AstNode *make_index_expr(AstFile *f, AstNode *expr, AstNode *index, To } -gb_inline AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, AstNode *low, AstNode *high, AstNode *max, b32 triple_indexed) { +AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, AstNode *low, AstNode *high, AstNode *max, b32 triple_indexed) { AstNode *result = make_node(f, AstNode_SliceExpr); result->SliceExpr.expr = expr; result->SliceExpr.open = open; @@ -584,7 +590,7 @@ gb_inline AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token return result; } -gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) { +AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) { AstNode *result = make_node(f, AstNode_DerefExpr); result->DerefExpr.expr = expr; result->DerefExpr.op = op; @@ -592,19 +598,19 @@ gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) { } -gb_inline 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); result->BasicLit = basic_lit; return result; } -gb_inline AstNode *make_ident(AstFile *f, Token token) { +AstNode *make_ident(AstFile *f, Token token) { AstNode *result = make_node(f, AstNode_Ident); result->Ident = token; return result; } -gb_inline AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) { +AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) { AstNode *result = make_node(f, AstNode_Ellipsis); result->Ellipsis.token = token; result->Ellipsis.expr = expr; @@ -612,7 +618,7 @@ gb_inline AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) { } -gb_inline AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) { +AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) { AstNode *result = make_node(f, AstNode_ProcLit); result->ProcLit.type = type; result->ProcLit.body = body; @@ -620,7 +626,7 @@ gb_inline AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 t return result; } -gb_inline AstNode *make_field_value(AstFile *f, AstNode *field, AstNode *value, Token eq) { +AstNode *make_field_value(AstFile *f, AstNode *field, AstNode *value, Token eq) { AstNode *result = make_node(f, AstNode_FieldValue); result->FieldValue.field = field; result->FieldValue.value = value; @@ -628,7 +634,7 @@ gb_inline AstNode *make_field_value(AstFile *f, AstNode *field, AstNode *value, return result; } -gb_inline AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token open, Token close) { +AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token open, Token close) { AstNode *result = make_node(f, AstNode_CompoundLit); result->CompoundLit.type = type; result->CompoundLit.elems = elems; @@ -637,33 +643,33 @@ gb_inline AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray ele return result; } -gb_inline AstNode *make_bad_stmt(AstFile *f, Token begin, Token end) { +AstNode *make_bad_stmt(AstFile *f, Token begin, Token end) { AstNode *result = make_node(f, AstNode_BadStmt); result->BadStmt.begin = begin; result->BadStmt.end = end; return result; } -gb_inline AstNode *make_empty_stmt(AstFile *f, Token token) { +AstNode *make_empty_stmt(AstFile *f, Token token) { AstNode *result = make_node(f, AstNode_EmptyStmt); result->EmptyStmt.token = token; return result; } -gb_inline AstNode *make_expr_stmt(AstFile *f, AstNode *expr) { +AstNode *make_expr_stmt(AstFile *f, AstNode *expr) { AstNode *result = make_node(f, AstNode_ExprStmt); result->ExprStmt.expr = expr; return result; } -gb_inline AstNode *make_inc_dec_stmt(AstFile *f, Token op, AstNode *expr) { +AstNode *make_inc_dec_stmt(AstFile *f, Token op, AstNode *expr) { AstNode *result = make_node(f, AstNode_IncDecStmt); result->IncDecStmt.op = op; result->IncDecStmt.expr = expr; return result; } -gb_inline AstNode *make_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rhs) { +AstNode *make_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rhs) { AstNode *result = make_node(f, AstNode_AssignStmt); result->AssignStmt.op = op; result->AssignStmt.lhs = lhs; @@ -671,7 +677,7 @@ gb_inline AstNode *make_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstN return result; } -gb_inline AstNode *make_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) { +AstNode *make_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) { AstNode *result = make_node(f, AstNode_BlockStmt); result->BlockStmt.stmts = stmts; result->BlockStmt.open = open; @@ -679,7 +685,7 @@ gb_inline AstNode *make_block_stmt(AstFile *f, AstNodeArray stmts, Token open, T return result; } -gb_inline AstNode *make_if_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body, AstNode *else_stmt) { +AstNode *make_if_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body, AstNode *else_stmt) { AstNode *result = make_node(f, AstNode_IfStmt); result->IfStmt.token = token; result->IfStmt.init = init; @@ -689,14 +695,14 @@ gb_inline AstNode *make_if_stmt(AstFile *f, Token token, AstNode *init, AstNode return result; } -gb_inline AstNode *make_return_stmt(AstFile *f, Token token, AstNodeArray results) { +AstNode *make_return_stmt(AstFile *f, Token token, AstNodeArray results) { AstNode *result = make_node(f, AstNode_ReturnStmt); result->ReturnStmt.token = token; result->ReturnStmt.results = results; return result; } -gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) { +AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) { AstNode *result = make_node(f, AstNode_ForStmt); result->ForStmt.token = token; result->ForStmt.init = init; @@ -707,7 +713,7 @@ gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode } -gb_inline AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) { +AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) { AstNode *result = make_node(f, AstNode_MatchStmt); result->MatchStmt.token = token; result->MatchStmt.init = init; @@ -717,7 +723,7 @@ gb_inline AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNo } -gb_inline AstNode *make_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *var, AstNode *body) { +AstNode *make_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *var, AstNode *body) { AstNode *result = make_node(f, AstNode_TypeMatchStmt); result->TypeMatchStmt.token = token; result->TypeMatchStmt.tag = tag; @@ -726,7 +732,7 @@ gb_inline AstNode *make_type_match_stmt(AstFile *f, Token token, AstNode *tag, A return result; } -gb_inline AstNode *make_case_clause(AstFile *f, Token token, AstNodeArray list, AstNodeArray stmts) { +AstNode *make_case_clause(AstFile *f, Token token, AstNodeArray list, AstNodeArray stmts) { AstNode *result = make_node(f, AstNode_CaseClause); result->CaseClause.token = token; result->CaseClause.list = list; @@ -735,27 +741,27 @@ gb_inline AstNode *make_case_clause(AstFile *f, Token token, AstNodeArray list, } -gb_inline AstNode *make_defer_stmt(AstFile *f, Token token, AstNode *stmt) { +AstNode *make_defer_stmt(AstFile *f, Token token, AstNode *stmt) { AstNode *result = make_node(f, AstNode_DeferStmt); result->DeferStmt.token = token; result->DeferStmt.stmt = stmt; return result; } -gb_inline AstNode *make_branch_stmt(AstFile *f, Token token) { +AstNode *make_branch_stmt(AstFile *f, Token token) { AstNode *result = make_node(f, AstNode_BranchStmt); result->BranchStmt.token = token; return result; } -gb_inline AstNode *make_using_stmt(AstFile *f, Token token, AstNode *node) { +AstNode *make_using_stmt(AstFile *f, Token token, AstNode *node) { AstNode *result = make_node(f, AstNode_UsingStmt); result->UsingStmt.token = token; result->UsingStmt.node = node; return result; } -gb_inline AstNode *make_asm_operand(AstFile *f, Token string, AstNode *operand) { +AstNode *make_asm_operand(AstFile *f, Token string, AstNode *operand) { AstNode *result = make_node(f, AstNode_AsmOperand); result->AsmOperand.string = string; result->AsmOperand.operand = operand; @@ -763,7 +769,7 @@ gb_inline AstNode *make_asm_operand(AstFile *f, Token string, AstNode *operand) } -gb_inline AstNode *make_asm_stmt(AstFile *f, Token token, b32 is_volatile, Token open, Token close, Token code_string, +AstNode *make_asm_stmt(AstFile *f, Token token, b32 is_volatile, Token open, Token close, Token code_string, AstNode *output_list, AstNode *input_list, AstNode *clobber_list, isize output_count, isize input_count, isize clobber_count) { AstNode *result = make_node(f, AstNode_AsmStmt); @@ -781,7 +787,7 @@ gb_inline AstNode *make_asm_stmt(AstFile *f, Token token, b32 is_volatile, Token return result; } -gb_inline AstNode *make_push_allocator(AstFile *f, Token token, AstNode *expr, AstNode *body) { +AstNode *make_push_allocator(AstFile *f, Token token, AstNode *expr, AstNode *body) { AstNode *result = make_node(f, AstNode_PushAllocator); result->PushAllocator.token = token; result->PushAllocator.expr = expr; @@ -789,7 +795,7 @@ gb_inline AstNode *make_push_allocator(AstFile *f, Token token, AstNode *expr, A return result; } -gb_inline AstNode *make_push_context(AstFile *f, Token token, AstNode *expr, AstNode *body) { +AstNode *make_push_context(AstFile *f, Token token, AstNode *expr, AstNode *body) { AstNode *result = make_node(f, AstNode_PushContext); result->PushContext.token = token; result->PushContext.expr = expr; @@ -800,14 +806,14 @@ gb_inline AstNode *make_push_context(AstFile *f, Token token, AstNode *expr, Ast -gb_inline AstNode *make_bad_decl(AstFile *f, Token begin, Token end) { +AstNode *make_bad_decl(AstFile *f, Token begin, Token end) { AstNode *result = make_node(f, AstNode_BadDecl); result->BadDecl.begin = begin; result->BadDecl.end = end; return result; } -gb_inline AstNode *make_var_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) { +AstNode *make_var_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) { AstNode *result = make_node(f, AstNode_VarDecl); result->VarDecl.names = names; result->VarDecl.type = type; @@ -815,7 +821,7 @@ gb_inline AstNode *make_var_decl(AstFile *f, AstNodeArray names, AstNode *type, return result; } -gb_inline AstNode *make_const_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) { +AstNode *make_const_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) { AstNode *result = make_node(f, AstNode_ConstDecl); result->ConstDecl.names = names; result->ConstDecl.type = type; @@ -823,7 +829,7 @@ gb_inline AstNode *make_const_decl(AstFile *f, AstNodeArray names, AstNode *type return result; } -gb_inline AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, b32 is_using) { +AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, b32 is_using) { AstNode *result = make_node(f, AstNode_Parameter); result->Parameter.names = names; result->Parameter.type = type; @@ -831,7 +837,7 @@ gb_inline AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, return result; } -gb_inline AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results) { +AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results) { AstNode *result = make_node(f, AstNode_ProcType); result->ProcType.token = token; result->ProcType.params = params; @@ -839,7 +845,7 @@ gb_inline AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, return result; } -gb_inline AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) { +AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) { AstNode *result = make_node(f, AstNode_ProcDecl); result->ProcDecl.name = name; result->ProcDecl.type = proc_type; @@ -850,14 +856,21 @@ gb_inline AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, return result; } -gb_inline AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type) { +AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type) { AstNode *result = make_node(f, AstNode_PointerType); result->PointerType.token = token; result->PointerType.type = type; return result; } -gb_inline AstNode *make_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem) { +AstNode *make_maybe_type(AstFile *f, Token token, AstNode *type) { + AstNode *result = make_node(f, AstNode_MaybeType); + result->MaybeType.token = token; + result->MaybeType.type = type; + return result; +} + +AstNode *make_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem) { AstNode *result = make_node(f, AstNode_ArrayType); result->ArrayType.token = token; result->ArrayType.count = count; @@ -865,7 +878,7 @@ gb_inline AstNode *make_array_type(AstFile *f, Token token, AstNode *count, AstN return result; } -gb_inline AstNode *make_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem) { +AstNode *make_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem) { AstNode *result = make_node(f, AstNode_VectorType); result->VectorType.token = token; result->VectorType.count = count; @@ -873,7 +886,7 @@ gb_inline AstNode *make_vector_type(AstFile *f, Token token, AstNode *count, Ast return result; } -gb_inline AstNode *make_struct_type(AstFile *f, Token token, AstNodeArray decls, isize decl_count, b32 is_packed, b32 is_ordered) { +AstNode *make_struct_type(AstFile *f, Token token, AstNodeArray decls, isize decl_count, b32 is_packed, b32 is_ordered) { AstNode *result = make_node(f, AstNode_StructType); result->StructType.token = token; result->StructType.decls = decls; @@ -884,7 +897,7 @@ gb_inline AstNode *make_struct_type(AstFile *f, Token token, AstNodeArray decls, } -gb_inline AstNode *make_union_type(AstFile *f, Token token, AstNodeArray decls, isize decl_count) { +AstNode *make_union_type(AstFile *f, Token token, AstNodeArray decls, isize decl_count) { AstNode *result = make_node(f, AstNode_UnionType); result->UnionType.token = token; result->UnionType.decls = decls; @@ -892,7 +905,7 @@ gb_inline AstNode *make_union_type(AstFile *f, Token token, AstNodeArray decls, return result; } -gb_inline AstNode *make_raw_union_type(AstFile *f, Token token, AstNodeArray decls, isize decl_count) { +AstNode *make_raw_union_type(AstFile *f, Token token, AstNodeArray decls, isize decl_count) { AstNode *result = make_node(f, AstNode_RawUnionType); result->RawUnionType.token = token; result->RawUnionType.decls = decls; @@ -901,7 +914,7 @@ gb_inline AstNode *make_raw_union_type(AstFile *f, Token token, AstNodeArray dec } -gb_inline AstNode *make_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArray fields) { +AstNode *make_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArray fields) { AstNode *result = make_node(f, AstNode_EnumType); result->EnumType.token = token; result->EnumType.base_type = base_type; @@ -909,7 +922,7 @@ gb_inline AstNode *make_enum_type(AstFile *f, Token token, AstNode *base_type, A return result; } -gb_inline AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNode *type) { +AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNode *type) { AstNode *result = make_node(f, AstNode_TypeDecl); result->TypeDecl.token = token; result->TypeDecl.name = name; @@ -917,7 +930,7 @@ gb_inline AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNod return result; } -gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_name, b32 is_load) { +AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_name, b32 is_load) { AstNode *result = make_node(f, AstNode_ImportDecl); result->ImportDecl.token = token; result->ImportDecl.relpath = relpath; @@ -926,7 +939,7 @@ gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Toke return result; } -gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) { +AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) { AstNode *result = make_node(f, AstNode_ForeignSystemLibrary); result->ForeignSystemLibrary.token = token; result->ForeignSystemLibrary.filepath = filepath; @@ -950,7 +963,7 @@ b32 next_token(AstFile *f) { return false; } -gb_inline Token expect_token(AstFile *f, TokenKind kind) { +Token expect_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind != kind) { syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`", @@ -961,7 +974,7 @@ gb_inline Token expect_token(AstFile *f, TokenKind kind) { return prev; } -gb_inline Token expect_token_after(AstFile *f, TokenKind kind, char *msg) { +Token expect_token_after(AstFile *f, TokenKind kind, char *msg) { Token prev = f->curr_token; if (prev.kind != kind) { syntax_error(f->curr_token, "Expected `%.*s` after %s, got `%.*s`", @@ -974,7 +987,7 @@ gb_inline Token expect_token_after(AstFile *f, TokenKind kind, char *msg) { } -gb_inline Token expect_operator(AstFile *f) { +Token expect_operator(AstFile *f) { Token prev = f->curr_token; if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) { syntax_error(f->curr_token, "Expected an operator, got `%.*s`", @@ -984,7 +997,7 @@ gb_inline Token expect_operator(AstFile *f) { return prev; } -gb_inline Token expect_keyword(AstFile *f) { +Token expect_keyword(AstFile *f) { Token prev = f->curr_token; if (!gb_is_between(prev.kind, Token__KeywordBegin+1, Token__KeywordEnd-1)) { syntax_error(f->curr_token, "Expected a keyword, got `%.*s`", @@ -994,7 +1007,7 @@ gb_inline Token expect_keyword(AstFile *f) { return prev; } -gb_inline b32 allow_token(AstFile *f, TokenKind kind) { +b32 allow_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind == kind) { next_token(f); @@ -1986,8 +1999,17 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { return e; } - case Token_Pointer: - return make_pointer_type(f, expect_token(f, Token_Pointer), parse_type(f)); + case Token_Pointer: { + Token token = expect_token(f, Token_Pointer); + AstNode *elem = parse_type(f); + return make_pointer_type(f, token, elem); + } + + case Token_Maybe: { + Token token = expect_token(f, Token_Maybe); + AstNode *elem = parse_type(f); + return make_maybe_type(f, token, elem); + } case Token_OpenBracket: { f->expr_level++; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index c86a4b2f8..224d9bc51 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -17,6 +17,7 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ TOKEN_KIND(Token_Hash, "#"), \ TOKEN_KIND(Token_At, "@"), \ TOKEN_KIND(Token_Pointer, "^"), \ + TOKEN_KIND(Token_Maybe, "?"), \ TOKEN_KIND(Token_Add, "+"), \ TOKEN_KIND(Token_Sub, "-"), \ TOKEN_KIND(Token_Mul, "*"), \ @@ -720,6 +721,7 @@ Token tokenizer_get_token(Tokenizer *t) { case '#': token.kind = Token_Hash; break; case '@': token.kind = Token_At; break; case '^': token.kind = Token_Pointer; break; + case '?': token.kind = Token_Maybe; break; case ';': token.kind = Token_Semicolon; break; case ',': token.kind = Token_Comma; break; case '(': token.kind = Token_OpenParen; break;