From 9c0a40a336da1dce89f15d8a3bee1e7a4df2524a Mon Sep 17 00:00:00 2001 From: IonutParau Date: Thu, 18 Jun 2026 23:37:28 +0200 Subject: [PATCH] compiler works --- src/compiler.c | 98 ++++++++++++++++++++++++++++---------------------- src/compiler.h | 2 +- src/lexer.h | 5 +++ src/main.c | 40 ++++++++++++++++++++- src/parser.h | 5 +++ src/vm.c | 28 +++++++++++++++ src/vm.h | 27 ++++++++++---- 7 files changed, 155 insertions(+), 50 deletions(-) diff --git a/src/compiler.c b/src/compiler.c index a0d3003..0c0a059 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -72,7 +72,7 @@ void noomC_compiler_init(noomC_Compiler* compiler) { compiler->localc = 0; compiler->upvalc = 0; - compiler->curstack = 0; + compiler->curstack = -1; } static noom_Exit noomC_emit(noomV_Function* func, const noomV_Inst inst) { @@ -167,7 +167,9 @@ static noom_Exit noomC_compile_expr( noomC_Compiler* compiler, const noomP_Parser* parser, noomV_Function* func, - const noomP_Node* node) { + const noomP_Node* node, + // retc of -1 means all values!!!!!!!!!!! + int retc) { noom_Exit result; // Baba is You OST is a very cool soundtrack to code to Can recommend if (node->type == NOOMP_NODE_NILLITERAL) { @@ -190,7 +192,8 @@ static noom_Exit noomC_compile_expr( if (node->type == NOOMP_NODE_STRINGLITERAL) { unsigned char fucking_destination = compiler->curstack++; noom_Exit result = noomC_addconst_str(compiler, vm, "but DID YOU KNOW", 16); - return result; + if(result) return result; + return noomC_emit_Aus(func, NOOMV_INSTR_PUSHCONST, 0, fucking_destination); } if (node->type == NOOMP_NODE_BINARYOPERATOR) { if (node->subnodec != 2) return NOOM_EINTERNAL; @@ -199,7 +202,7 @@ static noom_Exit noomC_compile_expr( // concat is special noom_uint_t amount = 1; const noomP_Node* n = node->subnodes[1]; - if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0]))) return result; + if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result; // we have no flattening so we unwind it ourselves // unlike all left-associative ones, like +, where 1 + 2 + 3 is (1 + 2) + 3, // concat is right-associate, like ^, meaning 1 .. 2 .. 3 is 1 .. (2 .. 3). @@ -208,10 +211,10 @@ static noom_Exit noomC_compile_expr( if (amount > NOOM_USHORT_MAX) return NOOM_EINTERNAL; amount++; if (noom_startswith(parser->code + n->source_offset, "..")) { - if ((result = noomC_compile_expr(vm, compiler, parser, func, n->subnodes[0]))) return result; + if ((result = noomC_compile_expr(vm, compiler, parser, func, n->subnodes[0], 1))) return result; n = n->subnodes[1]; } else { - if ((result = noomC_compile_expr(vm, compiler, parser, func, n))) return result; + if ((result = noomC_compile_expr(vm, compiler, parser, func, n, 1))) return result; break; } } @@ -220,30 +223,31 @@ static noom_Exit noomC_compile_expr( return noomC_emit_Aus(func, NOOMV_INSTR_CONCAT, 0, amount - 1); } - if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0]))) return result; - if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1]))) return result; + if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result; + if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1], 1))) return result; // this consumes 2 operands and pushes 1 value, thus having a net stack effect of removing 1 item compiler->curstack--; return noomC_emit_ABC(func, NOOMV_INSTR_OP, 1, noomC_what_bop_is_this(parser, node->source_offset), 0); } - if (node->type == NOOMP_NODE_CALL) { - unsigned char fucking_destination = compiler->curstack; - // Here we don't fucking increment this fucking destination - // Because the fucking function call fucking increments it fucking anyway - for (int i = 1; i < node->subnodec; i++) { - // push node->subnodes[i] to stack or something + if (node->type == NOOMP_NODE_CALL || node->type == NOOMP_NODE_METHODCALL) { + // welcome to multivalue hell + unsigned char returnToGlory = compiler->curstack; + noom_bool_t isMethod = node->type == NOOMP_NODE_METHODCALL; + if((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result; + unsigned char funcIdx = compiler->curstack; + if(isMethod) { + noomP_Node *field = node->subnodes[1]; + const char *fieldname = parser->code + field->source_offset; + noom_uint_t fieldlen = noomL_tokenlen(fieldname, 0, parser->version); + noom_uint_t constidx = func->constsize; + if((result = noomC_addconst_str(compiler, vm, fieldname, fieldlen))) return result; + if((result = noomC_emit_Aus(func, NOOMV_INSTR_GETMETHOD, 0, constidx))) return result; } - return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0); - } - if (node->type == NOOMP_NODE_METHODCALL) { - unsigned char fucking_destination = compiler->curstack; - // Here we don't fucking increment this fucking destination - // Because the fucking function call fucking increments it fucking anyway - // push parent value... probably already processed below if you make it i = 0 - for (int i = 1; i < node->subnodec; i++) { - // push node->subnodes[i] to stack or something + for(int i = isMethod ? 2 : 1; i < node->subnodec; i++) { + noom_bool_t isLast = i == (node->subnodec-1); + if((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[i], isLast ? -1 : 1))) return result; } - return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0); + return noomC_emit_Aus(func, NOOMV_INSTR_CALL, funcIdx, retc+1); } if (node->type == NOOMP_NODE_VARIABLE) { noomC_LocalInfo info; @@ -257,9 +261,24 @@ static noom_Exit noomC_compile_expr( return noomC_emit_Aus(func, NOOMV_INSTR_PUSHVAL, 0, info.idx); case NOOMC_UPVAL: return noomC_emit_Aus(func, NOOMV_INSTR_PUSHUPVAL, 0, info.idx); - case NOOMC_GLOBAL: - // FIXME: handle globals - return NOOM_EINTERNAL; + case NOOMC_GLOBAL: { + noom_uint_t constidx = compiler->target->constsize; + if((result = noomC_addconst_str(compiler, vm, varname, namelen))) return result; + if(parser->version == NOOM_VERSION_51) { + return noomC_emit_Aus(func, NOOMV_INSTR_PUSHGLOBAL, 0, constidx); + } + noomC_LocalInfo _ENV; + if((result = noomC_identifyLocal(compiler, &_ENV, "_ENV", 4))) 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) { + return noomC_emit_Aus(func, NOOMV_INSTR_PUSHUPVAL, _ENV.idx, constidx); + } + // bitchass + if((result = noomC_emit_Aus(func, NOOMV_INSTR_PUSHVAL, 0, _ENV.idx))) return result; + return noomC_emit_Aus(func, NOOMV_INSTR_GETFIELD, 0, constidx); + } } // forgot a case return NOOM_EINTERNAL; @@ -332,7 +351,7 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM* vm, noomC_Compiler* com compiler->curstack++; } else { const noomP_Node* value_node = node->subnodes[1]; - const noom_Exit r = noomC_compile_expr(vm, compiler, parser, func, value_node); + const noom_Exit r = noomC_compile_expr(vm, compiler, parser, func, value_node, 1); if (r != NOOM_OK) return r; } @@ -393,15 +412,22 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM* vm, noomC_Compiler* com return noomC_compile_block(vm, compiler, parser, func, node); } + if(node->type == NOOMP_NODE_CALL || node->type == NOOMP_NODE_METHODCALL) { + return noomC_compile_expr(vm, compiler, parser, func, node, 0); + } + return NOOM_EINTERNAL; } -noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_Node* node, noomV_String* chunkname, noomV_Table* env) { +noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_Node* node, noomV_String* chunkname, noomV_Table* env, noomV_Value *outFunc) { if (node->type != NOOMP_NODE_PROGRAM) return NOOM_EINTERNAL; noomV_Function* program = noomV_allocFunc(vm, chunkname); if (program == 0) return NOOM_ENOMEM; + outFunc->tag = NOOMV_VOBJ; + outFunc->obj = &program->obj; + noomC_Compiler compiler; noomC_compiler_init(&compiler); compiler.target = program; @@ -416,20 +442,8 @@ noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_ upval.stolen = 1; upval.constant = 0; noomC_addUpval(&compiler, upval); - } - - noom_Exit status = noomC_compile_block(vm, &compiler, parser, program, node); - if (status != NOOM_OK) return status; - - if (parser->version > NOOM_VERSION_51) { // TODO: we need to wrap the value as a *closure*, with one upvalue, the environment (_ENV). } - if (vm->mainThread->stacklen == vm->mainThread->stackcap) { - vm->mainThread->stackcap = vm->mainThread->stackcap ? vm->mainThread->stackcap * 2 : 16; - vm->mainThread->stack = noom_realloc(vm->mainThread->stack, sizeof(noomV_Value) * vm->mainThread->stackcap); - } - vm->mainThread->stack[vm->mainThread->stacklen++] = - (noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object*)program}; - return NOOM_OK; + return noomC_compile_block(vm, &compiler, parser, program, node); } diff --git a/src/compiler.h b/src/compiler.h index 14171e1..2a13742 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -39,4 +39,4 @@ typedef struct noomC_Compiler { void noomC_compiler_init(noomC_Compiler* compiler); // pushes the compiled function on the stack, or just crashes lol -noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_Node* node, noomV_String* chunkname, noomV_Table* env); +noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_Node* node, noomV_String* chunkname, noomV_Table* env, noomV_Value *outFunc); diff --git a/src/lexer.h b/src/lexer.h index 466b519..18757fb 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -1,3 +1,6 @@ +#ifndef NOOM_LEXER +#define NOOM_LEXER + #include "noom.h" typedef enum noomL_TokenType { @@ -50,3 +53,5 @@ const char* noomL_formatTokenType(noomL_TokenType token_type); noomL_ErrorType noomL_lex(const char* s, noom_uint_t start, noomL_Token* token, noom_LuaVersion version); // TODO: add more error data // UB if syntax error noom_uint_t noomL_tokenlen(const char* s, noom_uint_t start, noom_LuaVersion version); + +#endif diff --git a/src/main.c b/src/main.c index 71abae9..b9cf3f8 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,10 @@ #include // for now +#include #include "helper.h" #include "error.h" #include "noom.h" +#include "compiler.h" +#include "vm.h" void tab(noom_uint_t amount) { amount *= 2; @@ -38,8 +41,10 @@ int the_theoretical_function_to_execute_your_code_that_should_be_replaced_later( noomP_Parser parser; noomP_Node* program; + noom_LuaVM *vm = noom_createVM(NOOM_VERSION_51); + // goodbye "shitass" you will be missed - int success = noomP_parse(code, filename, NOOM_VERSION_54, &program, &parser); + int success = noomP_parse(code, filename, NOOM_VERSION_51, &program, &parser); if (success == 0) { puts("LEX OUTPUT:"); fputs("\x1b[48;2;10;10;10m", stdout); @@ -90,6 +95,36 @@ int the_theoretical_function_to_execute_your_code_that_should_be_replaced_later( noom_free(buf); } + noomV_Value peak; + + noom_Exit e = noomC_compile(vm, &parser, program, 0, 0, &peak); + if(e) { + printf("error: %d\n", e); + exit(e); + } + + noomV_Function *f = (noomV_Function *)peak.obj; + + for(int i = 0; i < f->codesize; i++) { + noomV_Inst inst = f->code[i]; + noomV_DisInfo dis = noomV_disInfo[inst.op]; + + printf("%s %d ", dis.name, inst.a); + + switch(dis.arg) { + case NOOMV_DIS_BC: + printf("%d, %d", inst.b, inst.c); + break; + case NOOMV_DIS_uD: + printf("%d", inst.us); + break; + case NOOMV_DIS_sD: + printf("%d", inst.ss); + break; + } + printf("\n"); + } + // freeing time noomP_Node* last_node = parser.last_node; while (last_node) { @@ -99,6 +134,9 @@ int the_theoretical_function_to_execute_your_code_that_should_be_replaced_later( noom_free(last_node); last_node = next; } + + noom_destroyVM(vm); + return success; } diff --git a/src/parser.h b/src/parser.h index 0f896de..8286347 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,3 +1,6 @@ +#ifndef NOOM_PARSER +#define NOOM_PARSER + #include "noom.h" #include "lexer.h" @@ -168,3 +171,5 @@ noomP_Node* noomP_parseStatement(noomP_Parser* parser); int noomP_parse(const char* code, const char* filename, noom_LuaVersion version, noomP_Node** outpointer, noomP_Parser* parser); int noomP_initParser(noomP_Parser* parser, const char* code, const char* filename, noom_LuaVersion version); + +#endif diff --git a/src/vm.c b/src/vm.c index 6006b4a..fd2ce3d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1,5 +1,25 @@ #include "vm.h" #include "helper.h" +#include + +noomV_DisInfo noomV_disInfo[NOOMV_INSTR_NOP2] = { + [NOOMV_INSTR_PUSHNIL] = { + .name = "PUSHNIL", + .arg = NOOMV_DIS_uD, + }, + [NOOMV_INSTR_PUSHCONST] = { + .name = "PUSHCONST", + .arg = NOOMV_DIS_uD, + }, + [NOOMV_INSTR_PUSHGLOBAL] = { + .name = "PUSHGLOBAL", + .arg = NOOMV_DIS_uD, + }, + [NOOMV_INSTR_CALL] = { + .name = "CALL", + .arg = NOOMV_DIS_uD, + }, +}; noomV_Object* noomV_allocObj(noom_LuaVM* vm, noomV_ObjTag tag, noom_uint_t size) { noomV_Object* o = noom_alloc(size); @@ -55,6 +75,14 @@ noomV_Table* noomV_allocTable(noom_LuaVM* vm) { } void noomV_freeObj(noomV_Object* obj) { + printf("%d\n", obj->tag); + if(obj->tag == NOOMV_OFUNC) { + noomV_Function *f = (noomV_Function *)obj; + noom_free(f->consts); + noom_free(f->upvals); + noom_free(f->locals); + noom_free(f->code); + } noom_free(obj); } diff --git a/src/vm.h b/src/vm.h index d7d0171..ce017f7 100644 --- a/src/vm.h +++ b/src/vm.h @@ -114,19 +114,23 @@ typedef enum noomV_Opcode : unsigned char { // all returns are pushed. NOOMV_INSTR_CALL, - // pops (table, field), and pushes table[field] + // pops (table, field), and pushes `table[field]` NOOMV_INSTR_GETTABLE, - // pops (table, field, value), and sets table[field] = value + // pops (table, field, value), and sets `table[field] = value` NOOMV_INSTR_SETTABLE, // pops op.uD values, then sets it as an array starting at op.a+1 in the table at the new top; // if that is confused, it basically does this: // int table = stacksize - op.uD - 1; - // for(int i = 0; i < op.uD; i++) stack[table][op.a + 1 + i] = stack[table + i + 1]; + // for(int i = 0; i < op.uD; i++) `stack[table][op.a + 1 + i] = stack[table + i + 1];` NOOMV_INSTR_SETLIST, - // pops table, pushes table[consts[op.uD]], an optimization for indexing fields + // pops table, pushes `table[consts[op.uD]]`, an optimization for indexing fields NOOMV_INSTR_GETFIELD, - // pops (table, value), sets table[consts[op.uD]] = value, an optimization for changing fields + // 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. @@ -155,7 +159,7 @@ typedef enum noomV_Opcode : unsigned char { // For bullshit - // Take the top value without popping it, push value[consts[op.uD]] like GETFIELD would, then swap the top 2 values. + // Take the top value without popping it, push `value[consts[op.uD]]` like GETFIELD would, then swap the top 2 values. // This is for a:foo() and such NOOMV_INSTR_GETMETHOD, // rotate the the top op.a items by op.sD @@ -174,6 +178,17 @@ typedef enum noomV_Opcode : unsigned char { NOOMV_INSTR_NOP2 = 0xff, } noomV_Opcode; +typedef struct noomV_DisInfo { + const char *name; + enum { + NOOMV_DIS_BC, + NOOMV_DIS_uD, + NOOMV_DIS_sD, + } arg; +} noomV_DisInfo; + +extern noomV_DisInfo noomV_disInfo[NOOMV_INSTR_NOP2]; + typedef struct noomV_Inst { noomV_Opcode op; unsigned char a;