From: Brendan Hansen Date: Mon, 20 Jul 2020 21:27:14 +0000 (-0500) Subject: Added 'sizeof' unary operator X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=fb1e2e86e376a7f5b4763c2b137c9153ed10edb4;p=onyx.git Added 'sizeof' unary operator --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index f33ef189..cfa65923 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; }; diff --git a/include/onyxlex.h b/include/onyxlex.h index c54fdbbc..a8726ec5 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -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 31c4540f..3bb51010 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/structs.onyx b/progs/structs.onyx index 55c676e0..4bd171aa 100644 --- a/progs/structs.onyx +++ b/progs/structs.onyx @@ -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 diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 0ff7d4fb..3a4f2096 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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) { diff --git a/src/onyxlex.c b/src/onyxlex.c index 5b2acd12..ead0fa15 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -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); diff --git a/src/onyxmsgs.c b/src/onyxmsgs.c index 2df639bf..0a45933f 100644 --- a/src/onyxmsgs.c +++ b/src/onyxmsgs.c @@ -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'", diff --git a/src/onyxparser.c b/src/onyxparser.c index fe9ec61d..9bc065b6 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 28a62d69..675cdef1 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; diff --git a/src/onyxutils.c b/src/onyxutils.c index edc56e13..967556c8 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -45,6 +45,7 @@ static const char* ast_node_names[] = { "DEREFERENCE", "ARRAY_ACCESS", "FIELD_ACCESS", + "SIZE OF", "IF", "FOR", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index cc3e89e5..cfeb97b9 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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;