From: Brendan Hansen Date: Mon, 24 Aug 2020 17:11:12 +0000 (-0500) Subject: Added slice types; bugfixes X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=c6257b799c5c54bb1333c1dd2b1a19d570b6f0ff;p=onyx.git Added slice types; bugfixes --- diff --git a/core/builtin.onyx b/core/builtin.onyx index 18788c37..ebac5985 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -1,8 +1,4 @@ package builtin -string :: struct { - data : ^u8; - len : u32; -} - +string :: #type []u8; cstring :: #type ^u8; \ No newline at end of file diff --git a/core/string.onyx b/core/string.onyx index c3b41433..ebfbfaaa 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -15,7 +15,7 @@ string_make :: proc #overloaded { string_make_from_cstring } string_make_from_cstring :: proc (s: cstring) -> string { len :: string_length(s); - return string.{ len = len, data = s }; + return string.{ count = len, data = s }; } string_length :: proc #overloaded { @@ -31,12 +31,12 @@ string_length :: proc #overloaded { }, proc (s: string) -> u32 { - return s.len; + return s.count; }, } #private -string_length_string :: proc (s: string) -> u32 do return s.len; +string_length_string :: proc (s: string) -> u32 do return s.count; string_concat :: proc (a: Allocator, s1: string, s2: string) -> string { len1 :: string_length(s1); @@ -58,27 +58,37 @@ StringSplitResult :: struct { string_split :: proc (a: Allocator, str: string, delim: u8) -> StringSplitResult { delim_count := 0; - for i: 0, str.len do if str.data[i] == delim do delim_count += 1; + for i: 0, str.count do if str.data[i] == delim do delim_count += 1; strarr := cast(^string) alloc(a, sizeof string * (delim_count + 1)); curr_str := 0; - begin := str.data; + begin := 0; - for i: 0, str.len { + for i: 0, str.count { if str.data[i] == delim { - strarr[curr_str] = string.{ begin, cast(u32) ^str.data[i] - cast(u32) begin }; - begin = ^str.data[i + 1]; + strarr[curr_str] = str.data[begin : i]; + begin = i + 1; curr_str += 1; } } - strarr[curr_str] = string.{ begin, cast(u32) str.data + str.len - cast(u32) begin }; + strarr[curr_str] = str.data[begin : str.count]; return StringSplitResult.{ strarr, delim_count + 1 }; } +string_substr :: proc (str: string, sub: string) -> string { + for i: 0, str.count { + while j := 0; j < sub.count && str.data[i + j] == sub.data[j] { + j += 1; + if j == sub.count do return str.data[i : i + j]; + } + } + + return str.data[0:0]; +} StringBuilder :: struct { alloc : Allocator; @@ -103,11 +113,11 @@ string_builder_make :: proc (a: Allocator, initial_cap: u32) -> StringBuilder { } string_builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^StringBuilder { - len_total :: len + str.len; + len_total :: len + str.count; if cap >= len_total { - for i: 0, str.len do data[len + i] = str.data[i]; - len += str.len; + for i: 0, str.count do data[len + i] = str.data[i]; + len += str.count; return sb; } @@ -120,8 +130,8 @@ string_builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^Stri data = new_data; cap = new_cap; - for i: 0, str.len do data[len + i] = str.data[i]; - len += str.len; + for i: 0, str.count do data[len + i] = str.data[i]; + len += str.count; return sb; } @@ -141,20 +151,19 @@ u64_to_string :: proc (n_: u64, base: u64, buf: Buffer) -> string { s :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - if n == 0l { - *c = #char "0"; + while n > 0l { + m :: n % base; + + *c = s.data[cast(u32) m]; len += 1; c -= 1; - } else { - while n > 0l { - m :: n % base; - *c = s.data[cast(u32) m]; - len += 1; - c -= 1; - - n /= base; - } + n /= base; + + } else { + *c = #char "0"; + len += 1; + c -= 1; } if base == 16l { @@ -175,7 +184,7 @@ u64_to_string :: proc (n_: u64, base: u64, buf: Buffer) -> string { c -= 1; } - return string.{ data = c + 1, len = len }; + return string.{ data = c + 1, count = len }; } string_builder_add_u64 :: proc (use sb: ^StringBuilder, n: u64) -> ^StringBuilder { diff --git a/docs/plan b/docs/plan index 0a230bab..b34d368c 100644 --- a/docs/plan +++ b/docs/plan @@ -199,6 +199,14 @@ HOW: // Loop never run } + [X] Add slices + - Arrays without a size + - Converted to a struct that looks like: + []T :: struct { + data : ^T; + count : u32; + } + [ ] 'use' enums and packages at an arbitrary scope [ ] convert to using an 'atom' like table @@ -218,14 +226,6 @@ HOW: - But, profiling says we are spending 50% of the program execution time in the lexer - That is awful - [ ] Add slices - - Arrays without a size - - Converted to a struct that looks like: - []T :: struct { - data : ^T; - count : u32; - } - [ ] Variadic arguments [ ] 'when' statements diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index c9814df0..c67803f9 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -19,6 +19,7 @@ typedef struct AstArgument AstArgument; typedef struct AstAddressOf AstAddressOf; typedef struct AstDereference AstDereference; typedef struct AstArrayAccess AstArrayAccess; +typedef struct AstSlice AstSlice; typedef struct AstFieldAccess AstFieldAccess; typedef struct AstSizeOf AstSizeOf; typedef struct AstAlignOf AstAlignOf; @@ -39,6 +40,7 @@ typedef struct AstBasicType AstBasicType; typedef struct AstPointerType AstPointerType; typedef struct AstFunctionType AstFunctionType; typedef struct AstArrayType AstArrayType; +typedef struct AstSliceType AstSliceType; typedef struct AstStructType AstStructType; typedef struct AstStructMember AstStructMember; typedef struct AstEnumType AstEnumType; @@ -93,6 +95,7 @@ typedef enum AstKind { Ast_Kind_Pointer_Type, Ast_Kind_Function_Type, Ast_Kind_Array_Type, + Ast_Kind_Slice_Type, Ast_Kind_Struct_Type, Ast_Kind_Enum_Type, Ast_Kind_Type_Alias, @@ -111,6 +114,7 @@ typedef enum AstKind { Ast_Kind_Address_Of, Ast_Kind_Dereference, Ast_Kind_Array_Access, + Ast_Kind_Slice, Ast_Kind_Field_Access, Ast_Kind_Ufc, Ast_Kind_Size_Of, @@ -283,6 +287,7 @@ 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; }; +struct AstSlice { AstTyped_base; AstTyped *addr; AstTyped *lo, *hi; u64 elem_size; }; struct AstFieldAccess { AstTyped_base; AstTyped *expr; u64 offset; }; struct AstSizeOf { AstTyped_base; AstType *so_type; u64 size; }; struct AstAlignOf { AstTyped_base; AstType *ao_type; u64 alignment; }; @@ -346,6 +351,7 @@ struct AstBasicType { AstType_base; Type* type; }; struct AstPointerType { AstType_base; AstType* elem; }; struct AstFunctionType { AstType_base; AstType* return_type; u64 param_count; AstType* params[]; }; struct AstArrayType { AstType_base; AstType* elem; AstTyped *count_expr; }; +struct AstSliceType { AstType_base; AstType* elem; }; struct AstStructType { AstType_base; diff --git a/include/onyxtypes.h b/include/onyxtypes.h index 27cd1a9d..1bfd25a5 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -62,7 +62,7 @@ typedef struct StructMember { TYPE_KIND(Struct, struct { \ char* name; \ u32 size; \ - u16 aligment, mem_count; \ + u16 alignment, mem_count; \ bh_table(StructMember) members; \ bh_arr(StructMember *) memarr; \ }) \ @@ -112,6 +112,7 @@ Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node); Type* type_build_function_type(bh_allocator alloc, struct AstFunction* func, struct AstType* return_type); Type* type_make_pointer(bh_allocator alloc, Type* to); +Type* type_make_slice(bh_allocator alloc, Type* of); const char* type_get_name(Type* type); u32 type_get_alignment_log2(Type* type); diff --git a/onyx b/onyx index a8ec7737..429da335 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/wasi_test.onyx b/progs/wasi_test.onyx index 4e1ff14d..6743d1b4 100644 --- a/progs/wasi_test.onyx +++ b/progs/wasi_test.onyx @@ -62,7 +62,7 @@ print_u64_with_base :: proc (n_: u64, base: u64) { } print_string :: proc (s: string) -> u32 { - vec := IOVec.{ buf = s.data, len = s.len }; + vec := IOVec.{ buf = s.data, len = s.count }; tmp : Size; fd_write(1, IOVecArray.{ ^vec, 1 }, ^tmp); fd_datasync(1); @@ -190,13 +190,25 @@ output_s :: proc (sb: ^StringBuilder, s: ^S) -> ^StringBuilder { return sb; } +print_arr :: proc (sb: ^StringBuilder, arr: []i32) { + sb |> string_builder_clear(); + + a := arr.data; + + for i: 0, arr.count { + sb |> sba(cast(u64) a[i]) |> sba(" "); + } + + sb |> sba("\n") |> string_builder_to_string() |> print(); +} + main :: proc (argc: u32, argv: ^cstring) { sb := string_builder_make(heap_allocator, 256); timer := timer_start(); defer { ^sb |> string_builder_clear() - |> sba("Time taken: ") + |> sba("\nTime taken: ") |> sba(cast(u64) timer_end(timer), 10l) |> sba("ms\n") |> string_builder_to_string() @@ -213,15 +225,7 @@ main :: proc (argc: u32, argv: ^cstring) { |> print(); fd: FileDescriptor = -1; - if err := path_open(3, - LookupFlags.SymLinkFollow, - string_make(argv[1]), - cast(OFlags) 0, - Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, - Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, - FDFlags.Sync, - ^fd); - err != Errno.Success { + if err := path_open(3, LookupFlags.SymLinkFollow, string_make(argv[1]), cast(OFlags) 0, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, FDFlags.Sync, ^fd); err != Errno.Success { print("Failed to open file\n"); print("Error code: "); print_u64_with_base(cast(u64) err, 16l); @@ -301,10 +305,27 @@ main :: proc (argc: u32, argv: ^cstring) { |> print(); } - while i := 10; i < 10 { - print("Looping\n"); + ^sb |> string_builder_clear(); + while i := 0; i < 10 { + ^sb |> sba("Loop: ") |> sba(cast(u64) i) |> sba("\n"); + i += 1; } else { print("Never ran the loop\n"); } + + ^sb |> string_builder_to_string() |> print(); + + + arr : [128] i32; + for i: 0, 128 do arr[i] = i * i; + + slice := arr[14 : 20]; + + print_arr(^sb, slice); + + ss := string_substr("Hello, WoWorld!", "World"); + if ss.count > 0 { + print(ss); + } } diff --git a/src/onyxchecker.c b/src/onyxchecker.c index feace16d..c93ed3c4 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -20,6 +20,7 @@ CHECK(expression, AstTyped** expr); CHECK(address_of, AstAddressOf* aof); CHECK(dereference, AstDereference* deref); CHECK(array_access, AstArrayAccess* expr); +CHECK(slice, AstSlice* sl); CHECK(field_access, AstFieldAccess** pfield); CHECK(size_of, AstSizeOf* so); CHECK(align_of, AstAlignOf* ao); @@ -757,6 +758,52 @@ CHECK(array_access, AstArrayAccess* aa) { return 0; } +CHECK(slice, AstSlice* sl) { + if (check_expression(&sl->addr)) return 1; + if (check_expression(&sl->lo)) return 1; + if (check_expression(&sl->hi)) return 1; + + if (!type_is_pointer(sl->addr->type)) { + onyx_message_add(Msg_Type_Literal, + sl->token->pos, + "expected pointer or array type for left of slice creation"); + return 1; + } + + if (sl->lo->type->kind != Type_Kind_Basic + || (sl->lo->type->Basic.kind != Basic_Kind_I32 && sl->lo->type->Basic.kind != Basic_Kind_U32)) { + onyx_message_add(Msg_Type_Literal, + sl->token->pos, + "expected 32-bit integer type for lower index"); + return 1; + } + + if (sl->hi->type->kind != Type_Kind_Basic + || (sl->hi->type->Basic.kind != Basic_Kind_I32 && sl->hi->type->Basic.kind != Basic_Kind_U32)) { + onyx_message_add(Msg_Type_Literal, + sl->token->pos, + "expected 32-bit integer type for upper index"); + return 1; + } + + Type *of = NULL; + if (sl->addr->type->kind == Type_Kind_Pointer) + of = sl->addr->type->Pointer.elem; + else if (sl->addr->type->kind == Type_Kind_Array) + of = sl->addr->type->Array.elem; + else { + onyx_message_add(Msg_Type_Literal, + sl->token->pos, + "invalid type for left of slice creation"); + return 1; + } + + sl->type = type_make_slice(semstate.node_allocator, of); + sl->elem_size = type_size_of(of); + + return 0; +} + CHECK(field_access, AstFieldAccess** pfield) { AstFieldAccess* field = *pfield; if (check_expression(&field->expr)) return 1; @@ -838,6 +885,7 @@ CHECK(expression, AstTyped** pexpr) { 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_Slice: retval = check_slice((AstSlice *) expr); break; case Ast_Kind_Field_Access: retval = check_field_access((AstFieldAccess **) pexpr); break; case Ast_Kind_Size_Of: retval = check_size_of((AstSizeOf *) expr); break; case Ast_Kind_Align_Of: retval = check_align_of((AstAlignOf *) expr); break; diff --git a/src/onyxparser.c b/src/onyxparser.c index bbd2cfa9..5c1b18c8 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -480,14 +480,32 @@ static AstTyped* parse_factor(OnyxParser* parser) { switch ((u16) parser->curr->type) { case '[': { - AstArrayAccess* aa_node = make_node(AstArrayAccess, Ast_Kind_Array_Access); - aa_node->token = expect_token(parser, '['); - aa_node->addr = retval; - aa_node->expr = parse_expression(parser); + OnyxToken *open_bracket = expect_token(parser, '['); + AstTyped *lo = parse_expression(parser); - expect_token(parser, ']'); + if (parser->curr->type == ':') { + consume_token(parser); + + AstSlice *sl_node = make_node(AstSlice, Ast_Kind_Slice); + sl_node->token = open_bracket; + sl_node->addr = retval; + sl_node->lo = lo; + sl_node->hi = parse_expression(parser); + + retval = (AstTyped *) sl_node; + expect_token(parser, ']'); + goto factor_parsed; + + } else { + AstArrayAccess* aa_node = make_node(AstArrayAccess, Ast_Kind_Array_Access); + aa_node->token = open_bracket; + aa_node->addr = retval; + aa_node->expr = lo; + + retval = (AstTyped *) aa_node; + expect_token(parser, ']'); + } - retval = (AstTyped *) aa_node; break; } @@ -1075,15 +1093,21 @@ static AstType* parse_type(OnyxParser* parser) { } else if (parser->curr->type == '[') { - AstArrayType* new = make_node(AstArrayType, Ast_Kind_Array_Type); - new->token = expect_token(parser, '['); + AstSliceType *new; + OnyxToken *open_bracket = expect_token(parser, '['); - if (parser->curr->type != ']') - new->count_expr = parse_expression(parser); + if (parser->curr->type == ']') { + new = make_node(AstSliceType, Ast_Kind_Slice_Type); + new->token = open_bracket; + } else { + new = make_node(AstArrayType, Ast_Kind_Array_Type); + new->token = open_bracket; + ((AstArrayType *) new)->count_expr = parse_expression(parser); + } - expect_token(parser, ']'); - *next_insertion = (AstType *) new; - next_insertion = &new->elem; + expect_token(parser, ']'); + *next_insertion = (AstType *) new; + next_insertion = &new->elem; } else if (parser->curr->type == Token_Type_Keyword_Proc) { diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 603e5a63..4c88b126 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -115,6 +115,13 @@ static AstType* symres_type(AstType* type) { return type; } + if (type->kind == Ast_Kind_Slice_Type) { + AstSliceType* s_node = (AstSliceType *) type; + s_node->elem = symres_type(s_node->elem); + + return type; + } + onyx_message_add(Msg_Type_Literal, (OnyxFilePos) { 0 }, onyx_ast_node_kind_string(type->kind)); @@ -217,16 +224,16 @@ static void symres_struct_literal(AstStructLiteral* sl) { if (sl->stnode != NULL) symres_expression(&sl->stnode); if (sl->stnode == NULL) return; - if (sl->stnode->kind != Ast_Kind_Struct_Type) { + sl->type_node = (AstType *) sl->stnode; + sl->type = type_build_from_ast(semstate.allocator, sl->type_node); + + if (sl->type->kind != Type_Kind_Struct) { onyx_message_add(Msg_Type_Literal, sl->token->pos, "type is not a struct type (BAD ERROR MESSAGE)"); return; } - sl->type_node = (AstType *) sl->stnode; - sl->type = type_build_from_ast(semstate.allocator, sl->type_node); - if (bh_arr_length(sl->values) == 0) { bh_arr_set_length(sl->values, sl->type->Struct.mem_count); bh_arr_zero(sl->values); @@ -312,6 +319,12 @@ static void symres_expression(AstTyped** expr) { symres_expression(&((AstArrayAccess *)(*expr))->expr); break; + case Ast_Kind_Slice: + symres_expression(&((AstSlice *)(*expr))->addr); + symres_expression(&((AstSlice *)(*expr))->lo); + symres_expression(&((AstSlice *)(*expr))->hi); + break; + case Ast_Kind_Struct_Literal: symres_struct_literal((AstStructLiteral *)(*expr)); break; diff --git a/src/onyxtypes.c b/src/onyxtypes.c index c921abfe..602c5dc9 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -47,8 +47,12 @@ b32 types_are_surface_compatible(Type* t1, Type* t2) { break; case Type_Kind_Pointer: - if (t2->kind == Type_Kind_Pointer) return 1; - break; + if (t2->kind != Type_Kind_Pointer) return 0; + + if (t1->Pointer.elem->kind == Type_Kind_Basic && t2->Pointer.elem->kind == Type_Kind_Basic) + return types_are_compatible(t1->Pointer.elem, t2->Pointer.elem); + + return 1; case Type_Kind_Array: { if (t2->kind != Type_Kind_Array) return 0; @@ -205,7 +209,7 @@ u32 type_alignment_of(Type* type) { case Type_Kind_Pointer: return 4; case Type_Kind_Function: return 4; case Type_Kind_Array: return type_alignment_of(type->Array.elem); - case Type_Kind_Struct: return type->Struct.aligment; + case Type_Kind_Struct: return type->Struct.alignment; case Type_Kind_Enum: return type_alignment_of(type->Enum.backing); default: return 1; } @@ -321,7 +325,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { } alignment = bh_max(s_node->min_alignment, alignment); - s_type->Struct.aligment = alignment; + s_type->Struct.alignment = alignment; if (size % alignment != 0) { size += alignment - (size % alignment); @@ -347,6 +351,10 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { return enum_type; } + case Ast_Kind_Slice_Type: { + return type_make_slice(alloc, type_build_from_ast(alloc, ((AstSliceType *) type_node)->elem)); + } + case Ast_Kind_Basic_Type: return ((AstBasicType *) type_node)->type; @@ -399,6 +407,31 @@ Type* type_make_pointer(bh_allocator alloc, Type* to) { return ptr_type; } +Type* type_make_slice(bh_allocator alloc, Type* of) { + Type* s_type = bh_alloc(alloc, sizeof(Type)); + s_type->kind = Type_Kind_Struct; + s_type->Struct.name = bh_aprintf(global_heap_allocator, "[] %s", type_get_name(of)); + s_type->Struct.mem_count = 2; + 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); + + StructMember smem; + smem = (StructMember) { .offset = 0, .type = type_make_pointer(alloc, of), .idx = 0, }; + bh_table_put(StructMember, s_type->Struct.members, "data", smem); + smem = (StructMember) { .offset = 4, .type = &basic_types[Basic_Kind_U32], .idx = 1, }; + bh_table_put(StructMember, s_type->Struct.members, "count", smem); + + bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, "data")); + bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, "count")); + + s_type->Struct.alignment = 4; + s_type->Struct.size = 8; + + return s_type; +} + const char* type_get_name(Type* type) { if (type == NULL) return "unknown"; diff --git a/src/onyxutils.c b/src/onyxutils.c index 8dbacf26..3ed98c55 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -40,6 +40,7 @@ static const char* ast_node_names[] = { "POINTER_TYPE", "FUNCTION_TYPE", "ARRAY TYPE", + "SLICE TYPE", "STRUCT TYPE", "ENUM TYPE", "TYPE_ALIAS", @@ -58,6 +59,7 @@ static const char* ast_node_names[] = { "ADDRESS OF", "DEREFERENCE", "ARRAY_ACCESS", + "SLICE", "FIELD_ACCESS", "UFC", "SIZE OF", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 3ba6923c..57978683 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -370,6 +370,7 @@ COMPILE_FUNC(array_access_location, AstArrayAccess* aa, u64* offset_retu COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return); COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return); COMPILE_FUNC(memory_reservation_location, AstMemRes* memres); +COMPILE_FUNC(location, AstTyped* expr); COMPILE_FUNC(struct_load, Type* type, u64 offset); COMPILE_FUNC(struct_lval, AstTyped* lval); COMPILE_FUNC(struct_store, Type* type, u64 offset); @@ -1150,11 +1151,19 @@ COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return) { bh_arr(WasmInstruction) code = *pcode; u64 local_offset = (u64) bh_imap_get(&mod->local_map, (u64) local); - assert((local_offset & (LOCAL_IS_WASM | LOCAL_F64)) == 0); - WIL(WI_LOCAL_GET, mod->stack_base_idx); + if (local_offset & LOCAL_IS_WASM) { + // HACK: This case doesn't feel quite right. I think the + // only way to end up here is if you are taking the slice + // off a pointer that is a local. But this still feels + // like the wrong long term solution. + WIL(WI_LOCAL_GET, local_offset); - *offset_return += local_offset; + } else { + WIL(WI_LOCAL_GET, mod->stack_base_idx); + + *offset_return += local_offset; + } *pcode = code; } @@ -1270,6 +1279,78 @@ COMPILE_FUNC(struct_literal, AstStructLiteral* sl) { *pcode = code; } +COMPILE_FUNC(location, AstTyped* expr) { + bh_arr(WasmInstruction) code = *pcode; + + switch (expr->kind) { + case Ast_Kind_Local: { + u64 offset = 0; + compile_local_location(mod, &code, (AstLocal *) expr, &offset); + if (offset != 0) { + WID(WI_I32_CONST, offset); + WI(WI_I32_ADD); + } + break; + } + + case Ast_Kind_Dereference: { + compile_expression(mod, &code, ((AstDereference *) expr)->expr); + break; + } + + case Ast_Kind_Array_Access: { + AstArrayAccess* aa = (AstArrayAccess *) expr; + u64 offset = 0; + compile_array_access_location(mod, &code, aa, &offset); + if (offset != 0) { + WID(WI_I32_CONST, offset); + WI(WI_I32_ADD); + } + break; + } + + case Ast_Kind_Field_Access: { + AstFieldAccess* field = (AstFieldAccess *) expr; + + if (field->expr->kind == Ast_Kind_Param && field->expr->type->kind == Type_Kind_Struct) { + StructMember smem; + + token_toggle_end(field->token); + type_struct_lookup_member(field->expr->type, field->token->text, &smem); + token_toggle_end(field->token); + + u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + smem.idx; + + WIL(WI_LOCAL_GET, localidx); + break; + } + + u64 offset = 0; + compile_field_access_location(mod, &code, field, &offset); + if (offset != 0) { + WID(WI_I32_CONST, offset); + WI(WI_I32_ADD); + } + break; + } + + case Ast_Kind_Memres: { + AstMemRes* memres = (AstMemRes *) expr; + WID(WI_I32_CONST, memres->addr); + break; + } + + default: { + onyx_message_add(Msg_Type_Literal, + (OnyxFilePos) { 0 }, + "location unknown"); + break; + } + } + + *pcode = code; +} + COMPILE_FUNC(expression, AstTyped* expr) { bh_arr(WasmInstruction) code = *pcode; @@ -1371,57 +1452,7 @@ COMPILE_FUNC(expression, AstTyped* expr) { case Ast_Kind_Address_Of: { AstAddressOf* aof = (AstAddressOf *) expr; - - switch (aof->expr->kind) { - case Ast_Kind_Local: { - u64 offset = 0; - compile_local_location(mod, &code, (AstLocal *) aof->expr, &offset); - if (offset != 0) { - WID(WI_I32_CONST, offset); - WI(WI_I32_ADD); - } - break; - } - - case Ast_Kind_Dereference: { - compile_expression(mod, &code, ((AstDereference *) aof->expr)->expr); - break; - } - - case Ast_Kind_Array_Access: { - AstArrayAccess* aa = (AstArrayAccess *) aof->expr; - u64 offset = 0; - compile_array_access_location(mod, &code, aa, &offset); - if (offset != 0) { - WID(WI_I32_CONST, offset); - WI(WI_I32_ADD); - } - break; - } - - case Ast_Kind_Field_Access: { - AstFieldAccess* field = (AstFieldAccess *) aof->expr; - u64 offset = 0; - compile_field_access_location(mod, &code, field, &offset); - if (offset != 0) { - WID(WI_I32_CONST, offset); - WI(WI_I32_ADD); - } - break; - } - - case Ast_Kind_Memres: { - AstMemRes* memres = (AstMemRes *) aof->expr; - WID(WI_I32_CONST, memres->addr); - break; - } - - default: - onyx_message_add(Msg_Type_Literal, - aof->token->pos, - "unsupported address of"); - } - + compile_location(mod, &code, aof->expr); break; } @@ -1478,6 +1509,25 @@ COMPILE_FUNC(expression, AstTyped* expr) { break; } + case Ast_Kind_Slice: { + AstSlice* sl = (AstSlice *) expr; + + u64 tmp_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + + compile_expression(mod, &code, sl->lo); + WIL(WI_LOCAL_TEE, tmp_local); + WID(WI_I32_CONST, sl->elem_size); + WI(WI_I32_MUL); + compile_location(mod, &code, sl->addr); + WI(WI_I32_ADD); + compile_expression(mod, &code, sl->hi); + WIL(WI_LOCAL_GET, tmp_local); + WI(WI_I32_SUB); + + local_raw_free(mod->local_alloc, tmp_local); + break; + } + case Ast_Kind_Size_Of: { AstSizeOf* so = (AstSizeOf *) expr; WID(WI_I32_CONST, so->size);