From dbd06388538b3ba38ab4e5d03c4bc695854f5ff0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Feb 2019 11:11:05 +0000 Subject: Fix untyped ternary string IR conversion --- src/ir.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index aca3c3ce9..bdccaa5a6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4644,6 +4644,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { } + // bool <-> llvm bool if (is_type_boolean(src) && dst == t_llvm_bool) { return ir_emit(proc, ir_instr_conv(proc, irConv_trunc, value, src_type, t)); @@ -4906,7 +4907,13 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { return ir_emit_load(proc, result); } - + if (is_type_untyped(src)) { + if (is_type_string(src) && is_type_string(dst)) { + irValue *result = ir_add_local_generated(proc, t, false); + ir_emit_store(proc, result, value); + return ir_emit_load(proc, result); + } + } gb_printf_err("ir_emit_conv: src -> dst\n"); gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); -- cgit v1.2.3 From a07232ea6367337d785ef07a1de659c7555357bf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Feb 2019 14:11:48 +0000 Subject: Fix missing `break` in switch statement for `deferred_in` in the IR --- src/ir.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index bdccaa5a6..cd7e8d99a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3035,6 +3035,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro break; case DeferredProcedure_in: result_as_args = in_args; + break; case DeferredProcedure_out: result_as_args = ir_value_to_array(p, result); break; -- cgit v1.2.3 From 4c51384ad64a2f63863e6bacab7aeee881659047 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Feb 2019 16:44:16 +0000 Subject: `intrinsics.vector` type (Experimental) --- core/fmt/fmt.odin | 24 +++++++++ core/runtime/core.odin | 8 ++- core/types/types.odin | 5 ++ src/check_expr.cpp | 54 +++++++++++++++++++ src/checker.cpp | 19 +++++++ src/checker.hpp | 5 ++ src/ir.cpp | 13 +++++ src/ir_print.cpp | 35 ++++++++++++ src/types.cpp | 144 ++++++++++++++++++++++++++++--------------------- 9 files changed, 246 insertions(+), 61 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index c4a535d77..0df06c0ec 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1008,6 +1008,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); } + case runtime.Type_Info_Simd_Vector: + if info.is_x86_mmx { + strings.write_string(fi.buf, "intrinsics.x86_mmx<>"); + } + strings.write_byte(fi.buf, '<'); + defer strings.write_byte(fi.buf, '>'); + for i in 0..info.count-1 { + if i > 0 do strings.write_string(fi.buf, ", "); + + data := uintptr(v.data) + uintptr(i*info.elem_size); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + } + + case runtime.Type_Info_Slice: strings.write_byte(fi.buf, '['); defer strings.write_byte(fi.buf, ']'); @@ -1448,5 +1462,15 @@ write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) { write_string(buf, "opaque "); write_type(buf, info.elem); + case runtime.Type_Info_Simd_Vector: + if info.is_x86_mmx { + write_string(buf, "intrinsics.x86_mmx"); + } else { + write_string(buf, "intrinsics.vector("); + write_i64(buf, i64(info.count)); + write_string(buf, ", "); + write_type(buf, info.elem); + write_byte(buf, ')'); + } } } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 9307b5589..38dd8f225 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -112,9 +112,14 @@ Type_Info_Bit_Set :: struct { lower: i64, upper: i64, }; - Type_Info_Opaque :: struct { elem: ^Type_Info, +}; +Type_Info_Simd_Vector :: struct { + elem: ^Type_Info, + elem_size: int, + count: int, + is_x86_mmx: bool, } Type_Info :: struct { @@ -145,6 +150,7 @@ Type_Info :: struct { Type_Info_Bit_Field, Type_Info_Bit_Set, Type_Info_Opaque, + Type_Info_Simd_Vector, }, } diff --git a/core/types/types.odin b/core/types/types.odin index 485530fea..dc4db549f 100644 --- a/core/types/types.odin +++ b/core/types/types.odin @@ -267,3 +267,8 @@ is_opaque :: proc(info: ^rt.Type_Info) -> bool { _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque); return ok; } +is_simd_vector :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector); + return ok; +} diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 79f980a79..75c16b705 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4072,6 +4072,46 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_vector: { + Operand x = {}; + Operand y = {}; + x = *operand; + if (!is_type_integer(x.type) || x.mode != Addressing_Constant) { + error(call, "Expected a constant integer for 'intrinsics.vector'"); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + if (x.value.value_integer.neg) { + error(call, "Negative vector element length"); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + i64 count = big_int_to_i64(&x.value.value_integer); + + check_expr_or_type(c, &y, ce->args[1]); + if (y.mode != Addressing_Type) { + error(call, "Expected a type 'intrinsics.vector'"); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + Type *elem = y.type; + if (!is_type_valid_vector_elem(elem)) { + gbString str = type_to_string(elem); + error(call, "Invalid element type for 'intrinsics.vector', expected an integer or float with no specific endianness, got '%s'", str); + gb_string_free(str); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + operand->mode = Addressing_Type; + operand->type = alloc_type_simd_vector(count, elem); + break; + } + case BuiltinProc_atomic_fence: case BuiltinProc_atomic_fence_acq: case BuiltinProc_atomic_fence_rel: @@ -5902,6 +5942,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Type_Slice: case Type_Array: case Type_DynamicArray: + case Type_SimdVector: { Type *elem_type = nullptr; String context_name = {}; @@ -5922,6 +5963,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type add_package_dependency(c, "runtime", "__dynamic_array_reserve"); add_package_dependency(c, "runtime", "__dynamic_array_append"); + } else if (t->kind == Type_SimdVector) { + elem_type = t->SimdVector.elem; + context_name = str_lit("simd vector literal"); + max_type_count = t->SimdVector.count; } else { GB_PANIC("unreachable"); } @@ -5972,6 +6017,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); } } + + if (t->kind == Type_SimdVector) { + if (!is_constant) { + error(node, "Expected all constant elements for a simd vector"); + } + if (t->SimdVector.is_x86_mmx) { + error(node, "Compound literals are not allowed with intrinsics.x86_mmx"); + } + } break; } diff --git a/src/checker.cpp b/src/checker.cpp index 9cac82911..7900555a5 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -712,6 +712,15 @@ void init_universal(void) { } } + // TODO(bill): Set the correct arch for this + if (bc->metrics.arch == TargetArch_amd64 || bc->metrics.arch == TargetArch_386) { + t_vector_x86_mmx = alloc_type(Type_SimdVector); + t_vector_x86_mmx->SimdVector.is_x86_mmx = true; + + Entity *entity = alloc_entity(Entity_TypeName, nullptr, make_token_ident(str_lit("x86_mmx")), t_vector_x86_mmx); + add_global_entity(entity, intrinsics_pkg->scope); + } + t_u8_ptr = alloc_type_pointer(t_u8); t_int_ptr = alloc_type_pointer(t_int); @@ -1248,6 +1257,10 @@ void add_type_info_type(CheckerContext *c, Type *t) { add_type_info_type(c, bt->Proc.results); break; + case Type_SimdVector: + add_type_info_type(c, bt->SimdVector.elem); + break; + default: GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind); break; @@ -1419,6 +1432,10 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->Proc.results); break; + case Type_SimdVector: + add_min_dep_type_info(c, bt->SimdVector.elem); + break; + default: GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind])); break; @@ -1795,6 +1812,7 @@ void init_core_type_info(Checker *c) { t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field")); t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set")); t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque")); + t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector")); t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); @@ -1818,6 +1836,7 @@ void init_core_type_info(Checker *c) { t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field); t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set); t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque); + t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector); } void init_mem_allocator(Checker *c) { diff --git a/src/checker.hpp b/src/checker.hpp index abc349129..de491671e 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -89,6 +89,8 @@ enum BuiltinProcId { BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures // "Intrinsics" + BuiltinProc_vector, + BuiltinProc_atomic_fence, BuiltinProc_atomic_fence_acq, BuiltinProc_atomic_fence_rel, @@ -194,6 +196,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { // "Intrinsics" + {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type + + {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/ir.cpp b/src/ir.cpp index cd7e8d99a..4df6665f7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7268,6 +7268,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { case Type_Array: et = bt->Array.elem; break; case Type_Slice: et = bt->Slice.elem; break; case Type_BitSet: et = bt->BitSet.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; } String proc_name = {}; @@ -9995,6 +9996,18 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info tag = ir_emit_conv(proc, variant_ptr, t_type_info_opaque_ptr); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->Opaque.elem)); break; + + case Type_SimdVector: + ir_emit_comment(proc, str_lit("Type_SimdVector")); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_simd_vector_ptr); + if (t->SimdVector.is_x86_mmx) { + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), v_true); + } else { + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->SimdVector.elem)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_int(type_size_of(t->SimdVector.elem))); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_int(t->SimdVector.count)); + } + break; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c6e717f74..0cc9f52e3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -574,6 +574,16 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { case Type_Opaque: ir_print_type(f, m, strip_opaque_type(t)); return; + + case Type_SimdVector: + if (t->SimdVector.is_x86_mmx) { + ir_write_str_lit(f, "x86_mmx"); + } else { + ir_fprintf(f, "<%lld x ", t->SimdVector.count);; + ir_print_type(f, m, t->SimdVector.elem); + ir_write_byte(f, '>'); + } + return; } } @@ -802,6 +812,31 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * } ir_write_byte(f, ']'); + } else if (is_type_simd_vector(type)) { + ast_node(cl, CompoundLit, value.value_compound); + + Type *elem_type = type->SimdVector.elem; + isize elem_count = cl->elems.count; + if (elem_count == 0) { + ir_write_str_lit(f, "zeroinitializer"); + break; + } + GB_ASSERT_MSG(elem_count == type->SimdVector.count, "%td != %td", elem_count, type->SimdVector.count); + + ir_write_byte(f, '<'); + + for (isize i = 0; i < elem_count; i++) { + if (i > 0) ir_write_str_lit(f, ", "); + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + ir_print_compound_element(f, m, tav.value, elem_type); + } + for (isize i = elem_count; i < type->SimdVector.count; i++) { + if (i >= elem_count) ir_write_str_lit(f, ", "); + ir_print_compound_element(f, m, empty_exact_value, elem_type); + } + + ir_write_byte(f, '>'); } else if (is_type_struct(type)) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); defer (gb_temp_arena_memory_end(tmp)); diff --git a/src/types.cpp b/src/types.cpp index 859805f29..6dcbf029f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -215,6 +215,12 @@ struct TypeUnion { i64 lower; \ i64 upper; \ }) \ + TYPE_KIND(SimdVector, struct { \ + i64 count; \ + Type *elem; \ + bool is_x86_mmx; \ + }) \ + @@ -460,13 +466,13 @@ gb_global Type *t_type_info_map = nullptr; gb_global Type *t_type_info_bit_field = nullptr; gb_global Type *t_type_info_bit_set = nullptr; gb_global Type *t_type_info_opaque = nullptr; +gb_global Type *t_type_info_simd_vector = nullptr; gb_global Type *t_type_info_named_ptr = nullptr; gb_global Type *t_type_info_integer_ptr = nullptr; gb_global Type *t_type_info_rune_ptr = nullptr; gb_global Type *t_type_info_float_ptr = nullptr; gb_global Type *t_type_info_complex_ptr = nullptr; -gb_global Type *t_type_info_quaternion_ptr = nullptr; gb_global Type *t_type_info_any_ptr = nullptr; gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr; @@ -484,6 +490,7 @@ gb_global Type *t_type_info_map_ptr = nullptr; gb_global Type *t_type_info_bit_field_ptr = nullptr; gb_global Type *t_type_info_bit_set_ptr = nullptr; gb_global Type *t_type_info_opaque_ptr = nullptr; +gb_global Type *t_type_info_simd_vector_ptr = nullptr; gb_global Type *t_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; @@ -496,6 +503,8 @@ gb_global Type *t_source_code_location_ptr = nullptr; gb_global Type *t_map_key = nullptr; gb_global Type *t_map_header = nullptr; +gb_global Type *t_vector_x86_mmx = nullptr; + i64 type_size_of (Type *t); @@ -722,6 +731,13 @@ Type *alloc_type_bit_set() { +Type *alloc_type_simd_vector(i64 count, Type *elem) { + Type *t = alloc_type(Type_SimdVector); + t->SimdVector.count = count; + t->SimdVector.elem = elem; + return t; +} + //////////////////////////////////////////////////////////////// @@ -971,6 +987,11 @@ bool is_type_generic(Type *t) { return t->kind == Type_Generic; } +bool is_type_simd_vector(Type *t) { + t = base_type(t); + return t->kind == Type_SimdVector; +} + Type *core_array_type(Type *t) { for (;;) { @@ -1193,6 +1214,25 @@ Type *bit_set_to_int(Type *t) { return nullptr; } +bool is_type_valid_vector_elem(Type *t) { + t = base_type(t); + if (t->kind == Type_Basic) { + if (t->Basic.flags & BasicFlag_EndianLittle) { + return false; + } + if (t->Basic.flags & BasicFlag_EndianBig) { + return false; + } + if (is_type_integer(t)) { + return true; + } + if (is_type_float(t)) { + return true; + } + } + return false; +} + bool is_type_indexable(Type *t) { Type *bt = base_type(t); @@ -1637,6 +1677,18 @@ bool are_types_identical(Type *x, Type *y) { are_types_identical(x->Map.value, y->Map.value); } break; + + case Type_SimdVector: + if (y->kind == Type_SimdVector) { + if (x->SimdVector.is_x86_mmx == y->SimdVector.is_x86_mmx) { + if (x->SimdVector.is_x86_mmx) { + return true; + } else if (x->SimdVector.count == y->SimdVector.count) { + return are_types_identical(x->SimdVector.elem, y->SimdVector.elem); + } + } + } + break; } return false; @@ -1681,65 +1733,6 @@ Type *default_type(Type *type) { return type; } -/* -// NOTE(bill): Valid Compile time execution #run type -bool is_type_cte_safe(Type *type) { - type = default_type(base_type(type)); - switch (type->kind) { - case Type_Basic: - switch (type->Basic.kind) { - case Basic_rawptr: - case Basic_any: - return false; - } - return true; - - case Type_Pointer: - return false; - - case Type_Array: - return is_type_cte_safe(type->Array.elem); - - case Type_DynamicArray: - return false; - case Type_Map: - return false; - - case Type_Slice: - return false; - - case Type_Struct: { - if (type->Struct.is_raw_union) { - return false; - } - for_array(i, type->Struct.fields) { - Entity *v = type->Struct.fields[i]; - if (!is_type_cte_safe(v->type)) { - return false; - } - } - return true; - } - - case Type_Tuple: { - for_array(i, type->Tuple.variables) { - Entity *v = type->Tuple.variables[i]; - if (!is_type_cte_safe(v->type)) { - return false; - } - } - return true; - } - - case Type_Proc: - // TODO(bill): How should I handle procedures in the CTE stage? - // return type->Proc.calling_convention == ProcCC_Odin; - return false; - } - - return false; -} - */ i64 union_variant_index(Type *u, Type *v) { u = base_type(u); GB_ASSERT(u->kind == Type_Union); @@ -2389,7 +2382,18 @@ i64 type_align_of_internal(Type *t, TypePath *path) { if (bits <= 32) return 4; if (bits <= 64) return 8; return 8; // NOTE(bill): Could be an invalid range so limit it for now + } + case Type_SimdVector: { + if (t->SimdVector.is_x86_mmx) { + return 8; + } + // align of + i64 count = t->SimdVector.count; + Type *elem = t->SimdVector.elem; + i64 size = count * type_size_of_internal(elem, path); + // IMPORTANT TODO(bill): Figure out the alignment of vector types + return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align); } } @@ -2622,6 +2626,15 @@ i64 type_size_of_internal(Type *t, TypePath *path) { if (bits <= 64) return 8; return 8; // NOTE(bill): Could be an invalid range so limit it for now } + + case Type_SimdVector: { + if (t->SimdVector.is_x86_mmx) { + return 8; + } + i64 count = t->SimdVector.count; + Type *elem = t->SimdVector.elem; + return count * type_size_of_internal(elem, path); + } } // Catch all @@ -2950,6 +2963,17 @@ gbString write_type_to_string(gbString str, Type *type) { } str = gb_string_appendc(str, "]"); break; + + case Type_SimdVector: + if (type->SimdVector.is_x86_mmx) { + return "intrinsics.x86_mmx"; + } else { + str = gb_string_appendc(str, "intrinsics.vector("); + str = gb_string_append_fmt(str, "%d, ", cast(int)type->SimdVector.count); + str = write_type_to_string(str, type->SimdVector.elem); + str = gb_string_appendc(str, ")"); + } + break; } return str; -- cgit v1.2.3 From a9ab90bd2488783c3523fa30315f9754937fd52e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Feb 2019 22:17:27 +0000 Subject: Make `static` an attribute rather than a keyword prefix --- core/strings/builder.odin | 4 ++-- src/check_decl.cpp | 7 +++++- src/check_stmt.cpp | 17 ++++++++++----- src/checker.cpp | 20 +++++++---------- src/checker.hpp | 1 + src/ir.cpp | 11 +++++++++- src/parser.cpp | 55 +++++++++++++++++++++++------------------------ src/parser.hpp | 1 - src/tokenizer.cpp | 1 - 9 files changed, 66 insertions(+), 51 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/strings/builder.odin b/core/strings/builder.odin index e86d748cc..547c456ba 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -61,8 +61,8 @@ write_bytes :: proc(b: ^Builder, x: []byte) { append(&b.buf, ..x); } -@(private) -static DIGITS_LOWER := "0123456789abcdefx"; +@(private, static) +DIGITS_LOWER := "0123456789abcdefx"; write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') { write_byte(b, quote); diff --git a/src/check_decl.cpp b/src/check_decl.cpp index e9d6d5860..c2796e1da 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -718,9 +718,14 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac); } + e->Variable.thread_local_model = ac.thread_local_model; e->Variable.is_export = ac.is_export; + if (ac.is_static) { + e->flags |= EntityFlag_Static; + } else { + e->flags &= ~EntityFlag_Static; + } ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); - e->Variable.thread_local_model = ac.thread_local_model; String context_name = str_lit("variable declaration"); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 3262aea5d..c861cfdf3 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1665,8 +1665,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (!is_blank_ident(str)) { found = scope_lookup_current(ctx->scope, str); new_name_count += 1; - } else if (vd->is_static) { - error(name, "'static' is now allowed to be applied to '_'"); } if (found == nullptr) { entity = alloc_entity_variable(ctx->scope, token, nullptr, false); @@ -1678,9 +1676,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { entity->Variable.is_foreign = true; entity->Variable.foreign_library_ident = fl; } - if (vd->is_static) { - entity->flags |= EntityFlag_Static; - } } else { TokenPos pos = found->token.pos; error(token, @@ -1744,6 +1739,16 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (ac.link_name.len > 0) { e->Variable.link_name = ac.link_name; } + + e->flags &= ~EntityFlag_Static; + if (ac.is_static) { + String name = e->token.string; + if (name == "_") { + error(e->token, "The 'static' attribute is not allowed to be applied to '_'"); + } else { + e->flags |= EntityFlag_Static; + } + } } check_arity_match(ctx, vd); @@ -1751,6 +1756,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { for (isize i = 0; i < entity_count; i++) { Entity *e = entities[i]; + if (e->Variable.is_foreign) { if (vd->values.count > 0) { error(e->token, "A foreign variable declaration cannot have a default value"); @@ -1842,6 +1848,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } } } + } else { // constant value declaration // NOTE(bill): Check `_` declarations diff --git a/src/checker.cpp b/src/checker.cpp index 9bbe64839..6389e3d30 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2070,6 +2070,14 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); + if (name == "static") { + if (value != nullptr) { + error(elem, "'static' does not have any parameters"); + } + ac->is_static = true; + return true; + } + if (c->curr_proc_decl != nullptr) { error(elem, "Only a variable at file scope can have a '%.*s'", LIT(name)); return true; @@ -2425,10 +2433,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { e->flags |= EntityFlag_NotExported; } - if (vd->is_static) { - e->flags |= EntityFlag_Static; - } - if (vd->is_using) { vd->is_using = false; // NOTE(bill): This error will be only caught once error(name, "'using' is not allowed at the file scope"); @@ -2527,14 +2531,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { e->flags |= EntityFlag_NotExported; } - if (vd->is_static) { - if (e->kind == Entity_Constant) { - e->flags |= EntityFlag_Static; - } else { - error(name, "'static' is not allowed on this constant value declaration"); - } - } - if (vd->is_using) { if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) { d->is_using = true; diff --git a/src/checker.hpp b/src/checker.hpp index 759e343bf..4420d6bb4 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -306,6 +306,7 @@ struct DeferredProcedure { struct AttributeContext { bool is_export; + bool is_static; String link_name; String link_prefix; isize init_expr_list_count; diff --git a/src/ir.cpp b/src/ir.cpp index 4df6665f7..e92fa7f60 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8166,7 +8166,16 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { if (vd->is_mutable) { irModule *m = proc->module; - if (vd->is_static) { + bool is_static = false; + if (vd->names.count > 0) { + Entity *e = entity_of_ident(vd->names[0]); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; + } + } + + if (is_static) { for_array(i, vd->names) { irValue *value = nullptr; if (vd->values.count > 0) { diff --git a/src/parser.cpp b/src/parser.cpp index 9d42b3828..a5526fd73 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1208,7 +1208,6 @@ void fix_advance_to_next_stmt(AstFile *f) { case Token_defer: case Token_asm: case Token_using: - case Token_static: case Token_break: case Token_continue: @@ -3751,33 +3750,33 @@ Ast *parse_stmt(AstFile *f) { return s; } - case Token_static: { - CommentGroup *docs = f->lead_comment; - Token token = expect_token(f, Token_static); - - Ast *decl = nullptr; - Array list = parse_lhs_expr_list(f); - if (list.count == 0) { - syntax_error(token, "Illegal use of 'static' statement"); - expect_semicolon(f, nullptr); - return ast_bad_stmt(f, token, f->curr_token); - } - - expect_token_after(f, Token_Colon, "identifier list"); - decl = parse_value_decl(f, list, docs); - - if (decl != nullptr && decl->kind == Ast_ValueDecl) { - if (decl->ValueDecl.is_mutable) { - decl->ValueDecl.is_static = true; - } else { - error(token, "'static' may only be currently used with variable declaration"); - } - return decl; - } - - syntax_error(token, "Illegal use of 'static' statement"); - return ast_bad_stmt(f, token, f->curr_token); - } break; + // case Token_static: { + // CommentGroup *docs = f->lead_comment; + // Token token = expect_token(f, Token_static); + + // Ast *decl = nullptr; + // Array list = parse_lhs_expr_list(f); + // if (list.count == 0) { + // syntax_error(token, "Illegal use of 'static' statement"); + // expect_semicolon(f, nullptr); + // return ast_bad_stmt(f, token, f->curr_token); + // } + + // expect_token_after(f, Token_Colon, "identifier list"); + // decl = parse_value_decl(f, list, docs); + + // if (decl != nullptr && decl->kind == Ast_ValueDecl) { + // if (decl->ValueDecl.is_mutable) { + // decl->ValueDecl.is_static = true; + // } else { + // error(token, "'static' may only be currently used with variable declaration"); + // } + // return decl; + // } + + // syntax_error(token, "Illegal use of 'static' statement"); + // return ast_bad_stmt(f, token, f->curr_token); + // } break; case Token_using: { CommentGroup *docs = f->lead_comment; diff --git a/src/parser.hpp b/src/parser.hpp index 13dd1258c..d685aa1af 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -376,7 +376,6 @@ AST_KIND(_DeclBegin, "", bool) \ Array attributes; \ CommentGroup *docs; \ CommentGroup *comment; \ - bool is_static; \ bool is_using; \ bool is_mutable; \ }) \ diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 31afe3d2e..11fae7120 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -107,7 +107,6 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_bit_field, "bit_field"), \ TOKEN_KIND(Token_bit_set, "bit_set"), \ TOKEN_KIND(Token_map, "map"), \ - TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_auto_cast, "auto_cast"), \ TOKEN_KIND(Token_cast, "cast"), \ -- cgit v1.2.3 From a0c81c79add95ce7a96b0d943545aa8b6bd71713 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Feb 2019 10:30:58 +0000 Subject: Fix bugs: Array Literals with constant elements; IR printing of raw procedure types --- src/ir.cpp | 2 +- src/ir_print.cpp | 7 +++++-- src/tokenizer.cpp | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index e92fa7f60..eba159472 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7360,7 +7360,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { case Type_Array: { if (cl->elems.count > 0) { - // ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); + ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); defer (array_free(&temp_data)); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index af5abe180..97194e794 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -316,8 +316,11 @@ void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { if (t->Proc.return_by_pointer) { ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results)); // ir_fprintf(f, "* sret noalias "); - ir_write_string(f, str_lit("* noalias ")); - if (param_count > 0) ir_write_string(f, str_lit(", ")); + // ir_write_string(f, str_lit("* noalias ")); + ir_write_string(f, str_lit("*")); + if (param_count > 0 || t->Proc.calling_convention == ProcCC_Odin) { + ir_write_string(f, str_lit(", ")); + } } isize param_index = 0; for (isize i = 0; i < param_count; i++) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 11fae7120..d7a39e824 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -100,7 +100,6 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_defer, "defer"), \ TOKEN_KIND(Token_return, "return"), \ TOKEN_KIND(Token_proc, "proc"), \ - TOKEN_KIND(Token_macro, "macro"), \ TOKEN_KIND(Token_struct, "struct"), \ TOKEN_KIND(Token_union, "union"), \ TOKEN_KIND(Token_enum, "enum"), \ @@ -121,6 +120,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_align_of, "align_of"), \ TOKEN_KIND(Token_offset_of, "offset_of"), \ TOKEN_KIND(Token_type_of, "type_of"), \ + TOKEN_KIND(Token_macro, "macro"), \ TOKEN_KIND(Token_const, "const"), \ TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_yield, "yield"), \ -- cgit v1.2.3 From 6faab8e47a09a480880399ea63e716ba51428d9e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 26 Feb 2019 13:51:56 +0100 Subject: Fix #345: panic when using enum as map key --- src/ir.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index eba159472..d52b4beaf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3215,6 +3215,9 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { key = ir_emit_conv(proc, key, key_type); if (is_type_integer(t)) { ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type)); + } else if (is_type_enum(t)) { + irValue *e = ir_emit_bitcast(proc, key, t_uint); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, e, hash_type)); } else if (is_type_typeid(t)) { irValue *i = ir_emit_bitcast(proc, key, t_uint); ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, i, hash_type)); -- cgit v1.2.3 From b6d6eb6ae2d22935d146df8bc715c580fe5cb321 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 2 Mar 2019 13:21:01 +0100 Subject: Fix #345: Panic when using enum as map key Also add a little map demo. --- examples/demo/demo.odin | 58 ++++++++++++++++++++++++++++++++++++++++++++++++- src/ir.cpp | 3 +-- 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b4c67938f..ad7a2666d 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -530,7 +530,7 @@ parametric_polymorphism :: proc() { // `I` is the type of N // `T` is the type passed fmt.printf("Generating an array of type %v from the value %v of type %v\n", - typeid_of(type_of(res)), N, typeid_of(I)); + typeid_of(type_of(res)), N, typeid_of(I)); for i in 0..N-1 { res[i] = T(i*i); } @@ -691,6 +691,61 @@ using_enum :: proc() { fmt.println(len(Foo)); } +map_type :: proc() { + fmt.println("# map type"); + + // enums of type u16, u32, i16 & i32 also work + Enum_u8 :: enum u8 { + A = 0, + B = 1 << 8 - 1, + } + Enum_u64 :: enum u64 { + A = 0, + B = 1 << 64 - 1, + } + Enum_i32 :: enum i32 { + A = 0, + B = -(1 << 31), + } + Enum_i64 :: enum i64 { + A = 0, + B = -(1 << 63), + } + + map_u8: map[Enum_u8]u8; + map_u8[Enum_u8.A] = u8(Enum_u8.B); + assert(map_u8[Enum_u8.A] == u8(Enum_u8.B)); + fmt.println(map_u8); + + map_u64: map[Enum_u64]u64; + map_u64[Enum_u64.A] = u64(Enum_u64.B); + assert(map_u64[Enum_u64.A] == u64(Enum_u64.B)); + fmt.println(map_u64); + + map_i8: map[Enum_i8]i8; + map_i8[Enum_i8.A] = i8(Enum_i8.B); + assert(map_i8[Enum_i8.A] == i8(Enum_i8.B)); + fmt.println(map_i8); + + map_i64: map[Enum_i64]i64; + map_i64[Enum_i64.A] = i64(Enum_i64.B); + assert(map_i64[Enum_i64.A] == i64(Enum_i64.B)); + fmt.println(map_i64); + + demo_struct :: struct { + member: Enum_i64, + } + + map_string: map[string]demo_struct; + map_string["Hellope!"] = demo_struct{Enum_i64.B}; + assert(map_string["Hellope!"].member == Enum_i64.B); + assert("Hellope?" notin map_string); + fmt.println(map_string); + fmt.println("Hellope! in map_string:", "Hellope!" in map_string); + fmt.println("Hellope? in map_string:", "Hellope?" in map_string); + +} + explicit_procedure_overloading :: proc() { fmt.println("# explicit procedure overloading"); @@ -884,6 +939,7 @@ main :: proc() { array_programming(); named_proc_return_parameters(); using_enum(); + map_type(); explicit_procedure_overloading(); complete_switch(); cstring_example(); diff --git a/src/ir.cpp b/src/ir.cpp index d52b4beaf..e3fe83c3b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3216,8 +3216,7 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { if (is_type_integer(t)) { ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type)); } else if (is_type_enum(t)) { - irValue *e = ir_emit_bitcast(proc, key, t_uint); - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, e, hash_type)); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type)); } else if (is_type_typeid(t)) { irValue *i = ir_emit_bitcast(proc, key, t_uint); ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, i, hash_type)); -- cgit v1.2.3 From ad3b6ab71854a638f2b769fc12e8776abfff48d6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 6 Mar 2019 16:19:47 +0000 Subject: Implicit Selector Expressions: `.A` --- core/odin/ast/ast.odin | 4 ++++ core/odin/parser/parser.odin | 7 +++++++ src/check_expr.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++-- src/ir.cpp | 7 +++++++ src/parser.cpp | 24 +++++++++++++++++++++- src/parser.hpp | 1 + 6 files changed, 89 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 8c43ee8e3..59d18a0c0 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -144,6 +144,10 @@ Selector_Expr :: struct { field: ^Ident, } +Implicit_Selector_Expr :: struct { + using node: Expr, + field: ^Ident, +} Index_Expr :: struct { using node: Expr, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index c10a83e47..90de2ca30 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2581,6 +2581,13 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { ue.expr = expr; return ue; + case token.Period: + op := advance_token(p); + field := parse_ident(p); + ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end); + ise.field = field; + return ise; + } return parse_atom_expr(p, parse_operand(p, lhs), lhs); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ea125a5eb..4c921f484 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -991,7 +991,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ o->expr = n; String name = n->Ident.token.string; - Entity *e = scope_lookup(c->scope, name); if (e == nullptr) { if (is_blank_ident(name)) { @@ -6177,7 +6176,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type continue; } - check_expr(c, o, elem); + check_expr_with_type_hint(c, o, elem, et); if (is_constant) { is_constant = o->mode == Addressing_Constant; @@ -6408,6 +6407,47 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; + case_ast_node(ise, ImplicitSelectorExpr, node); + o->type = t_invalid; + o->expr = node; + o->mode = Addressing_Invalid; + + if (type_hint == nullptr) { + gbString str = expr_to_string(node); + error(node, "Cannot determine type for implicit selector expression '%s'", str); + gb_string_free(str); + return Expr_Expr; + } + o->type = type_hint; + if (!is_type_enum(type_hint)) { + gbString typ = type_to_string(type_hint); + gbString str = expr_to_string(node); + error(node, "Invalid type '%s' for implicit selector expression '%s'", typ, str); + gb_string_free(str); + gb_string_free(typ); + return Expr_Expr; + } + GB_ASSERT(ise->selector->kind == Ast_Ident); + String name = ise->selector->Ident.token.string; + + Type *enum_type = base_type(type_hint); + GB_ASSERT(enum_type->kind == Type_Enum); + Entity *e = scope_lookup_current(enum_type->Enum.scope, name); + if (e == nullptr) { + gbString typ = type_to_string(type_hint); + error(node, "Undeclared name %.*s for type '%s'", LIT(name), typ); + gb_string_free(typ); + return Expr_Expr; + } + GB_ASSERT(are_types_identical(base_type(e->type), base_type(type_hint))); + GB_ASSERT(e->kind == Entity_Constant); + o->value = e->Constant.value; + o->mode = Addressing_Constant; + o->type = e->type; + + return Expr_Expr; + case_end; + case_ast_node(ie, IndexExpr, node); check_expr(c, o, ie->expr); if (o->mode == Addressing_Invalid) { @@ -6832,6 +6872,11 @@ gbString write_expr_to_string(gbString str, Ast *node) { str = write_expr_to_string(str, se->selector); case_end; + case_ast_node(se, ImplicitSelectorExpr, node); + str = gb_string_append_rune(str, '.'); + str = write_expr_to_string(str, se->selector); + case_end; + case_ast_node(ta, TypeAssertion, node); str = write_expr_to_string(str, ta->expr); str = gb_string_appendc(str, ".("); diff --git a/src/ir.cpp b/src/ir.cpp index e3fe83c3b..0d5e3fc36 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6268,6 +6268,13 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; + case_ast_node(ise, ImplicitSelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(expr); + GB_ASSERT(tav.mode == Addressing_Constant); + + return ir_add_module_constant(proc->module, tv.type, tv.value); + case_end; + case_ast_node(te, TernaryExpr, expr); ir_emit_comment(proc, str_lit("TernaryExpr")); diff --git a/src/parser.cpp b/src/parser.cpp index a5526fd73..84c03587d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -25,6 +25,11 @@ Token ast_token(Ast *node) { return ast_token(node->SelectorExpr.selector); } return node->SelectorExpr.token; + case Ast_ImplicitSelectorExpr: + if (node->ImplicitSelectorExpr.selector != nullptr) { + return ast_token(node->ImplicitSelectorExpr.selector); + } + return node->ImplicitSelectorExpr.token; case Ast_IndexExpr: return node->IndexExpr.open; case Ast_SliceExpr: return node->SliceExpr.open; case Ast_Ellipsis: return node->Ellipsis.token; @@ -165,6 +170,9 @@ Ast *clone_ast(Ast *node) { n->SelectorExpr.expr = clone_ast(n->SelectorExpr.expr); n->SelectorExpr.selector = clone_ast(n->SelectorExpr.selector); break; + case Ast_ImplicitSelectorExpr: + n->ImplicitSelectorExpr.selector = clone_ast(n->ImplicitSelectorExpr.selector); + break; case Ast_IndexExpr: n->IndexExpr.expr = clone_ast(n->IndexExpr.expr); n->IndexExpr.index = clone_ast(n->IndexExpr.index); @@ -504,11 +512,20 @@ Ast *ast_call_expr(AstFile *f, Ast *proc, Array args, Token open, Token c Ast *ast_selector_expr(AstFile *f, Token token, Ast *expr, Ast *selector) { Ast *result = alloc_ast_node(f, Ast_SelectorExpr); + result->SelectorExpr.token = token; result->SelectorExpr.expr = expr; result->SelectorExpr.selector = selector; return result; } +Ast *ast_implicit_selector_expr(AstFile *f, Token token, Ast *selector) { + Ast *result = alloc_ast_node(f, Ast_ImplicitSelectorExpr); + result->ImplicitSelectorExpr.token = token; + result->ImplicitSelectorExpr.selector = selector; + return result; +} + + Ast *ast_index_expr(AstFile *f, Ast *expr, Ast *index, Token open, Token close) { Ast *result = alloc_ast_node(f, Ast_IndexExpr); result->IndexExpr.expr = expr; @@ -1612,7 +1629,6 @@ Ast *parse_operand(AstFile *f, bool lhs) { case Token_offset_of: return parse_call_expr(f, ast_implicit(f, advance_token(f))); - case Token_String: return ast_basic_lit(f, advance_token(f)); @@ -2277,6 +2293,12 @@ Ast *parse_unary_expr(AstFile *f, bool lhs) { Ast *expr = parse_unary_expr(f, lhs); return ast_unary_expr(f, token, expr); } + + case Token_Period: { + Token token = expect_token(f, Token_Period); + Ast *ident = parse_ident(f); + return ast_implicit_selector_expr(f, token, ident); + } } return parse_atom_expr(f, parse_operand(f, lhs), lhs); diff --git a/src/parser.hpp b/src/parser.hpp index d685aa1af..816f3f534 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -245,6 +245,7 @@ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BinaryExpr, "binary expression", struct { Token op; Ast *left, *right; } ) \ AST_KIND(ParenExpr, "parentheses expression", struct { Ast *expr; Token open, close; }) \ AST_KIND(SelectorExpr, "selector expression", struct { Token token; Ast *expr, *selector; }) \ + AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \ AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \ AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \ AST_KIND(SliceExpr, "slice expression", struct { \ -- cgit v1.2.3