From a3c2ddbf9e729dc2b7faceabc30ffb5b83da19ea Mon Sep 17 00:00:00 2001 From: tema5002 Date: Sun, 24 May 2026 12:46:01 +0300 Subject: [PATCH] implement proper error handling --- .gitignore | 3 +- build.lua | 6 ++- src/error.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/error.h | 5 ++ src/helper.c | 29 ++++++++++ src/helper.h | 2 + src/main.c | 66 ++++++++++++++++++----- src/parser.c | 90 ++++++++++++++++--------------- src/parser.h | 55 +++++++++++++++++-- 9 files changed, 345 insertions(+), 61 deletions(-) create mode 100644 src/error.c create mode 100644 src/error.h diff --git a/.gitignore b/.gitignore index bccf78e..9ea7baa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /.zig-cache /zig-out .idea +Makefile noom -noom.* \ No newline at end of file +noom.* diff --git a/build.lua b/build.lua index d1aff88..0c5012b 100755 --- a/build.lua +++ b/build.lua @@ -15,7 +15,10 @@ end local function runCommand(cmd) print("> " .. cmd) - return os.execute(cmd) + local result = os.execute(cmd) + if result ~= true then + os.exit(1) + end end local function fixPath(path) @@ -58,6 +61,7 @@ if not needsDir then end local files = { + 'src/error.c', 'src/helper.c', 'src/lexer.c', 'src/parser.c', diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..d64c938 --- /dev/null +++ b/src/error.c @@ -0,0 +1,150 @@ +#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_UNEXPECTED_VALUE] = {"unexpected value", 1}, + // I want someone smarter than me [tema5002] to give these a proper description + [NOOMP_ERROR_UNEXPECTED_SOMETHING1] = {"", 1}, + [NOOMP_ERROR_UNEXPECTED_SOMETHING2] = {"", 1}, + [NOOMP_ERROR_UNEXPECTED_SOMETHING3] = {"", 1}, + [NOOMP_ERROR_UNEXPECTED_SOMETHING4] = {"", 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 eh = row; eh; eh /= 10, linedig++); + + return + sizeof("noom: ") - 1 + + noom_strlen(parser->filename) + + sizeof(":") - 1 + + linedig + + sizeof(":") - 1 + + noom_strlen(err.s) + + + 1 + // \0 + (err.near ? ( + (err.near == 1 ? sizeof(" near") - 1 : 0) + + sizeof(" '") - 1 + + parser->last_token_length + + sizeof("'\n") - 1 + ) : 0); + } + + 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; +} diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..81eef5e --- /dev/null +++ b/src/error.h @@ -0,0 +1,5 @@ +// js let me use include guards 🥀🥀🥀🥀🥀🥀🥀 +#include "types.h" +#include "parser.h" + +noom_uint_t noom_format_error(const noomP_Parser* parser, char* buffer, noom_uint_t buffer_size); diff --git a/src/helper.c b/src/helper.c index 84f6c92..276ced1 100644 --- a/src/helper.c +++ b/src/helper.c @@ -21,6 +21,35 @@ 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) +{ + const char *a = s; +#ifdef noouuuuu // __GNUC__ + // align + while ((noom_uint_t)s % sizeof(noom_uint_t)) { + if (!*s) return s - a; + s++; + } + + // word at a time scan + typedef noom_uint_t __attribute__((__may_alias__)) word; + const word *w = (const word *)s; + while (!((*w)-(0x101010101010101) & ~(*w) & (0x8080808080808080))) + w++; + + // find exact null byte + s = (const char *)w; +#endif + while (*s) s++; + return s - a; +} + +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 // TODO: remove void* noom_alloc(noom_uint_t size) { diff --git a/src/helper.h b/src/helper.h index b39b5ab..1e2ce55 100644 --- a/src/helper.h +++ b/src/helper.h @@ -2,6 +2,8 @@ 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); +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); diff --git a/src/main.c b/src/main.c index fac9a64..8f0fb45 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ #include // for now // #include "lexer.h" -#include "parser.h" #include "helper.h" +#include "error.h" void tab(noom_uint_t amount) { amount *= 2; @@ -10,17 +10,17 @@ void tab(noom_uint_t amount) { } } -void print_node(noomP_Node* node, noom_uint_t depth) { +void print_node(noomP_Node *node, noom_uint_t depth) { tab(depth); printf("{\n"); - tab(depth+1); + tab(depth + 1); printf("type: %s\n", noomP_formatNodeType(node->type)); - tab(depth+1); + tab(depth + 1); printf("location: %lld\n", node->source_offset); - tab(depth+1); + tab(depth + 1); printf("subnodes:\n"); for (noom_uint_t i = 0; i < node->subnodec; i++) { @@ -31,25 +31,56 @@ void print_node(noomP_Node* node, noom_uint_t depth) { printf("}\n"); } -int main(int argc, char** argv) { +int main(int argc, char **argv) { // uhh uhhh uhhhhh - const char* code = "local t = {'a'; 2; 6}}"; + const char *code = "local t = {'a'; 2; 6 \"\\xgg\""; noom_uint_t pos = 0; printf("LEX OUTPUT:\n"); - noomL_Token token; + fputs("\x1b[48;2;10;10;10m", stdout); while (1) { - noomL_lex(code, pos, &token, NOOM_VERSION_54); + noomL_Token token; + //noomL_lex(code, pos, &token, NOOM_VERSION_54); + noomL_ErrorType err = noomL_lex(code, pos, &token, NOOM_VERSION_54); + if (err) break; - printf("%s ", noomL_formatTokenType(token.type)); - for (noom_uint_t i = 0; i < token.length; i++) putchar((code + token.offset)[i]); - putchar('\n'); + 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]); + fflush(stdout); + } 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]); + fflush(stdout); + } 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]); + fflush(stdout); + } 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]); + fflush(stdout); + } 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]); + fflush(stdout); + } 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'); + fflush(stdout); + } pos += token.length; if (token.type == NOOML_TOKEN_EOF) break; } + fputs("\x1b[0m\n", stdout); // time for parser testing printf("\nPARSE OUTPUT:\n"); @@ -60,16 +91,23 @@ int main(int argc, char** argv) { int success = noomP_parse(code, "shitass", NOOM_VERSION_54, &program, &parser); if (success == 0) 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; + noomP_Node *next = last_node->previous_node; // subnodes could be null if we OOM'd during a realloc of it if (last_node->subnodes) noom_free(last_node->subnodes); noom_free(last_node); last_node = next; } - + return 0; } diff --git a/src/parser.c b/src/parser.c index be6f2ea..a83f041 100644 --- a/src/parser.c +++ b/src/parser.c @@ -109,6 +109,11 @@ int noomP_peek(noomP_Parser* parser, noomL_Token* token) { parser->lex_offset += token->length; continue; } + + if (token->type != NOOML_TOKEN_EOF) { + parser->last_token_offset = token->offset; + parser->last_token_length = token->length; + } return 0; } @@ -135,7 +140,7 @@ noomP_Node* noomP_allocNode(noomP_Parser* parser) { noom_free(node); return 0; } - + node->previous_node = parser->last_node; parser->last_node = node; @@ -163,7 +168,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); @@ -194,14 +199,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); @@ -278,7 +283,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); @@ -300,7 +305,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 @@ -331,7 +336,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 ] @@ -378,7 +383,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; } @@ -448,7 +453,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); @@ -601,7 +606,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); @@ -837,7 +842,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); @@ -889,7 +894,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); @@ -953,7 +958,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); @@ -976,7 +981,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); @@ -994,7 +999,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); @@ -1015,7 +1020,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; @@ -1028,7 +1033,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); @@ -1104,7 +1109,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 } @@ -1119,7 +1124,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 } @@ -1134,7 +1139,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); @@ -1160,14 +1165,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); @@ -1190,7 +1195,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` @@ -1202,7 +1207,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` @@ -1240,7 +1245,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); @@ -1265,7 +1270,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); @@ -1282,7 +1287,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); @@ -1316,7 +1321,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); @@ -1418,7 +1423,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; @@ -1468,7 +1473,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); @@ -1494,7 +1499,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); @@ -1519,7 +1524,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); @@ -1531,7 +1536,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); @@ -1548,7 +1553,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); @@ -1578,7 +1583,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); @@ -1606,7 +1611,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); @@ -1637,7 +1642,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); @@ -1680,7 +1685,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_UNEXPECTED_SOMETHING1; return 0; } @@ -1689,7 +1694,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_UNEXPECTED_SOMETHING2; return 0; // unexpected } @@ -1708,7 +1713,7 @@ noomP_Node* noomP_parseRawStatement(noomP_Parser* parser) { break; } } else { - parser->error_state = NOOMP_ERROR_UNEXPECTED; + parser->error_state = NOOMP_ERROR_UNEXPECTED_SOMETHING3; return 0; // unexpected } } @@ -1737,12 +1742,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_UNEXPECTED_SOMETHING4; return 0; // unexpected. e.g. random string or whatever } } - parser->error_state = NOOMP_ERROR_UNEXPECTED; + parser->error_state = NOOMP_ERROR_UNEXPECTED_VALUE; return 0; } @@ -1795,6 +1800,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; diff --git a/src/parser.h b/src/parser.h index 2622fa9..0d6f2a7 100644 --- a/src/parser.h +++ b/src/parser.h @@ -71,13 +71,59 @@ typedef enum noomP_NodeType { 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_UNEXPECTED_VALUE, + + // i am sorry + NOOMP_ERROR_UNEXPECTED_SOMETHING1, + NOOMP_ERROR_UNEXPECTED_SOMETHING2, + NOOMP_ERROR_UNEXPECTED_SOMETHING3, + NOOMP_ERROR_UNEXPECTED_SOMETHING4, + 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 +143,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;