From 672cdb692a5a6514f65d17a58efd60b993e139f8 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Tue, 25 Oct 2022 13:21:04 -0400 Subject: [PATCH] Display parseEval source in error messages. --- src/env.c | 2 +- src/main.c | 10 ++-- src/object.h | 7 ++- src/pebblisp.c | 14 +++--- src/pebblisp.h | 6 +-- src/plfunc/general.c | 6 +-- src/plfunc/web.c | 5 +- src/tokens.c | 112 +++++++++++++++++++++++++++++++------------ 8 files changed, 107 insertions(+), 55 deletions(-) diff --git a/src/env.c b/src/env.c index adb48d9..c331b15 100644 --- a/src/env.c +++ b/src/env.c @@ -476,7 +476,7 @@ Object help(Object* params, int length, struct Environment* env) int runTest(const char* test, const char* expected, int detailed) { struct Environment env = defaultEnv(); - Object o = parseEval(test, &env); + Object o = parseEval(test, "testCode", &env); size_t length; char* result = stringObj(&o, &length); cleanObject(&o); diff --git a/src/main.c b/src/main.c index edb2310..8987840 100644 --- a/src/main.c +++ b/src/main.c @@ -116,7 +116,7 @@ void repl(struct Environment* env) free(oldBuf); } - Object o = parseEval(buf, env); + Object o = parseEval(buf, "REPL", env); if (isFuncy(o) || isError(o, DID_NOT_FIND_SYMBOL)) { system(buf); } else { @@ -246,9 +246,9 @@ int main(int argc, const char* argv[]) readFile(SCRIPTDIR "/lib.pbl", &env); } - Object o = parseEval("(def prompt %%)", &env); + Object o = parseEval("(def prompt %%)", "[INTERNAL]", &env); cleanObject(&o); - o = parseEval("(def preprocess (fn (text) (text)))", &env); + o = parseEval("(def preprocess (fn (text) (text)))", "[INTERNAL]", &env); cleanObject(&o); if (!settings.ignoreConfig) { @@ -268,10 +268,10 @@ int main(int argc, const char* argv[]) if (file) { // Execute a file loadArgsIntoEnv(argc, argv, &env); - _readFile(file, &env); + _readFile(file, argv[argc - 1], &env); } else { // Run arguments directly as pl code - Object r = parseEval(argv[argc - 1], &env); + Object r = parseEval(argv[argc - 1], "[PL ARGUMENTS]", &env); printAndClean(&r); } } else { diff --git a/src/object.h b/src/object.h index 836a6e4..5b6a744 100644 --- a/src/object.h +++ b/src/object.h @@ -315,8 +315,11 @@ Object errorWithAllocatedContextLineNo(enum errorCode code, char* context, int l #define errorAddContext(x, y, z, a) ; #define throw(_code, ...) return errorObject(_code) #else -#define throw(_code, ...) do { char* ERROR_CONTEXT = malloc(sizeof(char) * ERR_LEN); sprintf(ERROR_CONTEXT, __VA_ARGS__); \ - return errorWithAllocatedContextLineNo(_code, ERROR_CONTEXT, __LINE__, __FILE__); } while (0) +#define throw(_code, ...) do { \ + char* ERROR_CONTEXT = malloc(sizeof(char) * ERR_LEN); \ + sprintf(ERROR_CONTEXT, __VA_ARGS__); \ + return errorWithAllocatedContextLineNo(_code, ERROR_CONTEXT, __LINE__, __FILE__); \ +} while (0) #define errorWithContext(_code, _context) errorWithContextLineNo(_code, _context, __LINE__, __FILE__) #endif diff --git a/src/pebblisp.c b/src/pebblisp.c index 6f36eaa..10ec35a 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -565,13 +565,13 @@ struct Slice* getLastOpen() return lastOpen; } -Object parseEval(const char* input, struct Environment* env) +Object parseEval(const char* input, const char* codeSource, struct Environment* env) { struct Error err = noError(); struct Slice* tokens = nf_tokenize(input, &err); if (err.context != NULL) { - Object o = errorWithContext(err.code, err.context); + Object o = errorWithContextLineNo(err.code, err.context, err.plContext->lineNumber, codeSource); free(err.context); return o; } @@ -681,21 +681,21 @@ char* readFileToString(FILE* input) } /// Returns 1 if the file could not be opened. Otherwise, 0 -int readFile(const char* filename, struct Environment* env) +int readFile(const char* fileName, struct Environment* env) { - FILE* input = fopen(filename, "r"); + FILE* input = fopen(fileName, "r"); if (!input) { return 1; } - _readFile(input, env); + _readFile(input, fileName, env); return 0; } -int _readFile(FILE* input, struct Environment* env) +int _readFile(FILE* input, const char* fileName, struct Environment* env) { char* fileText = readFileToString(input); fclose(input); - Object r = parseEval(fileText, env); + Object r = parseEval(fileText, fileName, env); cleanObject(&r); free(fileText - 1); diff --git a/src/pebblisp.h b/src/pebblisp.h index 761efd2..db703a8 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -27,7 +27,7 @@ Result readSeq(struct Slice* slices); Result parseAtom(struct Slice* slice); -Object parseEval(const char* input, struct Environment* env); +Object parseEval(const char* input, const char* fileName, struct Environment* env); Object evalList(const Object* obj, struct Environment* env); @@ -57,9 +57,9 @@ if (FAILED) { \ char* readFileToString(FILE* input); -int _readFile(FILE* input, struct Environment* env); +int _readFile(FILE* input, const char* fileName, struct Environment* env); -int readFile(const char* filename, struct Environment* env); +int readFile(const char* fileName, struct Environment* env); struct Slice* getLastOpen(); diff --git a/src/plfunc/general.c b/src/plfunc/general.c index 6a66b3e..1c0c1b9 100644 --- a/src/plfunc/general.c +++ b/src/plfunc/general.c @@ -176,14 +176,14 @@ Object parseEvalO(Object* params, unused int length, struct Environment* env) switch (text.type) { case TYPE_SYMBOL: { Object string = eval(&text, env); - Object parsed = parseEval(string.string, env); + Object parsed = parseEval(string.string, "(eval)", env); cleanObject(&string); return parsed; } case TYPE_SLIST: return evalList(&text, env); case TYPE_STRING: - return parseEval(text.string, env); + return parseEval(text.string, "(eval)", env); default: throw(CAN_ONLY_EVAL_STRINGS, "Tried to (eval) a %s, instead of a string or symbol list", getTypeName(&text)); @@ -329,7 +329,7 @@ int timeStructDefinition = -1; Object getTime(unused Object* params, unused int length, struct Environment* env) { if (timeStructDefinition == -1) { - parseEval("(struct Time (minute hour sec))", env); + parseEval("(struct Time (minute hour sec))", "[INTERNAL]", env); timeStructDefinition = getStructIndex("Time"); } time_t t = time(NULL); diff --git a/src/plfunc/web.c b/src/plfunc/web.c index 0960c38..5ef7b9f 100644 --- a/src/plfunc/web.c +++ b/src/plfunc/web.c @@ -59,7 +59,7 @@ add_query_param(void* queryParamsV, enum MHD_ValueKind kind, const char* key, Object pair = startList(nullTerminated(key)); Object parsed; if (isDigit(value[0])) { - parsed = parseEval(value, NULL); + parsed = parseEval(value, "[INTERNAL]", NULL); } else { parsed = stringFromSlice(value, strlen(value)); } @@ -127,8 +127,7 @@ void initialize() if (!initialized) { initialized = 1; } - eprintf("Initializing...\n"); - Object o = parseEval("(struct Request (queryParams username password))", global()); + Object o = parseEval("(struct Request (queryParams username password))", "[INTERNAL]", global()); cleanObject(&o); requestDefinition = getStructIndex("Request"); } diff --git a/src/tokens.c b/src/tokens.c index f51060e..28622d3 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -4,17 +4,55 @@ /* * Grammar: - * token - * expr - * (op expr expr) - * (list expr expr ... ) + * Number: + * Hex: + * 0x[0-9a-f]+ + * Bin: + * 0b[01]+ + * Dec: + * -?[0-9]+ + * + * String: + * "([^\n"])|(\\")*" + * """.*""" + * + * Boolean: + * T + * F + * + * List: + * (...Expression) + * + * SList: + * '(...Expression) + * + * Symbol: + * [a-z][a-z0-9]* + * + * Primitive: + * Symbol + * Number + * String + * Boolean + * List + * + * Function Call: + * (Symbol ...Expression) + * + * Struct Access: + * Symbol.Symbol + * + * Expression: + * Primitive + * Function Call + * Struct Access */ // Is the char a standalone token? -static const char singleTokens[] = "()'?"; - int isSingle(const char *c) { + static const char singleTokens[] = "()'?"; + int i = 0; while (singleTokens[i] != '\0') { if (singleTokens[i] == c[0]) { @@ -39,18 +77,18 @@ int isWhitespace(const char c) return c == ' ' || c == '\t' || c == '\n'; } -void buildErrFromInput(struct Error* err, enum errorCode code, int i, const char* input) +void buildErrFromInput(struct Error* err, enum errorCode code, int i, const char* input, struct Slice* slice) { err->context = malloc(sizeof(char) * ERR_LEN + 1); err->code = code; + err->plContext = slice; int start = i > ERR_LEN ? i - ERR_LEN : 0; strncpy(err->context, &input[start], ERR_LEN); } void collectSymbol(const char* input, int* i, int* length); -void processString(const char* input, struct Error* err, struct Slice* slices, int slice, int* i, int* lineNumber, - int* length); +void processString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber, int* length); struct Slice* nf_tokenize(const char* input, struct Error* err) { @@ -60,6 +98,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err) } struct Slice slices[MAX_TOK_CNT]; + struct Slice* slice = &slices[0]; //int token_count = MAX_TOK_CNT; // do { // slices = malloc(sizeof(struct Slice) * token_count); @@ -67,7 +106,6 @@ struct Slice* nf_tokenize(const char* input, struct Error* err) // } while (slices == NULL); int i = 0; - int slice = 0; int lineNumber = 1; int parens = 0; @@ -86,14 +124,14 @@ struct Slice* nf_tokenize(const char* input, struct Error* err) } else if (input[i] == ')') { parens--; if (parens < 0) { - buildErrFromInput(err, MISMATCHED_PARENS, i, input); + buildErrFromInput(err, MISMATCHED_PARENS, i, input, slice); //free(slices); return NULL; } } - slices[slice].text = &input[i]; - slices[slice].lineNumber = lineNumber; + slice->text = &input[i]; + slice->lineNumber = lineNumber; if (isSingle(&input[i])) { i++; @@ -103,28 +141,31 @@ struct Slice* nf_tokenize(const char* input, struct Error* err) } continue; } else if (input[i] == '"') { - processString(input, err, slices, slice, &i, &lineNumber, &length); + processString(input, err, slice, &i, &lineNumber, &length); + if (err->context != NULL) { + return NULL; + } } else { collectSymbol(input, &i, &length); + if (length == 0) { + buildErrFromInput(err, BAD_SYMBOL, i, input, slice); + return NULL; + } } - if (err->context != NULL) { - return NULL; - } - - slices[slice].length = length; + slice->length = length; slice++; } if (parens != 0) { - buildErrFromInput(err, MISMATCHED_PARENS, i, input); + buildErrFromInput(err, MISMATCHED_PARENS, i, input, slice); //free(slices); return NULL; } - slices[slice].text = NULL; - slices[slice].length = 0; - size_t size = sizeof(struct Slice) * (slice + 1); + slice->text = NULL; + slice->length = 0; + size_t size = sizeof(struct Slice) * ((slice - &slices[0]) + 1); struct Slice* allocated = malloc(size); memcpy(allocated, slices, size); @@ -136,20 +177,28 @@ void singleQuotedString(const char* input, int* i, int* lineNumber, int* length) void tripleQuotedString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber, int* length); -void processString(const char* input, struct Error* err, struct Slice* slices, int slice, int* i, int* lineNumber, - int* length) +void processString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber, int* length) { if (input[(*i) + 1] == '"' && input[(*i) + 2] == '"') { - tripleQuotedString(input, err, &slices[slice], i, lineNumber, length); + tripleQuotedString(input, err, slice, i, lineNumber, length); } else { singleQuotedString(input, i, lineNumber, length); } (*i)++; } +int validSymbolChar(const char* c) +{ + return !isWhitespace(*c) + && !isSingle(c) + && *c != '"' + && *c != '\0'; +} + void collectSymbol(const char* input, int* i, int* length) { - while (!isWhitespace(input[++(*i)]) && !isSingle(&input[(*i)]) && input[(*i)] != '"' && input[(*i)] != '\0') { + // TODO: Error if length is 0? + while (validSymbolChar(&input[++(*i)])) { (*length)++; } } @@ -171,7 +220,7 @@ void tripleQuotedString(const char* input, struct Error* err, struct Slice* slic } (*length)++; if (input[c] == '\0' || input[c + 1] == '\0' || input[c + 2] == '\0') { - buildErrFromInput(err, UNEXPECTED_EOF, c, input); + buildErrFromInput(err, UNEXPECTED_EOF, c, input, slice); return; } } @@ -180,9 +229,10 @@ void tripleQuotedString(const char* input, struct Error* err, struct Slice* slic void singleQuotedString(const char* input, int* i, int* lineNumber, int* length) { while (input[++(*i)] != '\0') { - if (input[(*i)] == '"') { + const int c = *i; + if (input[c] == '"') { int backslashes = 0; - while (input[((*i) - 1) - backslashes] == '\\') { + while (input[(c - 1) - backslashes] == '\\') { backslashes++; } // \\\" => Odd number of backslashes, quote IS escaped @@ -190,7 +240,7 @@ void singleQuotedString(const char* input, int* i, int* lineNumber, int* length) if (backslashes % 2 == 0) { break; } - } else if (input[(*i)] == '\n') { + } else if (input[c] == '\n') { (*lineNumber)++; } (*length)++;