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)
|
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);
|
||||||
|
|
10
src/main.c
10
src/main.c
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
112
src/tokens.c
112
src/tokens.c
|
@ -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);
|
||||||
|
if (err->context != NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
collectSymbol(input, &i, &length);
|
collectSymbol(input, &i, &length);
|
||||||
|
if (length == 0) {
|
||||||
|
buildErrFromInput(err, BAD_SYMBOL, i, input, slice);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err->context != NULL) {
|
slice->length = length;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
slices[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)++;
|
||||||
|
|
Loading…
Reference in New Issue