diff --git a/build.bat b/build.bat index 0114637b6..6b50ad58c 100644 --- a/build.bat +++ b/build.bat @@ -4,7 +4,7 @@ set exe_name=odin.exe :: Debug = 0, Release = 1 -set release_mode=1 +set release_mode=0 set compiler_flags= -nologo -Oi -TP -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR- @@ -44,10 +44,10 @@ rem pushd %build_dir% del *.pdb > NUL 2> NUL del *.ilk > NUL 2> NUL - rem cl %compiler_settings% "src\main.cpp" ^ - rem /link %linker_settings% -OUT:%exe_name% ^ - rem && odin run code/demo.odin - odin run code/demo.odin + cl %compiler_settings% "src\main.cpp" ^ + /link %linker_settings% -OUT:%exe_name% ^ + && odin run code/demo.odin + rem odin run code/demo.odin :do_not_compile_exe diff --git a/code/demo.odin b/code/demo.odin index 14f9f5b54..c517169b0 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -3,59 +3,17 @@ #import "hash.odin" #import "mem.odin" -main :: proc() { - { // New Standard Library stuff - s := "Hello" - fmt.println(s, - utf8.valid_string(s), - hash.murmur64(s.data, s.count)) - // utf8.odin - // hash.odin - // - crc, fnv, fnva, murmur - // mem.odin - // - Custom allocators - // - Helpers - } - - { - arena: mem.Arena - mem.init_arena_from_context(^arena, mem.megabytes(16)) // Uses default allocator - defer mem.free_arena(^arena) - - push_allocator mem.arena_allocator(^arena) { - x := new(int) - x^ = 1337 - - fmt.println(x^) - } - - /* - push_allocator x { - ... - } - - is equivalent to this: - - { - prev_allocator := current_context().allocator - current_context().allocator = x - defer current_context().allocator = prev_allocator - - ... - } - */ - - // You can also "push" a context - - c := current_context() - c.allocator = mem.arena_allocator(^arena) - - push_context c { - x := new(int) - x^ = 365 - - fmt.println(x^) - } - } +A :: struct { using e: [12]int } +Vector2 :: raw_union { + using _xy: struct #ordered { x, y: f32 } + using v: {2}f32 + e: [2]f32 +} + +main :: proc() { + v: Vector2 + v.x = 123 + v[1] = 321 + fmt.println(v) } diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index b5f73c187..32563de4c 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -129,6 +129,7 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, entity->Variable.field_index = field_index; entity->Variable.is_field = true; entity->Variable.anonymous = cast(b8)is_anonymous; + entity->Variable.is_using = cast(b8)is_anonymous; return entity; } diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 964e268fa..9bb28b2d3 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -224,6 +224,8 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, isize other_field_index = 0; + Entity *using_index_expr = NULL; + // TODO(bill): Random declarations with DeclInfo #if 0 @@ -365,6 +367,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = name->Ident; Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, vd->is_using, cast(i32)field_index); + e->identifier = name; if (name_token.string == "_") { fields[field_index++] = e; } else { @@ -386,8 +389,30 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Type *t = base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t)) { Token name_token = vd->names[0]->Ident; - error(name_token, "`using` on a field `%.*s` must be a type", LIT(name_token.string)); - continue; + if (is_type_indexable(t)) { + b32 ok = true; + gb_for_array(emi, entity_map.entries) { + Entity *e = entity_map.entries[emi].value; + if (e->kind == Entity_Variable && e->Variable.anonymous) { + if (is_type_indexable(e->type)) { + if (e->identifier != vd->names[0]) { + ok = false; + using_index_expr = e; + break; + } + } + } + } + if (ok) { + using_index_expr = fields[field_index-1]; + } else { + fields[field_index-1]->Variable.anonymous = false; + error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string)); + } + } else { + error(name_token, "`using` on a field `%.*s` must be a `struct` or `raw_union`", LIT(name_token.string)); + continue; + } } populate_using_entity_map(c, node, type, &entity_map); @@ -3080,6 +3105,28 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode } +Entity *find_using_index_expr(Type *t) { + t = base_type(t); + if (t->kind != Type_Record) { + return NULL; + } + + for (isize i = 0; i < t->Record.field_count; i++) { + Entity *f = t->Record.fields[i]; + if (f->kind == Entity_Variable && + f->Variable.is_field && f->Variable.anonymous) { + if (is_type_indexable(f->type)) { + return f; + } + Entity *res = find_using_index_expr(f->type); + if (res != NULL) { + return res; + } + } + } + return NULL; +} + ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { GB_ASSERT(call->kind == AstNode_CallExpr); ast_node(ce, CallExpr, call); @@ -3428,54 +3475,58 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } - b32 valid = false; - i64 max_count = -1; - Type *t = base_type(o->type); - switch (t->kind) { - case Type_Basic: - if (is_type_string(t)) { - valid = true; - if (o->mode == Addressing_Constant) { - max_count = o->value.value_string.len; + Type *t = base_type(type_deref(o->type)); + + auto set_index_data = [](Operand *o, Type *t, i64 *max_count) -> b32 { + t = base_type(type_deref(t)); + + switch (t->kind) { + case Type_Basic: + if (is_type_string(t)) { + if (o->mode == Addressing_Constant) { + *max_count = o->value.value_string.len; + } + if (o->mode != Addressing_Variable) + o->mode = Addressing_Value; + o->type = t_u8; + return true; } - if (o->mode != Addressing_Variable) + break; + + case Type_Array: + *max_count = t->Array.count; + if (o->mode != Addressing_Variable) { o->mode = Addressing_Value; - o->type = t_u8; - } - break; + } + o->type = t->Array.elem; + return true; - case Type_Array: - valid = true; - max_count = t->Array.count; - if (o->mode != Addressing_Variable) - o->mode = Addressing_Value; - o->type = t->Array.elem; - break; - - case Type_Vector: - valid = true; - max_count = t->Vector.count; - if (o->mode != Addressing_Variable) - o->mode = Addressing_Value; - o->type = t->Vector.elem; - break; + case Type_Vector: + *max_count = t->Vector.count; + if (o->mode != Addressing_Variable) { + o->mode = Addressing_Value; + } + o->type = t->Vector.elem; + return true; - case Type_Slice: - valid = true; - o->type = t->Slice.elem; - o->mode = Addressing_Variable; - break; - - case Type_Pointer: { - Type *bt = base_type(t->Pointer.elem); - if (bt->kind == Type_Array) { - valid = true; - max_count = bt->Array.count; + case Type_Slice: + o->type = t->Slice.elem; o->mode = Addressing_Variable; - o->type = bt->Array.elem; + return true; + } + + return false; + }; + + i64 max_count = -1; + b32 valid = set_index_data(o, t, &max_count); + + if (!valid && (is_type_struct(t) || is_type_raw_union(t))) { + Entity *found = find_using_index_expr(t); + if (found != NULL) { + valid = set_index_data(o, found->type, &max_count); } - } break; } if (!valid) { @@ -3506,7 +3557,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint b32 valid = false; i64 max_count = -1; - Type *t = base_type(o->type); + Type *t = base_type(type_deref(o->type)); switch (t->kind) { case Type_Basic: if (is_type_string(t)) { @@ -3536,15 +3587,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case Type_Slice: valid = true; break; - - case Type_Pointer: { - Type *bt = base_type(t->Pointer.elem); - if (bt->kind == Type_Array) { - valid = true; - max_count = bt->Array.count; - o->type = make_type_slice(c->allocator, bt->Array.elem); - } - } break; } if (!valid) { diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 34a18a6da..dded3826e 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -487,6 +487,10 @@ b32 is_type_u8(Type *t) { } return false; } +b32 is_type_array(Type *t) { + t = base_type(t); + return t->kind == Type_Array; +} b32 is_type_slice(Type *t) { t = base_type(t); return t->kind == Type_Slice; @@ -546,6 +550,11 @@ b32 is_type_any(Type *t) { } +b32 is_type_indexable(Type *t) { + return is_type_array(t) || is_type_slice(t) || is_type_vector(t) || is_type_string(t); +} + + b32 is_type_comparable(Type *t) { t = base_type(t); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index e11ead106..c56ff221f 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -2821,9 +2821,35 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { Type *t = base_type(type_of_expr(proc->module->info, ie->expr)); gbAllocator a = proc->module->allocator; + + b32 deref = is_type_pointer(t); + t = type_deref(t); + + ssaValue *using_addr = NULL; + if (!is_type_indexable(t)) { + // Using index expression + Entity *using_field = find_using_index_expr(t); + if (using_field != NULL) { + Selection sel = lookup_field(a, t, using_field->token.string, false); + ssaValue *e = ssa_build_addr(proc, ie->expr).addr; + using_addr = ssa_emit_deep_field_gep(proc, t, e, sel); + + t = using_field->type; + } + } + + switch (t->kind) { case Type_Vector: { - ssaValue *vector = ssa_build_addr(proc, ie->expr).addr; + ssaValue *vector = NULL; + if (using_addr != NULL) { + vector = using_addr; + } else { + vector = ssa_build_addr(proc, ie->expr).addr; + if (deref) { + vector = ssa_emit_load(proc, vector); + } + } ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); ssaValue *len = ssa_make_const_int(a, t->Vector.count); ssa_array_bounds_check(proc, ast_node_token(ie->index), index, len); @@ -2831,7 +2857,15 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { } break; case Type_Array: { - ssaValue *array = ssa_build_addr(proc, ie->expr).addr; + ssaValue *array = NULL; + if (using_addr != NULL) { + array = using_addr; + } else { + array = ssa_build_addr(proc, ie->expr).addr; + if (deref) { + array = ssa_emit_load(proc, array); + } + } Type *et = make_type_pointer(proc->module->allocator, t->Array.elem); ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); ssaValue *elem = ssa_emit_struct_gep(proc, array, index, et); @@ -2841,7 +2875,15 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { } break; case Type_Slice: { - ssaValue *slice = ssa_build_expr(proc, ie->expr); + ssaValue *slice = NULL; + if (using_addr != NULL) { + slice = ssa_emit_load(proc, using_addr); + } else { + slice = ssa_build_expr(proc, ie->expr); + if (deref) { + slice = ssa_emit_load(proc, slice); + } + } ssaValue *elem = ssa_slice_elem(proc, slice); ssaValue *len = ssa_slice_len(proc, slice); ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); @@ -2855,12 +2897,20 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(ie->expr)); ssaValue *elem = NULL; ssaValue *len = NULL; - if (tv->mode == Addressing_Constant) { + if (tv != NULL && tv->mode == Addressing_Constant) { ssaValue *array = ssa_add_global_string_array(proc->module, tv->value.value_string); elem = ssa_array_elem(proc, array); len = ssa_make_const_int(a, tv->value.value_string.len); } else { - ssaValue *str = ssa_build_expr(proc, ie->expr); + ssaValue *str = NULL; + if (using_addr != NULL) { + str = ssa_emit_load(proc, using_addr); + } else { + str = ssa_build_expr(proc, ie->expr); + if (deref) { + str = ssa_emit_load(proc, str); + } + } elem = ssa_string_elem(proc, str); len = ssa_string_len(proc, str); } @@ -2884,23 +2934,30 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { if (se->low != NULL) low = ssa_build_expr(proc, se->low); if (se->high != NULL) high = ssa_build_expr(proc, se->high); if (se->triple_indexed) max = ssa_build_expr(proc, se->max); - ssaAddr base = ssa_build_addr(proc, se->expr); - Type *type = base_type(ssa_addr_type(base)); + ssaValue *addr = ssa_build_addr(proc, se->expr).addr; + ssaValue *base = ssa_emit_load(proc, addr); + Type *type = base_type(ssa_type(base)); + + if (is_type_pointer(type)) { + type = type_deref(type); + addr = base; + base = ssa_emit_load(proc, base); + } // TODO(bill): Cleanup like mad! switch (type->kind) { case Type_Slice: { - Type *slice_type = ssa_addr_type(base); + Type *slice_type = type; - if (high == NULL) high = ssa_slice_len(proc, ssa_emit_load(proc, base.addr)); - if (max == NULL) max = ssa_slice_cap(proc, ssa_emit_load(proc, base.addr)); + if (high == NULL) high = ssa_slice_len(proc, base); + if (max == NULL) max = ssa_slice_cap(proc, base); GB_ASSERT(max != NULL); ssa_slice_bounds_check(proc, se->open, low, high, max, false); Token op_sub = {Token_Sub}; - ssaValue *elem = ssa_slice_elem(proc, ssa_emit_load(proc, base.addr)); + ssaValue *elem = ssa_slice_elem(proc, base); ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int); ssaValue *cap = ssa_emit_arith(proc, op_sub, max, low, t_int); ssaValue *slice = ssa_add_local_generated(proc, slice_type); @@ -2918,14 +2975,14 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case Type_Array: { Type *slice_type = make_type_slice(a, type->Array.elem); - if (high == NULL) high = ssa_array_len(proc, ssa_emit_load(proc, base.addr)); - if (max == NULL) max = ssa_array_cap(proc, ssa_emit_load(proc, base.addr)); + if (high == NULL) high = ssa_array_len(proc, base); + if (max == NULL) max = ssa_array_cap(proc, base); GB_ASSERT(max != NULL); ssa_slice_bounds_check(proc, se->open, low, high, max, false); Token op_sub = {Token_Sub}; - ssaValue *elem = ssa_array_elem(proc, base.addr); + ssaValue *elem = ssa_array_elem(proc, addr); ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int); ssaValue *cap = ssa_emit_arith(proc, op_sub, max, low, t_int); ssaValue *slice = ssa_add_local_generated(proc, slice_type); @@ -2943,7 +3000,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case Type_Basic: { GB_ASSERT(type == t_string); if (high == NULL) { - high = ssa_string_len(proc, ssa_emit_load(proc, base.addr)); + high = ssa_string_len(proc, base); } ssa_slice_bounds_check(proc, se->open, low, high, high, true); @@ -2952,7 +3009,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue *elem, *len; len = ssa_emit_arith(proc, op_sub, high, low, t_int); - elem = ssa_string_elem(proc, ssa_emit_load(proc, base.addr)); + elem = ssa_string_elem(proc, base); elem = ssa_emit_ptr_offset(proc, elem, low); ssaValue *str = ssa_add_local_generated(proc, t_string);