From c10b46af9feb76a9839efa292c5288ec4684055e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2016 17:21:34 +0100 Subject: [PATCH] Compound Literals - struct, array, slice, vector --- examples/main.ll | 122 ++++++++++++++++++++++++--- examples/main.odin | 27 ++++-- src/checker/expr.cpp | 31 +++++-- src/codegen/codegen.cpp | 3 +- src/codegen/print_llvm.cpp | 32 +++++-- src/codegen/ssa.cpp | 166 ++++++++++++++++++++++++++++++------- src/parser.cpp | 50 +++++++---- src/printer.cpp | 5 +- src/tokenizer.cpp | 7 +- 9 files changed, 356 insertions(+), 87 deletions(-) diff --git a/examples/main.ll b/examples/main.ll index d513bdfa8..9985d0d68 100644 --- a/examples/main.ll +++ b/examples/main.ll @@ -4,6 +4,7 @@ declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1) +%main.Vec2 = type <2 x float> define void @exec(i64 ()* %p) { "entry - 0": %0 = alloca i64 ()*, align 8 ; p @@ -18,21 +19,119 @@ define void @exec(i64 ()* %p) { define void @main() { "entry - 0": - %0 = alloca i8, align 1 ; a - store i8 zeroinitializer, i8* %0 - store i8 123, i8* %0 - %1 = load i8, i8* %0 - %2 = zext i8 %1 to i64 - call void @print_int(i64 %2) + %0 = alloca i64, align 8 ; i + store i64 zeroinitializer, i64* %0 + store i64 123, i64* %0 + %1 = load i64, i64* %0 + call void @print_int(i64 %1) call void @print_rune(i32 128149) call void @print_rune(i32 10) - call void @exec(i64 ()* @main$cool_beans) + %2 = alloca %main.Vec2, align 2 ; v + store %main.Vec2 zeroinitializer, %main.Vec2* %2 + %3 = alloca %main.Vec2, align 2 + store %main.Vec2 zeroinitializer, %main.Vec2* %3 + %4 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 0 + store float 0x3ff0000000000000, float* %4 + %5 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 1 + store float 0x4000000000000000, float* %5 + %6 = load %main.Vec2, %main.Vec2* %3 + store %main.Vec2 %6, %main.Vec2* %2 + %7 = alloca [4 x i64], align 8 ; a + store [4 x i64] zeroinitializer, [4 x i64]* %7 + %8 = alloca [4 x i64], align 8 + store [4 x i64] zeroinitializer, [4 x i64]* %8 + %9 = load i64, i64* %0 + %10 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 0 + store i64 %9, i64* %10 + %11 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 1 + store i64 2, i64* %11 + %12 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 2 + store i64 3, i64* %12 + %13 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 3 + store i64 7, i64* %13 + %14 = load [4 x i64], [4 x i64]* %8 + store [4 x i64] %14, [4 x i64]* %7 + %15 = alloca [4 x i64], align 8 ; e + store [4 x i64] zeroinitializer, [4 x i64]* %15 + %16 = alloca [4 x i64], align 8 + store [4 x i64] zeroinitializer, [4 x i64]* %16 + %17 = load i64, i64* %0 + %18 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 0 + store i64 %17, i64* %18 + %19 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 1 + store i64 2, i64* %19 + %20 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 2 + store i64 3, i64* %20 + %21 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 3 + store i64 7, i64* %21 + %22 = load [4 x i64], [4 x i64]* %16 + store [4 x i64] %22, [4 x i64]* %15 + %23 = alloca {i64*, i64, i64}, align 8 ; s + store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %23 + %24 = alloca {i64*, i64, i64}, align 8 + store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %24 + %25 = alloca [4 x i64], align 8 + store [4 x i64] zeroinitializer, [4 x i64]* %25 + %26 = load i64, i64* %0 + %27 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0 + store i64 %26, i64* %27 + %28 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 1 + store i64 2, i64* %28 + %29 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 2 + store i64 3, i64* %29 + %30 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 3 + store i64 7, i64* %30 + %31 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0 + %32 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 0 + store i64* %31, i64** %32 + %33 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 1 + store i64 4, i64* %33 + %34 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 2 + store i64 4, i64* %34 + %35 = load {i64*, i64, i64}, {i64*, i64, i64}* %24 + store {i64*, i64, i64} %35, {i64*, i64, i64}* %23 + %36 = alloca i64, align 8 ; i + store i64 zeroinitializer, i64* %36 + store i64 0, i64* %36 + br label %"for.loop - 2" + +"for.body - 1": + %37 = getelementptr inbounds [4 x i64], [4 x i64]* %7, i64 0, i64 0 + %38 = load i64, i64* %36 + %39 = getelementptr i64, i64* %37, i64 %38 + %40 = load i64, i64* %39 + call void @print_int(i64 %40) + %41 = getelementptr inbounds [2 x i8], [2 x i8]* @.str0, i64 0, i64 0 + %42 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %42 + %43 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 0 + %44 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 1 + store i8* %41, i8** %43 + store i64 2, i64* %44 + %45 = load %.string, %.string* %42 + call void @print_string(%.string %45) + br label %"for.post - 3" + +"for.loop - 2": + %46 = load i64, i64* %36 + %47 = icmp slt i64 %46, 4 + br i1 %47, label %"for.body - 1", label %"for.done - 4" + +"for.post - 3": + %48 = load i64, i64* %36 + %49 = add i64 %48, 1 + store i64 %49, i64* %36 + br label %"for.loop - 2" + +"for.done - 4": + call void @print_rune(i32 10) + call void @exec(i64 ()* @main$0) ret void } -define i64 @main$cool_beans() { +define i64 @main$0() { "entry - 0": - %0 = alloca i64, align 8 ; a + %0 = alloca i64, align 8 ; i store i64 zeroinitializer, i64* %0 store i64 1337, i64* %0 call void @print_rune(i32 128149) @@ -411,7 +510,7 @@ define void @print_int_base(i64 %i, i64 %base) { %16 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0 %17 = load i64, i64* %3 %18 = getelementptr i8, i8* %16, i64 %17 - %19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str0, i64 0, i64 0 + %19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str1, i64 0, i64 0 %20 = load i64, i64* %1 %21 = load i64, i64* %0 %22 = srem i64 %21, %20 @@ -494,4 +593,5 @@ define void @print_int_base(i64 %i, i64 %base) { ret void } -@.str0 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" +@.str0 = global [2 x i8] c"\2C\20" +@.str1 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" diff --git a/examples/main.odin b/examples/main.odin index 686e2884b..35807a47c 100644 --- a/examples/main.odin +++ b/examples/main.odin @@ -2,24 +2,37 @@ import "basic" TWO_HEARTS :: '💕'; + exec :: proc(p : proc() -> int) { print_int(p()); print_rune('\n'); } main :: proc() { - a : u8 = 123; - print_int(cast(int)a); + i := 123; + print_int(i); print_rune(TWO_HEARTS); print_rune('\n'); - cool_beans :: proc() -> int { - a : int = 1337; + type Vec2: {2}f32; + + v := Vec2{1, 2}; + a := [4] int{i, 2, 3, 7}; + e := [..]int{i, 2, 3, 7}; + s := [] int{i, 2, 3, 7}; + + for i := 0; i < len(a); i++ { + print_int(a[i]); + print_string(", "); + } + print_rune('\n'); + + exec(proc() -> int { + i : int = 1337; print_rune('💕'); print_rune('\n'); - return a; - } - exec(cool_beans); + return i; + }); } /* diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index dc5dc15cc..77854a603 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -18,10 +18,6 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { GB_ASSERT(node->kind == AstNode_StructType); GB_ASSERT(struct_type->kind == Type_Structure); ast_node(st, StructType, node); - if (st->field_count == 0) { - error(&c->error_collector, ast_node_token(node), "Empty struct{} definition"); - return; - } Map entity_map = {}; map_init(&entity_map, gb_heap_allocator()); @@ -1759,8 +1755,21 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ case_ast_node(cl, CompoundLit, node); Type *type = type_hint; + b32 ellipsis_array = false; if (cl->type != NULL) { - type = check_type(c, cl->type); + type = NULL; + + // [..]Type + if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) { + if (cl->type->ArrayType.count->kind == AstNode_Ellipsis) { + type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1); + ellipsis_array = true; + } + } + + if (type == NULL) { + type = check_type(c, cl->type); + } } if (type == NULL) { @@ -1798,12 +1807,16 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ case Type_Slice: case Type_Array: + case Type_Vector: { Type *elem_type = NULL; String context_name = {}; if (t->kind == Type_Slice) { elem_type = t->slice.elem; context_name = make_string("slice literal"); + } else if (t->kind == Type_Vector) { + elem_type = t->vector.elem; + context_name = make_string("vector literal"); } else { elem_type = t->array.elem; context_name = make_string("array literal"); @@ -1826,6 +1839,10 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ } if (max < index) max = index; + + if (t->kind == Type_Array && ellipsis_array) { + t->array.count = max; + } } break; default: { @@ -2277,6 +2294,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, ce->expr); case_end; + case_ast_node(e, Ellipsis, node); + str = gb_string_appendc(str, ".."); + case_end; + case_ast_node(pt, PointerType, node); str = gb_string_appendc(str, "^"); str = write_expr_to_string(str, pt->type); diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 678013385..c530b350b 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -60,7 +60,8 @@ void ssa_gen_code(ssaGen *s) { switch (e->kind) { case Entity_TypeName: { - ssaValue *t = ssa_make_value_type_name(a, e); + ssaValue *t = ssa_make_value_type_name(a, e->token.string, e->type); + map_set(&m->values, hash_pointer(e), t); map_set(&m->members, hash_string(name), t); } break; diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 71daf9851..d05cd0272 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -184,6 +184,12 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) { } void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type) { + if (is_type_float(type)) { + value = exact_value_to_float(value); + } else if (is_type_integer(type)) { + value = exact_value_to_integer(value); + } + switch (value.kind) { case ExactValue_Bool: ssa_fprintf(f, (value.value_bool ? "true" : "false")); @@ -238,7 +244,7 @@ void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) ssa_print_exact_value(f, m, value->constant.value, type_hint); break; case ssaValue_TypeName: - ssa_print_encoded_local(f, value->type_name.entity->token.string); + ssa_print_encoded_local(f, value->type_name.name); break; case ssaValue_Global: ssa_print_encoded_global(f, value->global.entity->token.string); @@ -592,16 +598,21 @@ void ssa_print_proc(gbFile *f, ssaModule *m, ssaProcedure *proc) { ssa_fprintf(f, "}\n\n"); } - gb_for_array(i, proc->anon_procs) { - ssa_print_proc(f, m, proc->anon_procs[i]); - } - gb_for_array(i, proc->nested_procs) { - ssa_print_proc(f, m, proc->nested_procs[i]); + gb_for_array(i, proc->children) { + ssa_print_proc(f, m, proc->children[i]); } } +void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) { + GB_ASSERT(v->kind == ssaValue_TypeName); + ssa_print_encoded_local(f, v->type_name.name); + ssa_fprintf(f, " = type "); + ssa_print_type(f, m->sizes, get_base_type(v->type_name.type)); + ssa_fprintf(f, "\n"); +} + void ssa_print_llvm_ir(gbFile *f, ssaModule *m) { -if (m->layout.len > 0) { + if (m->layout.len > 0) { ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout)); } @@ -618,12 +629,17 @@ if (m->layout.len > 0) { ssa_print_type(f, m->sizes, t_int); ssa_fprintf(f, ", i32, i1)\n\n"); + gb_for_array(i, m->nested_type_names) { + ssaValue *v = m->nested_type_names[i]; + ssa_print_type_name(f, m, v); + } + gb_for_array(member_index, m->members.entries) { auto *entry = &m->members.entries[member_index]; ssaValue *v = entry->value; switch (v->kind) { case ssaValue_TypeName: { - ssa_print_encoded_local(f, v->type_name.entity->token.string); + ssa_print_encoded_local(f, v->type_name.name); ssa_fprintf(f, " = type "); ssa_print_type(f, m->sizes, get_base_type(v->type_name.type)); ssa_fprintf(f, "\n"); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index f07fed9dc..c229156b7 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -14,6 +14,7 @@ struct ssaModule { Map values; // Key: Entity * Map members; // Key: String + gbArray(ssaValue *) nested_type_names; // ssaValue_TypeName i32 global_string_index; }; @@ -38,6 +39,8 @@ struct ssaTargetList { struct ssaProcedure { ssaProcedure *parent; + gbArray(ssaProcedure *) children; + ssaModule * module; String name; Type * type; @@ -47,9 +50,6 @@ struct ssaProcedure { gbArray(ssaBlock *) blocks; ssaBlock * curr_block; ssaTargetList * target_list; - - gbArray(ssaProcedure *) anon_procs; - gbArray(ssaProcedure *) nested_procs; }; @@ -208,7 +208,7 @@ struct ssaValue { ExactValue value; } constant; struct { - Entity *entity; + String name; Type * type; } type_name; struct { @@ -276,11 +276,13 @@ void ssa_module_init(ssaModule *m, Checker *c) { map_init(&m->values, m->allocator); map_init(&m->members, m->allocator); + gb_array_init(m->nested_type_names, m->allocator); } void ssa_module_destroy(ssaModule *m) { map_destroy(&m->values); map_destroy(&m->members); + gb_array_free(m->nested_type_names); gb_arena_free(&m->arena); } @@ -416,10 +418,10 @@ ssaValue *ssa_alloc_instr(gbAllocator a, ssaInstrKind kind) { return v; } -ssaValue *ssa_make_value_type_name(gbAllocator a, Entity *e) { +ssaValue *ssa_make_value_type_name(gbAllocator a, String name, Type *type) { ssaValue *v = ssa_alloc_value(a, ssaValue_TypeName); - v->type_name.entity = e; - v->type_name.type = e->type; + v->type_name.name = name; + v->type_name.type = type; return v; } @@ -1146,8 +1148,17 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { return value; if (value->kind == ssaValue_Constant) { - if (dst->kind == Type_Basic) - return ssa_make_value_constant(proc->module->allocator, t, value->constant.value); + if (dst->kind == Type_Basic) { + ExactValue ev = value->constant.value; + if (is_type_float(dst)) { + ev = exact_value_to_float(ev); + } else if (is_type_string(dst)) { + // + } else if (is_type_integer(dst)) { + ev = exact_value_to_integer(ev); + } + return ssa_make_value_constant(proc->module->allocator, t, ev); + } } // integer -> integer @@ -1337,34 +1348,113 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_end; case_ast_node(pl, ProcLit, expr); - if (proc->anon_procs == NULL) { - // TODO(bill): Cleanup - gb_array_init(proc->anon_procs, gb_heap_allocator()); + if (proc->children == NULL) { + gb_array_init(proc->children, gb_heap_allocator()); } // NOTE(bill): Generate a new name // parent$count isize name_len = proc->name.len + 1 + 8 + 1; u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); - name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)gb_array_count(proc->anon_procs)); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)gb_array_count(proc->children)); String name = make_string(name_text, name_len-1); - - // auto **found = map_get(&proc->module->info->definitions, - // hash_pointer(expr)) Type *type = type_of_expr(proc->module->info, expr); ssaValue *value = ssa_make_value_procedure(proc->module->allocator, proc->module, type, pl->type, pl->body, name); - ssaProcedure *np = &value->proc; - gb_array_append(proc->anon_procs, np); + gb_array_append(proc->children, &value->proc); ssa_build_proc(value, proc); - return value; // TODO(bill): Is this correct? + return value; case_end; - case_ast_node(pl, CompoundLit, expr); - GB_PANIC("TODO(bill): ssa_build_single_expr CompoundLit"); + case_ast_node(cl, CompoundLit, expr); + Type *type = type_of_expr(proc->module->info, expr); + Type *base_type = get_base_type(type); + ssaValue *v = ssa_add_local_generated(proc, type); + + Type *et = NULL; + switch (base_type->kind) { + case Type_Vector: et = base_type->vector.elem; break; + case Type_Array: et = base_type->array.elem; break; + case Type_Slice: et = base_type->slice.elem; break; + } + + switch (base_type->kind) { + default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + case Type_Structure: { + auto *st = &base_type->structure; + isize index = 0; + for (AstNode *elem = cl->elem_list; + elem != NULL; + elem = elem->next) { + ssaValue *field_expr = ssa_build_expr(proc, elem); + Type *t = ssa_value_type(field_expr); + if (t->kind != Type_Tuple) { + Entity *field = st->fields[index]; + Type *ft = field->type; + ssaValue *fv = ssa_emit_conv(proc, field_expr, ft); + ssaValue *gep = ssa_emit_struct_gep(proc, v, index, ft); + ssa_emit_store(proc, gep, fv); + index++; + } else { + GB_PANIC("TODO(bill): tuples in struct literals"); + } + } + + } break; + case Type_Vector: + case Type_Array: { + isize index = 0; + for (AstNode *elem = cl->elem_list; + elem != NULL; + elem = elem->next) { + ssaValue *field_expr = ssa_build_expr(proc, elem); + Type *t = ssa_value_type(field_expr); + if (t->kind != Type_Tuple) { + ssaValue *ev = ssa_emit_conv(proc, field_expr, et); + ssaValue *gep = ssa_emit_struct_gep(proc, v, index, et); + ssa_emit_store(proc, gep, ev); + index++; + } else { + GB_PANIC("TODO(bill): tuples in array literals"); + } + } + } break; + case Type_Slice: { + i64 count = cl->elem_count; + ssaValue *array = ssa_add_local_generated(proc, make_type_array(proc->module->allocator, et, count)); + isize index = 0; + for (AstNode *elem = cl->elem_list; + elem != NULL; + elem = elem->next) { + ssaValue *field_expr = ssa_build_expr(proc, elem); + Type *t = ssa_value_type(field_expr); + if (t->kind != Type_Tuple) { + ssaValue *ev = ssa_emit_conv(proc, field_expr, et); + ssaValue *gep = ssa_emit_struct_gep(proc, array, index, et); + ssa_emit_store(proc, gep, ev); + index++; + } else { + GB_PANIC("TODO(bill): tuples in array literals"); + } + } + + ssaValue *elem = ssa_emit_struct_gep(proc, array, v_zero32, + make_type_pointer(proc->module->allocator, et)); + ssaValue *len = ssa_array_len(proc, array); + ssaValue *gep = NULL; + gep = ssa_emit_struct_gep(proc, v, v_zero32, ssa_value_type(elem)); + ssa_emit_store(proc, gep, elem); + gep = ssa_emit_struct_gep(proc, v, v_one32, t_int); + ssa_emit_store(proc, gep, len); + gep = ssa_emit_struct_gep(proc, v, v_two32, t_int); + ssa_emit_store(proc, gep, len); + } break; + } + + return ssa_emit_load(proc, v); case_end; case_ast_node(ce, CastExpr, expr); @@ -1768,9 +1858,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_end; case_ast_node(pd, ProcDecl, node); - if (proc->nested_procs == NULL) { - // TODO(bill): Cleanup - gb_array_init(proc->nested_procs, gb_heap_allocator()); + if (proc->children == NULL) { + gb_array_init(proc->children, gb_heap_allocator()); } // NOTE(bill): Generate a new name // parent$name @@ -1780,15 +1869,36 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s", LIT(proc->name), LIT(pd_name)); String name = make_string(name_text, name_len-1); - Entity *e = *map_get(&proc->module->info->definitions, hash_pointer(pd->name)); + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); + GB_ASSERT(found != NULL); + Entity *e = *found; ssaValue *value = ssa_make_value_procedure(proc->module->allocator, proc->module, e->type, pd->type, pd->body, name); - ssaProcedure *np = &value->proc; - gb_array_append(proc->nested_procs, np); + + ssa_module_add_value(proc->module, e, value); + gb_array_append(proc->children, &value->proc); ssa_build_proc(value, proc); + case_end; - map_set(&proc->module->values, hash_pointer(e), value); + case_ast_node(td, TypeDecl, node); + // NOTE(bill): Generate a new name + // parent_proc.name + String td_name = td->name->Ident.token.string; + isize name_len = proc->name.len + 1 + td_name.len + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s", LIT(proc->name), LIT(td_name)); + String name = make_string(name_text, name_len-1); + + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(td->name)); + GB_ASSERT(found != NULL); + Entity *e = *found; + ssaValue *value = ssa_make_value_type_name(proc->module->allocator, + name, e->type); + // HACK(bill): Override name of type so printer prints it correctly + e->type->named.name = name; + ssa_module_add_value(proc->module, e, value); + gb_array_append(proc->module->nested_type_names, value); case_end; case_ast_node(ids, IncDecStmt, node); diff --git a/src/parser.cpp b/src/parser.cpp index 026ceac03..62d6ea35e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2,7 +2,6 @@ struct AstNode; struct Type; struct AstScope; - enum ParseFileError { ParseFile_None, @@ -110,6 +109,7 @@ AST_NODE_KIND(_ExprBegin, struct{}) \ AstNode *low, *high, *max; \ b32 triple_indexed; \ }) \ + AST_NODE_KIND(Ellipsis, struct { Token token; }) \ AST_NODE_KIND(_ExprEnd, struct{}) \ AST_NODE_KIND(_StmtBegin, struct{}) \ AST_NODE_KIND(BadStmt, struct { Token begin, end; }) \ @@ -164,7 +164,6 @@ AST_NODE_KIND(_DeclBegin, struct{}) \ isize name_count, value_count; \ }) \ AST_NODE_KIND(ProcDecl, struct { \ - DeclKind kind; \ AstNode *name; \ AstNode *type; \ AstNode *body; \ @@ -295,6 +294,8 @@ Token ast_node_token(AstNode *node) { return node->IndexExpr.open; case AstNode_SliceExpr: return node->SliceExpr.open; + case AstNode_Ellipsis: + return node->Ellipsis.token; case AstNode_CastExpr: return node->CastExpr.token; case AstNode_DerefExpr: @@ -553,6 +554,11 @@ gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) { } +gb_inline AstNode *make_ellipsis(AstFile *f, Token token) { + AstNode *result = make_node(f, AstNode_Ellipsis); + result->Ellipsis.token = token; + return result; +} gb_inline AstNode *make_basic_lit(AstFile *f, Token basic_lit) { AstNode *result = make_node(f, AstNode_BasicLit); result->BasicLit = basic_lit; @@ -678,7 +684,7 @@ gb_inline AstNode *make_bad_decl(AstFile *f, Token begin, Token end) { return result; } -gb_inline AstNode *make_variable_decl(AstFile *f, DeclKind kind, AstNode *name_list, isize name_count, AstNode *type, AstNode *value_list, isize value_count) { +gb_inline AstNode *make_var_decl(AstFile *f, DeclKind kind, AstNode *name_list, isize name_count, AstNode *type, AstNode *value_list, isize value_count) { AstNode *result = make_node(f, AstNode_VarDecl); result->VarDecl.kind = kind; result->VarDecl.name_list = name_list; @@ -707,9 +713,8 @@ gb_inline AstNode *make_proc_type(AstFile *f, Token token, AstNode *param_list, return result; } -gb_inline AstNode *make_procedure_decl(AstFile *f, DeclKind kind, AstNode *name, AstNode *proc_type, AstNode *body, AstNode *tag_list, isize tag_count) { +gb_inline AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, AstNode *tag_list, isize tag_count) { AstNode *result = make_node(f, AstNode_ProcDecl); - result->ProcDecl.kind = kind; result->ProcDecl.name = name; result->ProcDecl.type = proc_type; result->ProcDecl.body = body; @@ -1169,7 +1174,6 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { case Token_OpenBrace: { if (is_literal_type(operand) && f->expr_level >= 0) { - gb_printf_err("here\n"); if (lhs) { // TODO(bill): Handle this } @@ -1474,8 +1478,12 @@ AstNode *parse_identifier_or_type(AstFile *f) { Token token = expect_token(f, Token_OpenBracket); AstNode *count_expr = NULL; - if (f->cursor[0].kind != Token_CloseBracket) + if (f->cursor[0].kind == Token_Ellipsis) { + count_expr = make_ellipsis(f, f->cursor[0]); + next_token(f); + } else if (f->cursor[0].kind != Token_CloseBracket) { count_expr = parse_expr(f, false); + } expect_token(f, Token_CloseBracket); f->expr_level--; return make_array_type(f, token, count_expr, parse_type(f)); @@ -1596,7 +1604,7 @@ AstNode *parse_body(AstFile *f, AstScope *scope) { return make_block_stmt(f, statement_list, statement_list_count, open, close); } -AstNode *parse_procedure_decl(AstFile *f, Token proc_token, AstNode *name, DeclKind kind) { + AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { AstNode *param_list = NULL; AstNode *result_list = NULL; isize param_count = 0; @@ -1621,7 +1629,7 @@ AstNode *parse_procedure_decl(AstFile *f, Token proc_token, AstNode *name, DeclK close_ast_scope(f); AstNode *proc_type = make_proc_type(f, proc_token, param_list, param_count, result_list, result_count); - return make_procedure_decl(f, kind, name, proc_type, body, tag_list, tag_count); + return make_proc_decl(f, name, proc_type, body, tag_list, tag_count); } AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { @@ -1642,7 +1650,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { declaration_kind = Declaration_Immutable; next_token(f); - if (f->cursor[0].kind == Token_proc) { // NOTE(bill): Procedure declarations + if (f->cursor[0].kind == Token_proc && + declaration_kind == Declaration_Immutable) { + // NOTE(bill): Procedure declarations Token proc_token = f->cursor[0]; AstNode *name = name_list; if (name_count != 1) { @@ -1650,9 +1660,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { return make_bad_decl(f, name->Ident.token, proc_token); } - AstNode *procedure_decl = parse_procedure_decl(f, proc_token, name, declaration_kind); - add_ast_entity(f, f->curr_scope, procedure_decl, name_list); - return procedure_decl; + AstNode *proc_decl = parse_proc_decl(f, proc_token, name); + add_ast_entity(f, f->curr_scope, proc_decl, name_list); + return proc_decl; } else { value_list = parse_rhs_expr_list(f, &value_count); @@ -1684,9 +1694,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { return make_bad_decl(f, begin, f->cursor[0]); } - AstNode *variable_decl = make_variable_decl(f, declaration_kind, name_list, name_count, type, value_list, value_count); - add_ast_entity(f, f->curr_scope, variable_decl, name_list); - return variable_decl; + AstNode *var_decl = make_var_decl(f, declaration_kind, name_list, name_count, type, value_list, value_count); + add_ast_entity(f, f->curr_scope, var_decl, name_list); + return var_decl; } @@ -1761,7 +1771,8 @@ AstNode *parse_return_stmt(AstFile *f) { isize result_count = 0; if (f->cursor[0].kind != Token_Semicolon) result = parse_rhs_expr_list(f, &result_count); - expect_token(f, Token_Semicolon); + if (f->cursor[0].kind != Token_CloseBrace) + expect_token(f, Token_Semicolon); return make_return_stmt(f, token, result, result_count); } @@ -1899,7 +1910,10 @@ AstNode *parse_stmt(AstFile *f) { case Token_Xor: case Token_Not: s = parse_simple_stmt(f); - if (s->kind != AstNode_ProcDecl && !allow_token(f, Token_Semicolon)) { + if (s->kind != AstNode_ProcDecl && + !allow_token(f, Token_Semicolon) && + f->cursor[0].kind == Token_CloseBrace) { + // TODO(bill): Cleanup semicolon handling in parser ast_file_err(f, f->cursor[0], "Expected `;` after statement, got `%.*s`", LIT(token_strings[f->cursor[0].kind])); diff --git a/src/printer.cpp b/src/printer.cpp index cba9f0ddc..8dd61e0ca 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -146,10 +146,7 @@ void print_ast(AstNode *node, isize indent) { break; case AstNode_ProcDecl: print_indent(indent); - if (node->ProcDecl.kind == Declaration_Mutable) - gb_printf("(decl:proc,mutable)\n"); - else if (node->ProcDecl.kind == Declaration_Immutable) - gb_printf("(decl:proc,immutable)\n"); + gb_printf("(decl:proc)\n"); print_ast(node->ProcDecl.type, indent+1); print_ast(node->ProcDecl.body, indent+1); print_ast(node->ProcDecl.tag_list, indent+1); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 79a4ed755..6f319959c 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -95,7 +95,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ TOKEN_KIND(Token_Semicolon, ";"), \ TOKEN_KIND(Token_Period, "."), \ TOKEN_KIND(Token_Comma, ","), \ - TOKEN_KIND(Token_Ellipsis, "..."), \ + TOKEN_KIND(Token_Ellipsis, ".."), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ @@ -741,10 +741,7 @@ Token tokenizer_get_token(Tokenizer *t) { token = scan_number_to_token(t, true); } else if (t->curr_rune == '.') { // Could be an ellipsis advance_to_next_rune(t); - if (t->curr_rune == '.') { - advance_to_next_rune(t); - token.kind = Token_Ellipsis; - } + token.kind = Token_Ellipsis; } break;