Display parseEval source in error messages.

This commit is contained in:
Sage Vaillancourt 2022-10-25 13:21:04 -04:00
parent b03d4cbd3f
commit 672cdb692a
8 changed files with 107 additions and 55 deletions

View File

@ -476,7 +476,7 @@ Object help(Object* params, int length, struct Environment* env)
int runTest(const char* test, const char* expected, int detailed) int runTest(const char* test, const char* expected, int detailed)
{ {
struct Environment env = defaultEnv(); struct Environment env = defaultEnv();
Object o = parseEval(test, &env); Object o = parseEval(test, "testCode", &env);
size_t length; size_t length;
char* result = stringObj(&o, &length); char* result = stringObj(&o, &length);
cleanObject(&o); cleanObject(&o);

View File

@ -116,7 +116,7 @@ void repl(struct Environment* env)
free(oldBuf); free(oldBuf);
} }
Object o = parseEval(buf, env); Object o = parseEval(buf, "REPL", env);
if (isFuncy(o) || isError(o, DID_NOT_FIND_SYMBOL)) { if (isFuncy(o) || isError(o, DID_NOT_FIND_SYMBOL)) {
system(buf); system(buf);
} else { } else {
@ -246,9 +246,9 @@ int main(int argc, const char* argv[])
readFile(SCRIPTDIR "/lib.pbl", &env); readFile(SCRIPTDIR "/lib.pbl", &env);
} }
Object o = parseEval("(def prompt %%)", &env); Object o = parseEval("(def prompt %%)", "[INTERNAL]", &env);
cleanObject(&o); cleanObject(&o);
o = parseEval("(def preprocess (fn (text) (text)))", &env); o = parseEval("(def preprocess (fn (text) (text)))", "[INTERNAL]", &env);
cleanObject(&o); cleanObject(&o);
if (!settings.ignoreConfig) { if (!settings.ignoreConfig) {
@ -268,10 +268,10 @@ int main(int argc, const char* argv[])
if (file) { if (file) {
// Execute a file // Execute a file
loadArgsIntoEnv(argc, argv, &env); loadArgsIntoEnv(argc, argv, &env);
_readFile(file, &env); _readFile(file, argv[argc - 1], &env);
} else { } else {
// Run arguments directly as pl code // Run arguments directly as pl code
Object r = parseEval(argv[argc - 1], &env); Object r = parseEval(argv[argc - 1], "[PL ARGUMENTS]", &env);
printAndClean(&r); printAndClean(&r);
} }
} else { } else {

View File

@ -315,8 +315,11 @@ Object errorWithAllocatedContextLineNo(enum errorCode code, char* context, int l
#define errorAddContext(x, y, z, a) ; #define errorAddContext(x, y, z, a) ;
#define throw(_code, ...) return errorObject(_code) #define throw(_code, ...) return errorObject(_code)
#else #else
#define throw(_code, ...) do { char* ERROR_CONTEXT = malloc(sizeof(char) * ERR_LEN); sprintf(ERROR_CONTEXT, __VA_ARGS__); \ #define throw(_code, ...) do { \
return errorWithAllocatedContextLineNo(_code, ERROR_CONTEXT, __LINE__, __FILE__); } while (0) 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__) #define errorWithContext(_code, _context) errorWithContextLineNo(_code, _context, __LINE__, __FILE__)
#endif #endif

View File

@ -565,13 +565,13 @@ struct Slice* getLastOpen()
return lastOpen; 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 Error err = noError();
struct Slice* tokens = nf_tokenize(input, &err); struct Slice* tokens = nf_tokenize(input, &err);
if (err.context != NULL) { 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); free(err.context);
return o; return o;
} }
@ -681,21 +681,21 @@ char* readFileToString(FILE* input)
} }
/// Returns 1 if the file could not be opened. Otherwise, 0 /// 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) { if (!input) {
return 1; return 1;
} }
_readFile(input, env); _readFile(input, fileName, env);
return 0; return 0;
} }
int _readFile(FILE* input, struct Environment* env) int _readFile(FILE* input, const char* fileName, struct Environment* env)
{ {
char* fileText = readFileToString(input); char* fileText = readFileToString(input);
fclose(input); fclose(input);
Object r = parseEval(fileText, env); Object r = parseEval(fileText, fileName, env);
cleanObject(&r); cleanObject(&r);
free(fileText - 1); free(fileText - 1);

View File

@ -27,7 +27,7 @@ Result readSeq(struct Slice* slices);
Result parseAtom(struct Slice* slice); 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); Object evalList(const Object* obj, struct Environment* env);
@ -57,9 +57,9 @@ if (FAILED) { \
char* readFileToString(FILE* input); 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(); struct Slice* getLastOpen();

View File

@ -176,14 +176,14 @@ Object parseEvalO(Object* params, unused int length, struct Environment* env)
switch (text.type) { switch (text.type) {
case TYPE_SYMBOL: { case TYPE_SYMBOL: {
Object string = eval(&text, env); Object string = eval(&text, env);
Object parsed = parseEval(string.string, env); Object parsed = parseEval(string.string, "(eval)", env);
cleanObject(&string); cleanObject(&string);
return parsed; return parsed;
} }
case TYPE_SLIST: case TYPE_SLIST:
return evalList(&text, env); return evalList(&text, env);
case TYPE_STRING: case TYPE_STRING:
return parseEval(text.string, env); return parseEval(text.string, "(eval)", env);
default: default:
throw(CAN_ONLY_EVAL_STRINGS, "Tried to (eval) a %s, instead of a string or symbol list", throw(CAN_ONLY_EVAL_STRINGS, "Tried to (eval) a %s, instead of a string or symbol list",
getTypeName(&text)); getTypeName(&text));
@ -329,7 +329,7 @@ int timeStructDefinition = -1;
Object getTime(unused Object* params, unused int length, struct Environment* env) Object getTime(unused Object* params, unused int length, struct Environment* env)
{ {
if (timeStructDefinition == -1) { if (timeStructDefinition == -1) {
parseEval("(struct Time (minute hour sec))", env); parseEval("(struct Time (minute hour sec))", "[INTERNAL]", env);
timeStructDefinition = getStructIndex("Time"); timeStructDefinition = getStructIndex("Time");
} }
time_t t = time(NULL); time_t t = time(NULL);

View File

@ -59,7 +59,7 @@ add_query_param(void* queryParamsV, enum MHD_ValueKind kind, const char* key,
Object pair = startList(nullTerminated(key)); Object pair = startList(nullTerminated(key));
Object parsed; Object parsed;
if (isDigit(value[0])) { if (isDigit(value[0])) {
parsed = parseEval(value, NULL); parsed = parseEval(value, "[INTERNAL]", NULL);
} else { } else {
parsed = stringFromSlice(value, strlen(value)); parsed = stringFromSlice(value, strlen(value));
} }
@ -127,8 +127,7 @@ void initialize()
if (!initialized) { if (!initialized) {
initialized = 1; initialized = 1;
} }
eprintf("Initializing...\n"); Object o = parseEval("(struct Request (queryParams username password))", "[INTERNAL]", global());
Object o = parseEval("(struct Request (queryParams username password))", global());
cleanObject(&o); cleanObject(&o);
requestDefinition = getStructIndex("Request"); requestDefinition = getStructIndex("Request");
} }

View File

@ -4,17 +4,55 @@
/* /*
* Grammar: * Grammar:
* token * Number:
* expr * Hex:
* (op expr expr) * 0x[0-9a-f]+
* (list expr expr ... ) * 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? // Is the char a standalone token?
static const char singleTokens[] = "()'?";
int isSingle(const char *c) int isSingle(const char *c)
{ {
static const char singleTokens[] = "()'?";
int i = 0; int i = 0;
while (singleTokens[i] != '\0') { while (singleTokens[i] != '\0') {
if (singleTokens[i] == c[0]) { if (singleTokens[i] == c[0]) {
@ -39,18 +77,18 @@ int isWhitespace(const char c)
return c == ' ' || c == '\t' || c == '\n'; 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->context = malloc(sizeof(char) * ERR_LEN + 1);
err->code = code; err->code = code;
err->plContext = slice;
int start = i > ERR_LEN ? i - ERR_LEN : 0; int start = i > ERR_LEN ? i - ERR_LEN : 0;
strncpy(err->context, &input[start], ERR_LEN); strncpy(err->context, &input[start], ERR_LEN);
} }
void collectSymbol(const char* input, int* i, int* length); 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, void processString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber, int* length);
int* length);
struct Slice* nf_tokenize(const char* input, struct Error* err) 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 slices[MAX_TOK_CNT];
struct Slice* slice = &slices[0];
//int token_count = MAX_TOK_CNT; //int token_count = MAX_TOK_CNT;
// do { // do {
// slices = malloc(sizeof(struct Slice) * token_count); // slices = malloc(sizeof(struct Slice) * token_count);
@ -67,7 +106,6 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
// } while (slices == NULL); // } while (slices == NULL);
int i = 0; int i = 0;
int slice = 0;
int lineNumber = 1; int lineNumber = 1;
int parens = 0; int parens = 0;
@ -86,14 +124,14 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
} else if (input[i] == ')') { } else if (input[i] == ')') {
parens--; parens--;
if (parens < 0) { if (parens < 0) {
buildErrFromInput(err, MISMATCHED_PARENS, i, input); buildErrFromInput(err, MISMATCHED_PARENS, i, input, slice);
//free(slices); //free(slices);
return NULL; return NULL;
} }
} }
slices[slice].text = &input[i]; slice->text = &input[i];
slices[slice].lineNumber = lineNumber; slice->lineNumber = lineNumber;
if (isSingle(&input[i])) { if (isSingle(&input[i])) {
i++; i++;
@ -103,28 +141,31 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
} }
continue; continue;
} else if (input[i] == '"') { } else if (input[i] == '"') {
processString(input, err, slices, slice, &i, &lineNumber, &length); processString(input, err, slice, &i, &lineNumber, &length);
} else {
collectSymbol(input, &i, &length);
}
if (err->context != NULL) { if (err->context != NULL) {
return NULL; return NULL;
} }
} else {
collectSymbol(input, &i, &length);
if (length == 0) {
buildErrFromInput(err, BAD_SYMBOL, i, input, slice);
return NULL;
}
}
slices[slice].length = length; slice->length = length;
slice++; slice++;
} }
if (parens != 0) { if (parens != 0) {
buildErrFromInput(err, MISMATCHED_PARENS, i, input); buildErrFromInput(err, MISMATCHED_PARENS, i, input, slice);
//free(slices); //free(slices);
return NULL; return NULL;
} }
slices[slice].text = NULL; slice->text = NULL;
slices[slice].length = 0; slice->length = 0;
size_t size = sizeof(struct Slice) * (slice + 1); size_t size = sizeof(struct Slice) * ((slice - &slices[0]) + 1);
struct Slice* allocated = malloc(size); struct Slice* allocated = malloc(size);
memcpy(allocated, slices, 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, void tripleQuotedString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber,
int* length); int* length);
void processString(const char* input, struct Error* err, struct Slice* slices, int slice, int* i, int* lineNumber, void processString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber, int* length)
int* length)
{ {
if (input[(*i) + 1] == '"' && input[(*i) + 2] == '"') { if (input[(*i) + 1] == '"' && input[(*i) + 2] == '"') {
tripleQuotedString(input, err, &slices[slice], i, lineNumber, length); tripleQuotedString(input, err, slice, i, lineNumber, length);
} else { } else {
singleQuotedString(input, i, lineNumber, length); singleQuotedString(input, i, lineNumber, length);
} }
(*i)++; (*i)++;
} }
int validSymbolChar(const char* c)
{
return !isWhitespace(*c)
&& !isSingle(c)
&& *c != '"'
&& *c != '\0';
}
void collectSymbol(const char* input, int* i, int* length) 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)++; (*length)++;
} }
} }
@ -171,7 +220,7 @@ void tripleQuotedString(const char* input, struct Error* err, struct Slice* slic
} }
(*length)++; (*length)++;
if (input[c] == '\0' || input[c + 1] == '\0' || input[c + 2] == '\0') { 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; 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) void singleQuotedString(const char* input, int* i, int* lineNumber, int* length)
{ {
while (input[++(*i)] != '\0') { while (input[++(*i)] != '\0') {
if (input[(*i)] == '"') { const int c = *i;
if (input[c] == '"') {
int backslashes = 0; int backslashes = 0;
while (input[((*i) - 1) - backslashes] == '\\') { while (input[(c - 1) - backslashes] == '\\') {
backslashes++; backslashes++;
} }
// \\\" => Odd number of backslashes, quote IS escaped // \\\" => 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) { if (backslashes % 2 == 0) {
break; break;
} }
} else if (input[(*i)] == '\n') { } else if (input[c] == '\n') {
(*lineNumber)++; (*lineNumber)++;
} }
(*length)++; (*length)++;