diff --git a/code/demo.odin b/code/demo.odin index 3011b745a..78cee21d4 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,13 +1,25 @@ #import "fmt.odin" main :: proc() { - Thing :: struct { - f: f32 - a: any + Entity :: union { + Apple: int + Banana: f32 + Goat: struct { + x, y: int + z, w: f32 + } } - t := Thing{1, "Hello"} + a := 123 as Entity.Apple + e: Entity = a + fmt.println(a) - fmt.printf("Here % %\n", 123, 2.0) + if apple, ok := ^e union_cast ^Entity.Apple; ok { + apple^ = 321 + e = apple^ + } + + apple, ok := e union_cast Entity.Apple + fmt.println(apple) } diff --git a/core/fmt.odin b/core/fmt.odin index 6e2f24d1a..618fee9b9 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -4,35 +4,38 @@ PRINT_BUF_SIZE :: 1<<12 -fprint :: proc(f: ^os.File, args: ..any) { +fprint :: proc(f: ^os.File, args: ..any) -> int { data: [PRINT_BUF_SIZE]byte buf := data[:0] bprint(^buf, ..args) os.write(f, buf) + return buf.count } -fprintln :: proc(f: ^os.File, args: ..any) { +fprintln :: proc(f: ^os.File, args: ..any) -> int { data: [PRINT_BUF_SIZE]byte buf := data[:0] bprintln(^buf, ..args) os.write(f, buf) + return buf.count } -fprintf :: proc(f: ^os.File, fmt: string, args: ..any) { +fprintf :: proc(f: ^os.File, fmt: string, args: ..any) -> int { data: [PRINT_BUF_SIZE]byte buf := data[:0] bprintf(^buf, fmt, ..args) os.write(f, buf) + return buf.count } -print :: proc(args: ..any) { - fprint(os.stdout, ..args) +print :: proc(args: ..any) -> int { + return fprint(os.stdout, ..args) } -println :: proc(args: ..any) { - fprintln(os.stdout, ..args) +println :: proc(args: ..any) -> int { + return fprintln(os.stdout, ..args) } -printf :: proc(fmt: string, args: ..any) { - fprintf(os.stdout, fmt, ..args) +printf :: proc(fmt: string, args: ..any) -> int { + return fprintf(os.stdout, fmt, ..args) } @@ -288,9 +291,7 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { using Type_Info match type info : arg.type_info { case Named: - a: any - a.type_info = info.base - a.data = arg.data + a := make_any(info.base, arg.data) match type b : info.base { case Struct: print_string_to_buffer(buf, info.name) @@ -491,7 +492,7 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { } -bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) { +bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) -> int { is_digit :: proc(r: rune) -> bool #inline { return r >= #rune "0" && r <= #rune "9" } @@ -552,10 +553,11 @@ bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) { } print_string_to_buffer(buf, fmt[prev:]) + return buf.count } -bprint :: proc(buf: ^[]byte, args: ..any) { +bprint :: proc(buf: ^[]byte, args: ..any) -> int { is_type_string :: proc(info: ^Type_Info) -> bool { using Type_Info if info == nil { @@ -580,9 +582,10 @@ bprint :: proc(buf: ^[]byte, args: ..any) { print_any_to_buffer(buf, arg) prev_string = is_string; } + return buf.count } -bprintln :: proc(buf: ^[]byte, args: ..any) { +bprintln :: proc(buf: ^[]byte, args: ..any) -> int { for i := 0; i < args.count; i++ { if i > 0 { append(buf, #rune " ") @@ -590,4 +593,5 @@ bprintln :: proc(buf: ^[]byte, args: ..any) { print_any_to_buffer(buf, args[i]) } print_nl_to_buffer(buf) + return buf.count } diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index e71266edf..bb3a6db2e 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -933,11 +933,15 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl o->type = t_invalid; return; } - // if (e->Variable.param) { - // o->mode = Addressing_Value; - // } else { + #if 0 + if (e->Variable.param) { + o->mode = Addressing_Value; + } else { o->mode = Addressing_Variable; - // } + } + #else + o->mode = Addressing_Variable; + #endif break; case Entity_TypeName: { @@ -1869,14 +1873,14 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { return; } - i64 otz = type_size_of(c->sizes, c->allocator, x->type); - i64 ttz = type_size_of(c->sizes, c->allocator, type); - if (otz != ttz) { + i64 srcz = type_size_of(c->sizes, c->allocator, x->type); + i64 dstz = type_size_of(c->sizes, c->allocator, type); + if (srcz != dstz) { gbString expr_str = expr_to_string(x->expr); gbString type_str = type_to_string(type); defer (gb_string_free(expr_str)); defer (gb_string_free(type_str)); - error(ast_node_token(x->expr), "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, otz, ttz); + error(ast_node_token(x->expr), "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, srcz, dstz); x->mode = Addressing_Invalid; return; } @@ -1887,8 +1891,9 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { } else if (be->op.kind == Token_down_cast) { check_expr(c, x, be->left); Type *type = check_type(c, be->right); - if (x->mode == Addressing_Invalid) + if (x->mode == Addressing_Invalid) { return; + } if (x->mode == Addressing_Constant) { gbString expr_str = expr_to_string(node); @@ -1927,7 +1932,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { return; } - if (!(is_type_struct(bdst) || is_type_struct(bdst))) { + if (!(is_type_struct(bdst) || is_type_raw_union(bdst))) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); error(ast_node_token(node), "Can only `down_cast` pointer to structs or unions: `%s`", expr_str); @@ -1947,6 +1952,83 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { x->mode = Addressing_Value; x->type = type; return; + } else if (be->op.kind == Token_union_cast) { + check_expr(c, x, be->left); + Type *type = check_type(c, be->right); + if (x->mode == Addressing_Invalid) { + return; + } + + if (x->mode == Addressing_Constant) { + gbString expr_str = expr_to_string(node); + defer (gb_string_free(expr_str)); + error(ast_node_token(node), "Cannot `union_cast` a constant expression: `%s`", expr_str); + x->mode = Addressing_Invalid; + return; + } + + if (is_type_untyped(x->type)) { + gbString expr_str = expr_to_string(node); + defer (gb_string_free(expr_str)); + error(ast_node_token(node), "Cannot `union_cast` an untyped expression: `%s`", expr_str); + x->mode = Addressing_Invalid; + return; + } + + b32 src_is_ptr = is_type_pointer(x->type); + b32 dst_is_ptr = is_type_pointer(type); + Type *src = type_deref(x->type); + Type *dst = type_deref(type); + Type *bsrc = base_type(src); + Type *bdst = base_type(dst); + + if (src_is_ptr != dst_is_ptr) { + gbString src_type_str = type_to_string(x->type); + gbString dst_type_str = type_to_string(type); + defer (gb_string_free(src_type_str)); + defer (gb_string_free(dst_type_str)); + error(ast_node_token(node), "Invalid `union_cast` types: `%s` and `%s`", src_type_str, dst_type_str); + x->mode = Addressing_Invalid; + return; + } + + if (!is_type_union(src)) { + error(ast_node_token(node), "`union_cast` can only operate on unions"); + x->mode = Addressing_Invalid; + return; + } + + b32 ok = false; + for (isize i = 1; i < bsrc->Record.field_count; i++) { + Entity *f = bsrc->Record.fields[i]; + if (are_types_identical(f->type, dst)) { + ok = true; + break; + } + } + + if (!ok) { + gbString expr_str = expr_to_string(node); + gbString dst_type_str = type_to_string(type); + defer (gb_string_free(expr_str)); + defer (gb_string_free(dst_type_str)); + error(ast_node_token(node), "Cannot `union_cast` `%s` to `%s`", expr_str, dst_type_str); + x->mode = Addressing_Invalid; + return; + } + + Entity **variables = gb_alloc_array(c->allocator, Entity *, 2); + Token tok = make_token_ident(make_string("")); + variables[0] = make_entity_param(c->allocator, NULL, tok, type, 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; + + x->type = tuple; + x->mode = Addressing_Value; + return; } check_expr(c, x, be->left); @@ -3723,6 +3805,12 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->expr = node; case_end; + case_ast_node(re, RunExpr, node); + // TODO(bill): Tag expressions + kind = check_expr_base(c, o, re->expr, type_hint); + o->expr = node; + case_end; + case_ast_node(ue, UnaryExpr, node); check_expr(c, o, ue->expr); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 80f5b7e12..b93d42d21 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -840,7 +840,7 @@ ssaValue *ssa_make_instr_get_element_ptr(ssaProcedure *p, ssaValue *address, i->GetElementPtr.indices[1] = index1; i->GetElementPtr.index_count = index_count; i->GetElementPtr.elem_type = ssa_type(address); - i->GetElementPtr.inbounds = inbounds; + GB_ASSERT_MSG(is_type_pointer(ssa_type(address)), "%s", type_to_string(ssa_type(address))); return v; @@ -1169,8 +1169,12 @@ ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) { ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e); +#if 1 ssaValue *l = ssa_add_local(proc, e); ssa_emit_store(proc, l, v); +#else + ssa_module_add_value(proc->module, e, v); +#endif return v; } @@ -1418,7 +1422,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) { proc->curr_block = proc->decl_block; ssa_emit_jump(proc, proc->entry_block); -#if 0 +#if 1 ssa_optimize_blocks(proc); ssa_build_referrers(proc); ssa_build_dom_tree(proc); @@ -1902,6 +1906,10 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { return make_string(""); } +ssaValue *ssa_emit_bitcast(ssaProcedure *proc, ssaValue *data, Type *type) { + return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, data, ssa_type(data), type)); +} + ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_argument) { Type *src_type = ssa_type(value); @@ -2029,7 +2037,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg Type *tag_type = src_type; Type *tag_type_ptr = make_type_pointer(allocator, tag_type); - ssaValue *underlying = ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, data, t_rawptr, tag_type_ptr)); + ssaValue *underlying = ssa_emit_bitcast(proc, data, tag_type_ptr); ssa_emit_store(proc, underlying, value); return ssa_emit_load(proc, parent); @@ -2063,23 +2071,23 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg // Pointer <-> Pointer if (is_type_pointer(src) && is_type_pointer(dst)) { - return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + return ssa_emit_bitcast(proc, value, dst); } // proc <-> proc if (is_type_proc(src) && is_type_proc(dst)) { - return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + return ssa_emit_bitcast(proc, value, dst); } // pointer -> proc if (is_type_pointer(src) && is_type_proc(dst)) { - return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + return ssa_emit_bitcast(proc, value, dst); } // proc -> pointer if (is_type_proc(src) && is_type_pointer(dst)) { - return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + return ssa_emit_bitcast(proc, value, dst); } @@ -2180,7 +2188,7 @@ ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) { i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst); if (sz == dz) { - return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + return ssa_emit_bitcast(proc, value, dst); } @@ -2205,6 +2213,94 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) { return ssa_emit_conv(proc, head, t); } +ssaValue *ssa_emit_union_cast(ssaProcedure *proc, ssaValue *value, Type *tuple) { + GB_ASSERT(tuple->kind == Type_Tuple); + gbAllocator a = proc->module->allocator; + + Type *src_type = ssa_type(value); + b32 is_ptr = is_type_pointer(src_type); + + Type *t_bool_ptr = make_type_pointer(a, t_bool); + Type *t_int_ptr = make_type_pointer(a, t_int); + + ssaValue *v = ssa_add_local_generated(proc, tuple); + + if (is_ptr) { + Type *src = base_type(type_deref(src_type)); + Type *src_ptr = src_type; + GB_ASSERT(is_type_union(src)); + Type *dst_ptr = tuple->Tuple.variables[0]->type; + Type *dst = type_deref(dst_ptr); + + ssaValue *tag = ssa_emit_load(proc, ssa_emit_struct_gep(proc, value, v_one32, t_int_ptr)); + ssaValue *dst_tag = NULL; + for (isize i = 1; i < src->Record.field_count; i++) { + Entity *f = src->Record.fields[i]; + if (are_types_identical(f->type, dst)) { + dst_tag = ssa_make_const_int(a, i); + break; + } + } + GB_ASSERT(dst_tag != NULL); + + + ssaBlock *ok_block = ssa_add_block(proc, NULL, "union_cast.ok"); + ssaBlock *end_block = ssa_add_block(proc, NULL, "union_cast.end"); + ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag, dst_tag); + ssa_emit_if(proc, cond, ok_block, end_block); + proc->curr_block = ok_block; + + ssaValue *gep0 = ssa_emit_struct_gep(proc, v, v_zero32, make_type_pointer(a, dst_ptr)); + ssaValue *gep1 = ssa_emit_struct_gep(proc, v, v_one32, t_bool_ptr); + + ssaValue *data = ssa_emit_conv(proc, value, dst_ptr); + ssa_emit_store(proc, gep0, data); + ssa_emit_store(proc, gep1, v_true); + + ssa_emit_jump(proc, end_block); + proc->curr_block = end_block; + + } else { + Type *src = base_type(src_type); + GB_ASSERT(is_type_union(src)); + Type *dst = tuple->Tuple.variables[0]->type; + Type *dst_ptr = make_type_pointer(a, dst); + + ssaValue *tag = ssa_emit_struct_ev(proc, value, 1, t_int); + ssaValue *dst_tag = NULL; + for (isize i = 1; i < src->Record.field_count; i++) { + Entity *f = src->Record.fields[i]; + if (are_types_identical(f->type, dst)) { + dst_tag = ssa_make_const_int(a, i); + break; + } + } + GB_ASSERT(dst_tag != NULL); + + // HACK(bill): This is probably not very efficient + ssaValue *union_copy = ssa_add_local_generated(proc, src_type); + ssa_emit_store(proc, union_copy, value); + + ssaBlock *ok_block = ssa_add_block(proc, NULL, "union_cast.ok"); + ssaBlock *end_block = ssa_add_block(proc, NULL, "union_cast.end"); + ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag, dst_tag); + ssa_emit_if(proc, cond, ok_block, end_block); + proc->curr_block = ok_block; + + ssaValue *gep0 = ssa_emit_struct_gep(proc, v, v_zero32, dst_ptr); + ssaValue *gep1 = ssa_emit_struct_gep(proc, v, v_one32, t_bool_ptr); + + ssaValue *data = ssa_emit_load(proc, ssa_emit_conv(proc, union_copy, dst_ptr)); + ssa_emit_store(proc, gep0, data); + ssa_emit_store(proc, gep1, v_true); + + ssa_emit_jump(proc, end_block); + proc->curr_block = end_block; + + } + return ssa_emit_load(proc, v); +} + void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssaBlock *false_block); ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) { @@ -2325,6 +2421,7 @@ ssaValue *ssa_find_implicit_value_backing(ssaProcedure *proc, ImplicitValueId id ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) { + expr = unparen_expr(expr); switch (expr->kind) { case_ast_node(bl, BasicLit, expr); GB_PANIC("Non-constant basic literal"); @@ -2350,13 +2447,17 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue if (v->kind == ssaValue_Proc) { return v; } + // if (e->kind == Entity_Variable && e->Variable.param) { + // return v; + // } return ssa_emit_load(proc, v); } return NULL; case_end; - case_ast_node(pe, ParenExpr, expr); - return ssa_build_single_expr(proc, unparen_expr(expr), tv); + case_ast_node(re, RunExpr, expr); + // TODO(bill): Run Expression + return ssa_build_single_expr(proc, re->expr, tv); case_end; case_ast_node(de, DerefExpr, expr); @@ -2364,6 +2465,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_end; case_ast_node(se, SelectorExpr, expr); + TypeAndValue *tav = map_get(&proc->module->info->types, hash_pointer(expr)); + GB_ASSERT(tav != NULL); return ssa_lvalue_load(proc, ssa_build_addr(proc, expr)); case_end; @@ -2441,6 +2544,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssa_emit_comment(proc, make_string("cast - down_cast")); return ssa_emit_down_cast(proc, ssa_build_expr(proc, be->left), tv->type); + case Token_union_cast: + ssa_emit_comment(proc, make_string("cast - union_cast")); + return ssa_emit_union_cast(proc, ssa_build_expr(proc, be->left), tv->type); + default: GB_PANIC("Invalid binary expression"); break; diff --git a/src/gb/gb.h b/src/gb/gb.h index c1a461cbc..6c6cc4037 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -1,4 +1,4 @@ -/* gb.h - v0.26c - Ginger Bill's C Helper Library - public domain +/* gb.h - v0.26d - Ginger Bill's C Helper Library - public domain - no warranty implied; use at your own risk This is a single header file with a bunch of useful stuff @@ -58,6 +58,7 @@ TODOS - More date & time functions VERSION HISTORY + 0.26d - Minor changes to how gbFile works 0.26c - gb_str_to_f* fix 0.26b - Minor fixes 0.26a - gbString Fix diff --git a/src/main.cpp b/src/main.cpp index f25f17579..661c4dcfe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ i32 win32_exec_command_line_app(char *name, char *fmt, ...) { va_start(va, fmt); cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va); va_end(va); + // gb_printf("%.*s\n", cast(int)cmd_len, cmd_line); tmp = gb_temp_arena_memory_begin(&string_buffer_arena); defer (gb_temp_arena_memory_end(tmp)); @@ -173,7 +174,7 @@ int main(int argc, char **argv) { return exit_code; } - + #if 1 // For more arguments: http://llvm.org/docs/CommandGuide/llc.html exit_code = win32_exec_command_line_app("llvm-llc", "%.*sbin/llc %.*s.bc -filetype=obj -O%d " @@ -214,6 +215,7 @@ int main(int argc, char **argv) { if (run_output) { win32_exec_command_line_app("odin run", "%.*s.exe", cast(int)base_name_len, output_name); } + #endif #endif #endif #endif diff --git a/src/parser.cpp b/src/parser.cpp index 1cff4b573..6e6d44484 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -122,6 +122,7 @@ AstNodeArray make_ast_node_array(AstFile *f) { AST_NODE_KIND(_ExprBegin, "", struct{}) \ AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \ + AST_NODE_KIND(RunExpr, "run expression", struct { Token token, name; AstNode *expr; }) \ AST_NODE_KIND(UnaryExpr, "unary expression", struct { Token op; AstNode *expr; }) \ AST_NODE_KIND(BinaryExpr, "binary expression", struct { Token op; AstNode *left, *right; } ) \ AST_NODE_KIND(ParenExpr, "parentheses expression", struct { AstNode *expr; Token open, close; }) \ @@ -376,6 +377,8 @@ Token ast_node_token(AstNode *node) { return node->CompoundLit.open; case AstNode_TagExpr: return node->TagExpr.token; + case AstNode_RunExpr: + return node->RunExpr.token; case AstNode_BadExpr: return node->BadExpr.begin; case AstNode_UnaryExpr: @@ -512,6 +515,15 @@ AstNode *make_tag_expr(AstFile *f, Token token, Token name, AstNode *expr) { return result; } +AstNode *make_run_expr(AstFile *f, Token token, Token name, AstNode *expr) { + AstNode *result = make_node(f, AstNode_RunExpr); + result->RunExpr.token = token; + result->RunExpr.name = name; + result->RunExpr.expr = expr; + return result; +} + + AstNode *make_tag_stmt(AstFile *f, Token token, Token name, AstNode *stmt) { AstNode *result = make_node(f, AstNode_TagStmt); result->TagStmt.token = token; @@ -1352,9 +1364,9 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { } case Token_Hash: { - operand = parse_tag_expr(f, NULL); - String name = operand->TagExpr.name.string; - if (name == "rune") { + Token token = expect_token(f, Token_Hash); + Token name = expect_token(f, Token_Identifier); + if (name.string == "rune") { if (f->curr_token.kind == Token_String) { Token *s = &f->curr_token; @@ -1366,20 +1378,28 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { expect_token(f, Token_String); } operand = parse_operand(f, lhs); - } else if (name == "file") { - Token token = operand->TagExpr.name; + } else if (name.string == "file") { + Token token = name; token.kind = Token_String; token.string = token.pos.file; return make_basic_lit(f, token); - } else if (name == "line") { - Token token = operand->TagExpr.name; + } else if (name.string == "line") { + Token token = name; token.kind = Token_Integer; char *str = gb_alloc_array(gb_arena_allocator(&f->arena), char, 20); gb_i64_to_str(token.pos.line, str, 10); token.string = make_string(str); return make_basic_lit(f, token); + } else if (name.string == "run") { + AstNode *expr = parse_expr(f, false); + operand = make_run_expr(f, token, name, expr); + if (unparen_expr(expr)->kind != AstNode_CallExpr) { + error(ast_node_token(expr), "#run can only be applied to procedure calls"); + operand = make_bad_expr(f, token, f->curr_token); + } + warning(token, "#run is not yet implemented"); } else { - operand->TagExpr.expr = parse_expr(f, false); + operand = make_tag_expr(f, token, name, parse_expr(f, false)); } return operand; } @@ -1658,6 +1678,7 @@ i32 token_precedence(Token t) { case Token_as: case Token_transmute: case Token_down_cast: + case Token_union_cast: return 7; } @@ -1705,6 +1726,7 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { case Token_as: case Token_transmute: case Token_down_cast: + case Token_union_cast: right = parse_type(f); break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f7a4d5cf1..0dfab6fc6 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -30,9 +30,10 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ TOKEN_KIND(Token_Shl, "<<"), \ TOKEN_KIND(Token_Shr, ">>"), \ \ - TOKEN_KIND(Token_as, "as"), \ - TOKEN_KIND(Token_transmute, "transmute"), \ - TOKEN_KIND(Token_down_cast, "down_cast"), \ + TOKEN_KIND(Token_as, "as"), \ + TOKEN_KIND(Token_transmute, "transmute"), \ + TOKEN_KIND(Token_down_cast, "down_cast"), \ + TOKEN_KIND(Token_union_cast, "union_cast"), \ \ TOKEN_KIND(Token_Prime, "'"), \ TOKEN_KIND(Token_DoublePrime, "''"), \ @@ -635,6 +636,8 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = Token_transmute; } else if (token.string == token_strings[Token_down_cast]) { token.kind = Token_down_cast; + } else if (token.string == token_strings[Token_union_cast]) { + token.kind = Token_union_cast; } else { for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { if (token.string == token_strings[k]) {