diff --git a/src/compiler.c b/src/compiler.c index 730e388..a5e0fa2 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -42,8 +42,9 @@ void noomC_compiler_init(noomC_Compiler *compiler) { } static noom_Exit noomC_emit(noomV_Function *func, const noomV_Inst inst) { - func->code = noom_realloc(func->code, sizeof(noomV_Inst) * (func->codesize + 1)); - if (func->code == 0) return NOOM_ENOMEM; + noomV_Inst *newCode =noom_realloc(func->code, sizeof(noomV_Inst) * (func->codesize + 1)); + if (newCode == 0) return NOOM_ENOMEM; + func->code = newCode; func->code[func->codesize++] = inst; return NOOM_OK; } @@ -58,21 +59,13 @@ static noom_Exit noomC_emit_Aus(noomV_Function *func, const noomV_Opcode op, con static noom_Exit noomC_addconst(noomV_Function *func, const noomV_Value val) { if (func->constsize == NOOM_USHORT_MAX) return NOOM_PLEASEHELPMEIAMSCARED; - func->consts = noom_realloc(func->consts, sizeof(noomV_Value) * (func->constsize + 1)); - if (func->consts == 0) return NOOM_ENOMEM; + 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; } -// TODO get rid of these two vvvv -static noom_Exit noomC_addconst_nil(noomV_Function *func) { - return noomC_addconst(func, (noomV_Value){.tag = NOOMV_VNIL, .autoclose = 0, .isptr = 0}); -} -static noom_Exit noomC_addconst_bool(noomV_Function *func, const noom_bool_t b) { - return noomC_addconst(func, (noomV_Value){.tag = NOOMV_VBOOL, .autoclose = 0, .isptr = 0, .boolean = b}); -} -// yeah ^^^^^^^^^ - static noom_Exit noomC_addconst_str(noomV_Function *func, noom_LuaVM *vm, const char *str, const noom_uint_t len) { noomV_String *s = noomV_allocStr(vm, str, len); if (s == 0) return NOOM_ENOMEM; @@ -86,33 +79,34 @@ static noomL_Token noomC_token_at(const noomP_Parser *parser, noom_uint_t offset } // There is a high chance I forgot something here -static noomV_Opcode noomC_what_bop_is_this(const noomP_Parser *parser, noom_uint_t offset) { +static noom_BinOp noomC_what_bop_is_this(const noomP_Parser *parser, noom_uint_t offset) { + const char *op = parser->code + offset; // I AM THE LEXER NOW!!!!!!!!! - if (noom_startswith(parser->code + offset, "==")) return NOOMV_INSTR_EQ; - if (noom_startswith(parser->code + offset, "~=")) return NOOMV_INSTR_NEQ; - if (noom_startswith(parser->code + offset, "~=")) return NOOMV_INSTR_LTE; - if (noom_startswith(parser->code + offset, "~=")) return NOOMV_INSTR_GTE; - if (noom_startswith(parser->code + offset, "..")) return NOOMV_INSTR_CONCAT; + if (noom_startswith(op, "==")) return NOOM_BIN_EQL; + if (noom_startswith(op, "~=")) return NOOM_BIN_NEQL; + if (noom_startswith(op, "<")) return NOOM_BIN_LESS; + if (noom_startswith(op, "<=")) return NOOM_BIN_LESSEQL; + if (noom_startswith(op, ">")) return NOOM_BIN_GREATER; + if (noom_startswith(op, ">=")) return NOOM_BIN_GREATEREQL; + // no .., that is special cased due to funky behavior if (parser->version >= NOOM_VERSION_53) { // Fucking atom forgot to put make an instruction // update no i am unable to read - if (noom_startswith(parser->code + offset, "//")) return NOOMV_INSTR_FLOOR_DIV; - if (noom_startswith(parser->code + offset, ">>")) return NOOMV_INSTR_RSHIFT; - if (noom_startswith(parser->code + offset, "<<")) return NOOMV_INSTR_LSHIFT; - if (noom_startswith(parser->code + offset, "&")) return NOOMV_INSTR_BAND; - if (noom_startswith(parser->code + offset, "|")) return NOOMV_INSTR_BOR; - if (noom_startswith(parser->code + offset, "~")) return NOOMV_INSTR_BXOR; + if (noom_startswith(op, "//")) return NOOM_BIN_IDIV; + if (noom_startswith(op, ">>")) return NOOM_BIN_BSHIFTR; + if (noom_startswith(op, "<<")) return NOOM_BIN_BSHIFTL; + if (noom_startswith(op, "&")) return NOOM_BIN_BAND; + if (noom_startswith(op, "|")) return NOOM_BIN_BOR; + if (noom_startswith(op, "~")) return NOOM_BIN_BXOR; } - if (noom_startswith(parser->code + offset, "+")) return NOOMV_INSTR_ADD; - if (noom_startswith(parser->code + offset, "-")) return NOOMV_INSTR_SUB; - if (noom_startswith(parser->code + offset, "*")) return NOOMV_INSTR_MUL; - if (noom_startswith(parser->code + offset, "/")) return NOOMV_INSTR_DIV; - if (noom_startswith(parser->code + offset, "%")) return NOOMV_INSTR_MOD; - if (noom_startswith(parser->code + offset, "^")) return NOOMV_INSTR_POW; - if (noom_startswith(parser->code + offset, "<")) return NOOMV_INSTR_LT; - if (noom_startswith(parser->code + offset, ">")) return NOOMV_INSTR_GT; + if (noom_startswith(op, "+")) return NOOM_BIN_ADD; + if (noom_startswith(op, "-")) return NOOM_BIN_SUB; + if (noom_startswith(op, "*")) return NOOM_BIN_MLT; + if (noom_startswith(op, "/")) return NOOM_BIN_DIV; + if (noom_startswith(op, "%")) return NOOM_BIN_MOD; + if (noom_startswith(op, "^")) return NOOM_BIN_EXP; return 0; } @@ -125,24 +119,20 @@ static noom_Exit noomC_compile_expr( noomV_Function *func, const noomP_Node *node ) { + noom_Exit result; // Baba is You OST is a very cool soundtrack to code to Can recommend if (node->type == NOOMP_NODE_NILLITERAL) { - unsigned char fucking_destination = compiler->curstack++; - unsigned short fucking_constant = func->constsize; - noom_Exit result = noomC_addconst_nil(func); - if (result != NOOM_OK) return result; - - return noomC_emit_Aus(func, NOOMV_INSTR_LOADC, fucking_destination, fucking_constant); + compiler->curstack++; + // TODO: analyze last instruction to optimize automatically + return noomC_emit_Aus(func, NOOMV_INSTR_PUSHNIL, 0, 0); } if (node->type == NOOMP_NODE_BOOLEANLITERAL) { unsigned char fucking_destination = compiler->curstack++; unsigned short fucking_constant = func->constsize; noomL_Token bool_token = noomC_token_at(parser, node->source_offset); noom_bool_t val = noom_memeq(parser->code + bool_token.offset, bool_token.length, "true", 4); - noom_Exit result = noomC_addconst_bool(func, val); - if (result != NOOM_OK) return result; - - return noomC_emit_Aus(func, NOOMV_INSTR_LOADC, fucking_destination, fucking_constant); + // TODO: analyze last instruction to optimize automatically + return noomC_emit_Aus(func, NOOMV_INSTR_PUSHBOOLS, 0, val ? 1 : 0); } if (node->type == NOOMP_NODE_NUMBERLITERAL) { unsigned char fucking_destination = compiler->curstack++; @@ -154,16 +144,38 @@ static noom_Exit noomC_compile_expr( return result; } if (node->type == NOOMP_NODE_BINARYOPERATOR) { - unsigned char fucking_destination = compiler->curstack++; if (node->subnodec != 2) return NOOM_EINTERNAL; - const unsigned char B = compiler->curstack++; - noom_Exit result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0]); - if (result != NOOM_OK) return result; - const unsigned char C = compiler->curstack++; - result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1]); - if (result != NOOM_OK) return result; - - return noomC_emit_ABC(func, noomC_what_bop_is_this(parser, node->source_offset), fucking_destination, B, C); + const char *op = parser->code + node->source_offset; + if(noom_startswith(op, "..")) { + // 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; + // 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). + // VM will handle the concat order within the array for us + while(1) { + 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; + n = n->subnodes[1]; + } else { + if((result = noomC_compile_expr(vm, compiler, parser, func, n))) return result; + break; + } + } + compiler->curstack -= amount; + compiler->curstack++; + 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; + // 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; @@ -184,24 +196,6 @@ static noom_Exit noomC_compile_expr( } return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0); } - if (node->type == NOOMP_NODE_GETFIELD) { - unsigned char fucking_destination = compiler->curstack++; - if (node->subnodec != 2) return NOOM_EINTERNAL; - - unsigned char B = compiler->curstack; - noom_Exit result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0]); - if (result != NOOM_OK) return result; - - unsigned char C = compiler->curstack; - unsigned short C_constant = func->constsize; - noomL_Token field_token = noomC_token_at(parser, node->subnodes[1]->source_offset); - result = noomC_addconst_str(func, vm, parser->code + field_token.offset, field_token.length); - if (result != NOOM_OK) return result; - result = noomC_emit_Aus(func, NOOMV_INSTR_LOADC, C, C_constant); - if (result != NOOM_OK) return result; - - return noomC_emit_ABC(func, NOOMV_INSTR_GET, fucking_destination, B, C); - } return NOOM_EINTERNAL; } @@ -222,20 +216,27 @@ static noom_Exit noomC_compile_block(noom_LuaVM *vm, noomC_Compiler *compiler, c // I remember atom said there is a memory leak somewhere but I don't rememeememember where uhhhhhhhhhhhhhhhhh static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *compiler, const noomP_Parser *parser, noomV_Function *func, const noomP_Node *node) { + noom_Exit result; // local name = expression i think if (node->type == NOOMP_NODE_LOCALDECLARATION) { + // This code is awful for several reasons and we shall burn it if (node->subnodec != 1 && node->subnodec != 2) return NOOM_EINTERNAL; const noomP_Node *varname_node = node->subnodes[0]; if (varname_node->type != NOOMP_NODE_ASSIGNPLACE) return NOOM_EINTERNAL; + const char *namebuf = parser->code + varname_node->source_offset; + noomL_Token t; + noomL_lex(namebuf, 0, &t, parser->version); + noomC_Local local; local.startpc = func->codesize; local.endpc = 0; - local.dropped = 0; // FIXME? + local.dropped = 0; local.close = 0; local.constant = 0; - local.name = noom_strndup(parser->code + varname_node->source_offset, varname_node->source_offset); + local.name = namebuf; + local.namelen = t.length; for (noom_uint_t i = 0; i < varname_node->subnodec; i++) { if (varname_node->subnodes[i]->type != NOOMP_NODE_ATTRIBUTE) return NOOM_EINTERNAL; @@ -260,27 +261,30 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com if (compiler->curstack++ == NOOM_MAXSTACK) return NOOM_ENOSTACK; if (node->subnodec == 1) { - // according to atom this should be nil const unsigned short constptr = func->constsize; - noom_Exit result = noomC_addconst_nil(func); - if (result != NOOM_OK) return result; - result = noomC_emit_Aus(func, NOOMV_INSTR_LOADC, destination, constptr); + result = noomC_emit_Aus(func, NOOMV_INSTR_PUSHNIL, 0, 0); if (result != NOOM_OK) return result; + compiler->curstack++; } else { const noomP_Node *value_node = node->subnodes[1]; - const unsigned saved = compiler->curstack; - compiler->curstack = destination; const noom_Exit r = noomC_compile_expr(vm, compiler, parser, func, value_node); if (r != NOOM_OK) return r; - compiler->curstack = saved; } - compiler->locals = noom_realloc(compiler->locals, sizeof(noomC_Local) * (compiler->localc + 1)); - if (compiler->locals == 0) return NOOM_ENOMEM; + local.stackslot = compiler->curstack; + + // too many locals + if(compiler->localc == 200) return NOOM_EINTERNAL; + // resize backing array + if(compiler->localc == compiler->localcap) { + noom_uint_t newCap = compiler->localcap * 2; + noomC_Local *newLocals = noom_realloc(compiler->locals, sizeof(noomC_Local) * newCap); + if(newLocals == 0) return NOOM_ENOMEM; + compiler->locals = newLocals; + compiler->localcap = newCap; + } compiler->locals[compiler->localc++] = local; - // I guess??????? - if (compiler->localc > compiler->localcap) compiler->localcap = compiler->localc; return NOOM_OK; } @@ -310,8 +314,9 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com const noom_Exit result = noomC_compile_block(vm, &child, parser, proto, block_node); if (result != NOOM_OK) return result; - func->protos = noom_realloc(func->protos, sizeof(noomV_Function *) * (func->protosize + 1)); - if (func->protos == 0) return NOOM_ENOMEM; + noomV_Function **newProtos = noom_realloc(func->protos, sizeof(noomV_Function *) * (func->protosize + 1)); + if (newProtos == 0) return NOOM_ENOMEM; + func->protos = newProtos; func->protos[func->protosize++] = proto; noomC_Local local; @@ -320,8 +325,10 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com local.dropped = 0; // FIXME? local.close = 0; local.constant = 0; + // FIXME: this is WRONG, BUT I AM TIRED. local.name = noom_strndup(parser->code + varname_node->source_offset, varname_node->source_offset); - + + // FIXME: EXTREMELY WRONG. I AM STILL TIRED. compiler->locals = noom_realloc(compiler->locals, sizeof(noomC_Local) * (compiler->localc + 1)); if (compiler->locals == 0) return NOOM_ENOMEM; compiler->locals[compiler->localc++] = local; diff --git a/src/compiler.h b/src/compiler.h index 96ba375..05bc463 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -6,7 +6,8 @@ typedef struct noomC_Local { unsigned int startpc; unsigned int endpc; const char *name; - noom_uint_t namelen; + unsigned int namelen; + unsigned int stackslot; noom_bool_t dropped; noom_bool_t constant; noom_bool_t close; diff --git a/src/noom.h b/src/noom.h index 1e3c146..e362319 100644 --- a/src/noom.h +++ b/src/noom.h @@ -95,6 +95,8 @@ typedef enum noom_BinOp { NOOM_BIN_DIV, // a // b NOOM_BIN_IDIV, + // a % b + NOOM_BIN_MOD, // a ^ b NOOM_BIN_EXP, diff --git a/src/vm.h b/src/vm.h index 6552baf..f59c140 100644 --- a/src/vm.h +++ b/src/vm.h @@ -95,9 +95,9 @@ typedef enum noomV_Opcode : unsigned char { NOOMV_INSTR_PUSHGLOBAL, // Pushes op.sD itself as an integer NOOMV_INSTR_PUSHINT, - // Pushes op.uD nils + // Pushes [op.uD+1] nils NOOMV_INSTR_PUSHNIL, - // Pushes op.a+1 booleans, encoded in op.uD, where the ith (0-indexed) boolean is encoded in `uD & (1 << i)` + // Pushes [op.a+1] booleans, encoded in [op.uD], where the ith (0-indexed) boolean is encoded in `uD & (1 << i)` NOOMV_INSTR_PUSHBOOLS, // Pushes *upvals[op.uD] NOOMV_INSTR_PUSHUPVAL, @@ -165,7 +165,7 @@ typedef enum noomV_Opcode : unsigned char { // set the stack size to op.uD, inserting nils if need be, good for labels NOOMV_INSTR_SETSTACK, - // pop and concatenate the top op.uD values to a string and push it + // pop and concatenate the top [op.uD+1] values to a string and push it NOOMV_INSTR_CONCAT, // mark stack slot op.uD as to-be-closed