Added 'sizeof' unary operator
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 20 Jul 2020 21:27:14 +0000 (16:27 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 20 Jul 2020 21:27:14 +0000 (16:27 -0500)
include/onyxastnodes.h
include/onyxlex.h
onyx
progs/structs.onyx
src/onyxchecker.c
src/onyxlex.c
src/onyxmsgs.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c
src/onyxwasm.c

index f33ef189eee245ee1c121c9c74017a5ebc71a8b1..cfa65923bb68cf5658d55918ebd9399a5fa4ba65 100644 (file)
@@ -20,8 +20,8 @@ typedef struct AstAddressOf AstAddressOf;
 typedef struct AstDereference AstDereference;
 typedef struct AstArrayAccess AstArrayAccess;
 typedef struct AstFieldAccess AstFieldAccess;
+typedef struct AstSizeOf AstSizeOf;
 
-typedef struct AstAssign AstAssign;
 typedef struct AstReturn AstReturn;
 
 typedef struct AstBlock AstBlock;
@@ -90,6 +90,7 @@ typedef enum AstKind {
     Ast_Kind_Dereference,
     Ast_Kind_Array_Access,
     Ast_Kind_Field_Access,
+    Ast_Kind_Size_Of,
 
     Ast_Kind_If,
     Ast_Kind_For,
@@ -189,7 +190,7 @@ typedef enum OnyxIntrinsic {
 #define AstNode_base struct AstNode_members;
 struct AstNode AstNode_members;
 
-// NOTE: 'type_node' is filled out by the parser.                                               \
+// NOTE: 'type_node' is filled out by the parser.                                               
 // For a type such as '^^i32', the tree would look something like
 //
 //      Typed Thing -> AstPointerType -> AstPointerType -> AstNode (symbol node)
@@ -221,6 +222,7 @@ struct AstAddressOf     { AstTyped_base; AstTyped *expr; };
 struct AstDereference   { AstTyped_base; AstTyped *expr; };
 struct AstArrayAccess   { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
 struct AstFieldAccess   { AstTyped_base; AstTyped *expr; u64 offset; };
+struct AstSizeOf        { AstTyped_base; AstType *so_type; u64 size; };
 
 // Intruction Node
 struct AstReturn        { AstNode_base;  AstTyped* expr; };
index c54fdbbc5d2cb349ed18854fc06a37f15244c36f..a8726ec53b31eaa59c56ab0b38f47c366b400fc3 100644 (file)
@@ -24,28 +24,29 @@ typedef enum TokenType {
     Token_Type_Keyword_For          = 270,
     Token_Type_Keyword_Break        = 271,
     Token_Type_Keyword_Continue     = 272,
-
-    Token_Type_Right_Arrow          = 273,
-    Token_Type_Left_Arrow           = 274,
-    Token_Type_Empty_Block          = 275,
-
-    Token_Type_Greater_Equal        = 276,
-    Token_Type_Less_Equal           = 277,
-    Token_Type_Equal_Equal          = 278,
-    Token_Type_Not_Equal            = 279,
-    Token_Type_Plus_Equal           = 280,
-    Token_Type_Minus_Equal          = 281,
-    Token_Type_Star_Equal           = 282,
-    Token_Type_Fslash_Equal         = 283,
-    Token_Type_Percent_Equal        = 284,
-
-    Token_Type_Symbol               = 285,
-    Token_Type_Literal_String       = 286,
-    Token_Type_Literal_Numeric      = 287,
-    Token_Type_Literal_True         = 288,
-    Token_Type_Literal_False        = 289,
-
-    Token_Type_Count                = 290,
+    Token_Type_Keyword_Sizeof       = 273,
+
+    Token_Type_Right_Arrow          = 274,
+    Token_Type_Left_Arrow           = 275,
+    Token_Type_Empty_Block          = 276,
+
+    Token_Type_Greater_Equal        = 277,
+    Token_Type_Less_Equal           = 278,
+    Token_Type_Equal_Equal          = 279,
+    Token_Type_Not_Equal            = 280,
+    Token_Type_Plus_Equal           = 281,
+    Token_Type_Minus_Equal          = 282,
+    Token_Type_Star_Equal           = 283,
+    Token_Type_Fslash_Equal         = 284,
+    Token_Type_Percent_Equal        = 285,
+
+    Token_Type_Symbol               = 286,
+    Token_Type_Literal_String       = 287,
+    Token_Type_Literal_Numeric      = 288,
+    Token_Type_Literal_True         = 289,
+    Token_Type_Literal_False        = 290,
+
+    Token_Type_Count                = 291,
 } TokenType;
 
 typedef struct OnyxFilePos {
diff --git a/onyx b/onyx
index 31c4540f6fa05819643c6f039f7520aa5d69acfc..3bb5101005244791d12aaa0c1156ef0d3cf541cf 100755 (executable)
Binary files a/onyx and b/onyx differ
index 55c676e0b4fe8f574134185466cf3a2342a787cb..4bd171aa4f9cc013789de74be6c85fa1513cec1e 100644 (file)
@@ -28,7 +28,7 @@ alloc :: proc (size: u32) -> rawptr {
 }
 
 foo_make :: proc -> ^Foo {
-    return alloc(40) as ^Foo; 
+    return alloc(sizeof Foo) as ^Foo; 
 }
 
 foo_get :: proc (fooarr: ^Foo, i: i32) -> ^Foo {
@@ -42,12 +42,11 @@ proc #export "main" {
 
     // foo.foo = other_foo;
     // print(foo.foo.i);
-
     foo1 := foo_make();
     foo1.v.y = 123.0f;
     print(foo1.v.y);
 
-    foo := alloc(40* 5) as ^Foo;
+    foo := alloc(sizeof Foo * 5) as ^Foo;
 
     for i: 1, 6 {
         foo[i - 1].v.x = (i + 3) as f32;
@@ -86,44 +85,44 @@ Mut1 :: struct {
 
 Mut2 :: struct {
     foo : i32;
-    other : ^Foo;
+    other : ^Mut1;
 }
 
-mut_func :: proc #export (mut: ^Mut1) -> ^Foo {
+mut_func :: proc #export (mut: ^Mut1) -> ^Mut1 {
     return mut.other.other;
 }
 
 
 Link :: struct {
     data : i32;
-    other_data : i32;
     next : ^Link;
 }
 
-link_create :: proc (data: i32, parent: ^Link) -> ^Link {
-    link := alloc(12) as ^Link;
+link_create :: proc (data: i32, parent: ^^Link) {
+    link := alloc(sizeof Link) as ^Link;
     link.data = data;
-    link.other_data = 1234;
-    link.next = parent;
-    return link;
+    link.next = *parent;
+    *parent = link;
 }
 
 link_print :: proc (start: ^Link) {
     walker := start;
     while (walker as i32) != 0 {
-        print(walker.next.data);
+        print(walker.data);
         walker = walker.next;
     }
 }
 
 link_test :: proc #export "main2" {
-    dummy :: "H";
+    node_head := alloc(sizeof ^Link) as ^^Link;
+    *node_head = 0 as ^Link;
+
+    link_create(0, node_head);
+    link_create(1, node_head);
+    link_create(2, node_head);
+    link_create(3, node_head);
+    link_create(4, node_head);
 
-    node1 := link_create(1, 0 as ^Link);
-    node2 := link_create(2, node1);
-    node3 := link_create(3, node2);
-    node4 := link_create(4, node3);
-    node5 := link_create(5, node4);
 
-    link_print(node5);
+    link_print(*node_head);
 }
\ No newline at end of file
index 0ff7d4fb551411fda439d9d0b2a2d33ac7675ef9..3a4f2096aa2a43e10cd4a45c5b3fa4c4fd6657b8 100644 (file)
@@ -19,6 +19,7 @@ CHECK(address_of, AstAddressOf* aof);
 CHECK(dereference, AstDereference* deref);
 CHECK(array_access, AstArrayAccess* expr);
 CHECK(field_access, AstFieldAccess* field);
+CHECK(size_of, AstSizeOf* so);
 CHECK(global, AstGlobal* global);
 CHECK(function, AstFunction* func);
 CHECK(overloaded_function, AstOverloadedFunction* func);
@@ -462,6 +463,12 @@ CHECK(field_access, AstFieldAccess* field) {
     return 0;
 }
 
+CHECK(size_of, AstSizeOf* so) {
+    so->size = type_size_of(type_build_from_ast(semstate.allocator, so->so_type));
+
+    return 0;
+}
+
 CHECK(expression, AstTyped* expr) {
     if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) {
         onyx_message_add(Msg_Type_Literal,
@@ -509,6 +516,7 @@ CHECK(expression, AstTyped* expr) {
         case Ast_Kind_Dereference:  retval = check_dereference((AstDereference *) expr); break;
         case Ast_Kind_Array_Access: retval = check_array_access((AstArrayAccess *) expr); break;
         case Ast_Kind_Field_Access: retval = check_field_access((AstFieldAccess *) expr); break;
+        case Ast_Kind_Size_Of:      retval = check_size_of((AstSizeOf *) expr); break;
 
         case Ast_Kind_Global:
             if (expr->type == NULL) {
index 5b2acd127bd31e13414b54aed9e1d3eafd95a44f..ead0fa15285f4684ac70a375b70b1e73175043ae 100644 (file)
@@ -142,6 +142,7 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {
     LITERAL_TOKEN("for",        1, Token_Type_Keyword_For);
     LITERAL_TOKEN("break",      1, Token_Type_Keyword_Break);
     LITERAL_TOKEN("continue",   1, Token_Type_Keyword_Continue);
+    LITERAL_TOKEN("sizeof",     1, Token_Type_Keyword_Sizeof);
     LITERAL_TOKEN("true",       1, Token_Type_Literal_True);
     LITERAL_TOKEN("false",      1, Token_Type_Literal_False);
     LITERAL_TOKEN("->",         0, Token_Type_Right_Arrow);
index 2df639bfeba8890f05158da17d7c78a9946b1f7b..0a45933ff24f0c6a9ed26cbe552ed4ddb3efff66 100644 (file)
@@ -11,7 +11,7 @@ static const char* msg_formats[] = {
     "expected token '%s', got '%s'",
     "unexpected token '%s'",
     "unknown type '%s'",
-    "expected lval '%b'",
+    "cannot assign to '%b'",
     "attempt to assign to constant '%b'",
     "unknown symbol '%s'",
     "unknown directive '%b'",
index fe9ec61d0499bfaae4c4f435b83a131c30bee43e..9bc065b6d50d1b768c5cb94f12331cf1cdc2e132 100644 (file)
@@ -177,6 +177,16 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
+        case Token_Type_Keyword_Sizeof: {
+            AstSizeOf* so_node = make_node(AstSizeOf, Ast_Kind_Size_Of);
+            so_node->token = expect_token(parser, Token_Type_Keyword_Sizeof);
+            so_node->so_type = (AstType *) parse_type(parser);
+            so_node->type_node = (AstType *) &basic_type_i32;
+
+            retval = (AstTyped *) so_node;
+            break;
+        }
+
         case Token_Type_Symbol: {
             OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
             AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
index 28a62d69a6f6f3ee7150466f19621b6a2f0b5e42..675cdef129f3f3669555e5b1d8341b5e95bc3891 100644 (file)
@@ -15,7 +15,8 @@ AstBasicType basic_type_f32    = { { Ast_Kind_Basic_Type, 0, NULL, "f32"    }, &
 AstBasicType basic_type_f64    = { { Ast_Kind_Basic_Type, 0, NULL, "f64"    }, &basic_types[Basic_Kind_F64]   };
 AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
 
-AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, NULL, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
+static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } };
+AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
 
 const BuiltinSymbol builtin_symbols[] = {
     { "void",       (AstNode *) &basic_type_void },
@@ -46,6 +47,7 @@ static void scope_leave();
 static AstType* symres_type(AstType* type);
 static void symres_local(AstLocal** local);
 static void symres_call(AstCall* call);
+static void symres_size_of(AstSizeOf* so);
 static void symres_expression(AstTyped** expr);
 static void symres_return(AstReturn* ret);
 static void symres_if(AstIf* ifnode);
@@ -190,6 +192,11 @@ static void symres_call(AstCall* call) {
     symres_statement_chain((AstNode *) call->arguments, (AstNode **) &call->arguments);
 }
 
+static void symres_size_of(AstSizeOf* so) {
+    so->type_node = symres_type(so->type_node);
+    so->so_type = symres_type(so->so_type);
+}
+
 static void symres_unaryop(AstUnaryOp** unaryop) {
     if ((*unaryop)->operation == Unary_Op_Cast) {
         (*unaryop)->type_node = symres_type((*unaryop)->type_node);
@@ -222,23 +229,16 @@ static void symres_expression(AstTyped** expr) {
             (*expr)->type_node = symres_type((*expr)->type_node);
             break;
 
-        case Ast_Kind_Address_Of:
-            symres_expression(&((AstAddressOf *)(*expr))->expr);
-            break;
-
-        case Ast_Kind_Dereference:
-            symres_expression(&((AstDereference *)(*expr))->expr);
-            break;
+        case Ast_Kind_Address_Of:   symres_expression(&((AstAddressOf *)(*expr))->expr); break;
+        case Ast_Kind_Dereference:  symres_expression(&((AstDereference *)(*expr))->expr); break;
+        case Ast_Kind_Field_Access: symres_expression(&((AstFieldAccess *)(*expr))->expr); break;
+        case Ast_Kind_Size_Of:      symres_size_of((AstSizeOf *)*expr); break;
 
         case Ast_Kind_Array_Access:
             symres_expression(&((AstArrayAccess *)(*expr))->addr);
             symres_expression(&((AstArrayAccess *)(*expr))->expr);
             break;
 
-        case Ast_Kind_Field_Access:
-            symres_expression(&((AstFieldAccess *)(*expr))->expr);
-            break;
-
         default:
             DEBUG_HERE;
             break;
index edc56e130dd6d44c24044b3570515d525cc60872..967556c86978838a4ddc42aeb29edf064d9602cf 100644 (file)
@@ -45,6 +45,7 @@ static const char* ast_node_names[] = {
     "DEREFERENCE",
     "ARRAY_ACCESS",
     "FIELD_ACCESS",
+    "SIZE OF",
 
     "IF",
     "FOR",
index cc3e89e5855ccf328d54f61382800f18dc793f98..cfeb97b9269d1accf0b36d4228ff4f618e99faec 100644 (file)
@@ -378,17 +378,24 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
 
     i32 store_size = type_size_of(type);
-    i32 is_integer = (type->Basic.flags & Basic_Flag_Integer)
-                  || (type->Basic.flags & Basic_Flag_Pointer);
+    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;
 
     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 }));
         else if (store_size == 8)   WID(WI_I64_STORE,    ((WasmInstructionData) { alignment, offset }));
-    } else {
+    } else if (is_float) {
         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,
+            (OnyxFilePos) { 0 },
+            "failed to generate store instruction");
     }
 
     *pcode = code;
@@ -398,9 +405,12 @@ COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
 
     i32 load_size   = type_size_of(type);
-    i32 is_integer  = (type->Basic.flags & Basic_Flag_Integer)
-                   || (type->Basic.flags & Basic_Flag_Pointer);
-    i32 is_unsigned = type->Basic.flags & Basic_Flag_Unsigned;
+    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_unsigned = is_basic && type->Basic.flags & Basic_Flag_Unsigned;
 
     WasmInstructionType instr = WI_NOP;
     i32 alignment = type_get_alignment_log2(type);
@@ -412,7 +422,7 @@ COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
         else if (load_size == 8) instr = WI_I64_LOAD;
 
         if (load_size < 4 && is_unsigned) instr += 1;
-    } else {
+    } else if (is_float) {
         if      (load_size == 4) instr = WI_F32_LOAD;
         else if (load_size == 8) instr = WI_F64_LOAD;
     }
@@ -618,37 +628,36 @@ COMPILE_FUNC(unaryop, AstUnaryOp* unop) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (unop->operation) {
-        case Unary_Op_Negate:
-            {
-                TypeBasic* type = &unop->type->Basic;
-
-                if (type->kind == Basic_Kind_I32
-                        || type->kind == Basic_Kind_I16
-                        || type->kind == Basic_Kind_I8) {
-                    WID(WI_I32_CONST, 0x00);
-                    compile_expression(mod, &code, unop->expr);
-                    WI(WI_I32_SUB);
+        case Unary_Op_Negate: {
+            TypeBasic* type = &unop->type->Basic;
 
-                }
-                else if (type->kind == Basic_Kind_I64) {
-                    WID(WI_I64_CONST, 0x00);
-                    compile_expression(mod, &code, unop->expr);
-                    WI(WI_I64_SUB);
+            if (type->kind == Basic_Kind_I32
+                    || type->kind == Basic_Kind_I16
+                    || type->kind == Basic_Kind_I8) {
+                WID(WI_I32_CONST, 0x00);
+                compile_expression(mod, &code, unop->expr);
+                WI(WI_I32_SUB);
 
-                }
-                else {
-                    compile_expression(mod, &code, unop->expr);
+            }
+            else if (type->kind == Basic_Kind_I64) {
+                WID(WI_I64_CONST, 0x00);
+                compile_expression(mod, &code, unop->expr);
+                WI(WI_I64_SUB);
 
-                    if (type->kind == Basic_Kind_F32)
-                        WI(WI_F32_NEG);
+            }
+            else {
+                compile_expression(mod, &code, unop->expr);
 
-                    if (type->kind == Basic_Kind_F64)
-                        WI(WI_F64_NEG);
-                }
+                if (type->kind == Basic_Kind_F32)
+                    WI(WI_F32_NEG);
 
-                break;
+                if (type->kind == Basic_Kind_F64)
+                    WI(WI_F64_NEG);
             }
 
+            break;
+        }
+
         case Unary_Op_Not:
             compile_expression(mod, &code, unop->expr);
 
@@ -892,6 +901,12 @@ COMPILE_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Size_Of: {
+            AstSizeOf* so = (AstSizeOf *) expr;
+            WID(WI_I32_CONST, so->size);
+            break;
+        }
+
         default:
             bh_printf("Unhandled case: %d\n", expr->kind);
             DEBUG_HERE;
@@ -922,6 +937,14 @@ COMPILE_FUNC(cast, AstUnaryOp* cast) {
     Type* from = cast->expr->type;
     Type* to = cast->type;
 
+    if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) {
+        onyx_message_add(Msg_Type_Literal,
+                cast->token->pos,
+                "cannot cast to or from a struct");
+        WI(WI_DROP);
+        return;
+    }
+
     i32 fromidx = -1, toidx = -1;
     if (from->Basic.flags & Basic_Flag_Pointer) {
         fromidx = 8;