Added address of and deference operators
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 19 Jul 2020 17:51:59 +0000 (12:51 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 19 Jul 2020 17:51:59 +0000 (12:51 -0500)
include/onyxastnodes.h
include/onyxtypes.h
onyx
progs/arrays.onyx
progs/print_funcs.onyx
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index 8aec472030a66bd4669cfd7df1158b5af909c943..72dbe704fc231c500cf6c907a37aa0e6b3f29a75 100644 (file)
@@ -16,6 +16,8 @@ typedef struct AstLocal AstLocal;
 typedef struct AstCall AstCall;
 typedef struct AstIntrinsicCall AstIntrinsicCall;
 typedef struct AstArgument AstArgument;
+typedef struct AstAddressOf AstAddressOf;
+typedef struct AstDereference AstDereference;
 typedef struct AstArrayAccess AstArrayAccess;
 
 typedef struct AstAssign AstAssign;
@@ -77,6 +79,8 @@ typedef enum AstKind {
     Ast_Kind_Call,
     Ast_Kind_Intrinsic_Call,
     Ast_Kind_Return,
+    Ast_Kind_Address_Of,
+    Ast_Kind_Dereference,
     Ast_Kind_Array_Access,
 
     Ast_Kind_If,
@@ -201,6 +205,8 @@ struct AstLocal         { AstTyped_base; AstLocal *prev_local; };
 struct AstCall          { AstTyped_base; AstArgument *arguments; u64 arg_count; AstNode *callee; };
 struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; u64 arg_count; OnyxIntrinsic intrinsic; };
 struct AstArgument      { AstTyped_base; AstTyped *value; };
+struct AstAddressOf     { AstTyped_base; AstTyped *expr; }; 
+struct AstDereference   { AstTyped_base; AstTyped *expr; };
 struct AstArrayAccess   { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
 
 // Intruction Node
index 99af695c490d26f1662bb56ff5dded1f32a541c4..485a0d48cef03916a4109aa7c62ca0e77d734a4b 100644 (file)
@@ -86,6 +86,9 @@ extern Type basic_types[];
 struct AstType;
 b32 types_are_compatible(Type* t1, Type* t2);
 Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node);
+
+Type* type_make_pointer(bh_allocator alloc, Type* to);
+
 const char* type_get_name(Type* type);
 
 b32 type_is_pointer(Type* type);
diff --git a/onyx b/onyx
index c4f9619980dcb2287a0145c8a1c02333f1b33a04..b87f677f797237435b562b046eee5ccb7c096b6a 100755 (executable)
Binary files a/onyx and b/onyx differ
index a36a65f3ff940f8195729ebbf172a1aaa6ccbfcd..f2f61384e0cdd8c76a7ecccb3ac4eabf8687c391 100644 (file)
@@ -44,12 +44,8 @@ other_str :: "I can't believe this \n actually fricken worked!";
 str_test :: proc {
     hello_str :: "Hello World!";
 
-    walker := other_str;
-    while walker[0] != 0 as u8 {
-        print(walker[0] as i32);
-
-        walker = (walker as i32 + 1) as ^u8;
-    }
+    // Address of and dereference cancel each other out
+    print(^*hello_str);
 
     print("This is a test"[10] as i32);
 }
index 5bffff335b3c9ef4f830c3ab33007a1ef85966f2..3aadfc9dc39d12a83061b3cfd15a7a44cef00a99 100644 (file)
@@ -36,6 +36,15 @@ print_f64arr :: proc (arr: ^f64, len: i32) {
     }
 }
 
+// NOTE: print null-terminated string
+print_str :: proc (str: ^u8) {
+    c := str;
+    while *c != 0 as u8 {
+        print((*c) as i32);
+        c = (c as i32 + 1) as ^u8;
+    }
+}
+
 print :: proc #overloaded {
     print_bool,
     print_i32,
@@ -47,4 +56,6 @@ print :: proc #overloaded {
     print_i64arr,
     print_f32arr,
     print_f64arr,
+
+    print_str,
 }
index 759b677f9516b3e4d5e7694a3d67ec3a785aeab4..05b17017d25d36e7f3efc166aa9067e389a44eea 100644 (file)
@@ -13,6 +13,8 @@ CHECK(while, AstWhile* whilenode);
 CHECK(call, AstCall* call);
 CHECK(binaryop, AstBinaryOp* binop);
 CHECK(expression, AstTyped* expr);
+CHECK(address_of, AstAddressOf* aof);
+CHECK(dereference, AstDereference* deref);
 CHECK(array_access, AstArrayAccess* expr);
 CHECK(global, AstGlobal* global);
 CHECK(function, AstFunction* func);
@@ -338,9 +340,47 @@ CHECK(binaryop, AstBinaryOp* binop) {
     return 0;
 }
 
+CHECK(address_of, AstAddressOf* aof) {
+    if (check_expression(aof->expr)) return 1;
+
+    if (aof->expr->kind != Ast_Kind_Array_Access
+            && aof->expr->kind != Ast_Kind_Dereference) {
+        onyx_message_add(Msg_Type_Literal,
+                aof->token->pos,
+                "cannot take the address of this");
+        return 1;
+    }
+
+    aof->type = type_make_pointer(semstate.allocator, aof->expr->type);
+
+    return 0;
+}
+
+CHECK(dereference, AstDereference* deref) {
+    if (check_expression(deref->expr)) return 1;
+
+    if (!type_is_pointer(deref->expr->type)) {
+        onyx_message_add(Msg_Type_Literal,
+                deref->token->pos,
+                "cannot dereference non-pointer");
+        return 1;
+    }
+
+    if (deref->expr->type == basic_type_rawptr.type) {
+        onyx_message_add(Msg_Type_Literal,
+                deref->token->pos,
+                "cannot dereference rawptr");
+        return 1;
+    }
+
+    deref->type = deref->expr->type->Pointer.elem;
+
+    return 0;
+}
+
 CHECK(array_access, AstArrayAccess* aa) {
-    check_expression(aa->addr);
-    check_expression(aa->expr);
+    if (check_expression(aa->addr)) return 1;
+    if (check_expression(aa->expr)) return 1;
 
     if (!type_is_pointer(aa->addr->type)) {
         onyx_message_add(Msg_Type_Literal,
@@ -406,9 +446,9 @@ CHECK(expression, AstTyped* expr) {
 
         case Ast_Kind_Local: break;
 
-        case Ast_Kind_Array_Access:
-            retval = check_array_access((AstArrayAccess *) expr);
-            break;
+        case Ast_Kind_Address_Of:   retval = check_address_of((AstAddressOf *) expr); break;
+        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_Global:
             if (expr->type == NULL) {
index cb3c9d9f9dd3cac710737b0c98603790f098e7b8..0bee666a21f72af782caa4e5fccc10b530f51ca8 100644 (file)
@@ -133,96 +133,110 @@ static AstTyped* parse_factor(OnyxParser* parser) {
     AstTyped* retval = NULL;
 
     switch ((u16) parser->curr->type) {
-        case '(':
-            {
-                consume_token(parser);
-                AstTyped* expr = parse_expression(parser);
-                expect_token(parser, ')');
-                retval = expr;
-                break;
-            }
+        case '(': {
+            consume_token(parser);
+            AstTyped* expr = parse_expression(parser);
+            expect_token(parser, ')');
+            retval = expr;
+            break;
+        }
 
-        case '-':
-            {
-                consume_token(parser);
-                AstTyped* factor = parse_factor(parser);
+        case '-': {
+            consume_token(parser);
+            AstTyped* factor = parse_factor(parser);
 
-                AstUnaryOp* negate_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
-                negate_node->operation = Unary_Op_Negate;
-                negate_node->expr = factor;
+            AstUnaryOp* negate_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
+            negate_node->operation = Unary_Op_Negate;
+            negate_node->expr = factor;
 
-                if ((factor->flags & Ast_Flag_Comptime) != 0) {
-                    negate_node->flags |= Ast_Flag_Comptime;
-                }
+            if ((factor->flags & Ast_Flag_Comptime) != 0) {
+                negate_node->flags |= Ast_Flag_Comptime;
+            }
 
-                retval = (AstTyped *) negate_node;
-                break;
+            retval = (AstTyped *) negate_node;
+            break;
+        }
+
+        case '!': {
+            AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
+            not_node->operation = Unary_Op_Not;
+            not_node->token = expect_token(parser, '!');
+            not_node->expr = parse_factor(parser);
+
+            if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
+                not_node->flags |= Ast_Flag_Comptime;
             }
 
-        case '!':
-            {
-                AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
-                not_node->operation = Unary_Op_Not;
-                not_node->token = expect_token(parser, '!');
-                not_node->expr = parse_factor(parser);
+            retval = (AstTyped *) not_node;
+            break;
+        }
 
-                if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
-                    not_node->flags |= Ast_Flag_Comptime;
-                }
+        case '*': {
+            AstDereference* deref_node = make_node(AstDereference, Ast_Kind_Dereference);
+            deref_node->token = expect_token(parser, '*');
+            deref_node->expr  = parse_factor(parser);
 
-                retval = (AstTyped *) not_node;
+            retval = (AstTyped *) deref_node;
+            break;
+        }
+
+        case '^': {
+            AstAddressOf* aof_node = make_node(AstAddressOf, Ast_Kind_Address_Of);
+            aof_node->token = expect_token(parser, '^');
+            aof_node->expr  = parse_factor(parser);
+
+            retval = (AstTyped *) aof_node;
+            break;
+        }
+
+        case Token_Type_Symbol: {
+            OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
+            AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
+            sym_node->token = sym_token;
+
+            if (parser->curr->type != '(') {
+                retval = sym_node;
                 break;
             }
 
-        case Token_Type_Symbol:
-            {
-                OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
-                AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
-                sym_node->token = sym_token;
+            // NOTE: Function call
+            AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
+            call_node->token = expect_token(parser, '(');
+            call_node->callee = (AstNode *) sym_node;
+            call_node->arg_count = 0;
 
-                if (parser->curr->type != '(') {
-                    retval = sym_node;
-                    break;
+            AstArgument** prev = &call_node->arguments;
+            AstArgument* curr = NULL;
+            while (parser->curr->type != ')') {
+                curr = make_node(AstArgument, Ast_Kind_Argument);
+                curr->token = parser->curr;
+                curr->value = parse_expression(parser);
+
+                if (curr != NULL && curr->kind != Ast_Kind_Error) {
+                    *prev = curr;
+                    prev = (AstArgument **) &curr->next;
+
+                    call_node->arg_count++;
                 }
 
-                // NOTE: Function call
-                AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
-                call_node->token = expect_token(parser, '(');
-                call_node->callee = (AstNode *) sym_node;
-                call_node->arg_count = 0;
-
-                AstArgument** prev = &call_node->arguments;
-                AstArgument* curr = NULL;
-                while (parser->curr->type != ')') {
-                    curr = make_node(AstArgument, Ast_Kind_Argument);
-                    curr->token = parser->curr;
-                    curr->value = parse_expression(parser);
-
-                    if (curr != NULL && curr->kind != Ast_Kind_Error) {
-                        *prev = curr;
-                        prev = (AstArgument **) &curr->next;
-
-                        call_node->arg_count++;
-                    }
-
-                    if (parser->curr->type == ')')
-                        break;
-
-                    if (parser->curr->type != ',') {
-                        onyx_message_add(Msg_Type_Expected_Token,
-                                parser->curr->pos,
-                                token_name(','),
-                                token_name(parser->curr->type));
-                        return (AstTyped *) &error_node;
-                    }
-
-                    consume_token(parser);
+                if (parser->curr->type == ')')
+                    break;
+
+                if (parser->curr->type != ',') {
+                    onyx_message_add(Msg_Type_Expected_Token,
+                            parser->curr->pos,
+                            token_name(','),
+                            token_name(parser->curr->type));
+                    return (AstTyped *) &error_node;
                 }
-                consume_token(parser);
 
-                retval = (AstTyped *) call_node;
-                break;
+                consume_token(parser);
             }
+            consume_token(parser);
+
+            retval = (AstTyped *) call_node;
+            break;
+        }
 
         case Token_Type_Literal_Numeric:
             retval = (AstTyped *) parse_numeric_literal(parser);
index e72457466340f3a28ffd4b4494915ebdc137aa5e..00b81658a5a15e460bad2948a0806118c307c43a 100644 (file)
@@ -172,6 +172,14 @@ 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_Array_Access:
             symres_expression(&((AstArrayAccess *)(*expr))->addr);
             symres_expression(&((AstArrayAccess *)(*expr))->expr);
index 44605492b2502642bcc5061772999268a5f6e1e7..118651e61df1832632056ea517dbae9aeb5a1ccd 100644 (file)
@@ -56,14 +56,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
     switch (type_node->kind) {
         case Ast_Kind_Pointer_Type: {
-            Type* ptr_type = bh_alloc_item(alloc, Type);
-
-            ptr_type->kind = Type_Kind_Pointer;
-            ptr_type->Pointer.base.flags |= Basic_Flag_Pointer;
-            ptr_type->Pointer.base.size = 4;
-            ptr_type->Pointer.elem = type_build_from_ast(alloc, ((AstPointerType *) type_node)->elem);
-
-            return (Type *) ptr_type;
+            return type_make_pointer(alloc, type_build_from_ast(alloc, ((AstPointerType *) type_node)->elem));
         }
 
         case Ast_Kind_Function_Type: {
@@ -93,6 +86,17 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
     }
 }
 
+Type* type_make_pointer(bh_allocator alloc, Type* to) {
+    Type* ptr_type = bh_alloc_item(alloc, Type);
+
+    ptr_type->kind = Type_Kind_Pointer;
+    ptr_type->Pointer.base.flags |= Basic_Flag_Pointer;
+    ptr_type->Pointer.base.size = 4;
+    ptr_type->Pointer.elem = to;
+
+    return ptr_type;
+}
+
 const char* type_get_name(Type* type) {
     if (type == NULL) return "unknown";
 
index 1138f7cc0f461e7d94aac55179f76619cabc2606..06ed78a540e63d5a879c705110d5dd403b7d31df 100644 (file)
@@ -38,6 +38,8 @@ static const char* ast_node_names[] = {
     "ARGUMENT",
     "CALL",
     "RETURN",
+    "ADDRESS OF",
+    "DEREFERENCE",
     "ARRAY_ACCESS",
 
     "IF",
index 3a9d81f20fcf7f15bdb4019c605bac9dac0dca6f..536a0c8a205933bbeaf34989b5e32be540158f79 100644 (file)
@@ -192,6 +192,11 @@ static const char* wi_string(WasmInstructionType wit) {
         case WI_I64_REINTERPRET_F64: return "WI_I64_REINTERPRET_F64";
         case WI_F32_REINTERPRET_I32: return "WI_F32_REINTERPRET_I32";
         case WI_F64_REINTERPRET_I64: return "WI_F64_REINTERPRET_I64";
+        case WI_I32_EXTEND_8_S: return "WI_I32_EXTEND_8_S";
+        case WI_I32_EXTEND_16_S: return "WI_I32_EXTEND_16_S";
+        case WI_I64_EXTEND_8_S: return "WI_I64_EXTEND_8_S";
+        case WI_I64_EXTEND_16_S: return "WI_I64_EXTEND_16_S";
+        case WI_I64_EXTEND_32_S: return "WI_I64_EXTEND_32_S";
     }
 }
 
@@ -683,6 +688,70 @@ COMPILE_FUNC(expression, AstTyped* expr) {
         case Ast_Kind_Binary_Op:      compile_binop(mod, &code, (AstBinaryOp *) expr); break;
         case Ast_Kind_Unary_Op:       compile_unaryop(mod, &code, (AstUnaryOp *) expr); break;
 
+        case Ast_Kind_Address_Of: {
+            AstAddressOf* aof = (AstAddressOf *) expr;
+
+            switch (aof->expr->kind) {
+                case Ast_Kind_Dereference: {
+                    compile_expression(mod, &code, ((AstDereference *) aof->expr)->expr);
+                    break;
+                }
+
+                case Ast_Kind_Array_Access: {
+                    AstArrayAccess* aa = (AstArrayAccess *) aof->expr;
+
+                    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);
+                    WI(WI_I32_ADD);
+                    break;
+                }
+
+                default:
+                    onyx_message_add(Msg_Type_Literal,
+                            aof->token->pos,
+                            "unsupported address of");
+                }
+
+            break;
+        }
+
+        case Ast_Kind_Dereference: {
+            AstDereference* deref = (AstDereference *) expr;
+            compile_expression(mod, &code, deref->expr);
+
+            i32 load_size   = deref->type->Basic.size;
+            i32 is_integer  = (deref->type->Basic.flags & Basic_Flag_Integer)
+                           || (deref->type->Basic.flags & Basic_Flag_Pointer);
+            i32 is_unsigned = deref->type->Basic.flags & Basic_Flag_Unsigned;
+
+            WasmInstructionType instr = WI_NOP;
+            i32 alignment = log2_dumb(load_size);
+
+            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 (alignment < 4 && is_unsigned) instr += 1;
+            } else {
+                if      (load_size == 4) instr = WI_F32_LOAD;
+                else if (load_size == 8) instr = WI_F64_LOAD;
+            }
+
+            if (instr != WI_NOP) {
+                WID(instr, ((WasmInstructionData) { alignment, 0 }));
+            } else {
+                DEBUG_HERE;
+            }
+
+            break;
+        }
+
         case Ast_Kind_Array_Access: {
             AstArrayAccess* aa = (AstArrayAccess *) expr;
             compile_expression(mod, &code, aa->expr);