package builtin
-string :: struct {
- data : ^u8;
- len : u32;
-}
-
+string :: #type []u8;
cstring :: #type ^u8;
\ No newline at end of file
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 {
},
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);
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;
}
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;
}
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;
}
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 {
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 {
// 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
- 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
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;
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;
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,
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,
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; };
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;
TYPE_KIND(Struct, struct { \
char* name; \
u32 size; \
- u16 aligment, mem_count; \
+ u16 alignment, mem_count; \
bh_table(StructMember) members; \
bh_arr(StructMember *) memarr; \
}) \
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);
}
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);
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()
|> 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);
|> 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);
+ }
}
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);
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;
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;
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;
}
}
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) {
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));
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);
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;
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;
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;
}
}
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);
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;
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";
"POINTER_TYPE",
"FUNCTION_TYPE",
"ARRAY TYPE",
+ "SLICE TYPE",
"STRUCT TYPE",
"ENUM TYPE",
"TYPE_ALIAS",
"ADDRESS OF",
"DEREFERENCE",
"ARRAY_ACCESS",
+ "SLICE",
"FIELD_ACCESS",
"UFC",
"SIZE OF",
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);
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;
}
*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;
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;
}
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);