Added slice types; bugfixes
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 24 Aug 2020 17:11:12 +0000 (12:11 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 24 Aug 2020 17:11:12 +0000 (12:11 -0500)
13 files changed:
core/builtin.onyx
core/string.onyx
docs/plan
include/onyxastnodes.h
include/onyxtypes.h
onyx
progs/wasi_test.onyx
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index 18788c3744cdf0ceb14a816491f1617be5a46b1e..ebac598566db61ed461aebfa5d60ba75c27f555b 100644 (file)
@@ -1,8 +1,4 @@
 package builtin
 
-string :: struct {
-       data : ^u8;
-       len  : u32;
-}
-
+string  :: #type []u8;
 cstring :: #type ^u8;
\ No newline at end of file
index c3b41433ecd7f586451cb6b891fe050f9a4db391..ebfbfaaabc4dbbd6c31a377a50d99cc21a8ecee4 100644 (file)
@@ -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 {
index 0a230bab7f4d4c31231c8307b77e89b57893c924..b34d368c3eb7a6cda6e7fc97eee198cefc5d9133 100644 (file)
--- 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
index c9814df06f15d90c44e41fd8e81b843b9bb21961..c67803f9aa620a97695e20ecfb836a6f98df19d7 100644 (file)
@@ -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;
 
index 27cd1a9d16954bf10fd8e1ca3b700c399c7763d9..1bfd25a5568ae3c2610387567274f2948ab6ceef 100644 (file)
@@ -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 a8ec773716b9d5449f5a0adfaa03f6b21d7a0e87..429da3352666060f26715b90e66b31f200fb030f 100755 (executable)
Binary files a/onyx and b/onyx differ
index 4e1ff14d7897fdf5f1b75361d095c70da5a448e9..6743d1b4513c93b6503bd31150b1ca84cb5b0bf3 100644 (file)
@@ -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);
+    }
 }
index feace16df03ba6673912bbe6b70e99909d1e1a9f..c93ed3c4dcc51c110565b19beb59dd50b59ed276 100644 (file)
@@ -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;
index bbd2cfa9d01d740d6950bbda7766893a3f0db607..5c1b18c8e8c14b1356925d502b29acb861ddd476 100644 (file)
@@ -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) {
index 603e5a6329aba20daab54860b46e1bddf8652f49..4c88b126511117a2eb5418f8ca111014f77ca016 100644 (file)
@@ -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;
index c921abfe53fe5ca2832bcd05c688ddb74f11decc..602c5dc94e90cda675e680e8e10b1eb016540ca6 100644 (file)
@@ -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";
 
index 8dbacf26efdb1ce7c3ebda474a75e5db5d11b083..3ed98c55f24bed31629637b9af0acc7bddcf1c6a 100644 (file)
@@ -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",
index 3ba6923cf33e51703354d4292bf109eb4aea7a4a..57978683ac9a1ca7665de170b890007bf1bf104c 100644 (file)
@@ -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);