From: Brendan Hansen Date: Sun, 16 Aug 2020 20:28:42 +0000 (-0500) Subject: added basic struct literals; code cleanup X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=63ee39d26b6b200571ad8c89d2d31f34e4e9489f;p=onyx.git added basic struct literals; code cleanup --- diff --git a/core/test.onyx b/core/test.onyx new file mode 100644 index 00000000..07b11f28 --- /dev/null +++ b/core/test.onyx @@ -0,0 +1,6 @@ +package core + +Buffer :: struct { + length: u32; + data: rawptr; +} \ No newline at end of file diff --git a/docs/plan b/docs/plan index d35ece7a..c113975b 100644 --- a/docs/plan +++ b/docs/plan @@ -172,15 +172,26 @@ HOW: [ ] Struct literals + [ ] #union on structs + + [ ] #align on structs + [ ] 'use' enums and packages at an arbitrary scope + [ ] Array literals + + [ ] Top level variable initialization + - Works for numeric literals + [ ] multiple lvals and compound assignment a := 2 b := 5 a, b = b, a; - + [ ] All code paths return correct value + [ ] Type parameterized structs + [ ] Add slices - Arrays without a size - Converted to a struct that looks like: @@ -205,13 +216,6 @@ HOW: [ ] returning structs - This will put forward a lot of the work that will be done for multiple return values - [ ] Type parameterized structs - - [ ] Array literals - - [ ] Top level variable initialization - - Works for numeric literals - [X] Start work on evaluating compile time known values. - An expression marked COMPTIME will be reduced to its value in the parse tree. diff --git a/include/bh.h b/include/bh.h index da64fb1e..6ae5e58b 100644 --- a/include/bh.h +++ b/include/bh.h @@ -166,7 +166,7 @@ u8* double_to_ieee754(f64 f, b32 reverse); #define BH_BIT(x) (1 << (x)) #define BH_MASK_SET(var, set, mask) ((set) ? (var) |= (mask) : (var) &= ~(mask)) -#define fori(var, lo, hi) for (i64 var = (lo); var <= (hi); var++) +#define fori(var, lo, hi) for (i64 var = (lo); var < (hi); var++) #define forll(T, var, start, step) for (T* var = (start); var != NULL; var = var->step) #ifdef BH_DEBUG @@ -2142,7 +2142,7 @@ void bh_imap_init(bh_imap* imap, bh_allocator alloc, i32 hash_count) { bh_arr_new(alloc, imap->hashes, hash_count); bh_arr_new(alloc, imap->entries, 4); - fori(count, 0, hash_count - 1) bh_arr_push(imap->hashes, -1); + fori(count, 0, hash_count) bh_arr_push(imap->hashes, -1); } void bh_imap_free(bh_imap* imap) { diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index fa2af347..4334b4b4 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -23,6 +23,7 @@ typedef struct AstFieldAccess AstFieldAccess; typedef struct AstSizeOf AstSizeOf; typedef struct AstAlignOf AstAlignOf; typedef struct AstFileContents AstFileContents; +typedef struct AstStructLiteral AstStructLiteral; typedef struct AstReturn AstReturn; typedef struct AstBreak AstBreak; @@ -40,7 +41,6 @@ typedef struct AstPointerType AstPointerType; typedef struct AstFunctionType AstFunctionType; typedef struct AstArrayType AstArrayType; typedef struct AstStructType AstStructType; -typedef struct AstStructMember AstStructMember; typedef struct AstEnumType AstEnumType; typedef struct AstEnumValue AstEnumValue; typedef struct AstTypeAlias AstTypeAlias; @@ -116,6 +116,7 @@ typedef enum AstKind { Ast_Kind_Size_Of, Ast_Kind_Align_Of, Ast_Kind_File_Contents, + Ast_Kind_Struct_Literal, Ast_Kind_If, Ast_Kind_For, @@ -281,6 +282,7 @@ 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 AstFileContents { AstTyped_base; OnyxToken *filename; }; +struct AstStructLiteral { AstTyped_base; AstTyped *stnode; bh_arr(AstTyped *) values; }; // Intruction Node struct AstReturn { AstNode_base; AstTyped* expr; }; @@ -328,14 +330,13 @@ struct AstArrayType { AstType_base; AstType* elem; AstTyped *count_expr; }; struct AstStructType { AstType_base; - bh_arr(AstStructMember *) members; + bh_arr(AstTyped *) members; // NOTE: Used to cache the actual type, since building // a struct type is kind of complicated and should // only happen once. Type *stcache; }; -struct AstStructMember { AstTyped_base; u64 offset; }; struct AstEnumType { AstType_base; Scope *scope; diff --git a/onyx b/onyx index c33f8752..dbe7cd69 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/stack_based.onyx b/progs/stack_based.onyx index b9d80080..c85c1610 100644 --- a/progs/stack_based.onyx +++ b/progs/stack_based.onyx @@ -4,9 +4,11 @@ package main #include_file "printing" #include_file "alloc" +#include_file "test" use package printing use package memory +use package core as core sort :: proc (arr: [N]i32, cmp: proc (i32, i32) -> i32) -> [N] i32 { for i: 0, N { @@ -50,8 +52,8 @@ Vec3 :: struct { z: i32; } -mag_squared :: proc (v: Vec3) -> i32 { - return v.x * v.x + v.y * v.y + v.z * v.z; +mag_squared :: proc (use v: Vec3) -> i32 { + return x * x + y * y + z * z; } vec_add :: proc (v: Vec3, u: Vec3, use out: ^Vec3) { @@ -72,12 +74,12 @@ clamp :: proc (v: i32, lo: i32, hi: i32) -> i32 { // // This is intended behavior since creating new // procs at runtime is very difficult with WASM -stupid_idea :: proc (n: i32) -> proc () -> i32 { +stupid_idea :: proc (n: i32) -> proc (i32) -> i32 { if n == 1234 { - return proc -> i32 { return 5678; }; + return proc (a: i32) -> i32 { return 5678 + a; }; } - return proc -> i32 { return -1; }; + return proc (a: i32) -> i32 { return -1 + a; }; } some_value := 20 + 30 * 4 + 15 / 5; @@ -129,36 +131,32 @@ start :: proc #export { for i: 0, N do something[i] = N - i; for i: 0, N do print(something[i]); - val := something + something |> sort(proc (a: i32, b: i32) -> i32 { return a - b; }) |> sumN() - |> clamp(30, 100); - print(val); + |> clamp(30, 100) + |> print(); for i: 0, N do something[i] |> clamp(3, 6) |> print(); - stupid_idea(1234)() |> print(); + stupid_idea(1234)(1234) |> print(); varr : [5] Vec3; - varr[2].x = 4; - varr[2].y = 5; - varr[2].z = 6; - mag_squared(varr[2]) |> print(); + varr[2] = Vec3 .{4, 5, 6}; - v1 : Vec3; - v1.x = 1; - v1.y = 2; - v1.z = 4; + mag_squared(varr[2]) |> print(); - v2 := v1; + v1 := Vec3 .{ 1, 2, 4 }; + v2 := *vadd(Vec3.{4, 3, 2}, Vec3.{1, 1, 1}); + + print(v2.x); + print(v2.y); + print(v2.z); - v3 := *vadd(v1, v2); - print(v3.x); - print(v3.y); - print(v3.z); + buf := core.Buffer.{ 16, null }; } vadd :: proc (v1: Vec3, v2: Vec3) -> ^Vec3 { diff --git a/src/onyx.c b/src/onyx.c index 51c9a03c..9608963a 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -60,7 +60,7 @@ static OnyxCompileOptions compile_opts_parse(bh_allocator alloc, int argc, char // NOTE: Add the current folder bh_arr_push(options.included_folders, "."); - fori(i, 1, argc - 1) { + fori(i, 1, argc) { if (!strcmp(argv[i], "-help")) { options.action = ONYX_COMPILE_ACTION_PRINT_HELP; break; @@ -160,10 +160,10 @@ static void compiler_state_free(CompilerState* cs) { static char* lookup_included_file(CompilerState* cs, OnyxToken* filename) { static char path[256]; - fori (i, 0, 255) path[i] = 0; + fori (i, 0, 256) path[i] = 0; static char fn[128]; - fori (i, 0, 127) fn[i] = 0; + fori (i, 0, 128) fn[i] = 0; token_toggle_end(filename); if (!bh_str_ends_with(filename->text, ".onyx")) { bh_snprintf(fn, 128, "%s.onyx", filename->text); diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 68f21b10..ed4e045e 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -15,6 +15,7 @@ CHECK(for, AstFor* fornode); CHECK(call, AstCall* call); CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok); CHECK(unaryop, AstUnaryOp** punop); +CHECK(struct_literal, AstStructLiteral* sl); CHECK(expression, AstTyped** expr); CHECK(address_of, AstAddressOf* aof); CHECK(dereference, AstDereference* deref); @@ -630,6 +631,37 @@ CHECK(unaryop, AstUnaryOp** punop) { return 0; } +CHECK(struct_literal, AstStructLiteral* sl) { + fill_in_type((AstTyped *) sl); + + TypeStruct* st = &sl->type->Struct; + if (st->mem_count != bh_arr_length(sl->values)) { + onyx_message_add(Msg_Type_Literal, + sl->token->pos, + "incorrect number of initial values for this type"); + return 1; + } + + AstTyped** actual = sl->values; + StructMember** formal = st->memarr; + + fori (i, 0, st->mem_count) { + if (check_expression(actual)) return 1; + + if (!types_are_compatible((*formal)->type, (*actual)->type)) { + onyx_message_add(Msg_Type_Assignment_Mismatch, + (*actual)->token->pos, + type_get_name((*formal)->type), + type_get_name((*actual)->type)); + return 1; + } + + actual++, formal++; + } + + return 0; +} + CHECK(address_of, AstAddressOf* aof) { if (check_expression(&aof->expr)) return 1; @@ -813,6 +845,10 @@ CHECK(expression, AstTyped** pexpr) { assert(expr->type != NULL); break; + case Ast_Kind_Struct_Literal: + retval = check_struct_literal((AstStructLiteral *) expr); + break; + case Ast_Kind_Function: expr->flags |= Ast_Flag_Function_Used; break; @@ -951,7 +987,7 @@ CHECK(struct, AstStructType* s_node) { return 1; } - bh_arr_each(AstStructMember *, member, s_node->members) { + bh_arr_each(AstTyped *, member, s_node->members) { token_toggle_end((*member)->token); if (bh_table_has(i32, mem_set, (*member)->token->text)) { diff --git a/src/onyxparser.c b/src/onyxparser.c index 3187a492..39763fac 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -6,6 +6,14 @@ // NOTE: The one weird define you need to know before read the code below #define make_node(nclass, kind) onyx_ast_node_new(parser->allocator, sizeof(nclass), kind) +#define STORE_PARSER_STATE \ + OnyxToken* __parser_curr = parser->curr; \ + OnyxToken* __parser_prev = parser->prev; + +#define RESTORE_PARSER_STATE \ + parser->curr = __parser_curr; \ + parser->prev = __parser_prev; + static AstNode error_node = { Ast_Kind_Error, 0, NULL, NULL }; // NOTE: Forward declarations @@ -16,12 +24,13 @@ static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type); static AstNumLit* parse_int_literal(OnyxParser* parser); static AstNumLit* parse_float_literal(OnyxParser* parser); +static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret); static AstTyped* parse_factor(OnyxParser* parser); static AstTyped* parse_expression(OnyxParser* parser); static AstIf* parse_if_stmt(OnyxParser* parser); static AstWhile* parse_while_stmt(OnyxParser* parser); static AstFor* parse_for_stmt(OnyxParser* parser); -static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret); +static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret); static AstReturn* parse_return_statement(OnyxParser* parser); static AstBlock* parse_block(OnyxParser* parser); static AstNode* parse_statement(OnyxParser* parser); @@ -86,6 +95,19 @@ static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type) { return token; } +static OnyxToken* soft_expect_token(OnyxParser* parser, TokenType token_type) { + if (parser->hit_unexpected_token) return NULL; + + OnyxToken* token = parser->curr; + + if (token->type == token_type) { + consume_token(parser); + return token; + } + + return NULL; +} + static void add_node_to_process(OnyxParser* parser, AstNode* node) { bh_arr_push(parser->results.nodes_to_process, ((NodeToProcess) { .package = parser->package, @@ -141,6 +163,70 @@ static AstNumLit* parse_float_literal(OnyxParser* parser) { return float_node; } +static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret) { + if (parser->curr->type != Token_Type_Symbol) return 0; + + STORE_PARSER_STATE; + + OnyxToken *symbol1 = NULL, *symbol2 = NULL; + symbol1 = expect_token(parser, Token_Type_Symbol); + + if (!soft_expect_token(parser, '.')) { + RESTORE_PARSER_STATE; + return 0; + } + + if (parser->curr->type == Token_Type_Symbol) { + symbol2 = soft_expect_token(parser, Token_Type_Symbol); + + if (!soft_expect_token(parser, '.')) { + RESTORE_PARSER_STATE; + return 0; + } + } + + if (parser->curr->type != '{') { + RESTORE_PARSER_STATE; + return 0; + } + + AstStructLiteral* sl = make_node(AstStructLiteral, Ast_Kind_Struct_Literal); + sl->token = parser->curr; + bh_arr_new(global_heap_allocator, sl->values, 4); + + if (symbol2 != NULL) { + AstTyped *package = make_node(AstTyped, Ast_Kind_Symbol); + package->token = symbol1; + + AstFieldAccess *fa = make_node(AstFieldAccess, Ast_Kind_Field_Access); + fa->token = symbol2; + fa->expr = package; + + sl->stnode = (AstTyped *) fa; + + } else { + sl->stnode = make_node(AstTyped, Ast_Kind_Symbol); + sl->stnode->token = symbol1; + } + + expect_token(parser, '{'); + while (parser->curr->type != '}') { + if (parser->hit_unexpected_token) break; + + AstTyped *expr = parse_expression(parser); + bh_arr_push(sl->values, expr); + + if (parser->curr->type != '}') + expect_token(parser, ','); + } + + expect_token(parser, '}'); + + *ret = (AstTyped *) sl; + + return 1; +} + // ( ) // - // ! @@ -235,6 +321,8 @@ static AstTyped* parse_factor(OnyxParser* parser) { } case Token_Type_Symbol: { + if (parse_possible_struct_literal(parser, &retval)) return retval; + OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol); AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol); sym_node->token = sym_token; @@ -678,7 +766,7 @@ static AstFor* parse_for_stmt(OnyxParser* parser) { // : : // := // :: -static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret) { +static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret) { if (parser->curr->type != Token_Type_Symbol) return 0; if ((parser->curr + 1)->type != ':') return 0; @@ -772,7 +860,7 @@ static AstNode* parse_statement(OnyxParser* parser) { break; case Token_Type_Symbol: - if (parse_symbol_declaration(parser, &retval)) break; + if (parse_possible_symbol_declaration(parser, &retval)) break; // fallthrough case '(': @@ -969,7 +1057,7 @@ static AstType* parse_type(OnyxParser* parser) { new->return_type = return_type; if (param_count > 0) - fori (i, 0, param_count - 1) new->params[i] = params[i]; + fori (i, 0, param_count) new->params[i] = params[i]; *next_insertion = (AstType *) new; next_insertion = NULL; @@ -1026,8 +1114,7 @@ static AstStructType* parse_struct(OnyxParser* parser) { while (parser->curr->type != '}') { if (parser->hit_unexpected_token) return s_node; - AstStructMember* mem = make_node(AstStructMember, Ast_Kind_Struct_Member); - mem->offset = 0; + AstTyped* mem = make_node(AstTyped, Ast_Kind_Struct_Member); mem->token = expect_token(parser, Token_Type_Symbol); expect_token(parser, ':'); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 34573b4c..40ad2738 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -78,7 +78,7 @@ static AstType* symres_type(AstType* type) { ftype->return_type = symres_type(ftype->return_type); if (ftype->param_count > 0) - fori (i, 0, ftype->param_count - 1) { + fori (i, 0, ftype->param_count) { ftype->params[i] = symres_type(ftype->params[i]); } @@ -91,7 +91,7 @@ static AstType* symres_type(AstType* type) { s_node->flags |= Ast_Flag_Type_Is_Resolved; - bh_arr_each(AstStructMember *, member, s_node->members) { + bh_arr_each(AstTyped *, member, s_node->members) { (*member)->type_node = symres_type((*member)->type_node); } @@ -203,6 +203,22 @@ static void symres_unaryop(AstUnaryOp** unaryop) { (*unaryop)->type_node = ((AstUnaryOp *)(*unaryop))->expr->type_node; } +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) { + 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; + + bh_arr_each(AstTyped *, expr, sl->values) symres_expression(expr); +} + static void symres_expression(AstTyped** expr) { switch ((*expr)->kind) { case Ast_Kind_Symbol: @@ -213,7 +229,8 @@ static void symres_expression(AstTyped** expr) { symres_expression(&((AstBinaryOp *)(*expr))->left); symres_expression(&((AstBinaryOp *)(*expr))->right); - (*expr)->type_node = ((AstBinaryOp *)(*expr))->left->type_node; + if (((AstBinaryOp *) (*expr))->left) + (*expr)->type_node = ((AstBinaryOp *)(*expr))->left->type_node; break; case Ast_Kind_Unary_Op: symres_unaryop((AstUnaryOp **) expr); break; @@ -237,6 +254,10 @@ static void symres_expression(AstTyped** expr) { symres_expression(&((AstArrayAccess *)(*expr))->expr); break; + case Ast_Kind_Struct_Literal: + symres_struct_literal((AstStructLiteral *)(*expr)); + break; + default: break; } } @@ -335,6 +356,8 @@ static void symres_function(AstFunction* func) { param->type_node = symres_type(param->type_node); param->type = type_build_from_ast(semstate.allocator, param->type_node); + if (param->type == NULL) break; + symbol_introduce(semstate.curr_scope, param->token, (AstNode *) param); if (param->flags & Ast_Flag_Param_Use) { @@ -346,7 +369,7 @@ static void symres_function(AstFunction* func) { st = (AstStructType *) ((AstPointerType *) param->type_node)->elem; } - bh_arr_each(AstStructMember *, mem, st->members) { + bh_arr_each(AstTyped *, mem, st->members) { AstFieldAccess* fa = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access); fa->token = (*mem)->token; fa->type_node = (*mem)->type_node; diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 34f6c5ee..f683b292 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -138,8 +138,6 @@ b32 types_are_compatible(Type* t1, Type* t2) { case Type_Kind_Struct: { if (t2->kind != Type_Kind_Struct) return 0; if (t1->Struct.mem_count != t2->Struct.mem_count) return 0; - if (t1->Struct.name && t2->Struct.name) - if (strcmp(t1->Struct.name, t2->Struct.name) == 0) return 1; b32 works = 1; bh_table_each_start(StructMember, t1->Struct.members); @@ -169,7 +167,7 @@ b32 types_are_compatible(Type* t1, Type* t2) { if (!types_are_compatible(t1->Function.return_type, t2->Function.return_type)) return 0; if (t1->Function.param_count > 0) { - fori (i, 0, t1->Function.param_count - 1) { + fori (i, 0, t1->Function.param_count) { if (!types_are_compatible(t1->Function.params[i], t2->Function.params[i])) return 0; } } @@ -232,7 +230,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { func_type->Function.return_type = type_build_from_ast(alloc, ftype_node->return_type); if (param_count > 0) - fori (i, 0, param_count - 1) { + fori (i, 0, param_count) { func_type->Function.params[i] = type_build_from_ast(alloc, ftype_node->params[i]); } @@ -283,7 +281,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { u32 offset = 0; u32 alignment = 1, mem_alignment; u32 idx = 0; - bh_arr_each(AstStructMember *, member, s_node->members) { + bh_arr_each(AstTyped *, member, s_node->members) { (*member)->type = type_build_from_ast(alloc, (*member)->type_node); // TODO: Add alignment checking here @@ -301,13 +299,21 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { token_toggle_end((*member)->token); bh_table_put(StructMember, s_type->Struct.members, (*member)->token->text, smem); - bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, (*member)->token->text)); token_toggle_end((*member)->token); offset += type_size_of((*member)->type); idx++; } + // NOTE: Need to do a second pass because the references to the + // elements of the table may change if the internal arrays of the + // table need to be resized. + bh_arr_each(AstTyped *, member, s_node->members) { + token_toggle_end((*member)->token); + bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, (*member)->token->text)); + token_toggle_end((*member)->token); + } + s_type->Struct.aligment = alignment; if (offset % alignment != 0) { diff --git a/src/onyxwasm.c b/src/onyxwasm.c index c9ffe689..fe1de9d3 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -364,6 +364,7 @@ COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return) COMPILE_FUNC(memory_reservation_location, AstMemRes* memres); COMPILE_FUNC(struct_load, Type* type, u64 offset); COMPILE_FUNC(struct_store, AstTyped* lval); +COMPILE_FUNC(struct_literal, AstStructLiteral* sl); COMPILE_FUNC(expression, AstTyped* expr); COMPILE_FUNC(cast, AstUnaryOp* cast); COMPILE_FUNC(return, AstReturn* ret); @@ -1151,6 +1152,16 @@ COMPILE_FUNC(struct_store, AstTyped* lval) { *pcode = code; } +COMPILE_FUNC(struct_literal, AstStructLiteral* sl) { + bh_arr(WasmInstruction) code = *pcode; + + bh_arr_each(AstTyped *, val, sl->values) { + compile_expression(mod, &code, *val); + } + + *pcode = code; +} + COMPILE_FUNC(expression, AstTyped* expr) { bh_arr(WasmInstruction) code = *pcode; @@ -1221,6 +1232,11 @@ COMPILE_FUNC(expression, AstTyped* expr) { break; } + case Ast_Kind_Struct_Literal: { + compile_struct_literal(mod, &code, (AstStructLiteral *) expr); + break; + } + case Ast_Kind_Function: { i32 elemidx = get_element_idx(mod, (AstFunction *) expr); WID(WI_I32_CONST, elemidx); @@ -2610,7 +2626,7 @@ static i32 output_datasection(OnyxWasmModule* module, bh_buffer* buff) { leb = uint_to_uleb128((u64) datum->length, &leb_len); bh_buffer_append(&vec_buff, leb, leb_len); - fori (i, 0, datum->length - 1) bh_buffer_write_byte(&vec_buff, ((u8 *) datum->data)[i]); + fori (i, 0, datum->length) bh_buffer_write_byte(&vec_buff, ((u8 *) datum->data)[i]); } leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len);