compiler: various bits of progress

Reviewed-on: #12
Co-authored-by: tema5002 <tema5002@tuta.io>
Co-committed-by: tema5002 <tema5002@tuta.io>
This commit was merged in pull request #12.
This commit is contained in:
2026-07-02 16:40:25 +02:00
committed by Blendi
parent 404332fcba
commit d41993a06d
9 changed files with 841 additions and 369 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,48 @@ typedef struct noomC_Compiler {
noomC_Upval upvals[NOOMC_MAXUPVAL];
} 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);
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
noom_Exit noomC_compile(noom_LuaVM* vm, const noomP_Parser* parser, const noomP_Node* node, noomV_String* chunkname, noomV_Table* env, noomV_Value* outFunc);

View File

@@ -2,33 +2,32 @@
#include "lexer.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???????
double num = 0.0;
int error_but_different = 1;
noom_float_t num = 0.0;
const noom_bool_t negative = *s == '-';
if (*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') {
s += 2;
// 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)) {
int digit;
if (noomL_isnumber(*s)) digit = *s - '0';
else digit = noomL_lower(*s) - 'a' + 10;
num = num * 16.0 + digit;
are_we_cooked = 0;
error = 0;
s++;
}
if (are_we_cooked) goto fuck;
if (error) return (noomV_Value){ .tag = NOOMV_VNIL };
if (noomL_lower(*s) == 'p') {
// damn then
@@ -38,8 +37,8 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
if (*s == '-' || *s == '+')
s++;
if (!noomL_isnumber(*s)) goto fuck;
if (!noomL_isnumber(*s)) return (noomV_Value){ .tag = NOOMV_VNIL };
while (noomL_isnumber(*s)) {
exponent = exponent * 10 + (*s - '0');
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);
}
} else {
noom_bool_t are_we_cooked = 1;
noom_bool_t error = 1;
while (noomL_isnumber(*s)) {
num = num * 10.0 + (*s - '0');
are_we_cooked = 0;
error = 0;
s++;
}
if (*s == '.') {
@@ -59,13 +58,13 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
double fraction_divisor = 10.0;
while (noomL_isnumber(*s)) {
are_we_cooked = 0;
error = 0;
num += (double)(*s - '0') / fraction_divisor;
fraction_divisor *= 10.0;
s++;
}
}
if (are_we_cooked) goto fuck;
if (error) return (noomV_Value){ .tag = NOOMV_VNIL };
if (noomL_lower(*s) == 'e') {
s++;
@@ -74,7 +73,7 @@ double noom_strtod(const char* s, const char** endptr, int* error) {
if (*s == '-' || *s == '+')
s++;
if (!noomL_isnumber(*s)) goto fuck;
if (!noomL_isnumber(*s)) return (noomV_Value){ .tag = NOOMV_VNIL };
while (noomL_isnumber(*s)) {
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 (error) *error = error_but_different;
return negative ? -num : num;
return (noomV_Value){ .tag = NOOMV_VNUM, .number = negative ? -num : num };
}
// made by some stranger on stack overflow

View File

@@ -1,10 +1,9 @@
#include "noom.h"
#include "vm.h"
#define NOOM_USHORT_MAX 0xffff
// isn't quite strtod, is it
// doesn't skip whitespace unlike actual C stdlib strtod!!!!
double noom_strtod(const char* s, const char** endptr, int* error);
noomV_Value noom_tonumber_except_different_name_so_public_fucking_api_works(const char* s, const char** endptr, noom_LuaVersion luauauauaua);
double noom_pow(double x, int y);
int noom_startswith(const char* str, const char* compare);

View File

@@ -27,127 +27,145 @@ void print_node(const noomP_Node* node, noom_uint_t depth) {
tab(depth + 1);
printf("location: %lld\n", node->source_offset);
tab(depth + 1);
printf("subnodes:\n");
if (node->subnodec > 0) {
tab(depth + 1);
printf("subnodes (%llu):\n", node->subnodec);
for (noom_uint_t i = 0; i < node->subnodec; i++) {
print_node(node->subnodes[i], depth + 1);
for (noom_uint_t i = 0; i < node->subnodec; i++) {
print_node(node->subnodes[i], depth + 1);
}
}
tab(depth);
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) {
noomP_Parser parser;
noomP_Node* program;
// goodbye "shitass" you will be missed
int success = noomP_parse(code, filename, version, &program, &parser);
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);
if (noomP_parse(code, filename, version, &program, &parser) < 0) {
const noom_uint_t bleh = noom_format_error(&parser, program_name, NULL, 0);
char* buf = noom_alloc(bleh);
noom_format_error(&parser, program_name, buf, bleh);
fputs(buf, stdout);
noomP_freeNode(parser.last_node);
noom_free(buf);
}
if (success == 0) {
noom_LuaVM* vm = noom_createVM(version);
noomV_Value peak;
noom_Exit e = noomC_compile(vm, &parser, program, 0, 0, &peak);
if (e) {
printf("error: %d\n", e);
success = e;
noom_destroyVM(vm);
goto wellShit;
}
noomV_Function* f = (noomV_Function*)peak.obj;
printf("Insts: %u\n", f->codesize);
printf("Consts: %hu\n", f->constsize);
printf("Ups: %u\n", (int)f->upvalsize);
printf("Locals: %u\n", (int)f->localsize);
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");
}
noom_destroyVM(vm);
return 1;
}
wellShit:;
// freeing time
noomP_Node* last_node = parser.last_node;
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;
}
#ifdef LEX_OUTPUT
puts("LEX OUTPUT:");
fputs("\x1b[48;2;10;10;10m", stdout);
noom_uint_t pos = 0;
while (1) {
noomL_Token token;
return success;
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");
#endif
#ifdef PARSE_OUTPUT
puts("PARSE OUTPUT:");
pretty(code, version, program, 0);
//print_node(program, 0);
#endif
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) {
@@ -271,6 +289,8 @@ int main(int argc, char** argv) {
}
params.script_exec = argv[i];
params.do_i_already_know_what_to_do = 1;
i++;
continue;
}
if (argv[i][1] == 'l') {
@@ -283,6 +303,7 @@ int main(int argc, char** argv) {
goto die;
}
version_string = argv[i];
i++;
}
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;
@@ -304,12 +325,14 @@ int main(int argc, char** argv) {
goto die;
}
if (params.lua_version != 0) {
params.lua_version = NOOM_VERSION_54;
if (!params.do_i_already_know_what_to_do) {
params.enter_repl = 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) {
err = "script not set";
goto die;

View File

@@ -75,6 +75,7 @@ typedef enum noom_Exit {
NOOM_EERROR,
} noom_Exit;
// shouldn't this go to vm.h....?
typedef enum noom_UnaryOp {
// -x
NOOM_UNARY_NEGATE,

View File

@@ -1806,3 +1806,13 @@ int noomP_initParser(noomP_Parser* parser, const char* code, const char* filenam
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;
}
}

View File

@@ -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_initParser(noomP_Parser* parser, const char* code, const char* filename, noom_LuaVersion version);
void noomP_freeNode(noomP_Node* node);
#endif

View File

@@ -310,6 +310,7 @@ typedef struct noomV_Function {
// 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
// it IS 64 bit aligned with 7 bytes wasted ^^^^^^^
typedef struct noomV_CallFrame {
// stack index of function
noom_uint_t funcIdx;