basic compiler work
This commit is contained in:
116
src/compiler.c
116
src/compiler.c
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
6
src/vm.c
6
src/vm.c
@@ -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;
|
||||||
|
|||||||
9
src/vm.h
9
src/vm.h
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user