basic compiler work

This commit is contained in:
2026-06-16 12:24:11 +02:00
parent fc8d4d2c02
commit 7a496f58c5
6 changed files with 112 additions and 52 deletions

View File

@@ -29,16 +29,48 @@
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
typedef struct noomC_LocalInfo {
enum { NOOMC_GLOBAL, NOOMC_LOCAL, NOOMC_UPVAL } type;
unsigned int idx;
} noomC_LocalInfo;
noom_Exit noomC_addLocal(noomC_Compiler *c, noomC_Local local) {
if(c->localc == NOOMC_MAXLOCAL) return NOOM_EINTERNAL;
c->locals[c->localc++] = local;
return NOOM_OK;
}
noom_Exit noomC_addUpval(noomC_Compiler *c, noomC_Upval upval) {
if(c->upvalc == NOOMC_MAXUPVAL) return NOOM_EINTERNAL;
c->upvals[c->upvalc++] = upval;
return NOOM_OK;
}
noom_Exit noomC_identifyLocal(noomC_Compiler *compiler, noomC_LocalInfo *info, const char *name, noom_uint_t namelen) {
// TODO: attempt to steal locals for upvalues
for(int i = compiler->localc-1; i >= 0; i--) {
noomC_Local l = compiler->locals[i];
if(l.dropped) continue;
if(noom_memeq(l.name, l.namelen, name, namelen)) {
info->type = NOOMC_LOCAL;
info->idx = l.stackslot;
return NOOM_OK;
}
}
// fallback to global
info->type = NOOMC_GLOBAL;
return NOOM_OK;
}
void noomC_compiler_init(noomC_Compiler *compiler) { void noomC_compiler_init(noomC_Compiler *compiler) {
compiler->parent = 0; compiler->parent = 0;
compiler->target = 0;
compiler->localc = 0; compiler->localc = 0;
compiler->localcap = 0; compiler->upvalc = 0;
compiler->locals = 0; compiler->curstack = 0;
compiler->constidx = 0;
compiler->constc = 0;
compiler->constcap = 0;
} }
static noom_Exit noomC_emit(noomV_Function *func, const noomV_Inst inst) { static noom_Exit noomC_emit(noomV_Function *func, const noomV_Inst inst) {
@@ -196,6 +228,24 @@ static noom_Exit noomC_compile_expr(
} }
return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0); return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0);
} }
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;
switch(info.type) {
case NOOMC_LOCAL:
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;
}
// forgot a case
return NOOM_EINTERNAL;
}
return NOOM_EINTERNAL; return NOOM_EINTERNAL;
} }
@@ -219,6 +269,7 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
noom_Exit result; noom_Exit result;
// local name <attr> = expression i think // local name <attr> = expression i think
if (node->type == NOOMP_NODE_LOCALDECLARATION) { if (node->type == NOOMP_NODE_LOCALDECLARATION) {
// FIXME: there can be multiple locals defined
// This code is awful for several reasons and we shall burn it // This code is awful for several reasons and we shall burn it
if (node->subnodec != 1 && node->subnodec != 2) return NOOM_EINTERNAL; if (node->subnodec != 1 && node->subnodec != 2) return NOOM_EINTERNAL;
@@ -226,8 +277,6 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
if (varname_node->type != NOOMP_NODE_ASSIGNPLACE) return NOOM_EINTERNAL; if (varname_node->type != NOOMP_NODE_ASSIGNPLACE) return NOOM_EINTERNAL;
const char *namebuf = parser->code + varname_node->source_offset; const char *namebuf = parser->code + varname_node->source_offset;
noomL_Token t;
noomL_lex(namebuf, 0, &t, parser->version);
noomC_Local local; noomC_Local local;
local.startpc = func->codesize; local.startpc = func->codesize;
@@ -236,7 +285,7 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
local.close = 0; local.close = 0;
local.constant = 0; local.constant = 0;
local.name = namebuf; local.name = namebuf;
local.namelen = t.length; local.namelen = noomL_tokenlen(namebuf, 0, parser->version);
for (noom_uint_t i = 0; i < varname_node->subnodec; i++) { for (noom_uint_t i = 0; i < varname_node->subnodec; i++) {
if (varname_node->subnodes[i]->type != NOOMP_NODE_ATTRIBUTE) return NOOM_EINTERNAL; if (varname_node->subnodes[i]->type != NOOMP_NODE_ATTRIBUTE) return NOOM_EINTERNAL;
@@ -274,19 +323,7 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
local.stackslot = compiler->curstack; local.stackslot = compiler->curstack;
// too many locals return noomC_addLocal(compiler, local);
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;
return NOOM_OK;
} }
// local function name(...) ... end // local function name(...) ... end
@@ -301,7 +338,7 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
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); const noomL_Token name_token = noomC_token_at(parser, varname_node->source_offset);
noomV_Function *proto = noomV_allocFunc(vm, parser->code + name_token.offset, name_token.length); noomV_Function *proto = noomV_allocFunc(vm, func->chunkname);
if (proto == 0) return NOOM_ENOMEM; if (proto == 0) return NOOM_ENOMEM;
proto->argc = (unsigned char)params_node->subnodec; proto->argc = (unsigned char)params_node->subnodec;
@@ -322,20 +359,13 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
noomC_Local local; noomC_Local local;
local.startpc = proto->codesize; local.startpc = proto->codesize;
local.endpc = 0; local.endpc = 0;
local.dropped = 0; // FIXME? local.dropped = 0;
local.close = 0; local.close = 0;
local.constant = 0; local.constant = 0;
// FIXME: this is WRONG, BUT I AM TIRED. local.name = parser->code + varname_node->source_offset;
local.name = noom_strndup(parser->code + varname_node->source_offset, varname_node->source_offset); local.namelen = noomL_tokenlen(parser->code, varname_node->source_offset, parser->version);
// FIXME: EXTREMELY WRONG. I AM STILL TIRED. return noomC_addLocal(compiler, local);
compiler->locals = noom_realloc(compiler->locals, sizeof(noomC_Local) * (compiler->localc + 1));
if (compiler->locals == 0) return NOOM_ENOMEM;
compiler->locals[compiler->localc++] = local;
// I guess???????
if (compiler->localc > compiler->localcap) compiler->localcap = compiler->localc;
return NOOM_OK;
} }
// TODO // TODO
@@ -351,13 +381,27 @@ static noom_Exit noomC_add_stuff_to_function(noom_LuaVM *vm, noomC_Compiler *com
return NOOM_EINTERNAL; return NOOM_EINTERNAL;
} }
noom_Exit noomC_compile(noom_LuaVM *vm, const noomP_Parser *parser, const noomP_Node *node) { noom_Exit noomC_compile(noom_LuaVM *vm, const noomP_Parser *parser, const noomP_Node *node, noomV_String *chunkname, noomV_Table *env) {
if (node->type != NOOMP_NODE_PROGRAM) return NOOM_EINTERNAL; if (node->type != NOOMP_NODE_PROGRAM) return NOOM_EINTERNAL;
noomV_Function* program = noomV_allocFunc(vm, "main", 4); noomV_Function* program = noomV_allocFunc(vm, chunkname);
if(program == 0) return NOOM_ENOMEM;
noomC_Compiler compiler; noomC_Compiler compiler;
noomC_compiler_init(&compiler); noomC_compiler_init(&compiler);
compiler.target = program;
if(parser->version == NOOM_VERSION_51) {
program->env = env;
} else {
noomC_Upval upval;
upval.name = "_ENV";
upval.namelen = 4;
upval.slot = 0;
upval.stolen = 1;
upval.constant = 0;
noomC_addUpval(&compiler, upval);
}
noom_Exit status = noomC_compile_block(vm, &compiler, parser, program, node); noom_Exit status = noomC_compile_block(vm, &compiler, parser, program, node);
if (status != NOOM_OK) return status; if (status != NOOM_OK) return status;

View File

@@ -13,20 +13,30 @@ typedef struct noomC_Local {
noom_bool_t close; noom_bool_t close;
} noomC_Local; } noomC_Local;
typedef struct noomC_Upval {
const char *name;
unsigned int namelen;
unsigned short slot;
// if stolen, this means that slot is actually an upvalue index
noom_bool_t stolen;
noom_bool_t constant;
} noomC_Upval;
#define NOOMC_MAXLOCAL 200
#define NOOMC_MAXUPVAL 64
typedef struct noomC_Compiler { typedef struct noomC_Compiler {
// steal constants from this // steal constants from this
struct noomC_Compiler *parent; struct noomC_Compiler *parent;
unsigned localc, constc; noomV_Function *target;
unsigned localcap, constcap; unsigned localc;
// constants index in the stack. unsigned upvalc;
// We put it there so GC doesn't free them, and
// so we can allocate the function's consts arrays *ONCE*
unsigned constidx;
unsigned curstack; unsigned curstack;
noomC_Local *locals; noomC_Local locals[NOOMC_MAXLOCAL];
noomC_Upval upvals[NOOMC_MAXUPVAL];
} noomC_Compiler; } noomC_Compiler;
void noomC_compiler_init(noomC_Compiler* compiler); void noomC_compiler_init(noomC_Compiler* compiler);
// 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); noom_Exit noomC_compile(noom_LuaVM *vm, const noomP_Parser *parser, const noomP_Node *node, noomV_String *chunkname, noomV_Table *env);

View File

@@ -584,3 +584,8 @@ noomL_ErrorType noomL_lex(const char* s, noom_uint_t start, noomL_Token* token,
return NOOML_ERROR_UNKNOWN; return NOOML_ERROR_UNKNOWN;
} }
noom_uint_t noomL_tokenlen(const char *s, noom_uint_t start, noom_LuaVersion version) {
noomL_Token t;
noomL_lex(s, start, &t, version);
return t.length;
}

View File

@@ -49,4 +49,6 @@ noom_uint_t noomL_getnumber(const char* s, noomL_ErrorType* error, noom_LuaVersi
const char *noomL_formatTokenType(noomL_TokenType token_type); 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 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);

View File

@@ -21,11 +21,11 @@ noomV_String *noomV_allocStr(noom_LuaVM *vm, const char *str, noom_uint_t len) {
return s; return s;
} }
noomV_Function *noomV_allocFunc(noom_LuaVM *vm, const char *str, noom_uint_t len) { noomV_Function *noomV_allocFunc(noom_LuaVM *vm, noomV_String *chunkname) {
noomV_Function *f = (noomV_Function*)noomV_allocObj(vm, NOOMV_OFUNC, sizeof(noomV_Function)); noomV_Function *f = (noomV_Function*)noomV_allocObj(vm, NOOMV_OFUNC, sizeof(noomV_Function));
if (f == 0) return 0; if (f == 0) return 0;
f->chunkname = noomV_allocStr(vm, str, len); f->chunkname = chunkname;
if (f->chunkname == 0) return 0; f->env = 0;
f->code = 0; f->code = 0;
f->consts = 0; f->consts = 0;
f->protos = 0; f->protos = 0;

View File

@@ -87,11 +87,11 @@ typedef enum noomV_Opcode : unsigned char {
// Push data on the stack // Push data on the stack
// Pushes the value at stack[op.uD] // Pushes the value at `stack[op.uD]`
NOOMV_INSTR_PUSHVAL, NOOMV_INSTR_PUSHVAL,
// Pushes consts[op.uD] // Pushes `consts[op.uD]`
NOOMV_INSTR_PUSHCONST, NOOMV_INSTR_PUSHCONST,
// Pushes _G[consts[op.uD]], Lua 5.1 only. // Pushes `_G[consts[op.uD]]`, Lua 5.1 only.
NOOMV_INSTR_PUSHGLOBAL, NOOMV_INSTR_PUSHGLOBAL,
// Pushes op.sD itself as an integer // Pushes op.sD itself as an integer
NOOMV_INSTR_PUSHINT, NOOMV_INSTR_PUSHINT,
@@ -330,8 +330,7 @@ struct noom_LuaVM {
// Allocating objects // Allocating objects
noomV_Object *noomV_allocObj(noom_LuaVM *vm, noomV_ObjTag tag, noom_uint_t size); noomV_Object *noomV_allocObj(noom_LuaVM *vm, noomV_ObjTag tag, noom_uint_t size);
noomV_String *noomV_allocStr(noom_LuaVM *vm, const char *str, noom_uint_t len); noomV_String *noomV_allocStr(noom_LuaVM *vm, const char *str, noom_uint_t len);
noomV_Function *noomV_allocFunc(noom_LuaVM *vm, const char *str, noom_uint_t len); noomV_Function *noomV_allocFunc(noom_LuaVM *vm, noomV_String *chunkname);
noomV_Function *noomV_allocFunc(noom_LuaVM *vm, const char *str, noom_uint_t len);
void noomV_freeObj(noomV_Object *obj); void noomV_freeObj(noomV_Object *obj);
#endif #endif