Bug fixes on interactions between struct members and arrays
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 21 Jul 2020 19:40:22 +0000 (14:40 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 21 Jul 2020 19:40:22 +0000 (14:40 -0500)
include/onyxmsgs.h
include/onyxtypes.h
onyx
progs/arrays.onyx
progs/structs.onyx
src/onyxchecker.c
src/onyxmsgs.c
src/onyxtypes.c
src/onyxwasm.c

index 2af7b721ece169a12291cc456c87175a94c56237..26f2b57ce5bf0e2017f8b68277546c9cbaae8eed 100644 (file)
@@ -29,10 +29,14 @@ typedef enum MsgType {
     Msg_Type_Function_Param_Mismatch,
 
     Msg_Type_Duplicate_Member,
+    Msg_Type_No_Field,
 
     Msg_Type_Unresolved_Type,
     Msg_Type_Unresolved_Symbol,
 
+    Msg_Type_Failed_Gen_Load,
+    Msg_Type_Failed_Gen_Store,
+
     Msg_Type_Count,
 } MsgType;
 
index 2a941ab2d81ccf81bb5e79f3ed93861f025a8c38..cb21fb14f07256f09f029a7e0f10510f3771ea30 100644 (file)
@@ -100,9 +100,10 @@ Type* type_make_pointer(bh_allocator alloc, Type* to);
 const char* type_get_name(Type* type);
 u32 type_get_alignment_log2(Type* type);
 
-StructMember type_struct_lookup_member(Type* type, char* member);
+b32 type_struct_lookup_member(Type* type, char* member, StructMember* smem);
 
 b32 type_is_pointer(Type* type);
+b32 type_is_array(Type* tyoe);
 b32 type_is_struct(Type* type);
 b32 type_is_bool(Type* type);
 b32 type_results_in_void(Type* type);
diff --git a/onyx b/onyx
index f1f7782c6458ef9397401bd2873a73ef8212f916..6cb71073c234edd54da55f98b507d8b0cd4ce380 100755 (executable)
Binary files a/onyx and b/onyx differ
index d121c0f5766eb942abb90eb7361fa5818d13b381..669e310cea99c2ebae823722f28860315a87db0a 100644 (file)
@@ -1,7 +1,7 @@
 use "progs/intrinsics"
 use "progs/print_funcs"
 
-global_arr :: global ^i32;
+global_arr :: global []i32;
 
 min_i32 :: proc (a: i32, b: i32) -> i32 {
     least := a;
@@ -20,7 +20,7 @@ min :: proc #overloaded {
 }
 
 // NOTE: in-place insertion sort
-sort :: proc (src: ^i32, len: i32) {
+sort :: proc (src: []i32, len: i32) {
     for i: 0, len {
         smallest := i;
 
@@ -44,7 +44,7 @@ str_test :: proc #export {
     // Address of and dereference cancel each other out
     print(^*hello_str);
 
-    print(hello_str, 5);
+    print(hello_str as []u8, 5);
 
     for i: 0, 10, 2 print(i);
 
@@ -56,8 +56,8 @@ proc #export "main2" {
     print(__heap_start as i32);
 
     len :: 10;
-    global_arr = alloc((len * 4) as u32) as ^i32;
-    other_arr := alloc((len * 4) as u32) as ^i32;
+    global_arr = alloc(sizeof [10]i32) as []i32;
+    other_arr := alloc((len * 4) as u32) as []i32;
 
     print(global_arr as i32);
     print(other_arr as i32);
@@ -94,8 +94,8 @@ alloc :: proc (size: u32) -> rawptr {
     return ((__heap_start as u32) + curr_offset) as rawptr;
 }
 
-alloc_2darr :: proc (rows: u32, cols: u32) -> ^^i32 {
-    arr := alloc(rows * 4) as ^^i32;
+alloc_2darr :: proc (rows: u32, cols: u32) -> []^i32 {
+    arr := alloc(rows * 4) as []^i32;
     for i: 0, cols arr[i] = alloc(cols * 4) as ^i32;
     return arr;
 }
index 091e911d3d1267ac654462166ab0d6d5c3e43583..23bcce71de08491116fd126e44240a490e38a6c3 100644 (file)
@@ -37,7 +37,7 @@ foo_get :: proc (fooarr: []Foo, i: i32) -> ^Foo {
     return ^fooarr[i];
 }
 
-proc #export "main" {
+proc #export "main3" {
     // foo := foo_make();
     // other_foo := foo_make();
     // other_foo.i = 1234;
@@ -126,7 +126,7 @@ link_print :: proc (start: ^Link) -> i32 {
     return count;
 }
 
-link_test :: proc #export "main2" {
+link_test :: proc #export "main4" {
     node_head := alloc(sizeof ^Link) as ^^Link;
     *node_head = 0 as ^Link;
 
@@ -142,21 +142,63 @@ link_test :: proc #export "main2" {
 
 
 // TODO: Make everything below this comment work
-// SOA :: struct {
-//     x : [3]i32;
-//     y : [3]i32;
-// }
+multi_arr :: proc #export "main2" {
+    arr1 := alloc(sizeof [5][5] i32) as [5][5] i32; // Sizeof 25 * 4
+    arr2 := alloc(sizeof [5]^ i32) as [5]^ i32; // Sizeof 20
 
-// soa_test :: proc #export "main" {
-//     m_arr := alloc(sizeof [5][5]i32) as [5][5]i32;
+    arr2[3][2] = 5; // (arr1 + (3 * 5 * 4) + (2 * 4))
+    print(arr2[3][2]);
+    // arr2[3][2] = 5; // (arr1[3] + 2 * 4)
+}
+
+Vec2 :: struct {
+    x : i32;
+    y : i32;
+}
 
-//     for y: 0, 5 {
-//         for x: 0, 5 {
-//             m_arr[y][x] = x + y * 5;
-//         }
-//     }
+SOA :: struct {
+    positions  : [10] Vec2;
+    velocities : [10] Vec2;
+    things     : [10] ^Vec2;
+}
+
+vec2_set :: proc (v: ^Vec2) {
+    v.x = 1234;
+    v.y = 5678;
+}
 
-//     print(m_arr[2][4]); // 14
+soa_test :: proc #export "main" {
 
-//     print(sizeof SOA);
-// }
\ No newline at end of file
+    // print(sizeof SOA);  // 240
+
+    soa := alloc(sizeof SOA + 20 * sizeof Vec2) as ^SOA;
+
+    for i: 0, 10 {
+        soa.things[i] = alloc(sizeof Vec2) as ^Vec2;
+    }
+
+    soa.velocities[2].x = 10;
+    soa.velocities[2].y = 12;
+    soa.positions[5].x = 1;
+    soa.positions[5].y = 2;
+    soa.positions[2].x = 1001;
+    vec2_set(^(soa.positions[6]));
+    vec2_set(soa.things[2]);
+
+    print(soa.positions[5].y);
+    print(soa.velocities[2].x);
+    print(soa.things[2].x);
+    print(soa.things[2].y);
+    print(soa.positions[6].x);
+    print(soa.positions[6].y);
+
+    m_arr := alloc(sizeof [5][5]i32) as [5][5]i32;
+
+    for y: 0, 5 {
+        for x: 0, 5 {
+            m_arr[y][x] = x + y * 5;
+        }
+    }
+    
+    for i: 0, 25 print((m_arr as [] i32)[i]);
+}
\ No newline at end of file
index 3594564341c8dd2a9d9ec92088680d9a9a9fa39f..8ac0d5ebd0a1fbdebd59bf7523a38e5c2b21c15f 100644 (file)
@@ -88,6 +88,8 @@ CHECK(for, AstFor* fornode) {
     if (fornode->step)
         if (check_expression(fornode->step)) return 1;
 
+    if (check_expression((AstTyped *) fornode->var)) return 1;
+
     // HACK
     if (!types_are_compatible(fornode->start->type, &basic_types[Basic_Kind_I32])) {
         onyx_message_add(Msg_Type_Literal,
@@ -474,11 +476,20 @@ CHECK(field_access, AstFieldAccess* field) {
     }
 
     token_toggle_end(field->token);
-    StructMember smem = type_struct_lookup_member(field->expr->type, field->token->text);
+    StructMember smem;
+    if (!type_struct_lookup_member(field->expr->type, field->token->text, &smem)) {
+        onyx_message_add(Msg_Type_No_Field,
+            field->token->pos,
+            field->token->text,
+            type_get_name(field->expr->type));
+        token_toggle_end(field->token);
+        return 1;
+    }
+
     field->offset = smem.offset;
     field->type = smem.type;
-    token_toggle_end(field->token);
 
+    token_toggle_end(field->token);
     return 0;
 }
 
index 0a45933ff24f0c6a9ed26cbe552ed4ddb3efff66..afd766860806e25a2312a668d84011fe7d040c62 100644 (file)
@@ -27,9 +27,13 @@ static const char* msg_formats[] = {
     "function '%b' expected type '%s' in position '%d', got '%s'",
 
     "duplicate declaration of struct member '%s'",
+    "field '%s' does not exist on '%s'",
 
     "unable to resolve type for symbol '%b'",
     "unable to resolve symbol '%b'",
+
+    "failed to generate load instruction for type '%s'",
+    "failed to generate store instruction for type '%s'",
 };
 
 void onyx_message_init(bh_allocator allocator, bh_table(bh_file_contents)* files) {
index 1f01b57dcf7a6ce379111fa8ab6c45ac0e934fc3..4a56ecc5778a829daed4c14bc316ad4e05e0eb74 100644 (file)
@@ -298,15 +298,15 @@ u32 type_get_alignment_log2(Type* type) {
     return 2;
 }
 
-StructMember type_struct_lookup_member(Type* type, char* member) {
-    if (!type_is_struct(type)) return (StructMember) { 0 };
+b32 type_struct_lookup_member(Type* type, char* member, StructMember* smem) {
+    if (!type_is_struct(type)) return 0;
     if (type->kind == Type_Kind_Pointer) type = type->Pointer.elem;
 
     TypeStruct* stype = &type->Struct;
 
-    if (!bh_table_has(StructMember, stype->members, member)) return (StructMember) { 0 };
-    StructMember smem = bh_table_get(StructMember, stype->members, member);
-    return smem;
+    if (!bh_table_has(StructMember, stype->members, member)) return 0;
+    *smem = bh_table_get(StructMember, stype->members, member);
+    return 1;
 }
 
 b32 type_is_pointer(Type* type) {
@@ -314,6 +314,10 @@ b32 type_is_pointer(Type* type) {
         || (type->kind == Type_Kind_Array);
 }
 
+b32 type_is_array(Type* type) {
+    return type->kind == Type_Kind_Array;
+}
+
 b32 type_is_struct(Type* type) {
     if (type->kind == Type_Kind_Struct) return 1;
     if (type->kind == Type_Kind_Pointer && type->Pointer.elem->kind == Type_Kind_Struct) return 1;
index 93e21ead772065aeab79920960780786fbc43577..228561e38cdbf09b529b61fd3ce3d73261d960a3 100644 (file)
@@ -385,12 +385,13 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
 
     i32 store_size = type_size_of(type);
     i32 is_basic   = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer;
-    i32 is_integer = is_basic &&
-                    ((type->Basic.flags & Basic_Flag_Integer)
-                  || (type->Basic.flags & Basic_Flag_Pointer));
-    i32 is_float   = is_basic && type->Basic.flags & Basic_Flag_Float;
+    i32 is_pointer  = is_basic && (type->Basic.flags & Basic_Flag_Pointer);
+    i32 is_integer  = is_basic && (type->Basic.flags & Basic_Flag_Integer);
+    i32 is_float    = is_basic && type->Basic.flags & Basic_Flag_Float;
 
-    if (is_integer) {
+    if (is_pointer) {
+        WID(WI_I32_STORE, ((WasmInstructionData) { alignment, offset }));
+    } else if (is_integer) {
         if      (store_size == 1)   WID(WI_I32_STORE_8,  ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 2)   WID(WI_I32_STORE_16, ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 4)   WID(WI_I32_STORE,    ((WasmInstructionData) { alignment, offset }));
@@ -399,9 +400,9 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
         if      (store_size == 4)   WID(WI_F32_STORE, ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 8)   WID(WI_F64_STORE, ((WasmInstructionData) { alignment, offset }));
     } else {
-        onyx_message_add(Msg_Type_Literal,
+        onyx_message_add(Msg_Type_Failed_Gen_Store,
             (OnyxFilePos) { 0 },
-            "failed to generate store instruction");
+            type_get_name(type));
     }
 
     *pcode = code;
@@ -412,23 +413,26 @@ COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
 
     i32 load_size   = type_size_of(type);
     i32 is_basic    = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer;
-    i32 is_integer  = is_basic &&
-                     ((type->Basic.flags & Basic_Flag_Integer)
-                   || (type->Basic.flags & Basic_Flag_Pointer));
+    i32 is_pointer  = is_basic && (type->Basic.flags & Basic_Flag_Pointer);
+    i32 is_integer  = is_basic && (type->Basic.flags & Basic_Flag_Integer);
     i32 is_float    = is_basic && type->Basic.flags & Basic_Flag_Float;
     i32 is_unsigned = is_basic && type->Basic.flags & Basic_Flag_Unsigned;
 
     WasmInstructionType instr = WI_NOP;
     i32 alignment = type_get_alignment_log2(type);
 
-    if (is_integer) {
+    if (is_pointer) {
+        instr = WI_I32_LOAD;
+    }
+    else if (is_integer) {
         if      (load_size == 1) instr = WI_I32_LOAD_8_S;
         else if (load_size == 2) instr = WI_I32_LOAD_16_S;
         else if (load_size == 4) instr = WI_I32_LOAD;
         else if (load_size == 8) instr = WI_I64_LOAD;
 
         if (load_size < 4 && is_unsigned) instr += 1;
-    } else if (is_float) {
+    }
+    else if (is_float) {
         if      (load_size == 4) instr = WI_F32_LOAD;
         else if (load_size == 8) instr = WI_F64_LOAD;
     }
@@ -436,9 +440,9 @@ COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
     WID(instr, ((WasmInstructionData) { alignment, offset }));
 
     if (instr == WI_NOP) {
-        onyx_message_add(Msg_Type_Literal,
+        onyx_message_add(Msg_Type_Failed_Gen_Load,
                 (OnyxFilePos) { 0 },
-                "failed to generate load instruction");
+                type_get_name(type));
     }
 
     *pcode = code;
@@ -765,16 +769,26 @@ COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call) {
 COMPILE_FUNC(array_access_location, AstArrayAccess* aa, u64* offset_return) {
     bh_arr(WasmInstruction) code = *pcode;
 
-    *offset_return = 0;
-
     compile_expression(mod, &code, aa->expr);
     if (aa->elem_size != 1) {
         WID(WI_I32_CONST, aa->elem_size);
         WI(WI_I32_MUL);
     }
-    compile_expression(mod, &code, aa->addr);
+
+    u64 offset = 0;
+    if (aa->addr->kind == Ast_Kind_Array_Access
+        && aa->addr->type->kind == Type_Kind_Array) {
+        compile_array_access_location(mod, &code, (AstArrayAccess *) aa->addr, &offset);
+    } else if (aa->addr->kind == Ast_Kind_Field_Access
+        && aa->addr->type->kind == Type_Kind_Array) {
+        compile_field_access_location(mod, &code, (AstFieldAccess *) aa->addr, &offset);
+    } else {
+        compile_expression(mod, &code, aa->addr);
+    }
     WI(WI_I32_ADD);
 
+    *offset_return += offset;
+
     *pcode = code;
 }
 
@@ -789,7 +803,8 @@ COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) {
         source_expr = (AstTyped *) ((AstFieldAccess *) source_expr)->expr;
     }
 
-    if (source_expr->kind == Ast_Kind_Array_Access) {
+    if (source_expr->kind == Ast_Kind_Array_Access
+        && source_expr->type->kind != Type_Kind_Pointer) {
         u64 o2 = 0;
         compile_array_access_location(mod, &code, (AstArrayAccess *) source_expr, &o2);
         offset += o2;
@@ -1308,6 +1323,13 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ProgramInfo* program) {
     module->next_func_idx   = program->foreign_func_count;
     module->next_global_idx = program->foreign_global_count;
 
+    WasmExport mem_export = {
+        .kind = WASM_FOREIGN_MEMORY,
+        .idx = 0,
+    };
+    bh_table_put(WasmExport, module->exports, "memory", mem_export);
+    module->export_count++;
+
     bh_arr_each(Entity, entity, program->entities) {
         switch (entity->type) {
             case Entity_Type_Function_Header: {