Start dropping support for semicolon separators.
Simplify some error functions. Oh, right. strdup() exists.
This commit is contained in:
parent
e326af38f8
commit
3f4d8fd7af
12
src/env.c
12
src/env.c
|
@ -89,9 +89,7 @@ void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||||
existing->data = o.data;
|
existing->data = o.data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char* symbol = malloc(sizeof(char) * (strlen(name) + 1));
|
addToTable(&env->table, strdup(name), cloneObject(obj));
|
||||||
strcpy(symbol, name);
|
|
||||||
addToTable(&env->table, symbol, cloneObject(obj));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,7 +259,7 @@ void printEnv(struct Environment* env, int printPointers)
|
||||||
} else {
|
} else {
|
||||||
size_t length;
|
size_t length;
|
||||||
// SAFETY: Casting to Object is fine because stringObj() doesn't touch .forward
|
// SAFETY: Casting to Object is fine because stringObj() doesn't touch .forward
|
||||||
char* s = stringObj((Object *) &env->table.elements[i].object, &length);
|
char* s = stringObj((Object*) &env->table.elements[i].object, &length);
|
||||||
printColored(s);
|
printColored(s);
|
||||||
if (env->table.elements[i].object.type == TYPE_STRING) {
|
if (env->table.elements[i].object.type == TYPE_STRING) {
|
||||||
printf("\"");
|
printf("\"");
|
||||||
|
@ -420,8 +418,8 @@ Object help(Object* params, int length, struct Environment* env)
|
||||||
|
|
||||||
for (int i = 0; i < dictionary.structCount; i++) {
|
for (int i = 0; i < dictionary.structCount; i++) {
|
||||||
if (strcmp(dictionary.structDefs[i].name, symbol) == 0) {
|
if (strcmp(dictionary.structDefs[i].name, symbol) == 0) {
|
||||||
char structDef[128] = {'{', ' ', '\0'};
|
char structDef[128] = { '{', ' ', '\0' };
|
||||||
for(int field = 0; field < dictionary.structDefs[i].fieldCount; field++) {
|
for (int field = 0; field < dictionary.structDefs[i].fieldCount; field++) {
|
||||||
strcat(structDef, dictionary.structDefs[i].names[field]);
|
strcat(structDef, dictionary.structDefs[i].names[field]);
|
||||||
strcat(structDef, " ");
|
strcat(structDef, " ");
|
||||||
}
|
}
|
||||||
|
@ -505,7 +503,7 @@ int runTests(int detailed, int specificTest)
|
||||||
int passCount = 0;
|
int passCount = 0;
|
||||||
|
|
||||||
int isSpecificTest = specificTest != -1;
|
int isSpecificTest = specificTest != -1;
|
||||||
if(isSpecificTest) {
|
if (isSpecificTest) {
|
||||||
struct helpText h = helpTexts[specificTest];
|
struct helpText h = helpTexts[specificTest];
|
||||||
runHelpTests(h, detailed, &failureCount, &passCount);
|
runHelpTests(h, detailed, &failureCount, &passCount);
|
||||||
return failureCount;
|
return failureCount;
|
||||||
|
|
|
@ -69,8 +69,7 @@ char* completionGenerator(const char* text, int state)
|
||||||
struct ObjectTable* table = &global()->table;
|
struct ObjectTable* table = &global()->table;
|
||||||
for (; i < table->capacity; i++) {
|
for (; i < table->capacity; i++) {
|
||||||
if (table->elements[i].symbol && strncmp(table->elements[i].symbol, text, completionLength) == 0) {
|
if (table->elements[i].symbol && strncmp(table->elements[i].symbol, text, completionLength) == 0) {
|
||||||
char* symbol = malloc(sizeof(char) * (strlen(table->elements[i].symbol) + 1));
|
char* symbol = strdup(table->elements[i].symbol);
|
||||||
strcpy(symbol, table->elements[i].symbol);
|
|
||||||
i++;
|
i++;
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
21
src/object.c
21
src/object.c
|
@ -813,23 +813,20 @@ inline Object errorObject(enum errorCode err)
|
||||||
|
|
||||||
#ifndef SIMPLE_ERRORS
|
#ifndef SIMPLE_ERRORS
|
||||||
|
|
||||||
inline void errorAddContext(Object* o, const char* context, int lineNo, const char* fileName)
|
inline Object
|
||||||
|
errorWithAllocatedContextLineNo(enum errorCode code, char* context, int lineNo, const char* fileName)
|
||||||
{
|
{
|
||||||
o->error->context = malloc(sizeof(char) * RESULT_LENGTH);
|
Object o = errorObject(code);
|
||||||
char* cursor = o->error->context;
|
sprintf(context + strlen(context), " [33m%s:%d[0m", fileName, lineNo);
|
||||||
cursor += sprintf(cursor, "%s", context);
|
o.error->context = context;
|
||||||
if (fileName) {
|
return o;
|
||||||
sprintf(cursor, " [33m%s:%d[0m", fileName, lineNo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object errorWithContextLineNo(enum errorCode code, const char* context, int lineNo, const char* fileName)
|
inline Object errorWithContextLineNo(enum errorCode code, const char* context, int lineNo, const char* fileName)
|
||||||
{
|
{
|
||||||
Object o = errorObject(code);
|
char* copiedContext = malloc(sizeof(char) * ERR_LEN);
|
||||||
if (context) {
|
strcpy(copiedContext, context);
|
||||||
errorAddContext(&o, context, lineNo, fileName);
|
return errorWithAllocatedContextLineNo(code, copiedContext, lineNo, fileName);
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
10
src/object.h
10
src/object.h
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#define ERR_LEN 256
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define printd(...) printf(__VA_ARGS__)
|
#define printd(...) printf(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
|
@ -248,17 +250,17 @@ Object errorObject(enum errorCode err);
|
||||||
|
|
||||||
Object errorWithContextLineNo(enum errorCode code, const char* context, int lineNo, const char* fileName);
|
Object errorWithContextLineNo(enum errorCode code, const char* context, int lineNo, const char* fileName);
|
||||||
|
|
||||||
|
Object errorWithAllocatedContextLineNo(enum errorCode code, char* context, int lineNo, const char* fileName);
|
||||||
|
|
||||||
#ifdef SIMPLE_ERRORS
|
#ifdef SIMPLE_ERRORS
|
||||||
#define errorWithContext(code, context) errorObject(code)
|
#define errorWithContext(code, context) errorObject(code)
|
||||||
#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
|
||||||
char ERROR_CONTEXT[128];
|
#define throw(_code, ...) do { char* ERROR_CONTEXT = malloc(sizeof(char) * ERR_LEN); sprintf(ERROR_CONTEXT, __VA_ARGS__); \
|
||||||
#define throw(_code, ...) sprintf(ERROR_CONTEXT, __VA_ARGS__); return errorWithContext(_code, ERROR_CONTEXT)
|
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__)
|
||||||
|
|
||||||
void errorAddContext(Object* o, const char* context, int lineNo, const char* fileName);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Error noError();
|
struct Error noError();
|
||||||
|
|
|
@ -50,16 +50,14 @@ Object evalStructArgs(const Object* symbol, const Object* fields, unused struct
|
||||||
|
|
||||||
int fieldCount = listLength(fields);
|
int fieldCount = listLength(fields);
|
||||||
struct StructDef def = {
|
struct StructDef def = {
|
||||||
.name = malloc(sizeof(char) * (strlen(name) + 1)),
|
.name = strdup(name),
|
||||||
.fieldCount = fieldCount,
|
.fieldCount = fieldCount,
|
||||||
.names = malloc(sizeof(char*) * fieldCount),
|
.names = malloc(sizeof(char*) * fieldCount),
|
||||||
};
|
};
|
||||||
strcpy(def.name, name);
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
FOR_POINTER_IN_LIST(fields) {
|
FOR_POINTER_IN_LIST(fields) {
|
||||||
def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1));
|
def.names[i] = strdup(POINTER->string);
|
||||||
strcpy(def.names[i], POINTER->string);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,12 +315,14 @@ Object structAccess(Object* params, unused int length, unused struct Environment
|
||||||
}
|
}
|
||||||
if (isNumber(field)) {
|
if (isNumber(field)) {
|
||||||
if (structDef->fieldCount < field.number || field.number < 0) {
|
if (structDef->fieldCount < field.number || field.number < 0) {
|
||||||
throw(NULL_PARSE, "Could not find struct field at index %ld. Struct `%s` has %d fields.", field.number, structDef->name, structDef->fieldCount);
|
throw(NULL_PARSE, "Could not find struct field at index %ld. Struct `%s` has %d fields.", field.number,
|
||||||
|
structDef->name, structDef->fieldCount);
|
||||||
}
|
}
|
||||||
return cloneObject(structo.structObject->fields[field.number]);
|
return cloneObject(structo.structObject->fields[field.number]);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw(BAD_PARAMS, "Struct fields should be indexed with a string or a number, but received a %s", getTypeName(&field));
|
throw(BAD_PARAMS, "Struct fields should be indexed with a string or a number, but received a %s",
|
||||||
|
getTypeName(&field));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result parse(struct Slice* slices)
|
Result parse(struct Slice* slices)
|
||||||
|
@ -429,6 +429,7 @@ Object parseBin(struct Slice* s)
|
||||||
|
|
||||||
struct InlinedFunction {
|
struct InlinedFunction {
|
||||||
Object (* func)(Object*, int, struct Environment*);
|
Object (* func)(Object*, int, struct Environment*);
|
||||||
|
|
||||||
Object* arguments;
|
Object* arguments;
|
||||||
int argCount;
|
int argCount;
|
||||||
//struct Environment* env;
|
//struct Environment* env;
|
||||||
|
@ -514,7 +515,11 @@ Object parseEval(const char* input, struct Environment* env)
|
||||||
parens--;
|
parens--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parens == 0) {
|
if (parens != 0) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
cleanObject(&obj);
|
cleanObject(&obj);
|
||||||
Object parsed = parse(tok).obj;
|
Object parsed = parse(tok).obj;
|
||||||
if (parsed.type == TYPE_ERROR) {
|
if (parsed.type == TYPE_ERROR) {
|
||||||
|
@ -525,6 +530,7 @@ Object parseEval(const char* input, struct Environment* env)
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok[i].text[0] == ')') {
|
if (tok[i].text[0] == ')') {
|
||||||
// Skip `tok` past end of list that just closed
|
// Skip `tok` past end of list that just closed
|
||||||
tok = &tok[i + 1];
|
tok = &tok[i + 1];
|
||||||
|
@ -536,7 +542,6 @@ Object parseEval(const char* input, struct Environment* env)
|
||||||
obj = eval(&parsed, env);
|
obj = eval(&parsed, env);
|
||||||
cleanObject(&parsed);
|
cleanObject(&parsed);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
11
src/tests.sh
11
src/tests.sh
|
@ -167,9 +167,8 @@ check "MinRight" "(min 8429 192449)" "8429"
|
||||||
check "MinLeft" "(min 17294722 17294721)" "17294721"
|
check "MinLeft" "(min 17294722 17294721)" "17294721"
|
||||||
|
|
||||||
title "Lambdas"
|
title "Lambdas"
|
||||||
check "Multi-Statement" "(def yee (fn (a) (* 10 a))) ; (yee 5)" "50"
|
check "Multi-Statement" "(def yee (fn (a) (* 10 a))) (yee 5)" "50"
|
||||||
check "Multi-Statement, No Semicolon" "(def yee (fn (a) (* 10 a)))(yee 5)" "50"
|
check "Pre-Defined Map" "(def yee (fn (a) (* 10 a))) (map yee (5 10 2 (+ 12 0)))" "( 50 100 20 120 )"
|
||||||
check "Pre-Defined Map" "(def yee (fn (a) (* 10 a))) ; (map yee (5 10 2 (+ 12 0)))" "( 50 100 20 120 )"
|
|
||||||
check "AnonymousLambda" "\
|
check "AnonymousLambda" "\
|
||||||
(map (fn (a) (* a a)) (5 6 7))" "( 25 36 49 )"
|
(map (fn (a) (* a a)) (5 6 7))" "( 25 36 49 )"
|
||||||
check "FbnciSeq" "\
|
check "FbnciSeq" "\
|
||||||
|
@ -177,17 +176,17 @@ check "FbnciSeq" "\
|
||||||
(if (< a 2) \
|
(if (< a 2) \
|
||||||
a \
|
a \
|
||||||
(+ (fib (- a 1)) (fib (- a 2))) \
|
(+ (fib (- a 1)) (fib (- a 2))) \
|
||||||
)));\
|
)))\
|
||||||
(fib 11)" "89"
|
(fib 11)" "89"
|
||||||
check "Factorial" "\
|
check "Factorial" "\
|
||||||
(def fac (fn (a) \
|
(def fac (fn (a) \
|
||||||
(if (= a 1) \
|
(if (= a 1) \
|
||||||
1 \
|
1 \
|
||||||
(* a (fac (- a 1)) ) \
|
(* a (fac (- a 1)) ) \
|
||||||
)));\
|
)))\
|
||||||
(fac 11)" "39916800"
|
(fac 11)" "39916800"
|
||||||
check "Lambda Clone" "(def y (fn (a) (* 10 a))) (def b y) (def y 12345) ((b 5) y)" "( 50 12345 )"
|
check "Lambda Clone" "(def y (fn (a) (* 10 a))) (def b y) (def y 12345) ((b 5) y)" "( 50 12345 )"
|
||||||
check "Duplicate" "(def dupe (fn (a) (() (a a a))));(dupe (* 10 10))" "( 100 100 100 )"
|
check "Duplicate" "(def dupe (fn (a) (() (a a a)))) (dupe (* 10 10))" "( 100 100 100 )"
|
||||||
|
|
||||||
title "Cat"
|
title "Cat"
|
||||||
check "Basic Cat" '(cat "Big" " Kitty")' "Big Kitty"
|
check "Basic Cat" '(cat "Big" " Kitty")' "Big Kitty"
|
||||||
|
|
40
src/tokens.c
40
src/tokens.c
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define ERR_LEN 256
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grammar:
|
* Grammar:
|
||||||
* token
|
* token
|
||||||
|
@ -42,11 +40,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)
|
||||||
|
{
|
||||||
|
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
||||||
|
err->code = code;
|
||||||
|
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||||
|
strncpy(err->context, &input[start], ERR_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
struct Slice* nf_tokenize(const char* input, struct Error* err)
|
struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
{
|
{
|
||||||
if (!input) {
|
if (!input) {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN);
|
err->context = strdup("no input");
|
||||||
strcpy(err->context, "no input");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +68,8 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
|
|
||||||
int parens = 0;
|
int parens = 0;
|
||||||
while (input[i] != '\0') {
|
while (input[i] != '\0') {
|
||||||
int l = 1;
|
int length = 1;
|
||||||
if (isWhitespace(input[i]) || input[i] == ';') {
|
if (isWhitespace(input[i])) {
|
||||||
if (input[i] == '\n') {
|
if (input[i] == '\n') {
|
||||||
lineNumber++;
|
lineNumber++;
|
||||||
}
|
}
|
||||||
|
@ -77,10 +82,7 @@ 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) {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
buildErrFromInput(err, MISMATCHED_PARENS, i, input);
|
||||||
err->code = MISMATCHED_PARENS;
|
|
||||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
|
||||||
strncpy(err->context, &input[start], ERR_LEN);
|
|
||||||
//free(slices);
|
//free(slices);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -104,12 +106,9 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
if (input[i] == '\n') {
|
if (input[i] == '\n') {
|
||||||
lineNumber++;
|
lineNumber++;
|
||||||
}
|
}
|
||||||
l++;
|
length++;
|
||||||
if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
|
if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
buildErrFromInput(err, UNEXPECTED_EOF, i, input);
|
||||||
err->code = UNEXPECTED_EOF;
|
|
||||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
|
||||||
strncpy(err->context, &input[start], ERR_LEN);
|
|
||||||
//free(slices);
|
//free(slices);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -120,25 +119,22 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
if (input[i] == '\n') {
|
if (input[i] == '\n') {
|
||||||
lineNumber++;
|
lineNumber++;
|
||||||
}
|
}
|
||||||
l++;
|
length++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
while (!isWhitespace(input[++i]) && !isSingle(input[i]) && input[i] != '"' && input[i] != '\0') {
|
while (!isWhitespace(input[++i]) && !isSingle(input[i]) && input[i] != '"' && input[i] != '\0') {
|
||||||
l++;
|
length++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slices[slice].length = l;
|
slices[slice].length = length;
|
||||||
slice++;
|
slice++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parens != 0) {
|
if (parens != 0) {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN);
|
buildErrFromInput(err, MISMATCHED_PARENS, i, input);
|
||||||
err->code = MISMATCHED_PARENS;
|
|
||||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
|
||||||
strncpy(err->context, &input[start], ERR_LEN);
|
|
||||||
//free(slices);
|
//free(slices);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,8 +150,7 @@ int start(int port)
|
||||||
|
|
||||||
void addRouteO(Object path, Object textFunc, struct Environment* env, enum RouteType type)
|
void addRouteO(Object path, Object textFunc, struct Environment* env, enum RouteType type)
|
||||||
{
|
{
|
||||||
char* p = malloc(sizeof(char) * strlen(path.string) + 1);
|
char* p = strdup(path.string);
|
||||||
strcpy(p, path.string);
|
|
||||||
|
|
||||||
struct Route r;
|
struct Route r;
|
||||||
r.path = p;
|
r.path = p;
|
||||||
|
|
Loading…
Reference in New Issue