YOU CAN DO IT BUT NOT LIKE WE DO IT!!!!!!!
This commit is contained in:
820
src/compiler.c
820
src/compiler.c
@@ -48,22 +48,74 @@ noom_Exit noomC_addUpval(noomC_Compiler* c, noomC_Upval upval) {
|
|||||||
return NOOM_OK;
|
return NOOM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
noom_Exit noomC_identifyLocal(noomC_Compiler* compiler, noomC_LocalInfo* info, const char* name, noom_uint_t namelen) {
|
int noomC_stealUpval(noomC_Compiler* c, const char* name, noom_uint_t namelen) {
|
||||||
// TODO: attempt to steal locals for upvalues
|
// 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;
|
||||||
|
}
|
||||||
|
// damn it
|
||||||
|
|
||||||
for (int i = compiler->localc - 1; i >= 0; i--) {
|
if (c->parent == 0) return -1;
|
||||||
noomC_Local l = compiler->locals[i];
|
|
||||||
|
// maybe you have smth useful
|
||||||
|
for (int i = (int)c->parent->localc - 1; i >= 0; i--) {
|
||||||
|
const noomC_Local l = c->parent->locals[i];
|
||||||
if (l.dropped) continue;
|
if (l.dropped) continue;
|
||||||
if (noom_memeq(l.name, l.namelen, name, namelen)) {
|
if (noom_memeq(l.name, l.namelen, name, namelen)) {
|
||||||
info->type = NOOMC_LOCAL;
|
// yay!!!! wahoo!!!! yippee!!!!!!!!!!!
|
||||||
info->idx = l.stackslot;
|
if (c->upvalc == NOOMC_MAXUPVAL) return -1;
|
||||||
return NOOM_OK;
|
noomC_Upval upval;
|
||||||
|
upval.name = name;
|
||||||
|
upval.namelen = namelen;
|
||||||
|
upval.slot = (unsigned short)l.stackslot;
|
||||||
|
upval.stolen = 0;
|
||||||
|
upval.constant = l.constant;
|
||||||
|
const unsigned idx = c->upvalc;
|
||||||
|
c->upvals[c->upvalc++] = upval;
|
||||||
|
return (int)idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to global
|
const int parent_upval = noomC_stealUpval(c->parent, name, namelen);
|
||||||
info->type = NOOMC_GLOBAL;
|
if (parent_upval >= 0) {
|
||||||
return NOOM_OK;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noomC_LocalInfo noomC_identifyLocal(noomC_Compiler* compiler, const char* name, noom_uint_t namelen) {
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
static noom_Exit noomC_identifyLocalAndSet(noomC_Compiler* compiler, const char* name, noom_uint_t namelen) {
|
||||||
|
const noomC_LocalInfo info = noomC_identifyLocal(compiler, name, namelen);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void noomC_compiler_init(noomC_Compiler* compiler) {
|
void noomC_compiler_init(noomC_Compiler* compiler) {
|
||||||
@@ -72,10 +124,10 @@ void noomC_compiler_init(noomC_Compiler* compiler) {
|
|||||||
|
|
||||||
compiler->localc = 0;
|
compiler->localc = 0;
|
||||||
compiler->upvalc = 0;
|
compiler->upvalc = 0;
|
||||||
compiler->curstack = -1;
|
compiler->curstack = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noom_Exit noomC_emit(noomV_Function* func, const noomV_Inst inst) {
|
noom_Exit noomC_emit(noomV_Function* func, noomV_Inst inst) {
|
||||||
noomV_Inst* newCode = noom_realloc(func->code, sizeof(noomV_Inst) * (func->codesize + 1));
|
noomV_Inst* newCode = noom_realloc(func->code, sizeof(noomV_Inst) * (func->codesize + 1));
|
||||||
if (newCode == 0) return NOOM_ENOMEM;
|
if (newCode == 0) return NOOM_ENOMEM;
|
||||||
func->code = newCode;
|
func->code = newCode;
|
||||||
@@ -83,15 +135,7 @@ static noom_Exit noomC_emit(noomV_Function* func, const noomV_Inst inst) {
|
|||||||
return NOOM_OK;
|
return NOOM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noom_Exit noomC_emit_ABC(noomV_Function* func, const noomV_Opcode op, const unsigned char a, const unsigned char b, const unsigned char c) {
|
noom_Exit noomC_addconst(noomV_Function* func, noomV_Value val) {
|
||||||
return noomC_emit(func, (noomV_Inst){.op = op, .a = a, .b = b, .c = c});
|
|
||||||
}
|
|
||||||
|
|
||||||
static noom_Exit noomC_emit_AuD(noomV_Function* func, const noomV_Opcode op, const unsigned char a, const unsigned short us) {
|
|
||||||
return noomC_emit(func, (noomV_Inst){.op = op, .a = a, .us = us});
|
|
||||||
}
|
|
||||||
|
|
||||||
static noom_Exit noomC_addconst(noomV_Function* func, const noomV_Value val) {
|
|
||||||
if (func->constsize == NOOM_USHORT_MAX) return NOOM_PLEASEHELPMEIAMSCARED;
|
if (func->constsize == NOOM_USHORT_MAX) return NOOM_PLEASEHELPMEIAMSCARED;
|
||||||
noomV_Value* newConsts = noom_realloc(func->consts, sizeof(noomV_Value) * (func->constsize + 1));
|
noomV_Value* newConsts = noom_realloc(func->consts, sizeof(noomV_Value) * (func->constsize + 1));
|
||||||
if (newConsts == 0) return NOOM_ENOMEM;
|
if (newConsts == 0) return NOOM_ENOMEM;
|
||||||
@@ -100,11 +144,11 @@ static noom_Exit noomC_addconst(noomV_Function* func, const noomV_Value val) {
|
|||||||
return NOOM_OK;
|
return NOOM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noomV_String* noomC_internString(noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len) {
|
noomV_String* noomC_internString(const noomC_Compiler* c, noom_LuaVM* vm, const char* str, noom_uint_t len) {
|
||||||
while (c) {
|
while (c) {
|
||||||
noomV_Function* f = c->target;
|
const noomV_Function* f = c->target;
|
||||||
for (int i = 0; i < f->constsize; i++) {
|
for (int i = 0; i < f->constsize; i++) {
|
||||||
noomV_Value v = f->consts[i];
|
const noomV_Value v = f->consts[i];
|
||||||
if (v.tag != NOOMV_VOBJ) continue;
|
if (v.tag != NOOMV_VOBJ) continue;
|
||||||
noomV_Object* o = v.obj;
|
noomV_Object* o = v.obj;
|
||||||
if (o->tag != NOOMV_OSTR) continue;
|
if (o->tag != NOOMV_OSTR) continue;
|
||||||
@@ -116,32 +160,21 @@ static noomV_String* noomC_internString(noomC_Compiler* c, noom_LuaVM* vm, const
|
|||||||
return noomV_allocStr(vm, str, len);
|
return noomV_allocStr(vm, str, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noom_Exit noomC_addconst_str(noomC_Compiler* c, noom_LuaVM* vm, const char* str, const noom_uint_t 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);
|
noomV_String* s = noomC_internString(c, vm, str, len);
|
||||||
if (s == 0) return NOOM_ENOMEM;
|
if (s == 0) return NOOM_ENOMEM;
|
||||||
return noomC_addconst(c->target, (noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object*)s});
|
return noomC_addconst(c->target, (noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object*)s});
|
||||||
}
|
}
|
||||||
|
|
||||||
static noom_Exit noomC_addconst_num(noomC_Compiler *c, noom_LuaVM *vm, double num) {
|
noom_BinOp noomC_lex_bin_op(const noomP_Parser* parser, noom_uint_t offset) {
|
||||||
// TODO :(
|
|
||||||
}
|
|
||||||
|
|
||||||
static noomL_Token noomC_token_at(const noomP_Parser* parser, noom_uint_t offset) {
|
|
||||||
noomL_Token token;
|
|
||||||
noomL_lex(parser->code, offset, &token, parser->version);
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is a high chance I forgot something here
|
|
||||||
static noom_BinOp noomC_what_bop_is_this(const noomP_Parser* parser, noom_uint_t offset) {
|
|
||||||
const char* op = parser->code + offset;
|
const char* op = parser->code + offset;
|
||||||
// I AM THE LEXER NOW!!!!!!!!!
|
// I AM THE LEXER NOW!!!!!!!!!
|
||||||
if (noom_startswith(op, "==")) return NOOM_BIN_EQL;
|
if (noom_startswith(op, "==")) return NOOM_BIN_EQL;
|
||||||
if (noom_startswith(op, "~=")) return NOOM_BIN_NEQL;
|
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_LESSEQL;
|
||||||
if (noom_startswith(op, ">")) return NOOM_BIN_GREATER;
|
|
||||||
if (noom_startswith(op, ">=")) return NOOM_BIN_GREATEREQL;
|
if (noom_startswith(op, ">=")) return NOOM_BIN_GREATEREQL;
|
||||||
|
if (noom_startswith(op, "<")) return NOOM_BIN_LESS;
|
||||||
|
if (noom_startswith(op, ">")) return NOOM_BIN_GREATER;
|
||||||
// no .., that is special cased due to funky behavior
|
// no .., that is special cased due to funky behavior
|
||||||
|
|
||||||
if (parser->version >= NOOM_VERSION_53) {
|
if (parser->version >= NOOM_VERSION_53) {
|
||||||
@@ -162,9 +195,130 @@ static noom_BinOp noomC_what_bop_is_this(const noomP_Parser* parser, noom_uint_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noom_UnaryOp noomC_lex_un_op(const noomP_Parser* parser, noom_uint_t offset) {
|
||||||
|
const char* op = parser->code + offset;
|
||||||
|
// this can probably be simplified as just first character checks to avoid calling functions lol
|
||||||
|
if (noom_startswith(op, "-")) return NOOM_UNARY_NEGATE;
|
||||||
|
if (noom_startswith(op, "~")) return NOOM_UNARY_BNOT;
|
||||||
|
if (noom_startswith(op, "#")) return NOOM_UNARY_LEN;
|
||||||
|
if (noom_startswith(op, "not")) return NOOM_UNARY_NOT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* noomC_decode_string_token(const char* s, noom_LuaVersion how_the_fuck, noom_uint_t* outlen) {
|
||||||
|
// nah fuck it TODO atom pls save me
|
||||||
|
// actually don't i will repair this one day
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
noom_Exit noomC_compile_proto(
|
||||||
|
noom_LuaVM* vm,
|
||||||
|
noomC_Compiler* parent_compiler,
|
||||||
|
const noomP_Parser* parser,
|
||||||
|
noomV_Function* parent_func,
|
||||||
|
const noomP_Node* params_node,
|
||||||
|
const noomP_Node* block_node,
|
||||||
|
noom_bool_t has_self,
|
||||||
|
noomV_Function** out_proto) {
|
||||||
|
noom_Exit result;
|
||||||
|
|
||||||
|
noomV_Function* proto = noomV_allocFunc(vm, parent_func->chunkname);
|
||||||
|
if (proto == 0) return NOOM_ENOMEM;
|
||||||
|
|
||||||
|
noomC_Compiler child;
|
||||||
|
noomC_compiler_init(&child);
|
||||||
|
child.parent = parent_compiler;
|
||||||
|
child.target = proto;
|
||||||
|
|
||||||
|
// [varname..., vararg?]
|
||||||
|
noom_uint_t param_count = 0;
|
||||||
|
noom_bool_t has_vararg = 0; // do we even need that
|
||||||
|
for (noom_uint_t i = 0; i < params_node->subnodec; i++) {
|
||||||
|
if (params_node->subnodes[i]->type == NOOMP_NODE_VARARG) {
|
||||||
|
has_vararg = 1;
|
||||||
|
} else {
|
||||||
|
param_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_self) {
|
||||||
|
noomC_Local self_local;
|
||||||
|
self_local.startpc = 0;
|
||||||
|
self_local.endpc = 0;
|
||||||
|
self_local.name = "self";
|
||||||
|
self_local.namelen = 4;
|
||||||
|
self_local.stackslot = 0;
|
||||||
|
self_local.dropped = 0;
|
||||||
|
self_local.constant = 0;
|
||||||
|
self_local.close = 0;
|
||||||
|
if ((result = noomC_addLocal(&child, self_local)) != NOOM_OK) return result;
|
||||||
|
child.curstack = 1;
|
||||||
|
param_count++;
|
||||||
|
} else {
|
||||||
|
child.curstack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
proto->argc = (unsigned char)param_count;
|
||||||
|
|
||||||
|
// register arguments as locals
|
||||||
|
for (noom_uint_t i = 0; i < params_node->subnodec; i++) {
|
||||||
|
const noomP_Node* p = params_node->subnodes[i];
|
||||||
|
if (p->type == NOOMP_NODE_VARARG) continue;
|
||||||
|
const noom_uint_t length = noomL_tokenlen(parser->code, p->source_offset, parser->version);
|
||||||
|
noomC_Local a;
|
||||||
|
a.startpc = 0;
|
||||||
|
a.endpc = 0;
|
||||||
|
a.dropped = 0;
|
||||||
|
a.close = 0;
|
||||||
|
a.constant = 0;
|
||||||
|
a.name = parser->code + p->source_offset;
|
||||||
|
a.namelen = length;
|
||||||
|
a.stackslot = child.curstack++;
|
||||||
|
if ((result = noomC_addLocal(&child, a)) != NOOM_OK) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result = noomC_compile_block(vm, &child, parser, proto, block_node)) != NOOM_OK) return result;
|
||||||
|
|
||||||
|
noomV_Function** newProtos = noom_realloc(parent_func->protos, sizeof(noomV_Function*) * (parent_func->protosize + 1));
|
||||||
|
if (newProtos == 0) return NOOM_ENOMEM;
|
||||||
|
parent_func->protos = newProtos;
|
||||||
|
parent_func->protos[parent_func->protosize++] = proto;
|
||||||
|
|
||||||
|
*out_proto = proto;
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
noom_Exit noomC_emit_assign_to(
|
||||||
|
noom_LuaVM* vm,
|
||||||
|
noomC_Compiler* compiler,
|
||||||
|
const noomP_Parser* parser,
|
||||||
|
noomV_Function* func,
|
||||||
|
const noomP_Node* target,
|
||||||
|
unsigned char value_slot) {
|
||||||
|
noom_Exit result;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->type == NOOMP_NODE_GETFIELD) {
|
||||||
|
// TODO
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->type == NOOMP_NODE_INDEX) {
|
||||||
|
// TODO
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
// mmap ahh function 🥀🥀🥀🥀🥀🥀🥀
|
// mmap ahh function 🥀🥀🥀🥀🥀🥀🥀
|
||||||
// What 6 argument syscalls there even are other than mmap and clone and is there anything longer
|
// What 6 argument syscalls there even are other than mmap and clone and is there anything longer
|
||||||
static noom_Exit noomC_compile_expr(
|
noom_Exit noomC_compile_expr(
|
||||||
noom_LuaVM* vm,
|
noom_LuaVM* vm,
|
||||||
noomC_Compiler* compiler,
|
noomC_Compiler* compiler,
|
||||||
const noomP_Parser* parser,
|
const noomP_Parser* parser,
|
||||||
@@ -173,38 +327,98 @@ static noom_Exit noomC_compile_expr(
|
|||||||
// retc of -1 means all values!!!!!!!!!!!
|
// retc of -1 means all values!!!!!!!!!!!
|
||||||
int retc) {
|
int retc) {
|
||||||
noom_Exit result;
|
noom_Exit result;
|
||||||
|
|
||||||
if (node->type == NOOMP_NODE_NILLITERAL) {
|
if (node->type == NOOMP_NODE_NILLITERAL) {
|
||||||
compiler->curstack++;
|
compiler->curstack++;
|
||||||
if (func->codesize > 0 && func->code[func->codesize - 1].op == NOOMV_INSTR_PUSHNIL) {
|
if (func->codesize > 0 && func->code[func->codesize - 1].op == NOOMV_INSTR_PUSHNIL) {
|
||||||
func->code[func->codesize - 1].us++;
|
func->code[func->codesize - 1].us++;
|
||||||
|
return NOOM_OK;
|
||||||
}
|
}
|
||||||
else {
|
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHNIL, 0, 1);
|
||||||
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_PUSHNIL, 0, 0)) != NOOM_OK) return result;
|
|
||||||
}
|
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHNIL, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == NOOMP_NODE_BOOLEANLITERAL) {
|
if (node->type == NOOMP_NODE_BOOLEANLITERAL) {
|
||||||
unsigned char where = 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);
|
|
||||||
// TODO: analyze last instruction to optimize automatically
|
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHBOOLS, 0, val ? 1 : 0);
|
|
||||||
}
|
|
||||||
if (node->type == NOOMP_NODE_NUMBERLITERAL) {
|
|
||||||
unsigned char fucking_destination = compiler->curstack++;
|
|
||||||
noomL_Token number_token = noomC_token_at(parser, node->source_offset);
|
|
||||||
double val = noom_strtod(parser->code + number_token.offset, 0, 0);
|
|
||||||
if ((result = noomC_addconst_num(compiler, vm, val)) != NOOM_OK) return result;
|
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHCONST, 0, fucking_destination);
|
|
||||||
}
|
|
||||||
if (node->type == NOOMP_NODE_STRINGLITERAL) {
|
|
||||||
compiler->curstack++;
|
compiler->curstack++;
|
||||||
unsigned char fucking_destination = func->constsize;
|
noom_uint_t length = noomL_tokenlen(parser->code, node->source_offset, parser->version);
|
||||||
noom_Exit result = noomC_addconst_str(compiler, vm, "but DID YOU KNOW", 16);
|
noom_bool_t val = noom_memeq(parser->code + node->source_offset, length, "true", 4);
|
||||||
if (result) return result;
|
// TODO: analyze last instruction to optimize automatically
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHCONST, 0, fucking_destination);
|
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHBOOLS, 0, val ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_NUMBERLITERAL) {
|
||||||
|
const unsigned short const_idx = func->constsize;
|
||||||
|
noomV_Value val = noom_tonumber_except_different_name_so_public_fucking_api_works(parser->code + node->source_offset, 0, parser->version);
|
||||||
|
// TODO!!!!11 intern val
|
||||||
|
compiler->curstack++;
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHCONST, 0, const_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_STRINGLITERAL) {
|
||||||
|
const unsigned short const_idx = func->constsize;
|
||||||
|
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;
|
||||||
|
compiler->curstack++;
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHCONST, 0, const_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_VARARGLITERAL) {
|
||||||
|
// TODO how do i even push all (retc) varargs
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_PARENTHESIZED) {
|
||||||
|
return noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_TABLELITERAL) {
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_CREATETABLE, 0, node->subnodec))) return result;
|
||||||
|
const unsigned table_slot = compiler->curstack++; // FIXME is this right?
|
||||||
|
|
||||||
|
noom_uint_t array_idx = 1; // 1 BASED LUA ARRAY INDEXATION!!!!!!!!! DAMN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
||||||
|
const noomP_Node* entry = node->subnodes[i];
|
||||||
|
|
||||||
|
if (entry->type == NOOMP_NODE_TABLEENTRY) {
|
||||||
|
// [expr, expr] wow how profound and insightful
|
||||||
|
const noomP_Node* key_node = entry->subnodes[0];
|
||||||
|
const noomP_Node* val_node = entry->subnodes[1];
|
||||||
|
|
||||||
|
if (key_node->type == NOOMP_NODE_FIELDNAME) {
|
||||||
|
// string key
|
||||||
|
const unsigned short constidx = func->constsize;
|
||||||
|
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_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;
|
||||||
|
} else {
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, key_node, 1))) return result;
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, val_node, 1))) return result;
|
||||||
|
compiler->curstack -= 2;
|
||||||
|
if ((result = noomC_emit_ABC(func, NOOMV_INSTR_SETTABLE, table_slot, 0, 0))) return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const noom_bool_t is_last = i == node->subnodec - 1;
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, entry, is_last ? -1 : 1))) return result;
|
||||||
|
if (is_last) {
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_SETLIST, table_slot, (unsigned short)array_idx))) return result;
|
||||||
|
compiler->curstack = table_slot + 1;
|
||||||
|
} else {
|
||||||
|
array_idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_UNARYOPERATOR) {
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result;
|
||||||
|
return noomC_emit_ABC(func, NOOMV_INSTR_OP, 0, noomC_lex_un_op(parser, node->source_offset), 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (node->type == NOOMP_NODE_BINARYOPERATOR) {
|
if (node->type == NOOMP_NODE_BINARYOPERATOR) {
|
||||||
if (node->subnodec != 2) return NOOM_EINTERNAL;
|
if (node->subnodec != 2) return NOOM_EINTERNAL;
|
||||||
const char* op = parser->code + node->source_offset;
|
const char* op = parser->code + node->source_offset;
|
||||||
@@ -228,202 +442,422 @@ static noom_Exit noomC_compile_expr(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compiler->curstack -= amount;
|
compiler->curstack -= (unsigned)amount;
|
||||||
compiler->curstack++;
|
compiler->curstack++;
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_CONCAT, 0, amount - 1);
|
return noomC_emit_AuD(func, NOOMV_INSTR_CONCAT, 0, (unsigned short)(amount - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noom_startswith(op, "and")) {
|
||||||
|
// TODO *yawn*
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noom_startswith(op, "or")) {
|
||||||
|
// TODO *yawn*
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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[0], 1))) return result;
|
||||||
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1], 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
|
// this consumes 2 operands and pushes 1 value, thus having a net stack effect of removing 1 item
|
||||||
compiler->curstack--;
|
compiler->curstack--;
|
||||||
return noomC_emit_ABC(func, NOOMV_INSTR_OP, 1, noomC_what_bop_is_this(parser, node->source_offset), 0);
|
return noomC_emit_ABC(func, NOOMV_INSTR_OP, 1, noomC_lex_bin_op(parser, node->source_offset), 0);
|
||||||
}
|
}
|
||||||
if (node->type == NOOMP_NODE_CALL || node->type == NOOMP_NODE_METHODCALL) {
|
|
||||||
// welcome to multivalue hell
|
if (node->type == NOOMP_NODE_GETFIELD) {
|
||||||
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;
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result;
|
||||||
unsigned char funcIdx = compiler->curstack;
|
noom_uint_t constidx = func->constsize;
|
||||||
|
// 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;
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_GETFIELD, 0, (unsigned short)constidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_INDEX) {
|
||||||
|
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;
|
||||||
|
// FIXME we probably want to move the compiler->curstack here
|
||||||
|
return noomC_emit_ABC(func, NOOMV_INSTR_GETTABLE, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_CALL ||
|
||||||
|
node->type == NOOMP_NODE_METHODCALL ||
|
||||||
|
node->type == NOOMP_NODE_STRINGCALL ||
|
||||||
|
node->type == NOOMP_NODE_TABLECALL ||
|
||||||
|
node->type == NOOMP_NODE_STRINGMETHODCALL ||
|
||||||
|
node->type == NOOMP_NODE_TABLEMETHODCALL) {
|
||||||
|
// welcome to multivalue hell
|
||||||
|
const unsigned char returnToGlory = (unsigned char)compiler->curstack;
|
||||||
|
const noom_bool_t isMethod = node->type == NOOMP_NODE_METHODCALL || node->type == NOOMP_NODE_STRINGMETHODCALL || node->type == NOOMP_NODE_TABLEMETHODCALL;
|
||||||
|
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result;
|
||||||
|
const unsigned char funcIdx = (unsigned char)(compiler->curstack - 1);
|
||||||
|
|
||||||
if (isMethod) {
|
if (isMethod) {
|
||||||
noomP_Node* field = node->subnodes[1];
|
const char* fieldname = parser->code + node->subnodes[1]->source_offset;
|
||||||
const char* fieldname = parser->code + field->source_offset;
|
const noom_uint_t fieldlen = noomL_tokenlen(parser->code, node->subnodes[1]->source_offset, parser->version);
|
||||||
noom_uint_t fieldlen = noomL_tokenlen(fieldname, 0, parser->version);
|
|
||||||
noom_uint_t constidx = func->constsize;
|
noom_uint_t constidx = func->constsize;
|
||||||
if ((result = noomC_addconst_str(compiler, vm, fieldname, fieldlen))) return result;
|
if ((result = noomC_addconst_str(compiler, vm, fieldname, fieldlen))) return result;
|
||||||
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_GETMETHOD, 0, 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;
|
||||||
}
|
}
|
||||||
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_AuD(func, NOOMV_INSTR_CALL, funcIdx, retc + 1);
|
|
||||||
}
|
|
||||||
if (node->type == NOOMP_NODE_VARIABLE) {
|
|
||||||
noomC_LocalInfo info;
|
|
||||||
const char* varname = parser->code + node->source_offset;
|
|
||||||
noom_uint_t namelen = noomL_tokenlen(parser->code, node->source_offset, parser->version);
|
|
||||||
if ((result = noomC_identifyLocal(compiler, &info, varname, namelen))) return result;
|
|
||||||
compiler->curstack++;
|
|
||||||
|
|
||||||
switch (info.type) {
|
// push arguments
|
||||||
case NOOMC_LOCAL:
|
if (node->type == NOOMP_NODE_STRINGCALL || node->type == NOOMP_NODE_TABLECALL) {
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHVAL, 0, info.idx);
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1], 1))) return result;
|
||||||
case NOOMC_UPVAL:
|
} else if (node->type == NOOMP_NODE_STRINGMETHODCALL || node->type == NOOMP_NODE_TABLEMETHODCALL) {
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHUPVAL, 0, info.idx);
|
if (node->subnodec > 2) {
|
||||||
case NOOMC_GLOBAL: {
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[2], 1))) return result;
|
||||||
noom_uint_t constidx = compiler->target->constsize;
|
}
|
||||||
if ((result = noomC_addconst_str(compiler, vm, varname, namelen))) return result;
|
} else {
|
||||||
if (parser->version == NOOM_VERSION_51) {
|
for (noom_uint_t i = isMethod ? 2 : 1; i < node->subnodec; i++) {
|
||||||
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHGLOBAL, 0, constidx);
|
const 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;
|
||||||
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_AuD(func, NOOMV_INSTR_PUSHUPVAL, _ENV.idx, constidx);
|
|
||||||
}
|
|
||||||
// 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 ((result = noomC_emit_AuD(func, NOOMV_INSTR_CALL, funcIdx,( unsigned short)(retc < 0 ? 0 : retc + 1)))) return result;
|
||||||
|
|
||||||
|
if (retc >= 0) {
|
||||||
|
compiler->curstack = returnToGlory + (unsigned)retc;
|
||||||
|
}
|
||||||
|
return NOOM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_LAMBDAFUNCTIONLITERAL) {
|
||||||
|
const noomP_Node* params_node = node->subnodes[0];
|
||||||
|
const noomP_Node* block_node = node->subnodes[1];
|
||||||
|
|
||||||
|
noomV_Function* proto;
|
||||||
|
if ((result = noomC_compile_proto(vm, compiler, parser, func, params_node, block_node, 0, &proto))) return result;
|
||||||
|
|
||||||
|
const unsigned short proto_idx = (unsigned short)(func->protosize - 1);
|
||||||
|
compiler->curstack++;
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_PUSHCLOSURE, 0, proto_idx);
|
||||||
|
}
|
||||||
|
|
||||||
return NOOM_EINTERNAL;
|
return NOOM_EINTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 noomC_compile_block(noom_LuaVM* vm, noomC_Compiler* compiler, const noomP_Parser* parser, noomV_Function* func, const noomP_Node* node) {
|
||||||
|
|
||||||
static noom_Exit noomC_compile_block(noom_LuaVM* vm, noomC_Compiler* compiler, const noomP_Parser* parser, noomV_Function* func, const noomP_Node* node) {
|
|
||||||
noom_Exit r = NOOM_OK;
|
|
||||||
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
||||||
r = noomC_add_stuff_to_function(vm, compiler, parser, func, node->subnodes[i]);
|
noom_Exit r = noomC_add_stuff_to_function(vm, compiler, parser, func, node->subnodes[i]);
|
||||||
if (r != NOOM_OK) break;
|
if (r != NOOM_OK) return r;
|
||||||
}
|
}
|
||||||
return r;
|
return noomC_emit_AuD(func, NOOMV_INSTR_RET, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// They say you use only 10% of your brain
|
// They say you use only 10% of your brain
|
||||||
// Keep it
|
// Keep it
|
||||||
// If you think too much you will get headaches
|
// If you think too much you will get headaches
|
||||||
|
|
||||||
// I remember atom said there is a memory leak somewhere but I don't rememeememember where uhhhhhhhhhhhhhhhhh
|
noom_Exit noomC_add_stuff_to_function(noom_LuaVM* vm, noomC_Compiler* compiler, const noomP_Parser* parser, noomV_Function* func, const noomP_Node* node) {
|
||||||
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;
|
noom_Exit result;
|
||||||
// local name <attr> = expression
|
|
||||||
|
// local name1, name2 <attr> = expr1, expr2, ...
|
||||||
if (node->type == NOOMP_NODE_LOCALDECLARATION) {
|
if (node->type == NOOMP_NODE_LOCALDECLARATION) {
|
||||||
// FIXME: there can be multiple locals defined
|
// [VARNAME..., expr...]
|
||||||
// This code is awful for several reasons and we shall burn it
|
noom_uint_t name_count = 0;
|
||||||
// :(
|
while (name_count < node->subnodec && node->subnodes[name_count]->type == NOOMP_NODE_VARNAME) name_count++;
|
||||||
if (node->subnodec != 1 && node->subnodec != 2) return NOOM_EINTERNAL;
|
noom_uint_t value_count = node->subnodec - name_count;
|
||||||
|
|
||||||
const noomP_Node* varname_node = node->subnodes[0];
|
unsigned int base_slot = compiler->curstack;
|
||||||
if (varname_node->type != NOOMP_NODE_ASSIGNPLACE) return NOOM_EINTERNAL;
|
|
||||||
|
|
||||||
const char* namebuf = parser->code + varname_node->source_offset;
|
for (noom_uint_t i = 0; i < value_count; i++) {
|
||||||
|
noom_bool_t is_last = i == value_count - 1;
|
||||||
|
int wanted = is_last ? (int)(name_count - i) : 1;
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[name_count + i], wanted))) return result;
|
||||||
|
}
|
||||||
|
|
||||||
noomC_Local local;
|
for (noom_uint_t i = 0; i < name_count; i++) {
|
||||||
local.startpc = func->codesize;
|
const noomP_Node* varname_node = node->subnodes[i];
|
||||||
local.endpc = 0;
|
const noom_uint_t length = noomL_tokenlen(parser->code, varname_node->source_offset, parser->version);
|
||||||
local.dropped = 0;
|
|
||||||
local.close = 0;
|
|
||||||
local.constant = 0;
|
|
||||||
local.name = namebuf;
|
|
||||||
local.namelen = noomL_tokenlen(namebuf, 0, parser->version);
|
|
||||||
|
|
||||||
for (noom_uint_t i = 0; i < varname_node->subnodec; i++) {
|
noomC_Local local;
|
||||||
if (varname_node->subnodes[i]->type != NOOMP_NODE_ATTRIBUTE) return NOOM_EINTERNAL;
|
local.startpc = func->codesize;
|
||||||
|
local.endpc = 0;
|
||||||
|
local.name = parser->code + varname_node->source_offset;
|
||||||
|
local.namelen = length;
|
||||||
|
local.stackslot = base_slot + i;
|
||||||
|
local.dropped = 0;
|
||||||
|
local.constant = 0;
|
||||||
|
local.close = 0;
|
||||||
|
|
||||||
noomL_Token attr_token = noomC_token_at(parser, varname_node->subnodes[i]->source_offset);
|
for (noom_uint_t ai = 1; ai < varname_node->subnodec; ai++) {
|
||||||
const char* ap = parser->code + attr_token.offset;
|
noom_uint_t offset = varname_node->subnodes[ai]->source_offset;
|
||||||
noom_uint_t al = attr_token.length;
|
noom_uint_t alength = noomL_tokenlen(parser->code, offset, parser->version);
|
||||||
if (noom_memeq(ap, al, "close", 5)) {
|
const char* ap = parser->code + offset;
|
||||||
if (local.close) return NOOM_EINTERNAL;
|
noom_uint_t al = alength;
|
||||||
local.close = 1;
|
if (noom_memeq(ap, al, "close", 5)) {
|
||||||
} else if (noom_memeq(ap, al, "const", 5)) {
|
if (local.close) return NOOM_EINTERNAL;
|
||||||
if (local.constant) return NOOM_EINTERNAL;
|
local.close = 1;
|
||||||
local.constant = 1;
|
} else if (noom_memeq(ap, al, "const", 5)) {
|
||||||
} else {
|
if (local.constant) return NOOM_EINTERNAL;
|
||||||
return NOOM_EINTERNAL;
|
local.constant = 1;
|
||||||
|
} else {
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((result = noomC_addLocal(compiler, local))) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned destination = compiler->curstack;
|
return NOOM_OK;
|
||||||
if (compiler->curstack++ == NOOM_MAXSTACK) return NOOM_ENOSTACK;
|
|
||||||
|
|
||||||
if (node->subnodec == 1) {
|
|
||||||
const unsigned short constptr = func->constsize;
|
|
||||||
result = noomC_emit_AuD(func, NOOMV_INSTR_PUSHNIL, 0, 0);
|
|
||||||
if (result != NOOM_OK) return result;
|
|
||||||
compiler->curstack++;
|
|
||||||
} else {
|
|
||||||
const noomP_Node* value_node = node->subnodes[1];
|
|
||||||
const noom_Exit r = noomC_compile_expr(vm, compiler, parser, func, value_node, 1);
|
|
||||||
if (r != NOOM_OK) return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
local.stackslot = compiler->curstack;
|
|
||||||
|
|
||||||
return noomC_addLocal(compiler, local);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// local function name(...) ... end
|
// local function name(...) ... end
|
||||||
if (node->type == NOOMP_NODE_LOCALFUNCTIONDECLARATION) {
|
if (node->type == NOOMP_NODE_LOCALFUNCTIONDECLARATION) {
|
||||||
if (node->subnodec != 3) return NOOM_EINTERNAL;
|
if (node->subnodec != 3) return NOOM_EINTERNAL;
|
||||||
// Funny staircase huh
|
// Funny staircase huh
|
||||||
|
// please autoformatter be a good boy or a good girl or something don't remove it :(
|
||||||
|
// be a good person.
|
||||||
const noomP_Node* varname_node = node->subnodes[0];
|
const noomP_Node* varname_node = node->subnodes[0];
|
||||||
const noomP_Node* params_node = node->subnodes[1];
|
const noomP_Node* params_node = node->subnodes[1];
|
||||||
const noomP_Node* block_node = node->subnodes[2];
|
const noomP_Node* block_node = node->subnodes[2];
|
||||||
if (varname_node->type != NOOMP_NODE_VARNAME) return NOOM_EINTERNAL;
|
if (varname_node->type != NOOMP_NODE_VARNAME) return NOOM_EINTERNAL;
|
||||||
if (params_node->type != NOOMP_NODE_FUNCTIONPARAMETERS) return NOOM_EINTERNAL;
|
if (params_node->type != NOOMP_NODE_FUNCTIONPARAMETERS) return NOOM_EINTERNAL;
|
||||||
if (block_node->type != NOOMP_NODE_BLOCK) return NOOM_EINTERNAL;
|
if (block_node->type != NOOMP_NODE_BLOCK) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
const noomL_Token name_token = noomC_token_at(parser, varname_node->source_offset);
|
noom_uint_t length = noomL_tokenlen(parser->code, varname_node->source_offset, parser->version);
|
||||||
noomV_Function* proto = noomV_allocFunc(vm, func->chunkname);
|
unsigned int self_slot = compiler->curstack++;
|
||||||
if (proto == 0) return NOOM_ENOMEM;
|
|
||||||
|
|
||||||
proto->argc = (unsigned char)params_node->subnodec;
|
noomV_Function* proto;
|
||||||
|
if ((result = noomC_compile_proto(vm, compiler, parser, func, params_node, block_node, 0, &proto))) return result;
|
||||||
|
|
||||||
noomC_Compiler child;
|
unsigned short proto_idx = (unsigned short)(func->protosize - 1);
|
||||||
noomC_compiler_init(&child);
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_PUSHCLOSURE, (unsigned char)self_slot, proto_idx))) return result;
|
||||||
child.parent = compiler; // Is this correct????? Is this correct????????????????? It probably is
|
|
||||||
child.curstack = proto->argc;
|
|
||||||
|
|
||||||
const noom_Exit result = noomC_compile_block(vm, &child, parser, proto, block_node);
|
|
||||||
if (result != NOOM_OK) return result;
|
|
||||||
|
|
||||||
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;
|
noomC_Local local;
|
||||||
local.startpc = proto->codesize;
|
local.startpc = proto->codesize;
|
||||||
local.endpc = 0;
|
local.endpc = 0;
|
||||||
local.dropped = 0;
|
|
||||||
local.close = 0;
|
|
||||||
local.constant = 0;
|
|
||||||
local.name = parser->code + varname_node->source_offset;
|
local.name = parser->code + varname_node->source_offset;
|
||||||
local.namelen = noomL_tokenlen(parser->code, varname_node->source_offset, parser->version);
|
local.namelen = length;
|
||||||
|
local.stackslot = self_slot;
|
||||||
|
local.dropped = 0;
|
||||||
|
local.constant = 0;
|
||||||
|
local.close = 0;
|
||||||
|
|
||||||
return noomC_addLocal(compiler, local);
|
return noomC_addLocal(compiler, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// function shit.mp3.opus:method(...) ... end
|
||||||
if (node->type == NOOMP_NODE_RETURN) {
|
if (node->type == NOOMP_NODE_FUNCTIONDECLARATION) {
|
||||||
noomC_emit_AuD(func, NOOMV_INSTR_NOP, 0, 0);
|
// [FUNCTION_NAME[FIELDNAME..., METHODNAME?], FUNCTIONPARAMETERS[VARNAME...], BLOCK
|
||||||
|
if (node->subnodec != 3) return NOOM_EINTERNAL;
|
||||||
|
const noomP_Node* fname_node = node->subnodes[0];
|
||||||
|
const noomP_Node* params_node = node->subnodes[1];
|
||||||
|
const noomP_Node* block_node = node->subnodes[2];
|
||||||
|
|
||||||
|
noom_bool_t has_self = 0;
|
||||||
|
if (fname_node->subnodec > 0) {
|
||||||
|
const noomP_Node* last = fname_node->subnodes[fname_node->subnodec - 1];
|
||||||
|
if (last->type == NOOMP_NODE_METHODNAME) has_self = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
noomV_Function* proto;
|
||||||
|
if ((result = noomC_compile_proto(vm, compiler, parser, func, params_node, block_node, has_self, &proto))) return result;
|
||||||
|
|
||||||
|
unsigned short proto_idx = (unsigned short)(func->protosize - 1);
|
||||||
|
compiler->curstack++;
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_PUSHCLOSURE, 0, proto_idx))) return result;
|
||||||
|
|
||||||
|
// now assign it uhhh
|
||||||
|
if (fname_node->subnodec == 0) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
noom_uint_t chain_len = fname_node->subnodec;
|
||||||
|
|
||||||
|
if (chain_len == 1) {
|
||||||
|
// function foo() => assign closure to global foo
|
||||||
|
// TODO the fuck i look i know
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
} else {
|
||||||
|
// TODO idk either
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler->curstack--;
|
||||||
return NOOM_OK;
|
return NOOM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return expr1, expr2, ...
|
||||||
|
if (node->type == NOOMP_NODE_RETURN) {
|
||||||
|
if (node->subnodec == 0) {
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_RET, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char base_slot = (unsigned char)compiler->curstack;
|
||||||
|
|
||||||
|
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
||||||
|
noom_bool_t is_last = i == node->subnodec - 1;
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[i], is_last ? -1 : 1))) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_RET, base_slot, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// a, b.c, d[e] = expr1, expr2, ...
|
||||||
|
if (node->type == NOOMP_NODE_ASSIGNMENT) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
unsigned char value_base = (unsigned char)compiler->curstack;
|
||||||
|
for (noom_uint_t i = 0; i < value_count; i++) {
|
||||||
|
noom_bool_t is_last = i == value_count - 1;
|
||||||
|
int wanted = is_last ? (int)(place_count - i) : 1;
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[place_count + i], wanted))) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = (int)place_count - 1; i >= 0; i--) {
|
||||||
|
unsigned char val_slot = (unsigned char)(value_base + i);
|
||||||
|
const noomP_Node* target = node->subnodes[i]->subnodes[0];
|
||||||
|
if ((result = noomC_emit_assign_to(vm, compiler, parser, func, target, val_slot))) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler->curstack = value_base;
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if cond then block [elseif cond then block]... [else block] end
|
||||||
|
if (node->type == NOOMP_NODE_IFSTATEMENT) {
|
||||||
|
// [cond, block, cond, block, ..., block (else, no condition)]
|
||||||
|
|
||||||
|
noom_uint_t* end_jumps = noom_alloc(sizeof(noom_uint_t) * (node->subnodec / 2 + 1));
|
||||||
|
if (end_jumps == 0) return NOOM_ENOMEM;
|
||||||
|
noom_uint_t end_jump_count = 0;
|
||||||
|
|
||||||
|
noom_uint_t i = 0;
|
||||||
|
while (i < node->subnodec) {
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[i], 1)) != NOOM_OK) {
|
||||||
|
noom_free(end_jumps);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
compiler->curstack--;
|
||||||
|
|
||||||
|
noom_uint_t cond_jmp = func->codesize;
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_CNJMP, 0, 0)) != NOOM_OK) {
|
||||||
|
noom_free(end_jumps);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result = noomC_compile_block(vm, compiler, parser, func, node->subnodes[i + 1])) != NOOM_OK) {
|
||||||
|
noom_free(end_jumps);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there's more, jump over the remaining branches.
|
||||||
|
if (i + 2 < node->subnodec) {
|
||||||
|
end_jumps[end_jump_count++] = func->codesize;
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_JMP, 0, 0)) != NOOM_OK) {
|
||||||
|
noom_free(end_jumps);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func->code[cond_jmp].us = (unsigned short)func->codesize;
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else
|
||||||
|
if (i < node->subnodec) {
|
||||||
|
if ((result = noomC_compile_block(vm, compiler, parser, func, node->subnodes[i])) != NOOM_OK) {
|
||||||
|
noom_free(end_jumps);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (noom_uint_t j = 0; j < end_jump_count; j++) {
|
||||||
|
func->code[end_jumps[j]].us = (unsigned short)func->codesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
noom_free(end_jumps);
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// while cond do block end
|
||||||
|
if (node->type == NOOMP_NODE_WHILELOOP) {
|
||||||
|
// [condition, block]
|
||||||
|
if (node->subnodec != 2) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
noom_uint_t loop_start = func->codesize;
|
||||||
|
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0], 1))) return result;
|
||||||
|
compiler->curstack--;
|
||||||
|
|
||||||
|
noom_uint_t exit_jmp = func->codesize;
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_CNJMP, 0, 0))) return result;
|
||||||
|
if ((result = noomC_compile_block(vm, compiler, parser, func, node->subnodes[1]))) return result;
|
||||||
|
if ((result = noomC_emit_AuD(func, NOOMV_INSTR_JMP, 0, (unsigned short)loop_start))) return result;
|
||||||
|
func->code[exit_jmp].us = (unsigned short)func->codesize;
|
||||||
|
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat block until cond
|
||||||
|
if (node->type == NOOMP_NODE_REPEAT) {
|
||||||
|
// [block, cond]
|
||||||
|
if (node->subnodec != 2) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
noom_uint_t loop_start = func->codesize;
|
||||||
|
|
||||||
|
if ((result = noomC_compile_block(vm, compiler, parser, func, node->subnodes[0]))) return result;
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1], 1))) return result;
|
||||||
|
compiler->curstack--;
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_CNJMP, 0, (unsigned short)loop_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for i = start, stop [, step] do block end
|
||||||
|
if (node->type == NOOMP_NODE_FORLOOP) {
|
||||||
|
// [VARNAME, start, stop, step?, BLOCK]
|
||||||
|
noom_uint_t value_count = node->subnodec - 2;
|
||||||
|
|
||||||
|
for (noom_uint_t i = 1; i <= value_count; i++) {
|
||||||
|
if ((result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[i], 1))) return result;
|
||||||
|
}
|
||||||
|
// TODO i don't want to bother doing this
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for k, v in expr do block end
|
||||||
|
if (node->type == NOOMP_NODE_FORLOOPIN) {
|
||||||
|
// todo nah bro
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// break
|
||||||
|
if (node->type == NOOMP_NODE_BREAK) {
|
||||||
|
// TODO
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_NOP, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// goto label
|
||||||
|
if (node->type == NOOMP_NODE_GOTO) {
|
||||||
|
// TODO
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_NOP, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ::label::
|
||||||
|
if (node->type == NOOMP_NODE_LABEL) {
|
||||||
|
// TODO
|
||||||
|
return noomC_emit_AuD(func, NOOMV_INSTR_NOP, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (node->type == NOOMP_NODE_DOBLOCK || node->type == NOOMP_NODE_BLOCK) {
|
if (node->type == NOOMP_NODE_DOBLOCK || node->type == NOOMP_NODE_BLOCK) {
|
||||||
return noomC_compile_block(vm, compiler, parser, func, node);
|
return noomC_compile_block(vm, compiler, parser, func, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == NOOMP_NODE_CALL || node->type == NOOMP_NODE_METHODCALL) {
|
if (node->type == NOOMP_NODE_CALL ||
|
||||||
|
node->type == NOOMP_NODE_METHODCALL ||
|
||||||
|
node->type == NOOMP_NODE_STRINGCALL ||
|
||||||
|
node->type == NOOMP_NODE_TABLECALL ||
|
||||||
|
node->type == NOOMP_NODE_STRINGMETHODCALL ||
|
||||||
|
node->type == NOOMP_NODE_TABLEMETHODCALL) {
|
||||||
return noomC_compile_expr(vm, compiler, parser, func, node, 0);
|
return noomC_compile_expr(vm, compiler, parser, func, node, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,48 @@ typedef struct noomC_Compiler {
|
|||||||
noomC_Upval upvals[NOOMC_MAXUPVAL];
|
noomC_Upval upvals[NOOMC_MAXUPVAL];
|
||||||
} noomC_Compiler;
|
} 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_init(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);
|
||||||
|
|
||||||
|
static noom_Exit noomC_compile_proto(
|
||||||
|
noom_LuaVM* vm,
|
||||||
|
noomC_Compiler* parent_compiler,
|
||||||
|
const noomP_Parser* parser,
|
||||||
|
noomV_Function* parent_func,
|
||||||
|
const noomP_Node* params_node,
|
||||||
|
const noomP_Node* block_node,
|
||||||
|
noom_bool_t has_self,
|
||||||
|
noomV_Function** out_proto);
|
||||||
|
noom_Exit noomC_emit_assign_to(
|
||||||
|
noom_LuaVM* vm,
|
||||||
|
noomC_Compiler* compiler,
|
||||||
|
const noomP_Parser* parser,
|
||||||
|
noomV_Function* func,
|
||||||
|
const noomP_Node* target,
|
||||||
|
unsigned char value_slot);
|
||||||
|
noom_Exit noomC_compile_expr(
|
||||||
|
noom_LuaVM* vm,
|
||||||
|
noomC_Compiler* compiler,
|
||||||
|
const noomP_Parser* parser,
|
||||||
|
noomV_Function* func,
|
||||||
|
const noomP_Node* node,
|
||||||
|
// retc of -1 means all values!!!!!!!!!!!
|
||||||
|
int retc);
|
||||||
|
noom_Exit noomC_compile_block(noom_LuaVM* vm, noomC_Compiler* compiler, const noomP_Parser* parser, noomV_Function* func, const noomP_Node* node);
|
||||||
|
noom_Exit noomC_add_stuff_to_function(noom_LuaVM* vm, noomC_Compiler* compiler, const noomP_Parser* parser, noomV_Function* func, const noomP_Node* node);
|
||||||
|
|
||||||
// pushes the compiled function on the stack, or just crashes lol
|
// 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, noomV_Value* outFunc);
|
noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_Node* node, noomV_String* chunkname, noomV_Table* env, noomV_Value* outFunc);
|
||||||
|
|||||||
34
src/helper.c
34
src/helper.c
@@ -2,33 +2,32 @@
|
|||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "noom.h"
|
#include "noom.h"
|
||||||
|
|
||||||
double noom_strtod(const char* s, const char** endptr, int* error) {
|
// TODO make it actually output integers if the lua version allows that uhhhhh
|
||||||
|
noomV_Value noom_tonumber_except_different_name_so_public_fucking_api_works(const char* s, const char** endptr, noom_LuaVersion luauauauaua) {
|
||||||
// Num???? Is that a fucking noom reference???????
|
// Num???? Is that a fucking noom reference???????
|
||||||
double num = 0.0;
|
noom_float_t num = 0.0;
|
||||||
|
|
||||||
int error_but_different = 1;
|
|
||||||
|
|
||||||
const noom_bool_t negative = *s == '-';
|
const noom_bool_t negative = *s == '-';
|
||||||
if (*s == '-' || *s == '+')
|
if (*s == '-' || *s == '+')
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
if (!noomL_isnumber(s[*s == '.'])) goto fuck;
|
if (!noomL_isnumber(s[*s == '.'])) return (noomV_Value){ .tag = NOOMV_VNIL };
|
||||||
|
|
||||||
if (*s == '0' && noomL_lower(s[1]) == 'x') {
|
if (*s == '0' && noomL_lower(s[1]) == 'x') {
|
||||||
s += 2;
|
s += 2;
|
||||||
// if the string starts with "0x" but does not contain digits it's invalid
|
// if the string starts with "0x" but does not contain digits it's invalid
|
||||||
noom_bool_t are_we_cooked = 1;
|
noom_bool_t error = 1;
|
||||||
while (noomL_ishex(*s)) {
|
while (noomL_ishex(*s)) {
|
||||||
int digit;
|
int digit;
|
||||||
if (noomL_isnumber(*s)) digit = *s - '0';
|
if (noomL_isnumber(*s)) digit = *s - '0';
|
||||||
else digit = noomL_lower(*s) - 'a' + 10;
|
else digit = noomL_lower(*s) - 'a' + 10;
|
||||||
|
|
||||||
num = num * 16.0 + digit;
|
num = num * 16.0 + digit;
|
||||||
are_we_cooked = 0;
|
error = 0;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (are_we_cooked) goto fuck;
|
if (error) return (noomV_Value){ .tag = NOOMV_VNIL };
|
||||||
|
|
||||||
if (noomL_lower(*s) == 'p') {
|
if (noomL_lower(*s) == 'p') {
|
||||||
// damn then
|
// damn then
|
||||||
@@ -38,8 +37,8 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
|
|||||||
if (*s == '-' || *s == '+')
|
if (*s == '-' || *s == '+')
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
if (!noomL_isnumber(*s)) goto fuck;
|
if (!noomL_isnumber(*s)) return (noomV_Value){ .tag = NOOMV_VNIL };
|
||||||
|
|
||||||
while (noomL_isnumber(*s)) {
|
while (noomL_isnumber(*s)) {
|
||||||
exponent = exponent * 10 + (*s - '0');
|
exponent = exponent * 10 + (*s - '0');
|
||||||
s++;
|
s++;
|
||||||
@@ -48,10 +47,10 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
|
|||||||
num *= noom_pow(2.0, exponent_negative ? -exponent : exponent);
|
num *= noom_pow(2.0, exponent_negative ? -exponent : exponent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
noom_bool_t are_we_cooked = 1;
|
noom_bool_t error = 1;
|
||||||
while (noomL_isnumber(*s)) {
|
while (noomL_isnumber(*s)) {
|
||||||
num = num * 10.0 + (*s - '0');
|
num = num * 10.0 + (*s - '0');
|
||||||
are_we_cooked = 0;
|
error = 0;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
if (*s == '.') {
|
if (*s == '.') {
|
||||||
@@ -59,13 +58,13 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
|
|||||||
|
|
||||||
double fraction_divisor = 10.0;
|
double fraction_divisor = 10.0;
|
||||||
while (noomL_isnumber(*s)) {
|
while (noomL_isnumber(*s)) {
|
||||||
are_we_cooked = 0;
|
error = 0;
|
||||||
num += (double)(*s - '0') / fraction_divisor;
|
num += (double)(*s - '0') / fraction_divisor;
|
||||||
fraction_divisor *= 10.0;
|
fraction_divisor *= 10.0;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (are_we_cooked) goto fuck;
|
if (error) return (noomV_Value){ .tag = NOOMV_VNIL };
|
||||||
|
|
||||||
if (noomL_lower(*s) == 'e') {
|
if (noomL_lower(*s) == 'e') {
|
||||||
s++;
|
s++;
|
||||||
@@ -74,7 +73,7 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
|
|||||||
if (*s == '-' || *s == '+')
|
if (*s == '-' || *s == '+')
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
if (!noomL_isnumber(*s)) goto fuck;
|
if (!noomL_isnumber(*s)) return (noomV_Value){ .tag = NOOMV_VNIL };
|
||||||
|
|
||||||
while (noomL_isnumber(*s)) {
|
while (noomL_isnumber(*s)) {
|
||||||
exponent = exponent * 10 + (*s - '0');
|
exponent = exponent * 10 + (*s - '0');
|
||||||
@@ -85,11 +84,8 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error_but_different = 0;
|
|
||||||
fuck:
|
|
||||||
if (endptr) *endptr = s;
|
if (endptr) *endptr = s;
|
||||||
if (error) *error = error_but_different;
|
return (noomV_Value){ .tag = NOOMV_VNUM, .number = negative ? -num : num };
|
||||||
return negative ? -num : num;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// made by some stranger on stack overflow
|
// made by some stranger on stack overflow
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#include "noom.h"
|
#include "noom.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
#define NOOM_USHORT_MAX 0xffff
|
#define NOOM_USHORT_MAX 0xffff
|
||||||
|
|
||||||
// isn't quite strtod, is it
|
noomV_Value noom_tonumber_except_different_name_so_public_fucking_api_works(const char* s, const char** endptr, noom_LuaVersion luauauauaua);
|
||||||
// doesn't skip whitespace unlike actual C stdlib strtod!!!!
|
|
||||||
double noom_strtod(const char* s, const char** endptr, int* error);
|
|
||||||
double noom_pow(double x, int y);
|
double noom_pow(double x, int y);
|
||||||
|
|
||||||
int noom_startswith(const char* str, const char* compare);
|
int noom_startswith(const char* str, const char* compare);
|
||||||
|
|||||||
214
src/main.c
214
src/main.c
@@ -27,120 +27,145 @@ void print_node(const noomP_Node* node, noom_uint_t depth) {
|
|||||||
tab(depth + 1);
|
tab(depth + 1);
|
||||||
printf("location: %lld\n", node->source_offset);
|
printf("location: %lld\n", node->source_offset);
|
||||||
|
|
||||||
tab(depth + 1);
|
if (node->subnodec > 0) {
|
||||||
printf("subnodes:\n");
|
tab(depth + 1);
|
||||||
|
printf("subnodes (%llu):\n", node->subnodec);
|
||||||
|
|
||||||
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
||||||
print_node(node->subnodes[i], depth + 1);
|
print_node(node->subnodes[i], depth + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tab(depth);
|
tab(depth);
|
||||||
printf("}\n");
|
printf("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pretty(const char* code, noom_LuaVersion version, const noomP_Node* node, noom_uint_t indent) {
|
||||||
|
for (noom_uint_t i = 0; i < indent; i++) putchar('\t');
|
||||||
|
const noom_uint_t len = noomL_tokenlen(code, node->source_offset, version);
|
||||||
|
char* fuckoff = code;
|
||||||
|
const char c = fuckoff[node->source_offset + len];
|
||||||
|
fuckoff[node->source_offset + len] = '\0';
|
||||||
|
printf("%*s%s %s", (int)len, code + node->source_offset, code[node->source_offset] != '\0' ? " -" : "", noomP_formatNodeType(node->type));
|
||||||
|
fuckoff[node->source_offset + len] = c;
|
||||||
|
if (node->subnodec) {
|
||||||
|
printf(" with %lld entr%s {\n", node->subnodec, node->subnodec == 1 ? "y" : "ies");
|
||||||
|
for (int i = 0; i < node->subnodec; i++) {
|
||||||
|
pretty(code, version, node->subnodes[i], indent + 1);
|
||||||
|
}
|
||||||
|
for (noom_uint_t i = 0; i < indent; i++) putchar('\t');
|
||||||
|
putchar('}');
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// #define LEX_OUTPUT
|
||||||
|
#define PARSE_OUTPUT
|
||||||
|
#define COMPILER_OUTPUT
|
||||||
|
|
||||||
int execute(const char* code, noom_LuaVersion version, const char* program_name, const char* filename) {
|
int execute(const char* code, noom_LuaVersion version, const char* program_name, const char* filename) {
|
||||||
noomP_Parser parser;
|
noomP_Parser parser;
|
||||||
noomP_Node* program;
|
noomP_Node* program;
|
||||||
|
|
||||||
// goodbye "shitass" you will be missed
|
if (noomP_parse(code, filename, version, &program, &parser) < 0) {
|
||||||
int success = noomP_parse(code, filename, version, &program, &parser);
|
const noom_uint_t bleh = noom_format_error(&parser, program_name, NULL, 0);
|
||||||
if (success == 0) {
|
|
||||||
puts("LEX OUTPUT:");
|
|
||||||
fputs("\x1b[48;2;10;10;10m", stdout);
|
|
||||||
noom_uint_t pos = 0;
|
|
||||||
while (1) {
|
|
||||||
noomL_Token token;
|
|
||||||
|
|
||||||
noomL_ErrorType err = noomL_lex(code, pos, &token, version);
|
|
||||||
if (err) break;
|
|
||||||
|
|
||||||
if (token.type == NOOML_TOKEN_KEYWORD) {
|
|
||||||
fputs("\x1b[38;2;207;142;109m", stdout);
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
} else if (token.type == NOOML_TOKEN_WHITESPACE) {
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
} else if (token.type == NOOML_TOKEN_IDENTIFIER) {
|
|
||||||
fputs("\x1b[38;2;255;255;255m", stdout);
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
} else if (token.type == NOOML_TOKEN_SYMBOL) {
|
|
||||||
fputs("\x1b[38;2;0;255;255m", stdout);
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
} else if (token.type == NOOML_TOKEN_STRING) {
|
|
||||||
fputs("\x1b[38;2;255;0;0m", stdout);
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
} else if (token.type == NOOML_TOKEN_NUMBER) {
|
|
||||||
fputs("\x1b[38;2;0;255;0m", stdout);
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
} else {
|
|
||||||
fputs("\x1b[0m\n", stdout);
|
|
||||||
printf("%s ", noomL_formatTokenType(token.type));
|
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
|
||||||
fputs("\x1b[48;2;10;10;10m", stdout);
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += token.length;
|
|
||||||
|
|
||||||
if (token.type == NOOML_TOKEN_EOF) break;
|
|
||||||
}
|
|
||||||
puts("\x1b[0m");
|
|
||||||
puts("PARSE OUTPUT:");
|
|
||||||
print_node(program, 0);
|
|
||||||
} else {
|
|
||||||
noom_uint_t bleh = noom_format_error(&parser, program_name, NULL, 0);
|
|
||||||
char* buf = noom_alloc(bleh);
|
char* buf = noom_alloc(bleh);
|
||||||
noom_format_error(&parser, program_name, buf, bleh);
|
noom_format_error(&parser, program_name, buf, bleh);
|
||||||
fputs(buf, stdout);
|
fputs(buf, stdout);
|
||||||
|
noomP_freeNode(parser.last_node);
|
||||||
noom_free(buf);
|
noom_free(buf);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LEX_OUTPUT
|
||||||
|
puts("LEX OUTPUT:");
|
||||||
|
fputs("\x1b[48;2;10;10;10m", stdout);
|
||||||
|
noom_uint_t pos = 0;
|
||||||
|
while (1) {
|
||||||
|
noomL_Token token;
|
||||||
|
|
||||||
// freeing time
|
noomL_ErrorType err = noomL_lex(code, pos, &token, version);
|
||||||
noomP_Node* last_node = parser.last_node;
|
if (err) break;
|
||||||
while (last_node) {
|
|
||||||
noomP_Node* next = last_node->previous_node;
|
|
||||||
// subnodes could be null if we OOM'd during a realloc of it
|
|
||||||
if (last_node->subnodes) noom_free(last_node->subnodes);
|
|
||||||
noom_free(last_node);
|
|
||||||
last_node = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
if (token.type == NOOML_TOKEN_KEYWORD) {
|
||||||
noom_LuaVM* vm = noom_createVM(version);
|
fputs("\x1b[38;2;207;142;109m", stdout);
|
||||||
noomV_Value peak;
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
|
} else if (token.type == NOOML_TOKEN_WHITESPACE) {
|
||||||
noom_Exit e = noomC_compile(vm, &parser, program, 0, 0, &peak);
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
if (e) {
|
} else if (token.type == NOOML_TOKEN_IDENTIFIER) {
|
||||||
printf("error: %d\n", e);
|
fputs("\x1b[38;2;255;255;255m", stdout);
|
||||||
return 1;
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
|
} else if (token.type == NOOML_TOKEN_SYMBOL) {
|
||||||
|
fputs("\x1b[38;2;0;255;255m", stdout);
|
||||||
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
|
} else if (token.type == NOOML_TOKEN_STRING) {
|
||||||
|
fputs("\x1b[38;2;255;0;0m", stdout);
|
||||||
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
|
} else if (token.type == NOOML_TOKEN_NUMBER) {
|
||||||
|
fputs("\x1b[38;2;0;255;0m", stdout);
|
||||||
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
|
} else {
|
||||||
|
fputs("\x1b[0m\n", stdout);
|
||||||
|
printf("%s ", noomL_formatTokenType(token.type));
|
||||||
|
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
||||||
|
fputs("\x1b[48;2;10;10;10m", stdout);
|
||||||
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
noomV_Function* f = (noomV_Function*)peak.obj;
|
pos += token.length;
|
||||||
|
|
||||||
for (int i = 0; i < f->codesize; i++) {
|
if (token.type == NOOML_TOKEN_EOF) break;
|
||||||
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_NONE:
|
|
||||||
break;
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
noom_destroyVM(vm);
|
|
||||||
}
|
}
|
||||||
|
puts("\x1b[0m");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PARSE_OUTPUT
|
||||||
|
puts("PARSE OUTPUT:");
|
||||||
|
pretty(code, version, program, 0);
|
||||||
|
//print_node(program, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
return success;
|
noom_LuaVM* vm = noom_createVM(version);
|
||||||
|
noomV_Value peak;
|
||||||
|
|
||||||
|
const noom_Exit e = noomC_compile(vm, &parser, program, 0, 0, &peak);
|
||||||
|
if (e) {
|
||||||
|
printf("error: %d\n", e);
|
||||||
|
noomP_freeNode(parser.last_node);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
noomP_freeNode(parser.last_node);
|
||||||
|
|
||||||
|
#ifdef COMPILER_OUTPUT
|
||||||
|
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_NONE:
|
||||||
|
break;
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
noom_destroyVM(vm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* read_file(const char* filename) {
|
static char* read_file(const char* filename) {
|
||||||
@@ -264,6 +289,8 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
params.script_exec = argv[i];
|
params.script_exec = argv[i];
|
||||||
params.do_i_already_know_what_to_do = 1;
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[i][1] == 'l') {
|
if (argv[i][1] == 'l') {
|
||||||
@@ -276,6 +303,7 @@ int main(int argc, char** argv) {
|
|||||||
goto die;
|
goto die;
|
||||||
}
|
}
|
||||||
version_string = argv[i];
|
version_string = argv[i];
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
if (noom_strcmp(version_string, "51") == 0) params.lua_version = NOOM_VERSION_51;
|
if (noom_strcmp(version_string, "51") == 0) params.lua_version = NOOM_VERSION_51;
|
||||||
else if (noom_strcmp(version_string, "52") == 0) params.lua_version = NOOM_VERSION_52;
|
else if (noom_strcmp(version_string, "52") == 0) params.lua_version = NOOM_VERSION_52;
|
||||||
@@ -297,12 +325,14 @@ int main(int argc, char** argv) {
|
|||||||
goto die;
|
goto die;
|
||||||
}
|
}
|
||||||
if (params.lua_version != 0) {
|
if (params.lua_version != 0) {
|
||||||
params.lua_version = NOOM_VERSION_54;
|
|
||||||
if (!params.do_i_already_know_what_to_do) {
|
if (!params.do_i_already_know_what_to_do) {
|
||||||
params.enter_repl = 1;
|
params.enter_repl = 1;
|
||||||
params.do_i_already_know_what_to_do = 1;
|
params.do_i_already_know_what_to_do = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (params.lua_version == 0) {
|
||||||
|
params.lua_version = NOOM_VERSION_54;
|
||||||
|
}
|
||||||
if (!params.do_i_already_know_what_to_do) {
|
if (!params.do_i_already_know_what_to_do) {
|
||||||
err = "script not set";
|
err = "script not set";
|
||||||
goto die;
|
goto die;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ typedef enum noom_Exit {
|
|||||||
NOOM_EERROR,
|
NOOM_EERROR,
|
||||||
} noom_Exit;
|
} noom_Exit;
|
||||||
|
|
||||||
|
// shouldn't this go to vm.h....?
|
||||||
typedef enum noom_UnaryOp {
|
typedef enum noom_UnaryOp {
|
||||||
// -x
|
// -x
|
||||||
NOOM_UNARY_NEGATE,
|
NOOM_UNARY_NEGATE,
|
||||||
|
|||||||
10
src/parser.c
10
src/parser.c
@@ -1806,3 +1806,13 @@ int noomP_initParser(noomP_Parser* parser, const char* code, const char* filenam
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void noomP_freeNode(noomP_Node* node) {
|
||||||
|
while (node) {
|
||||||
|
noomP_Node* next = node->previous_node;
|
||||||
|
// subnodes could be null if we OOM'd during a realloc of it
|
||||||
|
if (node->subnodes) noom_free(node->subnodes);
|
||||||
|
noom_free(node);
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -171,5 +171,6 @@ 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_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);
|
int noomP_initParser(noomP_Parser* parser, const char* code, const char* filename, noom_LuaVersion version);
|
||||||
|
void noomP_freeNode(noomP_Node* node);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1
src/vm.h
1
src/vm.h
@@ -310,6 +310,7 @@ typedef struct noomV_Function {
|
|||||||
|
|
||||||
// exactly 64 bytes, aka one cache line.
|
// exactly 64 bytes, aka one cache line.
|
||||||
// TODO: ensure it is 64-byte aligned for a perfect 1:1 struct to cache line ratio for perf
|
// TODO: ensure it is 64-byte aligned for a perfect 1:1 struct to cache line ratio for perf
|
||||||
|
// it IS 64 bit aligned with 7 bytes wasted ^^^^^^^
|
||||||
typedef struct noomV_CallFrame {
|
typedef struct noomV_CallFrame {
|
||||||
// stack index of function
|
// stack index of function
|
||||||
noom_uint_t funcIdx;
|
noom_uint_t funcIdx;
|
||||||
|
|||||||
Reference in New Issue
Block a user