Compare commits
14 Commits
6310ec69d2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| be75ccd6f8 | |||
| 269d2c8ae9 | |||
| 20f9ee0a14 | |||
| 8e8b01b7d9 | |||
| 4fbb006072 | |||
| 09ac2a17f9 | |||
| 6d57f1fe6b | |||
| 2a22544464 | |||
| fbbe2e8285 | |||
| 0d6b1c6729 | |||
| 9acff5f893 | |||
| bb73054e2c | |||
| 5359461e9c | |||
|
|
d229116a8b |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
/build
|
||||
/.zig-cache
|
||||
/zig-out
|
||||
noom
|
||||
.idea
|
||||
/noom
|
||||
/noom.*
|
||||
Makefile
|
||||
|
||||
77
build.lua
Normal file → Executable file
77
build.lua
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
#!/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
|
||||
|
||||
local isBlendi = os.getenv("USER") == "blendi"
|
||||
local seperator = package.config:sub(1,1)
|
||||
local separator = package.config:sub(1,1)
|
||||
|
||||
local function filename(path)
|
||||
local s,e = 1, #path
|
||||
@@ -13,42 +13,86 @@ local function filename(path)
|
||||
return path:sub(s,e)
|
||||
end
|
||||
|
||||
local function runCommand(cmd)
|
||||
local function runCommand(cmd, ignore_fail)
|
||||
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
|
||||
|
||||
local function fixPath(path)
|
||||
local new = ""
|
||||
for i = 1,#path do
|
||||
local ch = path:sub(i,i)
|
||||
if ch == '/' then new = new .. seperator
|
||||
if ch == '/' then new = new .. separator
|
||||
else new = new .. ch end
|
||||
end
|
||||
return new
|
||||
end
|
||||
|
||||
if seperator == '\\' then
|
||||
runCommand('rmdir /S /Q build')
|
||||
if arg[1] == "clean" then
|
||||
if separator == '\\' then
|
||||
runCommand("rmdir /s /q build 2>nul", true)
|
||||
else
|
||||
runCommand('rm -rf build')
|
||||
runCommand("rm -rf build")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
runCommand('mkdir build')
|
||||
local needsDir = false
|
||||
|
||||
if separator == '\\' then
|
||||
needsDir = true
|
||||
else
|
||||
-- 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
|
||||
|
||||
local files = {
|
||||
'src/error.c',
|
||||
'src/helper.c',
|
||||
'src/lexer.c',
|
||||
'src/parser.c',
|
||||
'src/compiler.c',
|
||||
'src/vm.c',
|
||||
'src/main.c',
|
||||
}
|
||||
|
||||
local objects = {}
|
||||
|
||||
local coolArgs = {}
|
||||
|
||||
local function getTime(path)
|
||||
local handle = assert(io.popen('stat -c %Y "' .. path .. '" 2>/dev/null'))
|
||||
local result = handle:read("*a")
|
||||
handle:close()
|
||||
return tonumber(result) or 0
|
||||
end
|
||||
|
||||
local function needsRebuild(src, obj)
|
||||
if separator == '\\' then return true end
|
||||
local srcTime = getTime(src)
|
||||
local objTime = getTime(obj)
|
||||
return srcTime > objTime
|
||||
end
|
||||
|
||||
if not isBlendi then table.insert(coolArgs, '-fsanitize=undefined,address') end
|
||||
|
||||
local needsLinking = false
|
||||
|
||||
for i = 1,#files do
|
||||
local fname = files[i]
|
||||
local out = "build/" .. filename(fname) .. '.o'
|
||||
@@ -56,11 +100,20 @@ for i = 1,#files do
|
||||
fname = fixPath(fname)
|
||||
out = fixPath(out)
|
||||
|
||||
runCommand('clang -c -o ' .. out .. ' ' .. fname .. ' ' .. table.concat(coolArgs, ' '))
|
||||
if needsRebuild(fname, out) then
|
||||
needsLinking = true
|
||||
runCommand('clang -g -c -o ' .. out .. ' ' .. fname .. ' ' .. table.concat(coolArgs, ' '))
|
||||
end
|
||||
|
||||
objects[#objects+1] = out;
|
||||
end
|
||||
|
||||
local exe = seperator == '\\' and "noom.exe" or "noom"
|
||||
local exe = separator == '\\' and ".\\noom.exe" or "./noom"
|
||||
|
||||
runCommand('clang -o ' .. exe .. ' ' .. table.concat(objects, ' ') .. ' ' .. table.concat(coolArgs, ' '))
|
||||
if needsLinking then
|
||||
runCommand('clang -g -o ' .. exe .. ' ' .. table.concat(objects, ' ') .. ' ' .. table.concat(coolArgs, ' '))
|
||||
end
|
||||
|
||||
if arg[1] == "run" then
|
||||
runCommand(exe)
|
||||
end
|
||||
|
||||
@@ -21,6 +21,7 @@ pub fn build(b: *std.Build) void {
|
||||
"src/lexer.c",
|
||||
"src/parser.c",
|
||||
"src/compiler.c",
|
||||
"src/vm.c",
|
||||
"src/main.c",
|
||||
}
|
||||
});
|
||||
|
||||
1
shitass.lua
Normal file
1
shitass.lua
Normal file
@@ -0,0 +1 @@
|
||||
local t <close> = {6; 2}
|
||||
159
src/error.c
Normal file
159
src/error.c
Normal file
@@ -0,0 +1,159 @@
|
||||
#include "error.h"
|
||||
#include "helper.h"
|
||||
|
||||
noom_uint_t noom_format_error(const noomP_Parser* parser, 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;
|
||||
|
||||
space =
|
||||
sizeof("noom: ") - 1 +
|
||||
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;
|
||||
}
|
||||
|
||||
noom_safe_strcpy(buffer, &pos, buffer_size, "noom: ");
|
||||
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, char* buffer, noom_uint_t buffer_size);
|
||||
34
src/helper.c
34
src/helper.c
@@ -1,7 +1,12 @@
|
||||
#include "helper.h"
|
||||
#include "types.h"
|
||||
|
||||
int noom_startswith(const char* str, 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;
|
||||
while (1) {
|
||||
if (compare[i] == '\0') return 1; // we did it
|
||||
@@ -21,6 +26,33 @@ int noom_streql(const char* stra, noom_uint_t lena, const char* strb, noom_uint_
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
#include <stdlib.h> // TODO: remove
|
||||
|
||||
void* noom_alloc(noom_uint_t size) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "types.h"
|
||||
|
||||
int noom_startswith(const char* str, 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?
|
||||
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);
|
||||
|
||||
void* noom_alloc(noom_uint_t size);
|
||||
void noom_free(void* ptr);
|
||||
|
||||
233
src/main.c
233
src/main.c
@@ -1,7 +1,7 @@
|
||||
#include <stdio.h> // for now
|
||||
// #include "lexer.h"
|
||||
#include "parser.h"
|
||||
#include "helper.h"
|
||||
#include "error.h"
|
||||
#include "types.h"
|
||||
|
||||
void tab(noom_uint_t amount) {
|
||||
amount *= 2;
|
||||
@@ -10,7 +10,7 @@ void tab(noom_uint_t amount) {
|
||||
}
|
||||
}
|
||||
|
||||
void print_node(noomP_Node* node, noom_uint_t depth) {
|
||||
void print_node(const noomP_Node *node, noom_uint_t depth) {
|
||||
tab(depth);
|
||||
printf("{\n");
|
||||
|
||||
@@ -31,39 +31,65 @@ void print_node(noomP_Node* node, noom_uint_t depth) {
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// uhh uhhh uhhhhh
|
||||
const char* code = "local t = {'a'; 2; 6}";
|
||||
int the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(const char *code, const char *filename) {
|
||||
noomP_Parser parser;
|
||||
noomP_Node *program;
|
||||
|
||||
// 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;
|
||||
|
||||
printf("LEX OUTPUT:\n");
|
||||
|
||||
noomL_Token token;
|
||||
while (1) {
|
||||
noomL_lex(code, pos, &token, NOOM_VERSION_54);
|
||||
noomL_Token token;
|
||||
|
||||
noomL_ErrorType err = noomL_lex(code, pos, &token, NOOM_VERSION_54);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
puts("\x1b[0m");
|
||||
puts("PARSE OUTPUT:");
|
||||
print_node(program, 0);
|
||||
}
|
||||
else {
|
||||
noom_uint_t bleh = noom_format_error(&parser, NULL, 0);
|
||||
char* buf = noom_alloc(bleh);
|
||||
noom_format_error(&parser, buf, bleh);
|
||||
fputs(buf, stdout);
|
||||
noom_free(buf);
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -71,6 +97,169 @@ int main(int argc, char** argv) {
|
||||
noom_free(last_node);
|
||||
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;
|
||||
}
|
||||
|
||||
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, "(command line)");
|
||||
}
|
||||
char* code = read_file(params.script_path);
|
||||
if (code == 0) return 1;
|
||||
return the_theoretical_function_to_execute_your_code_that_should_be_replaced_later(code, 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, "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, "(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;
|
||||
}
|
||||
|
||||
16
src/noom.h
16
src/noom.h
@@ -3,6 +3,19 @@
|
||||
#ifndef 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 {
|
||||
// no 5.0, at least for now, cause it doesn't seem to be used much and is a bit *weird*
|
||||
NOOM_VERSION_51,
|
||||
@@ -45,4 +58,7 @@ typedef struct noom_LuaVM noom_LuaVM;
|
||||
typedef noom_Exit noom_CFunction(noom_LuaVM *vm);
|
||||
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
|
||||
|
||||
117
src/parser.c
117
src/parser.c
@@ -110,6 +110,11 @@ int noomP_peek(noomP_Parser* parser, noomL_Token* token) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token->type != NOOML_TOKEN_EOF) {
|
||||
parser->last_token_offset = token->offset;
|
||||
parser->last_token_length = token->length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -127,8 +132,6 @@ noomP_Node* noomP_allocNode(noomP_Parser* parser) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
node->previous_node = parser->last_node;
|
||||
|
||||
node->subnodec = 0;
|
||||
node->subnodes = noom_alloc(sizeof(noomP_Node*) * 2);
|
||||
node->subnode_cap = 2;
|
||||
@@ -138,6 +141,7 @@ noomP_Node* noomP_allocNode(noomP_Parser* parser) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
node->previous_node = parser->last_node;
|
||||
parser->last_node = node;
|
||||
|
||||
return node;
|
||||
@@ -145,13 +149,15 @@ noomP_Node* noomP_allocNode(noomP_Parser* parser) {
|
||||
|
||||
int noomP_addSubnode(noomP_Parser* parser, noomP_Node* node, noomP_Node* subnode) {
|
||||
if (node->subnodec == node->subnode_cap) {
|
||||
node->subnode_cap = node->subnode_cap * 2;
|
||||
node->subnodes = noom_realloc(node->subnodes, sizeof(noomP_Node*) * node->subnode_cap);
|
||||
noomP_Node** new = noom_realloc(node->subnodes, sizeof(noomP_Node*) * node->subnode_cap * 2);
|
||||
|
||||
if (node->subnodes == 0) {
|
||||
parser->error_state = NOOMP_ERROR_OOM;
|
||||
if (new == 0) {
|
||||
parser->error_state = NOOMP_ERROR_OOM; // well fuck
|
||||
return 1;
|
||||
}
|
||||
|
||||
node->subnodes = new;
|
||||
node->subnode_cap = node->subnode_cap * 2;
|
||||
}
|
||||
|
||||
node->subnodes[node->subnodec++] = subnode;
|
||||
@@ -164,7 +170,7 @@ noomP_Node* noomP_parseTableLiteral(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "{", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_LCURLY;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -195,14 +201,14 @@ noomP_Node* noomP_parseTableLiteral(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "]", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RBRACKET_AFTER_KEY;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "=", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_EQUALS_AFTER_KEY;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -279,7 +285,7 @@ noomP_Node* noomP_parseTableLiteral(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "}", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RCURLY;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -301,7 +307,7 @@ noomP_Node* noomP_parseComplexExpression(noomP_Parser* parser, noomP_Node* snode
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_FIELD_IDENTIFIER;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token); // skip the field name
|
||||
@@ -332,7 +338,7 @@ noomP_Node* noomP_parseComplexExpression(noomP_Parser* parser, noomP_Node* snode
|
||||
if (noomP_peek(parser, &token)) return 0; // look for ]
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || (!noom_streql(parser->code + token.offset, token.length, "]", 1))) {
|
||||
// damn it :(
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RBRACKET_AFTER_INDEX;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token); // skip ]
|
||||
@@ -379,7 +385,7 @@ noomP_Node* noomP_parseComplexExpression(noomP_Parser* parser, noomP_Node* snode
|
||||
// check for )
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || (!noom_streql(parser->code + token.offset, token.length, ")", 1))) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RPAREN_AFTER_EXPRESSION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -449,7 +455,7 @@ noomP_Node* noomP_parseComplexExpression(noomP_Parser* parser, noomP_Node* snode
|
||||
// check for )
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || (!noom_streql(parser->code + token.offset, token.length, ")", 1))) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RPAREN_AFTER_EXPRESSION;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -602,7 +608,7 @@ noomP_Node* noomP_parseRawExpression(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, ")", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RPAREN_AFTER_EXPRESSION;
|
||||
return 0; // unexpected
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -838,7 +844,7 @@ noomP_Node* noomP_parseFunctionParameters(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "(", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_LPAREN_FOR_PARAMETERS;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -890,7 +896,7 @@ noomP_Node* noomP_parseFunctionParameters(noomP_Parser* parser) {
|
||||
// closing paren
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, ")", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RPAREN_FOR_PARAMETERS;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -954,7 +960,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LOCAL_FUNCTION;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -977,7 +983,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "end", 3)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_END_AFTER_LOCAL_FUNCTION;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -995,7 +1001,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LOCAL;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1016,7 +1022,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
// the attribute is an identifier.
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_LANGLE;
|
||||
return 0; // unexpected
|
||||
}
|
||||
noom_uint_t attr = token.offset;
|
||||
@@ -1029,7 +1035,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, ">", 1)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_RANGLE_TO_CLOSE_ATTRIBUTE;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1105,7 +1111,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "then", 4)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_THEN_AFTER_EXPRESSION;
|
||||
return 0; // unexpected
|
||||
}
|
||||
|
||||
@@ -1120,7 +1126,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
|
||||
if (token.type != NOOML_TOKEN_KEYWORD) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_ELSE_ELSEIF_OR_END;
|
||||
return 0; // unexpected
|
||||
}
|
||||
|
||||
@@ -1135,7 +1141,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "then", 4)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_THEN_AFTER_EXPRESSION;
|
||||
return 0; // unexpected
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1161,14 +1167,14 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
break; // will check for end outside the loop because else and things
|
||||
} else {
|
||||
// unexpected
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_ELSE_ELSEIF_OR_END;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "end", 3)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_END_AFTER_IF;
|
||||
return 0; // unexpected
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1191,7 +1197,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "do", 2)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_DO_AFTER_EXPRESSION;
|
||||
return 0; // unexpected
|
||||
}
|
||||
noomP_skip(parser, &token); // skip `do`
|
||||
@@ -1203,7 +1209,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "end", 3)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_END_AFTER_WHILE;
|
||||
return 0; // unexpected
|
||||
}
|
||||
noomP_skip(parser, &token); // skip `end`
|
||||
@@ -1241,7 +1247,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
fname->source_offset = token.offset;
|
||||
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_FUNCTION;
|
||||
return 0; // unex.
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1266,7 +1272,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_FIELD_IDENTIFIER;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1283,7 +1289,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_METHOD_CALL;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1317,7 +1323,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
// remove `end`
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "end", 3)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_END_AFTER_FUNCTION;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1419,7 +1425,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_FOR;
|
||||
return 0;
|
||||
}
|
||||
noom_uint_t vname = token.offset;
|
||||
@@ -1469,7 +1475,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
while (1) {
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_VARIABLE_AFTER_COMMA_IN_FOR;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1495,7 +1501,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
// okay. that took a while. now for the in and the expressions
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "in", 2)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IN;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1520,7 +1526,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
// making this the same for all of them: do [block] end
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "do", 2)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_DO_AFTER_EXPRESSION;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1532,7 +1538,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "end", 3)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_END_AFTER_FOR;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1549,7 +1555,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_IDENTIFIER_AFTER_GOTO;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1579,7 +1585,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "until", 5)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_UNTIL;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1607,7 +1613,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_KEYWORD || !noom_streql(parser->code + token.offset, token.length, "end", 3)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_END_AFTER_DO;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1638,7 +1644,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "::", 2)) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_COLONCOLON;
|
||||
return 0;
|
||||
}
|
||||
noomP_skip(parser, &token);
|
||||
@@ -1681,7 +1687,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
|
||||
if (token.type != NOOML_TOKEN_IDENTIFIER && (token.type != NOOML_TOKEN_SYMBOL || !noom_streql(parser->code + token.offset, token.length, "(", 1))) {
|
||||
// unexpected
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_ASSIGNABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1690,7 +1696,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
if (item == 0) return 0;
|
||||
|
||||
if (item->type != NOOMP_NODE_INDEX && item->type != NOOMP_NODE_GETFIELD && item->type != NOOMP_NODE_VARIABLE) {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_NOT_ASSIGNABLE;
|
||||
return 0; // unexpected
|
||||
}
|
||||
|
||||
@@ -1709,7 +1715,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPECTED_COMMA_OR_EQUAL_IN_ASSIGNMENT;
|
||||
return 0; // unexpected
|
||||
}
|
||||
}
|
||||
@@ -1738,12 +1744,12 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) {
|
||||
// this expression is now a statement.
|
||||
return base; // no need to eat any more.
|
||||
} else {
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_EXPRESSION_NOT_STATEMENT;
|
||||
return 0; // unexpected. e.g. random string or whatever
|
||||
}
|
||||
}
|
||||
|
||||
parser->error_state = NOOMP_ERROR_UNEXPECTED;
|
||||
parser->error_state = NOOMP_ERROR_INVALID_STATEMENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1767,29 +1773,27 @@ noomP_Node* noomP_parseStatement(noomP_Parser* parser) {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
int noomP_parse(const char* code, const char* filename, noom_LuaVersion version, noomP_Node** outpointer, noomP_Node** last_node) {
|
||||
noomP_Parser parser;
|
||||
noomP_initParser(&parser, code, filename, version);
|
||||
int noomP_parse(const char* code, const char* filename, noom_LuaVersion version, noomP_Node** outpointer, noomP_Parser* parser) {
|
||||
noomP_initParser(parser, code, filename, version);
|
||||
|
||||
noomL_Token token;
|
||||
noomP_Node* node = noomP_allocNode(&parser);
|
||||
noomP_Node* node = noomP_allocNode(parser);
|
||||
if (node == 0) return -1;
|
||||
|
||||
node->source_offset = parser.lex_offset;
|
||||
node->source_offset = parser->lex_offset;
|
||||
node->type = NOOMP_NODE_PROGRAM;
|
||||
|
||||
while (1) {
|
||||
if (noomP_peek(&parser, &token)) return 0;
|
||||
if (noomP_peek(parser, &token)) return 0;
|
||||
if (token.type == NOOML_TOKEN_EOF) break;
|
||||
|
||||
noomP_Node* child = noomP_parseStatement(&parser);
|
||||
noomP_Node* child = noomP_parseStatement(parser);
|
||||
if (child == 0) return -1;
|
||||
|
||||
if (noomP_addSubnode(&parser, node, child)) return 0;
|
||||
if (noomP_addSubnode(parser, node, child)) return 0;
|
||||
}
|
||||
|
||||
*outpointer = node;
|
||||
*last_node = parser.last_node;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1798,6 +1802,7 @@ int noomP_initParser(noomP_Parser* parser, const char* code, const char* filenam
|
||||
parser->code = code;
|
||||
parser->filename = filename;
|
||||
parser->lex_offset = 0;
|
||||
parser->last_token_length = 0;
|
||||
parser->last_node = (void *)0;
|
||||
parser->version = version;
|
||||
|
||||
|
||||
54
src/parser.h
54
src/parser.h
@@ -72,12 +72,57 @@ typedef enum noomP_Error {
|
||||
NOOMP_ERROR_NONE = 0,
|
||||
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_RETURN_NOT_END,
|
||||
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;
|
||||
|
||||
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* filename;
|
||||
noom_uint_t last_token_offset;
|
||||
noom_uint_t last_token_length;
|
||||
|
||||
noom_uint_t lex_offset;
|
||||
|
||||
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_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);
|
||||
|
||||
|
||||
42
src/vm.c
Normal file
42
src/vm.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
26
src/vm.h
26
src/vm.h
@@ -25,7 +25,7 @@ typedef enum noomV_ObjTag {
|
||||
|
||||
typedef struct noomV_Object {
|
||||
noomV_ObjTag tag;
|
||||
bool marked;
|
||||
noom_bool_t marked;
|
||||
struct noomV_Object *next;
|
||||
struct noomV_Object *nextGray;
|
||||
} noomV_Object;
|
||||
@@ -43,14 +43,15 @@ typedef enum noomV_ValueTag : unsigned char {
|
||||
typedef struct noomV_Value {
|
||||
noomV_ValueTag tag;
|
||||
// for stack slots
|
||||
bool autoclose;
|
||||
noom_bool_t autoclose;
|
||||
// pointer to value
|
||||
bool isptr;
|
||||
noom_bool_t isptr;
|
||||
union {
|
||||
noom_bool_t boolean;
|
||||
noom_int_t integer;
|
||||
noom_float_t number;
|
||||
noomV_Object *obj;
|
||||
struct noomV_Pointer *ptr;
|
||||
};
|
||||
} noomV_Value;
|
||||
|
||||
@@ -64,8 +65,15 @@ typedef struct noomV_String {
|
||||
typedef struct noomV_Table {
|
||||
noomV_Object obj;
|
||||
struct noomV_Table *meta;
|
||||
// amount of entries allocated
|
||||
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;
|
||||
// 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_Table;
|
||||
|
||||
@@ -166,6 +174,7 @@ typedef struct noomV_Inst {
|
||||
typedef struct noomV_UpvalDesc {
|
||||
char *name;
|
||||
unsigned char idx;
|
||||
// whether the index is a stack index
|
||||
noom_bool_t isStack;
|
||||
} noomV_UpvalDesc;
|
||||
|
||||
@@ -184,11 +193,13 @@ typedef struct noomV_Function {
|
||||
noomV_String *chunkname;
|
||||
noomV_Inst *code;
|
||||
noomV_Value *consts;
|
||||
noomV_Function **protos;
|
||||
struct noomV_Function **protos;
|
||||
noomV_UpvalDesc *upvals;
|
||||
noomV_LocalDesc *locals;
|
||||
unsigned int codesize;
|
||||
// line of function
|
||||
unsigned int linedefined;
|
||||
// line of end
|
||||
unsigned int lastlinedefined;
|
||||
// very size limited
|
||||
// ░░░░░░░░░ ░ ▒░░▒ ▒░ ░░ ░
|
||||
@@ -260,7 +271,7 @@ typedef struct noomV_Function {
|
||||
typedef struct noomV_CallFrame {
|
||||
// stack index of function
|
||||
unsigned int funcIdx;
|
||||
bool isC;
|
||||
noom_bool_t isC;
|
||||
union {
|
||||
struct {
|
||||
//
|
||||
@@ -293,6 +304,11 @@ struct noom_LuaVM {
|
||||
noomV_Table *registry;
|
||||
noomV_Thread *mainThread;
|
||||
noomV_Thread *currentThread;
|
||||
noom_LuaVersion version;
|
||||
};
|
||||
|
||||
// Allocating objects
|
||||
noomV_Object *noomV_allocObj(noom_LuaVM *vm, noomV_ObjTag tag, noom_uint_t size);
|
||||
void noomV_freeObj(noomV_Object *obj);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user