From 9016b9fc533a3b66cbb7b1201ff6abced77aa65a Mon Sep 17 00:00:00 2001 From: IonutParau Date: Sun, 5 Jul 2026 13:35:03 +0200 Subject: [PATCH] fixed a lot of regressions and made strings somewhat functional --- src/compiler.c | 267 ++++++++++++++++++++++++++++++++++--------------- src/compiler.h | 13 +-- src/main.c | 1 + src/vm.c | 10 +- src/vm.h | 4 - 5 files changed, 194 insertions(+), 101 deletions(-) diff --git a/src/compiler.c b/src/compiler.c index 78ed14d..57f6b2e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1,6 +1,7 @@ #include "noom.h" #include "compiler.h" #include "helper.h" +#include // COMPILATION!!!!!!!!!!!!!!!!!!! // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⢲⣞⣭⣟⣿⣻⣷⢶⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ @@ -33,7 +34,8 @@ typedef struct noomC_LocalInfo { enum { NOOMC_GLOBAL, NOOMC_LOCAL, NOOMC_UPVAL } type; - unsigned int idx; + unsigned short idx; + noom_bool_t isConst; } noomC_LocalInfo; noom_Exit noomC_addLocal(noomC_Compiler* c, noomC_Local local) { @@ -48,15 +50,72 @@ noom_Exit noomC_addUpval(noomC_Compiler* c, noomC_Upval upval) { return NOOM_OK; } -int noomC_stealUpval(noomC_Compiler* c, const char* name, noom_uint_t namelen) { +noom_Exit noomC_addconst(noomV_Function* func, noomV_Value val) { + if (func->constsize == NOOM_USHORT_MAX) return NOOM_PLEASEHELPMEIAMSCARED; + noomV_Value* newConsts = noom_realloc(func->consts, sizeof(noomV_Value) * (func->constsize + 1)); + if (newConsts == 0) return NOOM_ENOMEM; + func->consts = newConsts; + func->consts[func->constsize++] = val; + return NOOM_OK; +} + +noom_Exit noomC_addconst_str(noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len, noom_uint_t *outIdx) { + noomV_Function *f = c->target; + for(int i = 0; i < f->constsize; i++) { + noomV_Value v = f->consts[i]; + if (v.tag != NOOMV_VOBJ) continue; + noomV_Object* o = v.obj; + if (o->tag != NOOMV_OSTR) continue; + noomV_String* s = (noomV_String*)o; + if (noom_memeq(s->data, s->len, str, len)) { + *outIdx = i; + return NOOM_OK; + } + } + noomV_String* s = 0; + { + noomC_Compiler *cp = c; + while(cp) { + for(int i = 0; i < f->constsize; i++) { + noomV_Value v = f->consts[i]; + if (v.tag != NOOMV_VOBJ) continue; + noomV_Object* o = v.obj; + if (o->tag != NOOMV_OSTR) continue; + noomV_String* os = (noomV_String*)o; + if (noom_memeq(os->data, os->len, str, len)) { + s = os; + goto found; + } + } + cp = cp->parent; + } + } + s = noomV_allocStr(vm, str, len); + if (s == 0) return NOOM_ENOMEM; +found: + *outIdx = c->target->constsize; + return noomC_addconst(c->target, (noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object*)s}); +} + +noom_Exit noomC_stealUpval(noomC_Compiler* c, const char* name, noom_uint_t namelen, noomC_LocalInfo *local) { // hold on hold on hold on but what if... for (unsigned i = 0; i < c->upvalc; i++) { const noomC_Upval u = c->upvals[i]; - if (noom_memeq(u.name, u.namelen, name, namelen)) return (int)i; + if (noom_memeq(u.name, u.namelen, name, namelen)) { + local->type = NOOMC_UPVAL; + local->idx = i; + local->isConst = u.constant; + return NOOM_OK; + } } // damn it - if (c->parent == 0) return -1; + if (c->parent == 0) { + // signal that this is not found + local->type = NOOMC_GLOBAL; + local->isConst = 0; + return NOOM_OK; + } // maybe you have smth useful for (int i = (int)c->parent->localc - 1; i >= 0; i--) { @@ -64,58 +123,79 @@ int noomC_stealUpval(noomC_Compiler* c, const char* name, noom_uint_t namelen) { if (l.dropped) continue; if (noom_memeq(l.name, l.namelen, name, namelen)) { // yay!!!! wahoo!!!! yippee!!!!!!!!!!! - if (c->upvalc == NOOMC_MAXUPVAL) return -1; noomC_Upval upval; upval.name = name; upval.namelen = namelen; upval.slot = (unsigned short)l.stackslot; - upval.stolen = 0; + upval.isParentUpvalue = 0; upval.constant = l.constant; - const unsigned idx = c->upvalc; - c->upvals[c->upvalc++] = upval; - return (int)idx; + local->type = NOOMC_UPVAL; + local->idx = c->upvalc; + local->isConst = upval.constant; + return noomC_addUpval(c, upval); } } - const int parent_upval = noomC_stealUpval(c->parent, name, namelen); - if (parent_upval >= 0) { - if (c->upvalc == NOOMC_MAXUPVAL) return -1; - noomC_Upval upval; - upval.name = name; - upval.namelen = namelen; - upval.slot = (unsigned short)parent_upval; - upval.stolen = 1; - upval.constant = c->parent->upvals[parent_upval].constant; - const unsigned idx = c->upvalc; - c->upvals[c->upvalc++] = upval; - return (int)idx; + noomC_LocalInfo parentUpval; + noom_Exit e = noomC_stealUpval(c->parent, name, namelen, &parentUpval); + if(e) return e; + if(parentUpval.type == NOOMC_GLOBAL) { + // not found + *local = parentUpval; + return NOOM_OK; } - - return -1; + noomC_Upval upval; + upval.name = name; + upval.namelen = namelen; + upval.slot = parentUpval.idx; + upval.isParentUpvalue = 1; + upval.constant = parentUpval.isConst; + local->type = NOOMC_UPVAL; + local->idx = c->upvalc; + local->isConst = upval.constant; + return noomC_addUpval(c, upval); } -static noomC_LocalInfo noomC_identifyLocal(noomC_Compiler* compiler, const char* name, noom_uint_t namelen) { +static noom_Exit noomC_identifyLocal(noomC_Compiler* compiler, const char* name, noom_uint_t namelen, noomC_LocalInfo *info) { for (int i = compiler->localc - 1; i >= 0; i--) { const noomC_Local l = compiler->locals[i]; if (l.dropped) continue; if (noom_memeq(l.name, l.namelen, name, namelen)) { - return (noomC_LocalInfo){ .type = NOOMC_LOCAL, .idx = l.stackslot }; + info->type = NOOMC_LOCAL; + info->idx = l.stackslot; + info->isConst = l.constant; + return NOOM_OK; } } - const int upval_idx = noomC_stealUpval(compiler, name, namelen); - if (upval_idx >= 0) { - return (noomC_LocalInfo){ .type = NOOMC_UPVAL, .idx = (unsigned)upval_idx }; - } - - return (noomC_LocalInfo){ .type = NOOMC_GLOBAL }; + return noomC_stealUpval(compiler, name, namelen, info); } -static noom_Exit noomC_identifyLocalAndSet(noomC_Compiler* compiler, const char* name, noom_uint_t namelen) { - const noomC_LocalInfo info = noomC_identifyLocal(compiler, name, namelen); +static noom_Exit noomC_identifyLocalAndSet(noomC_Compiler* compiler, noom_LuaVM *vm, const char* name, noom_uint_t namelen) { + // TODO: burn this with fire + noomC_LocalInfo info; + noom_Exit e = noomC_identifyLocal(compiler, name, namelen, &info); + if(e) return e; if (info.type == NOOMC_LOCAL) return noomC_emit_AuD(compiler->target, NOOMV_INSTR_SETVAL, compiler->curstack++, (unsigned short)info.idx); if (info.type == NOOMC_UPVAL) return noomC_emit_AuD(compiler->target, NOOMV_INSTR_SETUPVAL, compiler->curstack++, (unsigned short)info.idx); - if (info.type == NOOMC_GLOBAL) return noomC_emit_AuD(compiler->target, NOOMV_INSTR_SETGLOBAL, compiler->curstack++, (unsigned short)info.idx); + noom_uint_t fieldIdx; + e = noomC_addconst_str(compiler, vm, name, namelen, &fieldIdx); + if(e) return e; + if (info.type == NOOMC_GLOBAL) { + if(vm->version > NOOM_VERSION_51) { + noomC_LocalInfo _ENV; + e = noomC_identifyLocal(compiler, "_ENV", 4, &_ENV); + if(e) return e; + if(_ENV.type == NOOMC_GLOBAL) return NOOM_EINTERNAL; + if(_ENV.type == NOOMC_UPVAL) { + return noomC_emit_AuD(compiler->target, NOOMV_INSTR_SETGLOBAL, compiler->curstack++, fieldIdx); + } + // TODO: impl this bullshit + return NOOM_EINTERNAL; + } + return noomC_emit_AuD(compiler->target, NOOMV_INSTR_SETGLOBAL, compiler->curstack++, fieldIdx); + } + return NOOM_EINTERNAL; } void noomC_compiler_init(noomC_Compiler* compiler) { @@ -125,6 +205,13 @@ void noomC_compiler_init(noomC_Compiler* compiler) { compiler->localc = 0; compiler->upvalc = 0; compiler->curstack = 0; + + compiler->stringTmpBuf = 0; + compiler->maxStringLen = 0; +} + +void noomC_compiler_deinit(noomC_Compiler* compiler) { + noom_free(compiler->stringTmpBuf); } noom_Exit noomC_emit(noomV_Function* func, noomV_Inst inst) { @@ -135,36 +222,6 @@ noom_Exit noomC_emit(noomV_Function* func, noomV_Inst inst) { return NOOM_OK; } -noom_Exit noomC_addconst(noomV_Function* func, noomV_Value val) { - if (func->constsize == NOOM_USHORT_MAX) return NOOM_PLEASEHELPMEIAMSCARED; - noomV_Value* newConsts = noom_realloc(func->consts, sizeof(noomV_Value) * (func->constsize + 1)); - if (newConsts == 0) return NOOM_ENOMEM; - func->consts = newConsts; - func->consts[func->constsize++] = val; - return NOOM_OK; -} - -noomV_String* noomC_internString(const noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len) { - while (c) { - const noomV_Function* f = c->target; - for (int i = 0; i < f->constsize; i++) { - const noomV_Value v = f->consts[i]; - if (v.tag != NOOMV_VOBJ) continue; - noomV_Object* o = v.obj; - if (o->tag != NOOMV_OSTR) continue; - noomV_String* s = (noomV_String*)o; - if (noom_memeq(s->data, s->len, str, len)) return s; - } - c = c->parent; - } - return noomV_allocStr(vm, str, len); -} - -noom_Exit noomC_addconst_str(noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len) { - noomV_String* s = noomC_internString(c, vm, str, len); - if (s == 0) return NOOM_ENOMEM; - return noomC_addconst(c->target, (noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object*)s}); -} noom_BinOp noomC_lex_bin_op(const noomP_Parser* parser, noom_uint_t offset) { const char* op = parser->code + offset; @@ -205,10 +262,20 @@ noom_UnaryOp noomC_lex_un_op(const noomP_Parser* parser, noom_uint_t offset) { return 0; } -static const char* noomC_decode_string_token(const char* s, noom_LuaVersion how_the_fuck, noom_uint_t* outlen) { +static const char* noomC_decode_string_token(noomC_Compiler *c, const char* s, noom_uint_t tokenlen, noom_LuaVersion how_the_fuck, noom_uint_t* outlen) { + // token is bigger than contents, so if we can't even fit token, we def can't fit contents + if(c->maxStringLen < tokenlen) { + char *s = noom_realloc(c->stringTmpBuf, tokenlen); + if(s == 0) return 0; + c->stringTmpBuf = s; + c->maxStringLen = tokenlen; + } + // really not good for now + noom_memcpy(c->stringTmpBuf, s + 1, tokenlen - 1); + *outlen = tokenlen - 2; // nah fuck it TODO atom pls save me // actually don't i will repair this one day - return s; + return c->stringTmpBuf; } noom_Exit noomC_compile_proto( @@ -300,7 +367,7 @@ noom_Exit noomC_emit_assign_to( if (target->type == NOOMP_NODE_VARIABLE) { const char* varname = parser->code + target->source_offset; noom_uint_t namelen = noomL_tokenlen(varname, 0, parser->version); - return noomC_identifyLocalAndSet(compiler, varname, namelen); + return noomC_identifyLocalAndSet(compiler, vm, varname, namelen); } if (target->type == NOOMP_NODE_GETFIELD) { @@ -354,10 +421,11 @@ noom_Exit noomC_compile_expr( } if (node->type == NOOMP_NODE_STRINGLITERAL) { - const unsigned short const_idx = func->constsize; + noom_uint_t const_idx; noom_uint_t len; - const char* sptr = noomC_decode_string_token(parser->code + node->source_offset, parser->version, &len); - if ((result = noomC_addconst_str(compiler, vm, sptr, len)) != NOOM_OK) return result; + const char* sptr = noomC_decode_string_token(compiler, parser->code + node->source_offset, noomL_tokenlen(parser->code, node->source_offset, parser->version), parser->version, &len); + if(sptr == 0) return NOOM_ENOMEM; + if ((result = noomC_addconst_str(compiler, vm, sptr, len, &const_idx)) != NOOM_OK) return result; compiler->curstack++; return noomC_emit_AuD(func, NOOMV_INSTR_PUSHCONST, 0, const_idx); } @@ -387,9 +455,9 @@ noom_Exit noomC_compile_expr( if (key_node->type == NOOMP_NODE_FIELDNAME) { // string key - const unsigned short constidx = func->constsize; + noom_uint_t constidx; const noom_uint_t length = noomL_tokenlen(parser->code, key_node->source_offset, parser->version); - if ((result = noomC_addconst_str(compiler, vm, parser->code + key_node->source_offset, length))) return result; + if ((result = noomC_addconst_str(compiler, vm, parser->code + key_node->source_offset, length, &constidx))) return result; if ((result = noomC_compile_expr(vm, compiler, parser, func, val_node, 1))) return result; compiler->curstack--; if ((result = noomC_emit_AuD(func, NOOMV_INSTR_SETFIELD, table_slot, constidx))) return result; @@ -466,9 +534,9 @@ noom_Exit noomC_compile_expr( if (node->type == NOOMP_NODE_GETFIELD) { if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result; - noom_uint_t constidx = func->constsize; + noom_uint_t constidx; // dumbass oneliner - if ((result = noomC_addconst_str(compiler, vm, parser->code + node->subnodes[1]->source_offset, noomL_tokenlen(parser->code, node->subnodes[1]->source_offset, parser->version)))) return result; + if ((result = noomC_addconst_str(compiler, vm, parser->code + node->subnodes[1]->source_offset, noomL_tokenlen(parser->code, node->subnodes[1]->source_offset, parser->version), &constidx))) return result; return noomC_emit_AuD(func, NOOMV_INSTR_GETFIELD, 0, (unsigned short)constidx); } @@ -495,8 +563,8 @@ noom_Exit noomC_compile_expr( if (isMethod) { const char* fieldname = parser->code + node->subnodes[1]->source_offset; const noom_uint_t fieldlen = noomL_tokenlen(parser->code, node->subnodes[1]->source_offset, parser->version); - noom_uint_t constidx = func->constsize; - if ((result = noomC_addconst_str(compiler, vm, fieldname, fieldlen))) return result; + noom_uint_t constidx; + if ((result = noomC_addconst_str(compiler, vm, fieldname, fieldlen, &constidx))) return result; compiler->curstack++; // self is pushed alongside the method if ((result = noomC_emit_AuD(func, NOOMV_INSTR_GETMETHOD, funcIdx, (unsigned short)constidx))) return result; } @@ -526,7 +594,38 @@ noom_Exit noomC_compile_expr( if (node->type == NOOMP_NODE_VARIABLE) { const char* varname = parser->code + node->source_offset; noom_uint_t namelen = noomL_tokenlen(varname, 0, parser->version); - return noomC_identifyLocalAndSet(compiler, varname, namelen); + noomC_LocalInfo info; + result = noomC_identifyLocal(compiler, varname, namelen, &info); + if(result) return result; + compiler->curstack++; + + switch (info.type) { + case NOOMC_LOCAL: + return noomC_emit_AuD(func, NOOMV_INSTR_PUSHVAL, 0, info.idx); + case NOOMC_UPVAL: + return noomC_emit_AuD(func, NOOMV_INSTR_PUSHUPVAL, 0, info.idx); + case NOOMC_GLOBAL: { + noom_uint_t constidx; + if((result = noomC_addconst_str(compiler, vm, varname, namelen, &constidx))) return result; + if(parser->version == NOOM_VERSION_51) { + return noomC_emit_AuD(func, NOOMV_INSTR_PUSHGLOBAL, 0, constidx); + } + noomC_LocalInfo _ENV; + if((result = noomC_identifyLocal(compiler, "_ENV", 4, &_ENV))) return result; + // not meant to be possible + if(_ENV.type == NOOMC_GLOBAL) return NOOM_EINTERNAL; + // most likely branch in human history + if(_ENV.type == NOOMC_UPVAL) { + if((result = noomC_emit_AuD(func, NOOMV_INSTR_PUSHUPVAL, _ENV.idx, constidx))) return result; + } else { + // bitchass + if((result = noomC_emit_AuD(func, NOOMV_INSTR_PUSHVAL, 0, _ENV.idx))) return result; + } + return noomC_emit_AuD(func, NOOMV_INSTR_GETFIELD, 0, constidx); + } + } + // forgot a case + return NOOM_EINTERNAL; } if (node->type == NOOMP_NODE_LAMBDAFUNCTIONLITERAL) { @@ -705,6 +804,14 @@ noom_Exit noomC_add_stuff_to_function(noom_LuaVM* vm, noomC_Compiler* compiler, noom_uint_t place_count = 0; while (place_count < node->subnodec && node->subnodes[place_count]->type == NOOMP_NODE_ASSIGNPLACE) place_count++; noom_uint_t value_count = node->subnodec - place_count; + + // subtly wrong execution but also just wrong... order of instructions! + // TODO: burn it with fire + // WHY: assigning instructions fundamentally assume the value is on the top of the stack, + // so this is just bad. Lua also evalutes stuff differently, with f().x = g() calling f before g. + // IF WE WANT TO KEEP THE BROKEN ORDER: we should push all of the values first, then do the assignments in reverse order. + // IF WE WANT TO FIX THE ORDER: we'd need the emit_assign_to output extra information for the 2nd half of the assingment, + // so it can for example call f() and get th return but store how to assign to its result. unsigned char value_base = (unsigned char)compiler->curstack; for (noom_uint_t i = 0; i < value_count; i++) { @@ -884,11 +991,13 @@ noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_ upval.name = "_ENV"; upval.namelen = 4; upval.slot = 0; - upval.stolen = 1; + upval.isParentUpvalue = 1; upval.constant = 0; noomC_addUpval(&compiler, upval); // TODO: we need to wrap the value as a *closure*, with one upvalue, the environment (_ENV). } - return noomC_compile_block(vm, &compiler, parser, program, node); + noom_Exit err = noomC_compile_block(vm, &compiler, parser, program, node); + noomC_compiler_deinit(&compiler); + return err; } diff --git a/src/compiler.h b/src/compiler.h index a5a5972..2f3a092 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -18,7 +18,7 @@ typedef struct noomC_Upval { unsigned int namelen; unsigned short slot; // if stolen, this means that slot is actually an upvalue index - noom_bool_t stolen; + noom_bool_t isParentUpvalue; noom_bool_t constant; } noomC_Upval; @@ -29,6 +29,8 @@ typedef struct noomC_Compiler { // steal constants from this struct noomC_Compiler* parent; noomV_Function* target; + char *stringTmpBuf; + noom_uint_t maxStringLen; unsigned localc; unsigned upvalc; unsigned curstack; @@ -36,19 +38,12 @@ typedef struct noomC_Compiler { noomC_Upval upvals[NOOMC_MAXUPVAL]; } noomC_Compiler; -// TODO: probably many of these don't really need to be exposed to other code but whatever -noom_Exit noomC_addLocal(noomC_Compiler* c, noomC_Local local); -noom_Exit noomC_addUpval(noomC_Compiler* c, noomC_Upval upval); -int noomC_stealUpval(noomC_Compiler* c, const char* name, noom_uint_t namelen); - void noomC_compiler_init(noomC_Compiler* compiler); +void noomC_compiler_deinit(noomC_Compiler* compiler); noom_Exit noomC_emit(noomV_Function* func, noomV_Inst inst); #define noomC_emit_ABC(func, _op, _a, _b, _c) noomC_emit((func), (noomV_Inst){.op = (_op), .a = (_a), .b = (_b), .c = (_c)}) #define noomC_emit_AuD(func, _op, _a, _uD) noomC_emit((func), (noomV_Inst){.op = (_op), .a = (_a), .us = (_uD)}) -noom_Exit noomC_addconst(noomV_Function* func, noomV_Value val); -noomV_String* noomC_internString(const noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len); -noom_Exit noomC_addconst_str(noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len); noom_BinOp noomC_lex_bin_op(const noomP_Parser* parser, noom_uint_t offset); noom_UnaryOp noomC_lex_un_op(const noomP_Parser* parser, noom_uint_t offset); diff --git a/src/main.c b/src/main.c index aa4230d..ebcdd87 100644 --- a/src/main.c +++ b/src/main.c @@ -133,6 +133,7 @@ int execute(const char* code, noom_LuaVersion version, const char* program_name, if (e) { printf("error: %d\n", e); noomP_freeNode(parser.last_node); + noom_destroyVM(vm); return 1; } noomP_freeNode(parser.last_node); diff --git a/src/vm.c b/src/vm.c index 0fcd8e4..12e4a92 100644 --- a/src/vm.c +++ b/src/vm.c @@ -76,14 +76,6 @@ noomV_DisInfo noomV_disInfo[NOOMV_INSTR_NOP2] = { .name = "SETFIELD", .arg = NOOMV_DIS_uD, }, - [NOOMV_INSTR_GETUPFIELD] = { - .name = "GETUPFIELD", - .arg = NOOMV_DIS_uD, - }, - [NOOMV_ISNTR_SETUPFIELD] = { - .name = "SETUPFIELD", - .arg = NOOMV_DIS_uD, - }, [NOOMV_INSTR_OP] = { .name = "OP", @@ -358,7 +350,7 @@ noom_Exit noomV_rawsetTable(noom_LuaVM* vm, noomV_Table* t, noomV_Value key, noo noomV_Value key2 = t->entrydata[idx]; // tombstone, for creation! if(key2.isptr) { - freshTomb = t->entrydata + idx; + if(freshTomb == 0) freshTomb = t->entrydata + idx; idx++; idx %= t->entries; count++; diff --git a/src/vm.h b/src/vm.h index 9078149..615c3d7 100644 --- a/src/vm.h +++ b/src/vm.h @@ -130,10 +130,6 @@ typedef enum noomV_Opcode : unsigned char { NOOMV_INSTR_GETFIELD, // pops (table, value), sets `table[consts[op.uD]] = value`, an optimization for changing fields NOOMV_INSTR_SETFIELD, - // pushes `(*upvals[op.A])[consts[op.uD]]` - NOOMV_INSTR_GETUPFIELD, - // pops [value], sets `(*upvals[op.A])[consts[op.uD]] = value` - NOOMV_ISNTR_SETUPFIELD, // does a unary or binary operation. // if op.a == 1, its a unary operation.