Added 'splatting' of struct members to call arguments
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 22 Jul 2020 15:15:13 +0000 (10:15 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 22 Jul 2020 15:15:13 +0000 (10:15 -0500)
include/onyxastnodes.h
include/onyxtypes.h
onyx
progs/structs.onyx
src/onyxchecker.c
src/onyxmsgs.c
src/onyxtypes.c

index 7c80e385bc29b0a31d5dd9b4e41acc76369125c8..e13af87d501530126d1617dda7586d2024aba5f4 100644 (file)
@@ -331,11 +331,11 @@ struct AstOverloadedFunction {
 // processed later down the pipeline.
 typedef enum EntityType {
     Entity_Type_Unknown,
+    Entity_Type_String_Literal,
+    Entity_Type_Struct,
     Entity_Type_Function_Header,
     Entity_Type_Global_Header,
     Entity_Type_Expression,
-    Entity_Type_String_Literal,
-    Entity_Type_Struct,
     Entity_Type_Global,
     Entity_Type_Overloaded_Function,
     Entity_Type_Function,
index cb21fb14f07256f09f029a7e0f10510f3771ea30..d90faefb1d5973f52fd1571be567be4be3b44913 100644 (file)
@@ -54,8 +54,18 @@ typedef struct StructMember {
 #define TYPE_KINDS \
     TYPE_KIND(Basic, TypeBasic)                                 \
     TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; })  \
-    TYPE_KIND(Function, struct { Type *return_type; u64 param_count; Type* params[]; }) \
-    TYPE_KIND(Struct, struct { char* name; u32 size; u32 mem_count; bh_table(StructMember) members; }) \
+    TYPE_KIND(Function, struct {                                \
+        Type *return_type;                                      \
+        u64 param_count;                                        \
+        Type* params[];                                         \
+    })                                                          \
+    TYPE_KIND(Struct, struct {                                  \
+        char* name;                                             \
+        u32 size;                                               \
+        u32 mem_count;                                          \
+        bh_table(StructMember) members;                         \
+        bh_arr(StructMember *) memarr;                          \
+    })                                                          \
     TYPE_KIND(Array, struct { u32 size; u32 count; Type *elem; })
 
 typedef enum TypeKind {
diff --git a/onyx b/onyx
index 7e20302084da8389fec557c6b1daa23b601b856c..8e1d6afeb1e6ffdf56be82e1c5fc7ccc7a1e3ac1 100755 (executable)
Binary files a/onyx and b/onyx differ
index 1b20acc9469091a3d761433f1701dfb2a9ac71d5..f07ef921e73237a5edb14089519251c2b65dd036 100644 (file)
@@ -95,7 +95,7 @@ multi_arr :: proc #export "main2" {
     print(arr2[3][2]);
     // arr2[3][2] = 5; // (arr1[3] + 2 * 4)
 }
-
+                
 Vec2 :: struct {
     x : i32;
     y : i32;
@@ -133,6 +133,8 @@ proc #export "main" {
     v3.z = 1;
     print(v3.magnitude());
 
+    vec2_splat(*v2, *(v3 as ^Vec2));
+
     print((1).minus(2));
 }
 
@@ -147,6 +149,14 @@ vec2_set :: proc (v: ^Vec2) {
     v.y = 5678;
 }
 
+vec2_splat :: proc (vx: i32, vy: i32, other: i32, otherother: i32) {
+    print(vx);
+    print(vy);
+
+    print(other);
+    print(otherother);
+}
+
 soa_test :: proc #export "main9" {
 
     // print(sizeof SOA);  // 240
index 8ac0d5ebd0a1fbdebd59bf7523a38e5c2b21c15f..34a75f2fb1c95f54a354f16a126cb13fff863116 100644 (file)
@@ -24,6 +24,7 @@ CHECK(global, AstGlobal* global);
 CHECK(function, AstFunction* func);
 CHECK(overloaded_function, AstOverloadedFunction* func);
 CHECK(struct, AstStructType* s_node);
+CHECK(function_header, AstFunction* func);
 
 static inline void fill_in_type(AstTyped* node) {
     if (node->type == NULL)
@@ -163,10 +164,40 @@ CHECK(call, AstCall* call) {
         return 1;
     }
 
-    // NOTE: Check arguments
+    // NOTE: Check arguments and splat structs
+    AstNode** prev_param = (AstNode **) &call->arguments;
     AstArgument* actual_param = call->arguments;
     while (actual_param != NULL) {
         if (check_expression((AstTyped *) actual_param)) return 1;
+
+        // NOTE: Splat structures into multiple arguments
+        if (actual_param->type->kind == Type_Kind_Struct) {
+            bh_arr_each(StructMember *, smem, actual_param->type->Struct.memarr) {
+                AstFieldAccess* field = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access);
+                field->expr = actual_param->value;
+
+                // HACK: Since dereferences are not used for struct types, we need a
+                // special case here.
+                if (field->expr->kind == Ast_Kind_Dereference) {
+                    field->expr = ((AstDereference *) field->expr)->expr;
+                }
+
+                field->offset = (*smem)->offset;
+                field->type = (*smem)->type;
+
+                AstArgument* arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument);
+                arg->value = (AstTyped *) field;
+                arg->type = field->type;
+                arg->token = actual_param->token;
+                arg->next = actual_param->next;
+
+                *prev_param = (AstNode *) arg;
+                prev_param = (AstNode **) &arg->next;
+            }
+        } else {
+            prev_param = (AstNode **) &actual_param->next;
+        }
+
         actual_param = (AstArgument *) actual_param->next;
     }
 
@@ -641,56 +672,6 @@ CHECK(block, AstBlock* block) {
 }
 
 CHECK(function, AstFunction* func) {
-    for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
-        fill_in_type((AstTyped *) param);
-
-        if (param->type == NULL) {
-            onyx_message_add(Msg_Type_Literal,
-                    param->token->pos,
-                    "function parameter types must be known");
-            return 1;
-        }
-
-        if (param->type->Basic.size == 0) {
-            onyx_message_add(Msg_Type_Literal,
-                    param->token->pos,
-                    "function parameters must have non-void types");
-            return 1;
-        }
-    }
-
-    fill_in_type((AstTyped *) func);
-
-    if ((func->flags & Ast_Flag_Exported) != 0) {
-        if ((func->flags & Ast_Flag_Foreign) != 0) {
-            onyx_message_add(Msg_Type_Literal,
-                    func->token->pos,
-                    "exporting a foreign function");
-            return 1;
-        }
-
-        if ((func->flags & Ast_Flag_Intrinsic) != 0) {
-            onyx_message_add(Msg_Type_Literal,
-                    func->token->pos,
-                    "exporting a intrinsic function");
-            return 1;
-        }
-
-        if ((func->flags & Ast_Flag_Inline) != 0) {
-            onyx_message_add(Msg_Type_Literal,
-                    func->token->pos,
-                    "exporting a inlined function");
-            return 1;
-        }
-
-        if (func->exported_name == NULL) {
-            onyx_message_add(Msg_Type_Literal,
-                    func->token->pos,
-                    "exporting function without a name");
-            return 1;
-        }
-    }
-
     semstate.expected_return_type = func->type->Function.return_type;
     if (func->body) {
         return check_block(func->body);
@@ -749,6 +730,60 @@ CHECK(struct, AstStructType* s_node) {
     return 0;
 }
 
+CHECK(function_header, AstFunction* func) {
+    for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
+        fill_in_type((AstTyped *) param);
+
+        if (param->type == NULL) {
+            onyx_message_add(Msg_Type_Literal,
+                    param->token->pos,
+                    "function parameter types must be known");
+            return 1;
+        }
+
+        if (param->type->Basic.size == 0) {
+            onyx_message_add(Msg_Type_Literal,
+                    param->token->pos,
+                    "function parameters must have non-void types");
+            return 1;
+        }
+    }
+
+    fill_in_type((AstTyped *) func);
+
+    if ((func->flags & Ast_Flag_Exported) != 0) {
+        if ((func->flags & Ast_Flag_Foreign) != 0) {
+            onyx_message_add(Msg_Type_Literal,
+                    func->token->pos,
+                    "exporting a foreign function");
+            return 1;
+        }
+
+        if ((func->flags & Ast_Flag_Intrinsic) != 0) {
+            onyx_message_add(Msg_Type_Literal,
+                    func->token->pos,
+                    "exporting a intrinsic function");
+            return 1;
+        }
+
+        if ((func->flags & Ast_Flag_Inline) != 0) {
+            onyx_message_add(Msg_Type_Literal,
+                    func->token->pos,
+                    "exporting a inlined function");
+            return 1;
+        }
+
+        if (func->exported_name == NULL) {
+            onyx_message_add(Msg_Type_Literal,
+                    func->token->pos,
+                    "exporting function without a name");
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 CHECK(node, AstNode* node) {
     switch (node->kind) {
         case Ast_Kind_Function:             return check_function((AstFunction *) node);
@@ -766,9 +801,12 @@ CHECK(node, AstNode* node) {
 void onyx_type_check(ProgramInfo* program) {
     bh_arr_each(Entity, entity, program->entities) {
         switch (entity->type) {
-            case Entity_Type_Function:
+            case Entity_Type_Function_Header:
                 if (entity->function->flags & Ast_Kind_Foreign) program->foreign_func_count++;
+                if (check_function_header(entity->function)) return;
+                break;
 
+            case Entity_Type_Function:
                 if (check_function(entity->function)) return;
                 break;
 
@@ -792,7 +830,6 @@ void onyx_type_check(ProgramInfo* program) {
 
             case Entity_Type_String_Literal: break;
 
-            case Entity_Type_Function_Header: break;
             case Entity_Type_Global_Header: break;
 
             default: DEBUG_HERE; break;
index 37f0fd97c7d76acf9b06d2fd85ee69ef06c1537e..a79f4e118c251b093211eb1e165a12e2079d719d 100644 (file)
@@ -67,13 +67,13 @@ static void print_detailed_message(Message* msg, bh_file_contents* fc) {
     char* walker = msg->pos.line_start;
     while (*walker != '\n') linelength++, walker++;
 
-    i32 numlen = bh_printf(" %d |", msg->pos.line);
+    i32 numlen = bh_printf(" %d | ", msg->pos.line);
     bh_printf("%b\n", msg->pos.line_start, linelength);
 
     char* pointer_str = bh_alloc_array(global_scratch_allocator, char, linelength + numlen);
     memset(pointer_str, ' ', linelength + numlen);
-    memset(pointer_str + msg->pos.column + numlen, '~', msg->pos.length - 1);
-    pointer_str[msg->pos.column + numlen - 1] = '^';
+    memset(pointer_str + msg->pos.column + numlen - 1, '~', msg->pos.length - 1);
+    pointer_str[msg->pos.column + numlen - 2] = '^';
     pointer_str[msg->pos.column + numlen + msg->pos.length - 1] = 0;
 
     bh_printf("%s\n", pointer_str);
index 4a56ecc5778a829daed4c14bc316ad4e05e0eb74..dbd6db847e4f5f752a6ebfaffbbbf01ce7d68ce0 100644 (file)
@@ -213,7 +213,9 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
             s_type->Struct.name = s_node->name;
             s_type->Struct.mem_count = bh_arr_length(s_node->members);
+            s_type->Struct.memarr = NULL;
             bh_table_init(global_heap_allocator, s_type->Struct.members, s_type->Struct.mem_count);
+            bh_arr_new(global_heap_allocator, s_type->Struct.memarr, s_type->Struct.mem_count);
 
             u32 offset = 0;
             u32 min_alignment = 1;
@@ -229,6 +231,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
                 token_toggle_end((*member)->token);
                 bh_table_put(StructMember, s_type->Struct.members, (*member)->token->text, smem);
+                bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, (*member)->token->text));
                 token_toggle_end((*member)->token);
 
                 offset += type_size_of((*member)->type);