From: Brendan Hansen Date: Sun, 19 Jul 2020 17:51:59 +0000 (-0500) Subject: Added address of and deference operators X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=b4b0bc34a8c084ed0f45d5eee9b90a47c252016c;p=onyx.git Added address of and deference operators --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 8aec4720..72dbe704 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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 diff --git a/include/onyxtypes.h b/include/onyxtypes.h index 99af695c..485a0d48 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -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 c4f96199..b87f677f 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/arrays.onyx b/progs/arrays.onyx index a36a65f3..f2f61384 100644 --- a/progs/arrays.onyx +++ b/progs/arrays.onyx @@ -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); } diff --git a/progs/print_funcs.onyx b/progs/print_funcs.onyx index 5bffff33..3aadfc9d 100644 --- a/progs/print_funcs.onyx +++ b/progs/print_funcs.onyx @@ -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, } diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 759b677f..05b17017 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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) { diff --git a/src/onyxparser.c b/src/onyxparser.c index cb3c9d9f..0bee666a 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index e7245746..00b81658 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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); diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 44605492..118651e6 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -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"; diff --git a/src/onyxutils.c b/src/onyxutils.c index 1138f7cc..06ed78a5 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -38,6 +38,8 @@ static const char* ast_node_names[] = { "ARGUMENT", "CALL", "RETURN", + "ADDRESS OF", + "DEREFERENCE", "ARRAY_ACCESS", "IF", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 3a9d81f2..536a0c8a 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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);