Display parseEval source in error messages.
This commit is contained in:
parent
b03d4cbd3f
commit
672cdb692a
|
@ -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);
|
||||
|
|
10
src/main.c
10
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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
112
src/tokens.c
112
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)++;
|
||||
|
|
Loading…
Reference in New Issue