Compare commits
16 Commits
5359461e9c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 268d1be18b | |||
| c29c2796d7 | |||
| 8709efda7d | |||
| 5ff0594791 | |||
| be75ccd6f8 | |||
| 269d2c8ae9 | |||
| 20f9ee0a14 | |||
| 8e8b01b7d9 | |||
| 4fbb006072 | |||
| 09ac2a17f9 | |||
| 6d57f1fe6b | |||
| 2a22544464 | |||
| fbbe2e8285 | |||
| 0d6b1c6729 | |||
| 9acff5f893 | |||
| bb73054e2c |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,4 +1,7 @@
|
|||||||
/build
|
/build
|
||||||
/.zig-cache
|
/.zig-cache
|
||||||
/zig-out
|
/zig-out
|
||||||
noom
|
.idea
|
||||||
|
/noom
|
||||||
|
/noom.*
|
||||||
|
Makefile
|
||||||
|
|||||||
51
build.lua
Normal file → Executable file
51
build.lua
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
|
#!/usr/bin/env lua
|
||||||
-- i love build scripts i love build scripts i love build scripts scripts build love i script build love me i love script build i script love build
|
-- i love build scripts i love build scripts i love build scripts scripts build love i script build love me i love script build i script love build
|
||||||
|
|
||||||
local isBlendi = os.getenv("USER") == "blendi"
|
local isBlendi = os.getenv("USER") == "blendi"
|
||||||
local separator = package.config:sub(1,1)
|
local separator = package.config:sub(1,1)
|
||||||
|
|
||||||
@@ -13,9 +13,12 @@ local function filename(path)
|
|||||||
return path:sub(s,e)
|
return path:sub(s,e)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function runCommand(cmd)
|
local function runCommand(cmd, ignore_fail)
|
||||||
print("> " .. cmd)
|
print("> " .. cmd)
|
||||||
return os.execute(cmd)
|
local result = os.execute(cmd)
|
||||||
|
if (result ~= true and result ~= 0) and (not ignore_fail) then
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fixPath(path)
|
local function fixPath(path)
|
||||||
@@ -28,17 +31,43 @@ local function fixPath(path)
|
|||||||
return new
|
return new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if arg[1] == "clean" then
|
||||||
|
if separator == '\\' then
|
||||||
|
runCommand("rmdir /s /q build 2>nul", true)
|
||||||
|
else
|
||||||
|
runCommand("rm -rf build")
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local needsDir = false
|
||||||
|
|
||||||
if separator == '\\' then
|
if separator == '\\' then
|
||||||
runCommand('mkdir build 2>nul')
|
needsDir = true
|
||||||
else
|
else
|
||||||
runCommand('mkdir -p build')
|
-- TODO: maybe use exit code instead of the first return value?
|
||||||
|
local ok, _, code = os.execute('test -d build');
|
||||||
|
|
||||||
|
local exists = (ok == 0 or (ok == true and code == 0))
|
||||||
|
|
||||||
|
needsDir = not exists;
|
||||||
|
end
|
||||||
|
|
||||||
|
if needsDir then
|
||||||
|
if separator == '\\' then
|
||||||
|
runCommand('mkdir build 2>nul')
|
||||||
|
else
|
||||||
|
runCommand('mkdir -p build')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local files = {
|
local files = {
|
||||||
|
'src/error.c',
|
||||||
'src/helper.c',
|
'src/helper.c',
|
||||||
'src/lexer.c',
|
'src/lexer.c',
|
||||||
'src/parser.c',
|
'src/parser.c',
|
||||||
'src/compiler.c',
|
'src/compiler.c',
|
||||||
|
'src/vm.c',
|
||||||
'src/main.c',
|
'src/main.c',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +76,7 @@ local objects = {}
|
|||||||
local coolArgs = {}
|
local coolArgs = {}
|
||||||
|
|
||||||
local function getTime(path)
|
local function getTime(path)
|
||||||
local handle = io.popen('stat -c %Y "' .. path .. '" 2>/dev/null')
|
local handle = assert(io.popen('stat -c %Y "' .. path .. '" 2>/dev/null'))
|
||||||
local result = handle:read("*a")
|
local result = handle:read("*a")
|
||||||
handle:close()
|
handle:close()
|
||||||
return tonumber(result) or 0
|
return tonumber(result) or 0
|
||||||
@@ -73,14 +102,18 @@ for i = 1,#files do
|
|||||||
|
|
||||||
if needsRebuild(fname, out) then
|
if needsRebuild(fname, out) then
|
||||||
needsLinking = true
|
needsLinking = true
|
||||||
runCommand('clang -c -o ' .. out .. ' ' .. fname .. ' ' .. table.concat(coolArgs, ' '))
|
runCommand('clang -g -c -o ' .. out .. ' ' .. fname .. ' ' .. table.concat(coolArgs, ' '))
|
||||||
end
|
end
|
||||||
|
|
||||||
objects[#objects+1] = out;
|
objects[#objects+1] = out;
|
||||||
end
|
end
|
||||||
|
|
||||||
local exe = separator == '\\' and "noom.exe" or "noom"
|
local exe = separator == '\\' and ".\\noom.exe" or "./noom"
|
||||||
|
|
||||||
if needsLinking then
|
if needsLinking then
|
||||||
runCommand('clang -o ' .. exe .. ' ' .. table.concat(objects, ' ') .. ' ' .. table.concat(coolArgs, ' '))
|
runCommand('clang -g -o ' .. exe .. ' ' .. table.concat(objects, ' ') .. ' ' .. table.concat(coolArgs, ' '))
|
||||||
|
end
|
||||||
|
|
||||||
|
if arg[1] == "run" then
|
||||||
|
runCommand(exe)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ pub fn build(b: *std.Build) void {
|
|||||||
"src/lexer.c",
|
"src/lexer.c",
|
||||||
"src/parser.c",
|
"src/parser.c",
|
||||||
"src/compiler.c",
|
"src/compiler.c",
|
||||||
|
"src/vm.c",
|
||||||
|
"src/error.c",
|
||||||
"src/main.c",
|
"src/main.c",
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
365
src/compiler.c
365
src/compiler.c
@@ -0,0 +1,365 @@
|
|||||||
|
#include "noom.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
// COMPILATION!!!!!!!!!!!!!!!!!!!
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⢲⣞⣭⣟⣿⣻⣷⢶⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⣤⣞⣵⢯⣿⣞⣷⣿⣷⣿⣿⣿⣿⣜⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⣤⣶⢿⣾⣽⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣯⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⡤⢿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⢫⡀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⢆⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⡗⡇⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⢠⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⢰⣾⣿⣿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡑⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠋⠉⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠻⠿⢿⣿⠟⠛⠛⠻⣿⣿⣿⣿⡿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣇⠀⠀⠀⠉⢿⡟⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⣼⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠁⠀⠀⠀⢨⣿⡷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⣿⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⡀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⢼⣿⣧⡴⢤⣶⡴⢻⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠘⠛⠿⠻⠷⠾⠶⠷⠾⠶⡷⣿⣿⣀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⣀⠴⠮⠃⠉⠛⢷⣦⣠⡄⠀⣸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⣠⠶⠘⠁⠀⠀⠀⠀⠀⠙⢮⡿⣧⢾⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⣤⠓⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣈⣽⡿⢿⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢀⣠⣠⣴⣮⠾⠟⠋⠉⢹⠌⠈⠙⠻⢷⣶⣤⣤⣀⡀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⡘⠂⠀⠀⠀⠀⠈⠉⠛⠛⠻⠿⠷⠦
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
|
||||||
|
void noomC_compiler_init(noomC_Compiler *compiler) {
|
||||||
|
compiler->parent = 0;
|
||||||
|
|
||||||
|
compiler->localc = 0;
|
||||||
|
compiler->localcap = 0;
|
||||||
|
compiler->locals = 0;
|
||||||
|
|
||||||
|
compiler->constidx = 0;
|
||||||
|
compiler->constc = 0;
|
||||||
|
compiler->constcap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noom_Exit noomC_emit(noomV_Function *func, const noomV_Inst inst) {
|
||||||
|
func->code = noom_realloc(func->code, sizeof(noomV_Inst) * (func->codesize + 1));
|
||||||
|
if (func->code == 0) return NOOM_ENOMEM;
|
||||||
|
func->code[func->codesize++] = inst;
|
||||||
|
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) {
|
||||||
|
return noomC_emit(func, (noomV_Inst){.op = op, .a = a, .b = b, .c = c});
|
||||||
|
}
|
||||||
|
|
||||||
|
static noom_Exit noomC_emit_Aus(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;
|
||||||
|
func->consts = noom_realloc(func->consts, sizeof(noomV_Value) * (func->constsize + 1));
|
||||||
|
if (func->consts == 0) return NOOM_ENOMEM;
|
||||||
|
func->consts[func->constsize++] = val;
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO get rid of these two vvvv
|
||||||
|
static noom_Exit noomC_addconst_nil(noomV_Function *func) {
|
||||||
|
return noomC_addconst(func, (noomV_Value){.tag = NOOMV_VNIL, .autoclose = 0, .isptr = 0});
|
||||||
|
}
|
||||||
|
static noom_Exit noomC_addconst_bool(noomV_Function *func, const noom_bool_t b) {
|
||||||
|
return noomC_addconst(func, (noomV_Value){.tag = NOOMV_VBOOL, .autoclose = 0, .isptr = 0, .boolean = b});
|
||||||
|
}
|
||||||
|
// yeah ^^^^^^^^^
|
||||||
|
|
||||||
|
static noom_Exit noomC_addconst_str(noomV_Function *func, noom_LuaVM *vm, const char *str, const noom_uint_t len) {
|
||||||
|
noomV_String *s = noomV_allocStr(vm, str, len);
|
||||||
|
if (s == 0) return NOOM_ENOMEM;
|
||||||
|
return noomC_addconst(func, (noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object *)s});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 noomV_Opcode noomC_what_bop_is_this(const noomP_Parser *parser, noom_uint_t offset) {
|
||||||
|
// I AM THE LEXER NOW!!!!!!!!!
|
||||||
|
if (noom_startswith(parser->code + offset, "==")) return NOOMV_INSTR_EQ;
|
||||||
|
if (noom_startswith(parser->code + offset, "~=")) return NOOMV_INSTR_NEQ;
|
||||||
|
if (noom_startswith(parser->code + offset, "~=")) return NOOMV_INSTR_LTE;
|
||||||
|
if (noom_startswith(parser->code + offset, "~=")) return NOOMV_INSTR_GTE;
|
||||||
|
if (noom_startswith(parser->code + offset, "..")) return NOOMV_INSTR_CONCAT;
|
||||||
|
|
||||||
|
if (parser->version >= NOOM_VERSION_53) {
|
||||||
|
// Fucking atom forgot to put make an instruction
|
||||||
|
// update no i am unable to read
|
||||||
|
if (noom_startswith(parser->code + offset, "//")) return NOOMV_INSTR_FLOOR_DIV;
|
||||||
|
if (noom_startswith(parser->code + offset, ">>")) return NOOMV_INSTR_RSHIFT;
|
||||||
|
if (noom_startswith(parser->code + offset, "<<")) return NOOMV_INSTR_LSHIFT;
|
||||||
|
if (noom_startswith(parser->code + offset, "&")) return NOOMV_INSTR_BAND;
|
||||||
|
if (noom_startswith(parser->code + offset, "|")) return NOOMV_INSTR_BOR;
|
||||||
|
if (noom_startswith(parser->code + offset, "~")) return NOOMV_INSTR_BXOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noom_startswith(parser->code + offset, "+")) return NOOMV_INSTR_ADD;
|
||||||
|
if (noom_startswith(parser->code + offset, "-")) return NOOMV_INSTR_SUB;
|
||||||
|
if (noom_startswith(parser->code + offset, "*")) return NOOMV_INSTR_MUL;
|
||||||
|
if (noom_startswith(parser->code + offset, "/")) return NOOMV_INSTR_DIV;
|
||||||
|
if (noom_startswith(parser->code + offset, "%")) return NOOMV_INSTR_MOD;
|
||||||
|
if (noom_startswith(parser->code + offset, "^")) return NOOMV_INSTR_POW;
|
||||||
|
if (noom_startswith(parser->code + offset, "<")) return NOOMV_INSTR_LT;
|
||||||
|
if (noom_startswith(parser->code + offset, ">")) return NOOMV_INSTR_GT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mmap ahh function 🥀🥀🥀🥀🥀🥀🥀
|
||||||
|
// What 6 argument syscalls there even are other than mmap and clone and is there anything longer
|
||||||
|
static noom_Exit noomC_compile_expr(
|
||||||
|
noom_LuaVM *vm,
|
||||||
|
noomC_Compiler *compiler,
|
||||||
|
const noomP_Parser *parser,
|
||||||
|
noomV_Function *func,
|
||||||
|
const noomP_Node *node
|
||||||
|
) {
|
||||||
|
// Baba is You OST is a very cool soundtrack to code to Can recommend
|
||||||
|
if (node->type == NOOMP_NODE_NILLITERAL) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack++;
|
||||||
|
unsigned short fucking_constant = func->constsize;
|
||||||
|
noom_Exit result = noomC_addconst_nil(func);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
|
||||||
|
return noomC_emit_Aus(func, NOOMV_INSTR_LOADC, fucking_destination, fucking_constant);
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_BOOLEANLITERAL) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack++;
|
||||||
|
unsigned short fucking_constant = func->constsize;
|
||||||
|
noomL_Token bool_token = noomC_token_at(parser, node->source_offset);
|
||||||
|
noom_bool_t val = noom_memeq(parser->code + bool_token.offset, bool_token.length, "true", 4);
|
||||||
|
noom_Exit result = noomC_addconst_bool(func, val);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
|
||||||
|
return noomC_emit_Aus(func, NOOMV_INSTR_LOADC, fucking_destination, fucking_constant);
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_NUMBERLITERAL) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack++;
|
||||||
|
return NOOM_PLEASEHELPMEIAMSCARED; // 😭😭😭😭😭😭😭😭
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_STRINGLITERAL) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack++;
|
||||||
|
noom_Exit result = noomC_addconst_str(func, vm, "but DID YOU KNOW", 16);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_BINARYOPERATOR) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack++;
|
||||||
|
if (node->subnodec != 2) return NOOM_EINTERNAL;
|
||||||
|
const unsigned char B = compiler->curstack++;
|
||||||
|
noom_Exit result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0]);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
const unsigned char C = compiler->curstack++;
|
||||||
|
result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[1]);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
|
||||||
|
return noomC_emit_ABC(func, noomC_what_bop_is_this(parser, node->source_offset), fucking_destination, B, C);
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_CALL) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack;
|
||||||
|
// Here we don't fucking increment this fucking destination
|
||||||
|
// Because the fucking function call fucking increments it fucking anyway
|
||||||
|
for (int i = 1; i < node->subnodec; i++) {
|
||||||
|
// push node->subnodes[i] to stack or something
|
||||||
|
}
|
||||||
|
return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0);
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_METHODCALL) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack;
|
||||||
|
// Here we don't fucking increment this fucking destination
|
||||||
|
// Because the fucking function call fucking increments it fucking anyway
|
||||||
|
// push parent value... probably already processed below if you make it i = 0
|
||||||
|
for (int i = 1; i < node->subnodec; i++) {
|
||||||
|
// push node->subnodes[i] to stack or something
|
||||||
|
}
|
||||||
|
return noomC_emit_Aus(func, NOOMV_INSTR_JMP, 0, /* where do i start......... */ 0);
|
||||||
|
}
|
||||||
|
if (node->type == NOOMP_NODE_GETFIELD) {
|
||||||
|
unsigned char fucking_destination = compiler->curstack++;
|
||||||
|
if (node->subnodec != 2) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
unsigned char B = compiler->curstack;
|
||||||
|
noom_Exit result = noomC_compile_expr(vm, compiler, parser, func, node->subnodes[0]);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
|
||||||
|
unsigned char C = compiler->curstack;
|
||||||
|
unsigned short C_constant = func->constsize;
|
||||||
|
noomL_Token field_token = noomC_token_at(parser, node->subnodes[1]->source_offset);
|
||||||
|
result = noomC_addconst_str(func, vm, parser->code + field_token.offset, field_token.length);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
result = noomC_emit_Aus(func, NOOMV_INSTR_LOADC, C, C_constant);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
|
||||||
|
return noomC_emit_ABC(func, NOOMV_INSTR_GET, fucking_destination, B, C);
|
||||||
|
}
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
r = noomC_add_stuff_to_function(vm, compiler, parser, func, node->subnodes[i]);
|
||||||
|
if (r != NOOM_OK) break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// They say you use only 10% of your brain
|
||||||
|
// Keep it
|
||||||
|
// 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
|
||||||
|
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) {
|
||||||
|
// local name <attr> = expression i think
|
||||||
|
if (node->type == NOOMP_NODE_LOCALDECLARATION) {
|
||||||
|
if (node->subnodec != 1 && node->subnodec != 2) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
const noomP_Node *varname_node = node->subnodes[0];
|
||||||
|
if (varname_node->type != NOOMP_NODE_ASSIGNPLACE) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
noomC_Local local;
|
||||||
|
local.startpc = func->codesize;
|
||||||
|
local.endpc = 0;
|
||||||
|
local.dropped = 0; // FIXME?
|
||||||
|
local.close = 0;
|
||||||
|
local.constant = 0;
|
||||||
|
local.name = noom_strndup(parser->code + varname_node->source_offset, varname_node->source_offset);
|
||||||
|
|
||||||
|
for (noom_uint_t i = 0; i < varname_node->subnodec; i++) {
|
||||||
|
if (varname_node->subnodes[i]->type != NOOMP_NODE_ATTRIBUTE) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
noomL_Token attr_token = noomC_token_at(parser, varname_node->subnodes[i]->source_offset);
|
||||||
|
const char *ap = parser->code + attr_token.offset;
|
||||||
|
noom_uint_t al = attr_token.length;
|
||||||
|
if (noom_memeq(ap, al, "close", 5)) {
|
||||||
|
if (local.close) return NOOM_EINTERNAL;
|
||||||
|
local.close = 1;
|
||||||
|
}
|
||||||
|
else if (noom_memeq(ap, al, "const", 5)) {
|
||||||
|
if (local.constant) return NOOM_EINTERNAL;
|
||||||
|
local.constant = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned destination = compiler->curstack;
|
||||||
|
if (compiler->curstack++ == NOOM_MAXSTACK) return NOOM_ENOSTACK;
|
||||||
|
|
||||||
|
if (node->subnodec == 1) {
|
||||||
|
// according to atom this should be nil
|
||||||
|
const unsigned short constptr = func->constsize;
|
||||||
|
noom_Exit result = noomC_addconst_nil(func);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
result = noomC_emit_Aus(func, NOOMV_INSTR_LOADC, destination, constptr);
|
||||||
|
if (result != NOOM_OK) return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const noomP_Node *value_node = node->subnodes[1];
|
||||||
|
const unsigned saved = compiler->curstack;
|
||||||
|
compiler->curstack = destination;
|
||||||
|
const noom_Exit r = noomC_compile_expr(vm, compiler, parser, func, value_node);
|
||||||
|
if (r != NOOM_OK) return r;
|
||||||
|
compiler->curstack = saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler->locals = noom_realloc(compiler->locals, sizeof(noomC_Local) * (compiler->localc + 1));
|
||||||
|
if (compiler->locals == 0) return NOOM_ENOMEM;
|
||||||
|
compiler->locals[compiler->localc++] = local;
|
||||||
|
// I guess???????
|
||||||
|
if (compiler->localc > compiler->localcap) compiler->localcap = compiler->localc;
|
||||||
|
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// local function name(...) ... end
|
||||||
|
if (node->type == NOOMP_NODE_LOCALFUNCTIONDECLARATION) {
|
||||||
|
if (node->subnodec != 3) return NOOM_EINTERNAL;
|
||||||
|
// Funny staircase huh
|
||||||
|
const noomP_Node *varname_node = node->subnodes[0];
|
||||||
|
const noomP_Node *params_node = node->subnodes[1];
|
||||||
|
const noomP_Node *block_node = node->subnodes[2];
|
||||||
|
if (varname_node->type != NOOMP_NODE_VARNAME) return NOOM_EINTERNAL;
|
||||||
|
if (params_node->type != NOOMP_NODE_FUNCTIONPARAMETERS) 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);
|
||||||
|
noomV_Function *proto = noomV_allocFunc(vm, parser->code + name_token.offset, name_token.length);
|
||||||
|
if (proto == 0) return NOOM_ENOMEM;
|
||||||
|
|
||||||
|
proto->argc = (unsigned char)params_node->subnodec;
|
||||||
|
|
||||||
|
noomC_Compiler child;
|
||||||
|
noomC_compiler_init(&child);
|
||||||
|
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;
|
||||||
|
|
||||||
|
func->protos = noom_realloc(func->protos, sizeof(noomV_Function *) * (func->protosize + 1));
|
||||||
|
if (func->protos == 0) return NOOM_ENOMEM;
|
||||||
|
func->protos[func->protosize++] = proto;
|
||||||
|
|
||||||
|
noomC_Local local;
|
||||||
|
local.startpc = proto->codesize;
|
||||||
|
local.endpc = 0;
|
||||||
|
local.dropped = 0; // FIXME?
|
||||||
|
local.close = 0;
|
||||||
|
local.constant = 0;
|
||||||
|
local.name = noom_strndup(parser->code + varname_node->source_offset, varname_node->source_offset);
|
||||||
|
|
||||||
|
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
|
||||||
|
if (node->type == NOOMP_NODE_RETURN) {
|
||||||
|
noomC_emit_Aus(func, NOOMV_INSTR_NOP, 0, 0);
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == NOOMP_NODE_DOBLOCK || node->type == NOOMP_NODE_BLOCK) {
|
||||||
|
return noomC_compile_block(vm, compiler, parser, func, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOOM_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
noom_Exit noomC_compile(noom_LuaVM *vm, const noomP_Parser *parser, const noomP_Node *node) {
|
||||||
|
if (node->type != NOOMP_NODE_PROGRAM) return NOOM_EINTERNAL;
|
||||||
|
|
||||||
|
noomV_Function* program = noomV_allocFunc(vm, "main", 4);
|
||||||
|
|
||||||
|
noomC_Compiler compiler;
|
||||||
|
noomC_compiler_init(&compiler);
|
||||||
|
|
||||||
|
noom_Exit status = noomC_compile_block(vm, &compiler, parser, program, node);
|
||||||
|
if (status != NOOM_OK) return status;
|
||||||
|
|
||||||
|
if (vm->mainThread->stacklen == vm->mainThread->stackcap) {
|
||||||
|
vm->mainThread->stackcap = vm->mainThread->stackcap ? vm->mainThread->stackcap * 2 : 16;
|
||||||
|
vm->mainThread->stack = noom_realloc(vm->mainThread->stack, sizeof(noomV_Value) * vm->mainThread->stackcap);
|
||||||
|
}
|
||||||
|
vm->mainThread->stack[vm->mainThread->stacklen++] =
|
||||||
|
(noomV_Value){.tag = NOOMV_VOBJ, .autoclose = 0, .isptr = 0, .obj = (noomV_Object*)program};
|
||||||
|
return NOOM_OK;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
typedef struct noomC_Local {
|
typedef struct noomC_Local {
|
||||||
unsigned int startpc;
|
unsigned int startpc;
|
||||||
unsigned int endpc;
|
unsigned int endpc;
|
||||||
char *name;
|
const char *name;
|
||||||
bool dropped;
|
noom_bool_t dropped;
|
||||||
bool constant;
|
noom_bool_t constant;
|
||||||
bool close;
|
noom_bool_t close;
|
||||||
} noomC_Local;
|
} noomC_Local;
|
||||||
|
|
||||||
typedef struct noomC_Compiler {
|
typedef struct noomC_Compiler {
|
||||||
@@ -23,5 +23,7 @@ typedef struct noomC_Compiler {
|
|||||||
noomC_Local *locals;
|
noomC_Local *locals;
|
||||||
} noomC_Compiler;
|
} noomC_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, noomP_Node *node);
|
noom_Exit noomC_compile(noom_LuaVM *vm, const noomP_Parser *parser, const noomP_Node *node);
|
||||||
|
|||||||
162
src/error.c
Normal file
162
src/error.c
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
#include "error.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
noom_uint_t noom_format_error(const noomP_Parser* parser, const char* program_name, char* buffer, noom_uint_t buffer_size) {
|
||||||
|
struct noom_error {
|
||||||
|
const char* s;
|
||||||
|
int near; // 0:none 1: near '%s'\n 2: '%s'\n
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct noom_error parser_errors[] = {
|
||||||
|
[NOOMP_ERROR_NONE] = {0, 0},
|
||||||
|
|
||||||
|
[NOOMP_ERROR_OOM] = {"Whoops! Out of memory :(\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_LCURLY] = {"expected '{'", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_RCURLY] = {"expected '}' to close table literal", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_RBRACKET_AFTER_KEY] = {"expected ']' to close computed key", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_EQUALS_AFTER_KEY] = {"expected '=' after table key", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_FIELD_IDENTIFIER] = {"expected identifier after '.' for field access", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_METHOD_CALL] = {"expected identifier after ':' for method call", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_RBRACKET_AFTER_INDEX] = {"expected ']' after index expression", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_RPAREN_AFTER_EXPRESSION] = {"expected ')' after expression", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_LPAREN_FOR_PARAMETERS] = {"expected '(' for function parameters", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_RPAREN_FOR_PARAMETERS] = {"expected ')' for function parameters", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LOCAL_FUNCTION] = {"expected identifier after 'local function'\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_FUNCTION] = {"expected identifier after 'function'\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_END_AFTER_LOCAL_FUNCTION] = {"expected 'end' to close local function declaration", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_END_AFTER_FUNCTION] = {"expected 'end' to close function declaration", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LOCAL] = {"expected identifier after 'local'\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LANGLE] = {"expected identifier after '<' for attribute\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_RANGLE_TO_CLOSE_ATTRIBUTE] = {"expected '>' to close attribute after identifier", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_THEN_AFTER_EXPRESSION] = {"expected 'then' after expression", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_ELSE_ELSEIF_OR_END] = {"expected 'else', 'elseif', or 'end'", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_END_AFTER_IF] = {"expected 'end' to close if statement", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_DO_AFTER_EXPRESSION] = {"expected 'do' after expression", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_END_AFTER_WHILE] = {"expected 'end' to close while statement", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_END_AFTER_FOR] = {"expected 'end' to close for statement", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_END_AFTER_DO] = {"expected 'end' to close do statement", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_FOR] = {"expected identifier after 'for'\n", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_VARIABLE_AFTER_COMMA_IN_FOR] = {"expected variable name after ',' in for loop\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IN] = {"expected 'in'", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_UNTIL] = {"expected 'until' to close repeat expression", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_GOTO] = {"expected identifier after goto\n", 0},
|
||||||
|
[NOOMP_ERROR_EXPECTED_COLONCOLON] = {"expected :: to end label identifier", 1},
|
||||||
|
[NOOMP_ERROR_INVALID_STATEMENT] = {"expected statement, got", 2},
|
||||||
|
// I want someone smarter than me [tema5002] to give these a proper description
|
||||||
|
// ^ alrighty then
|
||||||
|
[NOOMP_ERROR_EXPECTED_ASSIGNABLE] = {"expected assignable expression after comma in assignment", 1},
|
||||||
|
[NOOMP_ERROR_NOT_ASSIGNABLE] = {"expression in assignment is not assignable", 1},
|
||||||
|
[NOOMP_ERROR_EXPECTED_COMMA_OR_EQUAL_IN_ASSIGNMENT] = {"expected a comma or equals after assignable in assignment", 1},
|
||||||
|
[NOOMP_ERROR_EXPRESSION_NOT_STATEMENT] = {"loose expression is not a valid statement", 1},
|
||||||
|
[NOOMP_ERROR_FAKEATTRIBUTE] = {"invalid attribute", 2},
|
||||||
|
[NOOMP_ERROR_RETURN_NOT_END] = {"'return' must be the last statement in a block\n", 0},
|
||||||
|
[NOOMP_ERROR_FOR_WRONG_AMOUNT] = {"'for' initializer must have 2 or 3 expressions\n", 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct noom_error lexer_errors[] = {
|
||||||
|
[NOOML_ERROR_NONE] = {0, 0},
|
||||||
|
|
||||||
|
[NOOML_ERROR_UNKNOWN] = {"unknown token", 1},
|
||||||
|
[NOOML_ERROR_MALFORMED_NUM] = {"malformed number", 1},
|
||||||
|
[NOOML_ERROR_UNFINISHED_COMMENT] = {"unfinished comment", 1},
|
||||||
|
[NOOML_ERROR_UNFINISHED_STRING] = {"unfinished string", 1},
|
||||||
|
[NOOML_ERROR_UNFINISHED_LONG_STRING] = {"unfinished long string", 1},
|
||||||
|
[NOOML_ERROR_DECIMAL_ESCAPE_TOO_BIG] = {"decimal escape sequence too big (max 255)", 1},
|
||||||
|
[NOOML_ERROR_HEX_ESCAPE_INVALID] = {"invalid hexadecimal escape sequence", 1},
|
||||||
|
[NOOML_ERROR_UNICODE_ESCAPE_UNOPENED] = {"expected '{' after '\\u' for Unicode escape", 1},
|
||||||
|
[NOOML_ERROR_UNICODE_ESCAPE_UNCLOSED] = {"expected '}' to close Unicode escape sequence", 1},
|
||||||
|
[NOOML_ERROR_UNICODE_ESCAPE_TOO_BIG] = {"Unicode escape sequence exceeds maximum (0x10FFFF)", 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
noomP_Error base_err = parser->error_state;
|
||||||
|
noom_uint_t lexer_code = 0;
|
||||||
|
noom_uint_t pos = 0;
|
||||||
|
|
||||||
|
if (parser->error_state & NOOMP_ERROR_LEXER) {
|
||||||
|
base_err = NOOMP_ERROR_LEXER;
|
||||||
|
lexer_code = parser->error_state & ~NOOMP_ERROR_LEXER;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct noom_error err = (base_err == NOOMP_ERROR_LEXER) ? lexer_errors[lexer_code] : parser_errors[base_err];
|
||||||
|
|
||||||
|
noom_uint_t row = 1, column = 1;
|
||||||
|
for (noom_uint_t i = 0; i < parser->lex_offset; i++) {
|
||||||
|
if (parser->code[i] == '\n') {
|
||||||
|
row++;
|
||||||
|
column = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer == 0) {
|
||||||
|
noom_uint_t linedig = 0;
|
||||||
|
for (noom_uint_t n = row; n; n /= 10, linedig++);
|
||||||
|
|
||||||
|
noom_uint_t space = 0;
|
||||||
|
|
||||||
|
if (program_name) space +=
|
||||||
|
noom_strlen(program_name) +
|
||||||
|
sizeof(": ") - 1;
|
||||||
|
|
||||||
|
space +=
|
||||||
|
noom_strlen(parser->filename) +
|
||||||
|
sizeof(":") - 1 +
|
||||||
|
linedig +
|
||||||
|
sizeof(": ") - 1 +
|
||||||
|
noom_strlen(err.s) +
|
||||||
|
+ 1; // \0;
|
||||||
|
|
||||||
|
if (err.near) space +=
|
||||||
|
(err.near == 1 ? sizeof(" near") - 1 : 0) +
|
||||||
|
sizeof(" '") - 1 +
|
||||||
|
parser->last_token_length +
|
||||||
|
sizeof("'\n") - 1;
|
||||||
|
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program_name) {
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, program_name);
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, ": ");
|
||||||
|
}
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, parser->filename);
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, ":");
|
||||||
|
|
||||||
|
char num_buf[20];
|
||||||
|
noom_uint_t num_len = 0;
|
||||||
|
|
||||||
|
if (row == 0) {
|
||||||
|
num_buf[num_len++] = '0';
|
||||||
|
} else {
|
||||||
|
noom_uint_t temp = row;
|
||||||
|
noom_uint_t divisor = 1;
|
||||||
|
while (temp / divisor >= 10) divisor *= 10;
|
||||||
|
while (divisor > 0) {
|
||||||
|
num_buf[num_len++] = '0' + (temp / divisor);
|
||||||
|
temp %= divisor;
|
||||||
|
divisor /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (noom_uint_t i = 0; i < num_len && pos < buffer_size - 1; i++) {
|
||||||
|
buffer[pos++] = num_buf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, ": ");
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, err.s);
|
||||||
|
if (err.near) {
|
||||||
|
if (err.near == 1) {
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, " near");
|
||||||
|
}
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, " '");
|
||||||
|
for (noom_uint_t i = 0; i < parser->last_token_length && pos < buffer_size - 1; i++) {
|
||||||
|
buffer[pos++] = parser->code[parser->last_token_offset + i];
|
||||||
|
}
|
||||||
|
noom_safe_strcpy(buffer, &pos, buffer_size, "'\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < buffer_size) buffer[pos] = '\0';
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
6
src/error.h
Normal file
6
src/error.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// js let me use include guards 🥀🥀🥀🥀🥀🥀🥀
|
||||||
|
// ^ header guards r 4 noobz!
|
||||||
|
#include "types.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
noom_uint_t noom_format_error(const noomP_Parser* parser, const char* program_name, char* buffer, noom_uint_t buffer_size);
|
||||||
58
src/helper.c
58
src/helper.c
@@ -1,7 +1,13 @@
|
|||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
int noom_startswith(const char* str, const char* compare) {
|
int noom_startswith(const char* str, const char* compare) {
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#if __has_builtin(__builtin_strncmp)
|
||||||
|
return __builtin_strncmp(compare, str, noom_strlen(compare)) == 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
noom_uint_t i = 0;
|
noom_uint_t i = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (compare[i] == '\0') return 1; // we did it
|
if (compare[i] == '\0') return 1; // we did it
|
||||||
@@ -11,7 +17,7 @@ int noom_startswith(const char* str, const char* compare) {
|
|||||||
return 0; // unreachable but whatevs
|
return 0; // unreachable but whatevs
|
||||||
}
|
}
|
||||||
|
|
||||||
int noom_streql(const char* stra, noom_uint_t lena, const char* strb, noom_uint_t lenb) {
|
int noom_memeq(const char* stra, noom_uint_t lena, const char* strb, noom_uint_t lenb) {
|
||||||
if (lena != lenb) return 0;
|
if (lena != lenb) return 0;
|
||||||
|
|
||||||
for (noom_uint_t i = 0; i < lena; i++) {
|
for (noom_uint_t i = 0; i < lena; i++) {
|
||||||
@@ -21,6 +27,56 @@ int noom_streql(const char* stra, noom_uint_t lena, const char* strb, noom_uint_
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noom_uint_t noom_strlen(const char *s) {
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#if __has_builtin(__builtin_strlen)
|
||||||
|
return __builtin_strlen(s);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
const char *a = s;
|
||||||
|
while (*s) s++;
|
||||||
|
return s - a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int noom_strcmp(const char *a, const char *b) {
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#if __has_builtin(__builtin_strcmp)
|
||||||
|
return __builtin_strcmp(a, b);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
for (; *a && *a == *b; a++, b++);
|
||||||
|
return *(const unsigned char*)a - *(const unsigned char*)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noom_safe_strcpy(char* buffer, noom_uint_t* pos, noom_uint_t buffer_size, const char* src) {
|
||||||
|
while (*src && *pos < buffer_size - 1) {
|
||||||
|
buffer[(*pos)++] = *src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *noom_strndup(const char *s, const noom_uint_t len) {
|
||||||
|
char *whar = noom_alloc(len + 1);
|
||||||
|
if (whar == 0) return 0;
|
||||||
|
noom_memcpy(whar, s, len);
|
||||||
|
whar[len] = '\0';
|
||||||
|
return whar;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noom_memcpy(void* dst, const void* src, noom_uint_t n) {
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#if __has_builtin(__builtin_memcpy)
|
||||||
|
__builtin_memcpy(dst, src, n);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
unsigned char *d = dst;
|
||||||
|
const unsigned char *s = src;
|
||||||
|
|
||||||
|
while (n--) {
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include <stdlib.h> // TODO: remove
|
#include <stdlib.h> // TODO: remove
|
||||||
|
|
||||||
void* noom_alloc(noom_uint_t size) {
|
void* noom_alloc(noom_uint_t size) {
|
||||||
|
|||||||
10
src/helper.h
10
src/helper.h
@@ -1,7 +1,15 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define NOOM_USHORT_MAX 0xffff
|
||||||
|
|
||||||
int noom_startswith(const char* str, const char* compare);
|
int noom_startswith(const char* str, const char* compare);
|
||||||
int noom_streql(const char* stra, noom_uint_t lena, const char* strb, noom_uint_t lenb); // rename to something better?
|
int noom_memeq(const char* stra, noom_uint_t lena, const char* strb, noom_uint_t lenb);
|
||||||
|
noom_uint_t noom_strlen(const char *s);
|
||||||
|
int noom_strcmp(const char *a, const char* b);
|
||||||
|
void noom_safe_strcpy(char* buffer, noom_uint_t* pos, noom_uint_t buffer_size, const char* src);
|
||||||
|
char *noom_strndup(const char *s, noom_uint_t len);
|
||||||
|
|
||||||
|
void noom_memcpy(void* dst, const void* src, noom_uint_t n);
|
||||||
|
|
||||||
void* noom_alloc(noom_uint_t size);
|
void* noom_alloc(noom_uint_t size);
|
||||||
void noom_free(void* ptr);
|
void noom_free(void* ptr);
|
||||||
|
|||||||
45
src/lexer.c
45
src/lexer.c
@@ -433,34 +433,34 @@ noom_uint_t noomL_getstring(const char* s, noomL_ErrorType* error, noom_LuaVersi
|
|||||||
}
|
}
|
||||||
|
|
||||||
int noomL_iskeyword(const char* s, noom_uint_t len, noom_LuaVersion version) {
|
int noomL_iskeyword(const char* s, noom_uint_t len, noom_LuaVersion version) {
|
||||||
if (noom_streql(s, len, "true", 4)) return 1;
|
if (noom_memeq(s, len, "true", 4)) return 1;
|
||||||
if (noom_streql(s, len, "false", 5)) return 1;
|
if (noom_memeq(s, len, "false", 5)) return 1;
|
||||||
if (noom_streql(s, len, "nil", 3)) return 1;
|
if (noom_memeq(s, len, "nil", 3)) return 1;
|
||||||
|
|
||||||
if (noom_streql(s, len, "if", 2)) return 1;
|
if (noom_memeq(s, len, "if", 2)) return 1;
|
||||||
if (noom_streql(s, len, "then", 4)) return 1;
|
if (noom_memeq(s, len, "then", 4)) return 1;
|
||||||
if (noom_streql(s, len, "else", 4)) return 1;
|
if (noom_memeq(s, len, "else", 4)) return 1;
|
||||||
if (noom_streql(s, len, "elseif", 6)) return 1;
|
if (noom_memeq(s, len, "elseif", 6)) return 1;
|
||||||
|
|
||||||
if (noom_streql(s, len, "and", 3)) return 1;
|
if (noom_memeq(s, len, "and", 3)) return 1;
|
||||||
if (noom_streql(s, len, "or", 2)) return 1;
|
if (noom_memeq(s, len, "or", 2)) return 1;
|
||||||
if (noom_streql(s, len, "not", 3)) return 1;
|
if (noom_memeq(s, len, "not", 3)) return 1;
|
||||||
|
|
||||||
if (noom_streql(s, len, "local", 5)) return 1;
|
if (noom_memeq(s, len, "local", 5)) return 1;
|
||||||
|
|
||||||
if (noom_streql(s, len, "for", 3)) return 1;
|
if (noom_memeq(s, len, "for", 3)) return 1;
|
||||||
if (noom_streql(s, len, "function", 8)) return 1;
|
if (noom_memeq(s, len, "function", 8)) return 1;
|
||||||
if (noom_streql(s, len, "do", 2)) return 1;
|
if (noom_memeq(s, len, "do", 2)) return 1;
|
||||||
if (noom_streql(s, len, "until", 5)) return 1;
|
if (noom_memeq(s, len, "until", 5)) return 1;
|
||||||
if (noom_streql(s, len, "while", 5)) return 1;
|
if (noom_memeq(s, len, "while", 5)) return 1;
|
||||||
if (noom_streql(s, len, "repeat", 6)) return 1;
|
if (noom_memeq(s, len, "repeat", 6)) return 1;
|
||||||
if (noom_streql(s, len, "end", 3)) return 1;
|
if (noom_memeq(s, len, "end", 3)) return 1;
|
||||||
if (noom_streql(s, len, "in", 2)) return 1;
|
if (noom_memeq(s, len, "in", 2)) return 1;
|
||||||
if (noom_streql(s, len, "return", 6)) return 1;
|
if (noom_memeq(s, len, "return", 6)) return 1;
|
||||||
if (noom_streql(s, len, "break", 5)) return 1;
|
if (noom_memeq(s, len, "break", 5)) return 1;
|
||||||
|
|
||||||
if (version >= NOOM_VERSION_52) {
|
if (version >= NOOM_VERSION_52) {
|
||||||
if (noom_streql(s, len, "goto", 4)) return 1;
|
if (noom_memeq(s, len, "goto", 4)) return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -580,7 +580,6 @@ noomL_ErrorType noomL_lex(const char* s, noom_uint_t start, noomL_Token* token,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// god damn it we errorrreed
|
// god damn it we errorrreed
|
||||||
return NOOML_ERROR_UNKNOWN;
|
return NOOML_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|||||||
258
src/main.c
258
src/main.c
@@ -1,26 +1,29 @@
|
|||||||
#include <stdio.h> // for now
|
#include <stdio.h> // for now
|
||||||
// #include "lexer.h"
|
|
||||||
#include "parser.h"
|
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
void tab(noom_uint_t amount) {
|
void tab(noom_uint_t amount) {
|
||||||
amount *= 2;
|
amount *= 2;
|
||||||
for (noom_uint_t i = 0; i < amount; i++) {
|
for (noom_uint_t i = 0; i < amount; i++) {
|
||||||
putchar(' ');
|
putchar(' ');
|
||||||
|
putchar(' ');
|
||||||
|
putchar(' ');
|
||||||
|
putchar(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_node(noomP_Node* node, noom_uint_t depth) {
|
void print_node(const noomP_Node *node, noom_uint_t depth) {
|
||||||
tab(depth);
|
tab(depth);
|
||||||
printf("{\n");
|
printf("{\n");
|
||||||
|
|
||||||
tab(depth+1);
|
tab(depth + 1);
|
||||||
printf("type: %s\n", noomP_formatNodeType(node->type));
|
printf("type: %s\n", noomP_formatNodeType(node->type));
|
||||||
|
|
||||||
tab(depth+1);
|
tab(depth + 1);
|
||||||
printf("location: %lld\n", node->source_offset);
|
printf("location: %lld\n", node->source_offset);
|
||||||
|
|
||||||
tab(depth+1);
|
tab(depth + 1);
|
||||||
printf("subnodes:\n");
|
printf("subnodes:\n");
|
||||||
|
|
||||||
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
for (noom_uint_t i = 0; i < node->subnodec; i++) {
|
||||||
@@ -31,46 +34,237 @@ void print_node(noomP_Node* node, noom_uint_t depth) {
|
|||||||
printf("}\n");
|
printf("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(const char *code, const char *program_name, const char *filename) {
|
||||||
// uhh uhhh uhhhhh
|
noomP_Parser parser;
|
||||||
const char* code = "local t = {'a'; 2; 6}";
|
noomP_Node *program;
|
||||||
noom_uint_t pos = 0;
|
|
||||||
|
|
||||||
printf("LEX OUTPUT:\n");
|
// goodbye "shitass" you will be missed
|
||||||
|
int success = noomP_parse(code, filename, NOOM_VERSION_54, &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_Token token;
|
noomL_ErrorType err = noomL_lex(code, pos, &token, NOOM_VERSION_54);
|
||||||
while (1) {
|
if (err) break;
|
||||||
noomL_lex(code, pos, &token, NOOM_VERSION_54);
|
|
||||||
|
|
||||||
printf("%s ", noomL_formatTokenType(token.type));
|
if (token.type == NOOML_TOKEN_KEYWORD) {
|
||||||
for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]);
|
fputs("\x1b[38;2;207;142;109m", stdout);
|
||||||
putchar('\n');
|
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;
|
pos += token.length;
|
||||||
|
|
||||||
if (token.type == NOOML_TOKEN_EOF) break;
|
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);
|
||||||
|
noom_format_error(&parser, program_name, buf, bleh);
|
||||||
|
fputs(buf, stdout);
|
||||||
|
noom_free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// time for parser testing
|
|
||||||
printf("\nPARSE OUTPUT:\n");
|
|
||||||
|
|
||||||
noomP_Node *program;
|
|
||||||
noomP_Node *last_node;
|
|
||||||
|
|
||||||
int success = noomP_parse(code, "shitass", NOOM_VERSION_54, &program, &last_node);
|
|
||||||
if (success != 0) return success;
|
|
||||||
|
|
||||||
print_node(program, 0);
|
|
||||||
|
|
||||||
// freeing time
|
// freeing time
|
||||||
|
noomP_Node *last_node = parser.last_node;
|
||||||
while (last_node) {
|
while (last_node) {
|
||||||
noomP_Node* next = last_node->previous_node;
|
noomP_Node *next = last_node->previous_node;
|
||||||
// subnodes could be null if we OOM'd during a realloc of it
|
// subnodes could be null if we OOM'd during a realloc of it
|
||||||
if (last_node->subnodes) noom_free(last_node->subnodes);
|
if (last_node->subnodes) noom_free(last_node->subnodes);
|
||||||
noom_free(last_node);
|
noom_free(last_node);
|
||||||
last_node = next;
|
last_node = next;
|
||||||
}
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* read_file(const char* filename) {
|
||||||
|
FILE* file = fopen(filename, "r");
|
||||||
|
if (file == 0) {
|
||||||
|
fprintf(stderr, "Failed to open '%s'.\n", filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
const unsigned long filesize = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
char* buffer = noom_alloc(filesize + 1);
|
||||||
|
|
||||||
|
if (fread(buffer, 1, filesize, file) != filesize) {
|
||||||
|
fprintf(stderr, "Reached the end of the file\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buffer[filesize] = '\0';
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* read_stdin() {
|
||||||
|
noom_uint_t capacity = 4096;
|
||||||
|
noom_uint_t size = 0;
|
||||||
|
char* buffer = noom_alloc(capacity);
|
||||||
|
|
||||||
|
size_t n;
|
||||||
|
while ((n = fread(buffer + size, 1, capacity - size, stdin)) > 0) {
|
||||||
|
size += n;
|
||||||
|
if (size == capacity) {
|
||||||
|
capacity *= 2;
|
||||||
|
buffer = noom_realloc(buffer, capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[size] = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// code stolen from my different project
|
||||||
|
static int read_prompt(char* buf, int buf_size, char* prompt, const int required) {
|
||||||
|
do {
|
||||||
|
printf("%s", prompt);
|
||||||
|
fflush(stdout);
|
||||||
|
if (!fgets(buf, buf_size, stdin)) return 1;
|
||||||
|
const size_t len = noom_strlen(buf);
|
||||||
|
if (len > 0 && buf[len - 1] != '\n') {
|
||||||
|
while (getchar() != '\n' && !feof(stdin)) ;
|
||||||
|
}
|
||||||
|
else if (len > 0) {
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
} while (buf[0] == '\0' && required);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
const char *err = 0;
|
||||||
|
struct {
|
||||||
|
noom_bool_t enter_repl;
|
||||||
|
noom_bool_t use_stdin;
|
||||||
|
const char* script_exec;
|
||||||
|
const char* script_path;
|
||||||
|
noom_bool_t do_i_already_know_what_to_do;
|
||||||
|
} params = {0};
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
params.enter_repl = 1;
|
||||||
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (noom_strcmp(argv[i], "-") == 0) {
|
||||||
|
params.use_stdin = 1;
|
||||||
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noom_strcmp(argv[i], "--") == 0) {
|
||||||
|
if (++i >= argc) break;
|
||||||
|
if (params.do_i_already_know_what_to_do) {
|
||||||
|
err = "too many arguments";
|
||||||
|
goto die;
|
||||||
|
}
|
||||||
|
params.script_exec = argv[i];
|
||||||
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[i][0] != '-') {
|
||||||
|
if (params.do_i_already_know_what_to_do) {
|
||||||
|
err = "too many arguments";
|
||||||
|
goto die;
|
||||||
|
}
|
||||||
|
params.script_path = argv[i];
|
||||||
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[i][1] == 'e') {
|
||||||
|
if (params.do_i_already_know_what_to_do) {
|
||||||
|
goto die;
|
||||||
|
}
|
||||||
|
/* "-estat" or "-e stat" */
|
||||||
|
if (argv[i][2] != '\0') {
|
||||||
|
params.script_exec = argv[i] + 2;
|
||||||
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++i >= argc) {
|
||||||
|
err = "-e needs an argument";
|
||||||
|
goto die;
|
||||||
|
}
|
||||||
|
params.script_exec = argv[i];
|
||||||
|
params.do_i_already_know_what_to_do = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[i][1] == 'v') {
|
||||||
|
puts(NOOM_VERSION_TEXT);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = "unknown option";
|
||||||
|
goto die;
|
||||||
|
}
|
||||||
|
if (!params.do_i_already_know_what_to_do) {
|
||||||
|
err = "script not set";
|
||||||
|
goto die;
|
||||||
|
}
|
||||||
|
if (params.script_exec || params.script_path) {
|
||||||
|
if (params.script_exec) {
|
||||||
|
return the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(params.script_exec, argv[0], "(command line)");
|
||||||
|
}
|
||||||
|
char* code = read_file(params.script_path);
|
||||||
|
if (code == 0) return 1;
|
||||||
|
int offset = 0;
|
||||||
|
if (code[0] == '#' && code[1] == '!') for (offset = 2; code[offset] && code[offset] != '\n'; offset++);
|
||||||
|
return the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(code + offset, argv[0], params.script_path);
|
||||||
|
}
|
||||||
|
if (params.use_stdin) {
|
||||||
|
char* code = read_stdin();
|
||||||
|
if (code == 0) return 1;
|
||||||
|
return the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(code, argv[0], "stdin");
|
||||||
|
}
|
||||||
|
if (params.enter_repl) {
|
||||||
|
puts(NOOM_VERSION_TEXT);
|
||||||
|
for (;;) {
|
||||||
|
char code[4096];
|
||||||
|
if (read_prompt(code, sizeof(code), "> ", 1)) return 0;
|
||||||
|
the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(code, 0, "(noom input)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die:
|
||||||
|
fprintf(stderr, "%s: %s\n"
|
||||||
|
"usage: %s [options] [script [args]]\n"
|
||||||
|
"Available options are:\n"
|
||||||
|
" - execute stdin\n"
|
||||||
|
" -e stat execute string 'stat'\n"
|
||||||
|
" -v show version\n",
|
||||||
|
argv[0], err, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
20
src/noom.h
20
src/noom.h
@@ -3,6 +3,19 @@
|
|||||||
#ifndef NOOM_H
|
#ifndef NOOM_H
|
||||||
#define NOOM_H
|
#define NOOM_H
|
||||||
|
|
||||||
|
#define NN_STR(x) #x
|
||||||
|
#define NN_XSTR(x) NN_STR(x)
|
||||||
|
|
||||||
|
#define NOOM_VERSION_MAJOR 0
|
||||||
|
#define NOOM_VERSION_MINOR 0
|
||||||
|
#define NOOM_VERSION_PATCH 0
|
||||||
|
#if NOOM_VERSION_PATCH==0
|
||||||
|
#define NOOM_VERSION_FULL NN_XSTR(NOOM_VERSION_MAJOR) "." NN_XSTR(NOOM_VERSION_MINOR)
|
||||||
|
#else
|
||||||
|
#define NOOM_VERSION_FULL NN_XSTR(NOOM_VERSION_MAJOR) "." NN_XSTR(NOOM_VERSION_MINOR) "." NN_XSTR(NOOM_VERSION_PATCH)
|
||||||
|
#endif
|
||||||
|
#define NOOM_VERSION_TEXT "Noom " NOOM_VERSION_FULL " (C) 2026 NeoFlock and Noom contributors"
|
||||||
|
|
||||||
typedef enum noom_LuaVersion {
|
typedef enum noom_LuaVersion {
|
||||||
// no 5.0, at least for now, cause it doesn't seem to be used much and is a bit *weird*
|
// no 5.0, at least for now, cause it doesn't seem to be used much and is a bit *weird*
|
||||||
NOOM_VERSION_51,
|
NOOM_VERSION_51,
|
||||||
@@ -25,6 +38,10 @@ typedef enum noom_LuaType {
|
|||||||
|
|
||||||
typedef enum noom_Exit {
|
typedef enum noom_Exit {
|
||||||
NOOM_OK = 0,
|
NOOM_OK = 0,
|
||||||
|
NOOM_PLEASEHELPMEIAMSCARED,
|
||||||
|
NOOM_IAMNOTSCAREDJUSTLAZYTHISTIME,
|
||||||
|
// unknown internal error
|
||||||
|
NOOM_EINTERNAL,
|
||||||
NOOM_YIELD,
|
NOOM_YIELD,
|
||||||
// out of memory
|
// out of memory
|
||||||
NOOM_ENOMEM,
|
NOOM_ENOMEM,
|
||||||
@@ -45,4 +62,7 @@ typedef struct noom_LuaVM noom_LuaVM;
|
|||||||
typedef noom_Exit noom_CFunction(noom_LuaVM *vm);
|
typedef noom_Exit noom_CFunction(noom_LuaVM *vm);
|
||||||
typedef noom_Exit noom_KFunction(noom_LuaVM *vm, noom_Exit status, void *ctx);
|
typedef noom_Exit noom_KFunction(noom_LuaVM *vm, noom_Exit status, void *ctx);
|
||||||
|
|
||||||
|
noom_LuaVM *noom_createVM(noom_LuaVersion version);
|
||||||
|
void noom_destroyVM(noom_LuaVM *vm);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
365
src/parser.c
365
src/parser.c
File diff suppressed because it is too large
Load Diff
54
src/parser.h
54
src/parser.h
@@ -72,12 +72,57 @@ typedef enum noomP_Error {
|
|||||||
NOOMP_ERROR_NONE = 0,
|
NOOMP_ERROR_NONE = 0,
|
||||||
NOOMP_ERROR_OOM,
|
NOOMP_ERROR_OOM,
|
||||||
|
|
||||||
NOOMP_ERROR_UNEXPECTED, // TODO: maybe split into multiple for better errors?
|
NOOMP_ERROR_EXPECTED_LCURLY, // table start
|
||||||
|
NOOMP_ERROR_EXPECTED_RCURLY, // table end
|
||||||
|
NOOMP_ERROR_EXPECTED_RBRACKET_AFTER_KEY,
|
||||||
|
NOOMP_ERROR_EXPECTED_EQUALS_AFTER_KEY,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_FIELD_IDENTIFIER,
|
||||||
|
NOOMP_ERROR_EXPECTED_METHOD_CALL,
|
||||||
|
NOOMP_ERROR_EXPECTED_RBRACKET_AFTER_INDEX,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_RPAREN_AFTER_EXPRESSION,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_LPAREN_FOR_PARAMETERS,
|
||||||
|
NOOMP_ERROR_EXPECTED_RPAREN_FOR_PARAMETERS,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LOCAL_FUNCTION,
|
||||||
|
NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_FUNCTION,
|
||||||
|
NOOMP_ERROR_EXPECTED_END_AFTER_LOCAL_FUNCTION,
|
||||||
|
NOOMP_ERROR_EXPECTED_END_AFTER_FUNCTION,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LOCAL,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LANGLE,
|
||||||
|
NOOMP_ERROR_EXPECTED_RANGLE_TO_CLOSE_ATTRIBUTE,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_THEN_AFTER_EXPRESSION,
|
||||||
|
NOOMP_ERROR_EXPECTED_ELSE_ELSEIF_OR_END,
|
||||||
|
NOOMP_ERROR_EXPECTED_END_AFTER_IF,
|
||||||
|
NOOMP_ERROR_EXPECTED_DO_AFTER_EXPRESSION,
|
||||||
|
NOOMP_ERROR_EXPECTED_END_AFTER_WHILE,
|
||||||
|
NOOMP_ERROR_EXPECTED_END_AFTER_FOR,
|
||||||
|
NOOMP_ERROR_EXPECTED_END_AFTER_DO,
|
||||||
|
NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_FOR,
|
||||||
|
NOOMP_ERROR_EXPECTED_VARIABLE_AFTER_COMMA_IN_FOR,
|
||||||
|
NOOMP_ERROR_EXPECTED_IN,
|
||||||
|
NOOMP_ERROR_EXPECTED_UNTIL,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_GOTO,
|
||||||
|
NOOMP_ERROR_EXPECTED_COLONCOLON,
|
||||||
|
|
||||||
|
NOOMP_ERROR_INVALID_STATEMENT,
|
||||||
|
|
||||||
|
NOOMP_ERROR_EXPECTED_ASSIGNABLE,
|
||||||
|
NOOMP_ERROR_NOT_ASSIGNABLE,
|
||||||
|
NOOMP_ERROR_EXPECTED_COMMA_OR_EQUAL_IN_ASSIGNMENT,
|
||||||
|
NOOMP_ERROR_EXPRESSION_NOT_STATEMENT,
|
||||||
|
|
||||||
NOOMP_ERROR_FAKEATTRIBUTE,
|
NOOMP_ERROR_FAKEATTRIBUTE,
|
||||||
NOOMP_ERROR_RETURN_NOT_END,
|
NOOMP_ERROR_RETURN_NOT_END,
|
||||||
NOOMP_ERROR_FOR_WRONG_AMOUNT,
|
NOOMP_ERROR_FOR_WRONG_AMOUNT,
|
||||||
|
|
||||||
NOOMP_ERROR_LEXER = 1 << 31, // bitwise or'd with the lexer error number
|
NOOMP_ERROR_LEXER = 1 << 31, // bitwise or's with the lexer error number
|
||||||
} noomP_Error;
|
} noomP_Error;
|
||||||
|
|
||||||
typedef struct noomP_Node {
|
typedef struct noomP_Node {
|
||||||
@@ -97,6 +142,9 @@ typedef struct noomP_Parser { // todo: track location in code with line/column?
|
|||||||
|
|
||||||
const char* code;
|
const char* code;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
|
noom_uint_t last_token_offset;
|
||||||
|
noom_uint_t last_token_length;
|
||||||
|
|
||||||
noom_uint_t lex_offset;
|
noom_uint_t lex_offset;
|
||||||
|
|
||||||
noom_uint_t error_state;
|
noom_uint_t error_state;
|
||||||
@@ -117,7 +165,7 @@ noomP_Node* noomP_parseBlock(noomP_Parser* parser);
|
|||||||
noomP_Node* noomP_parseExpression(noomP_Parser* parser);
|
noomP_Node* noomP_parseExpression(noomP_Parser* parser);
|
||||||
noomP_Node* noomP_parseStatement(noomP_Parser* parser);
|
noomP_Node* noomP_parseStatement(noomP_Parser* parser);
|
||||||
|
|
||||||
int noomP_parse(const char* code, const char* filename, noom_LuaVersion version, noomP_Node** outpointer, noomP_Node** last_node);
|
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);
|
||||||
|
|
||||||
|
|||||||
83
src/vm.c
Normal file
83
src/vm.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#include "vm.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
noomV_Object *noomV_allocObj(noom_LuaVM *vm, noomV_ObjTag tag, noom_uint_t size) {
|
||||||
|
noomV_Object *o = noom_alloc(size);
|
||||||
|
if(o == 0) return o;
|
||||||
|
|
||||||
|
o->tag = tag;
|
||||||
|
o->marked = 0;
|
||||||
|
o->next = vm->heap;
|
||||||
|
o->nextGray = 0;
|
||||||
|
vm->heap = o;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
noomV_String *noomV_allocStr(noom_LuaVM *vm, const char *str, noom_uint_t len) {
|
||||||
|
noomV_String *s = (noomV_String*)noomV_allocObj(vm, NOOMV_OSTR, sizeof(noomV_String) + len + 1);
|
||||||
|
if (s == 0) return 0;
|
||||||
|
noom_memcpy(s->data, str, len);
|
||||||
|
s->data[len] = '\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
noomV_Function *noomV_allocFunc(noom_LuaVM *vm, const char *str, noom_uint_t len) {
|
||||||
|
noomV_Function *f = (noomV_Function*)noomV_allocObj(vm, NOOMV_OFUNC, sizeof(noomV_Function));
|
||||||
|
if (f == 0) return 0;
|
||||||
|
f->chunkname = noomV_allocStr(vm, str, len);
|
||||||
|
if (f->chunkname == 0) return 0;
|
||||||
|
f->code = 0;
|
||||||
|
f->consts = 0;
|
||||||
|
f->protos = 0;
|
||||||
|
f->upvals = 0;
|
||||||
|
f->locals = 0;
|
||||||
|
f->codesize = 0;
|
||||||
|
f->linedefined = 0;
|
||||||
|
f->lastlinedefined = 0;
|
||||||
|
f->argc = 0;
|
||||||
|
f->flags = 0;
|
||||||
|
f->constsize = 0;
|
||||||
|
f->protosize = 0;
|
||||||
|
f->upvalsize = 0;
|
||||||
|
f->localsize = 0;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
noomV_Table *noomV_allocTable(noom_LuaVM *vm) {
|
||||||
|
noomV_Table *t = (noomV_Table *)noomV_allocObj(vm, NOOMV_OTABLE, sizeof(noomV_Table));
|
||||||
|
if (t == 0) return 0;
|
||||||
|
t->meta = 0;
|
||||||
|
t->entries = 0;
|
||||||
|
t->used = 0;
|
||||||
|
t->len = 0;
|
||||||
|
t->entrydata = 0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noomV_freeObj(noomV_Object *obj) {
|
||||||
|
noom_free(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
noom_LuaVM *noom_createVM(noom_LuaVersion version) {
|
||||||
|
noom_LuaVM *vm = noom_alloc(sizeof(*vm));
|
||||||
|
if(vm == 0) return 0;
|
||||||
|
// initialize the universe to NULL, handles partial OOMs nicely
|
||||||
|
vm->heap = 0;
|
||||||
|
vm->graySet = 0;
|
||||||
|
vm->globals = 0;
|
||||||
|
vm->registry = 0;
|
||||||
|
vm->mainThread = 0;
|
||||||
|
vm->currentThread = 0;
|
||||||
|
vm->version = version;
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noom_destroyVM(noom_LuaVM *vm) {
|
||||||
|
noomV_Object *iter = vm->heap;
|
||||||
|
while(iter) {
|
||||||
|
noomV_Object *cur = iter;
|
||||||
|
iter = iter->next;
|
||||||
|
noomV_freeObj(cur);
|
||||||
|
}
|
||||||
|
noom_free(vm);
|
||||||
|
}
|
||||||
29
src/vm.h
29
src/vm.h
@@ -25,7 +25,7 @@ typedef enum noomV_ObjTag {
|
|||||||
|
|
||||||
typedef struct noomV_Object {
|
typedef struct noomV_Object {
|
||||||
noomV_ObjTag tag;
|
noomV_ObjTag tag;
|
||||||
bool marked;
|
noom_bool_t marked;
|
||||||
struct noomV_Object *next;
|
struct noomV_Object *next;
|
||||||
struct noomV_Object *nextGray;
|
struct noomV_Object *nextGray;
|
||||||
} noomV_Object;
|
} noomV_Object;
|
||||||
@@ -43,14 +43,15 @@ typedef enum noomV_ValueTag : unsigned char {
|
|||||||
typedef struct noomV_Value {
|
typedef struct noomV_Value {
|
||||||
noomV_ValueTag tag;
|
noomV_ValueTag tag;
|
||||||
// for stack slots
|
// for stack slots
|
||||||
bool autoclose;
|
noom_bool_t autoclose;
|
||||||
// pointer to value
|
// pointer to value
|
||||||
bool isptr;
|
noom_bool_t isptr;
|
||||||
union {
|
union {
|
||||||
noom_bool_t boolean;
|
noom_bool_t boolean;
|
||||||
noom_int_t integer;
|
noom_int_t integer;
|
||||||
noom_float_t number;
|
noom_float_t number;
|
||||||
noomV_Object *obj;
|
noomV_Object *obj;
|
||||||
|
struct noomV_Pointer *ptr;
|
||||||
};
|
};
|
||||||
} noomV_Value;
|
} noomV_Value;
|
||||||
|
|
||||||
@@ -64,8 +65,15 @@ typedef struct noomV_String {
|
|||||||
typedef struct noomV_Table {
|
typedef struct noomV_Table {
|
||||||
noomV_Object obj;
|
noomV_Object obj;
|
||||||
struct noomV_Table *meta;
|
struct noomV_Table *meta;
|
||||||
|
// amount of entries allocated
|
||||||
noom_uint_t entries;
|
noom_uint_t entries;
|
||||||
|
// how many entries are defined.
|
||||||
|
// Note, this includes keys with null values, which are still scanned.
|
||||||
|
noom_uint_t used;
|
||||||
|
// cache of #t, for faster subsequent fetches
|
||||||
noom_uint_t len;
|
noom_uint_t len;
|
||||||
|
// actual values. Given index i, V[i] is the key and V[i+entries] is the value.
|
||||||
|
// This is because we mostly read the key, so we should put more keys in cache.
|
||||||
noomV_Value *entrydata;
|
noomV_Value *entrydata;
|
||||||
} noomV_Table;
|
} noomV_Table;
|
||||||
|
|
||||||
@@ -166,6 +174,7 @@ typedef struct noomV_Inst {
|
|||||||
typedef struct noomV_UpvalDesc {
|
typedef struct noomV_UpvalDesc {
|
||||||
char *name;
|
char *name;
|
||||||
unsigned char idx;
|
unsigned char idx;
|
||||||
|
// whether the index is a stack index
|
||||||
noom_bool_t isStack;
|
noom_bool_t isStack;
|
||||||
} noomV_UpvalDesc;
|
} noomV_UpvalDesc;
|
||||||
|
|
||||||
@@ -184,11 +193,13 @@ typedef struct noomV_Function {
|
|||||||
noomV_String *chunkname;
|
noomV_String *chunkname;
|
||||||
noomV_Inst *code;
|
noomV_Inst *code;
|
||||||
noomV_Value *consts;
|
noomV_Value *consts;
|
||||||
noomV_Function **protos;
|
struct noomV_Function **protos;
|
||||||
noomV_UpvalDesc *upvals;
|
noomV_UpvalDesc *upvals;
|
||||||
noomV_LocalDesc *locals;
|
noomV_LocalDesc *locals;
|
||||||
unsigned int codesize;
|
unsigned int codesize;
|
||||||
|
// line of function
|
||||||
unsigned int linedefined;
|
unsigned int linedefined;
|
||||||
|
// line of end
|
||||||
unsigned int lastlinedefined;
|
unsigned int lastlinedefined;
|
||||||
// very size limited
|
// very size limited
|
||||||
// ░░░░░░░░░ ░ ▒░░▒ ▒░ ░░ ░
|
// ░░░░░░░░░ ░ ▒░░▒ ▒░ ░░ ░
|
||||||
@@ -260,7 +271,7 @@ typedef struct noomV_Function {
|
|||||||
typedef struct noomV_CallFrame {
|
typedef struct noomV_CallFrame {
|
||||||
// stack index of function
|
// stack index of function
|
||||||
unsigned int funcIdx;
|
unsigned int funcIdx;
|
||||||
bool isC;
|
noom_bool_t isC;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
//
|
//
|
||||||
@@ -293,6 +304,14 @@ struct noom_LuaVM {
|
|||||||
noomV_Table *registry;
|
noomV_Table *registry;
|
||||||
noomV_Thread *mainThread;
|
noomV_Thread *mainThread;
|
||||||
noomV_Thread *currentThread;
|
noomV_Thread *currentThread;
|
||||||
|
noom_LuaVersion version;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Allocating objects
|
||||||
|
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_Function *noomV_allocFunc(noom_LuaVM *vm, const char *str, noom_uint_t len);
|
||||||
|
noomV_Function *noomV_allocFunc(noom_LuaVM *vm, const char *str, noom_uint_t len);
|
||||||
|
void noomV_freeObj(noomV_Object *obj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user