union_cast

This commit is contained in:
Ginger Bill
2016-10-16 21:31:06 +01:00
parent b9719df0ad
commit a675d3f94d
8 changed files with 292 additions and 53 deletions

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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]) {