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;
|
||||
return;
|
||||
}
|
||||
char* symbol = malloc(sizeof(char) * (strlen(name) + 1));
|
||||
strcpy(symbol, name);
|
||||
addToTable(&env->table, symbol, cloneObject(obj));
|
||||
addToTable(&env->table, strdup(name), cloneObject(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,7 +259,7 @@ void printEnv(struct Environment* env, int printPointers)
|
|||
} else {
|
||||
size_t length;
|
||||
// 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);
|
||||
if (env->table.elements[i].object.type == TYPE_STRING) {
|
||||
printf("\"");
|
||||
|
@ -420,8 +418,8 @@ Object help(Object* params, int length, struct Environment* env)
|
|||
|
||||
for (int i = 0; i < dictionary.structCount; i++) {
|
||||
if (strcmp(dictionary.structDefs[i].name, symbol) == 0) {
|
||||
char structDef[128] = {'{', ' ', '\0'};
|
||||
for(int field = 0; field < dictionary.structDefs[i].fieldCount; field++) {
|
||||
char structDef[128] = { '{', ' ', '\0' };
|
||||
for (int field = 0; field < dictionary.structDefs[i].fieldCount; field++) {
|
||||
strcat(structDef, dictionary.structDefs[i].names[field]);
|
||||
strcat(structDef, " ");
|
||||
}
|
||||
|
@ -505,7 +503,7 @@ int runTests(int detailed, int specificTest)
|
|||
int passCount = 0;
|
||||
|
||||
int isSpecificTest = specificTest != -1;
|
||||
if(isSpecificTest) {
|
||||
if (isSpecificTest) {
|
||||
struct helpText h = helpTexts[specificTest];
|
||||
runHelpTests(h, detailed, &failureCount, &passCount);
|
||||
return failureCount;
|
||||
|
|
|
@ -69,8 +69,7 @@ char* completionGenerator(const char* text, int state)
|
|||
struct ObjectTable* table = &global()->table;
|
||||
for (; i < table->capacity; i++) {
|
||||
if (table->elements[i].symbol && strncmp(table->elements[i].symbol, text, completionLength) == 0) {
|
||||
char* symbol = malloc(sizeof(char) * (strlen(table->elements[i].symbol) + 1));
|
||||
strcpy(symbol, table->elements[i].symbol);
|
||||
char* symbol = strdup(table->elements[i].symbol);
|
||||
i++;
|
||||
return symbol;
|
||||
}
|
||||
|
|
21
src/object.c
21
src/object.c
|
@ -813,23 +813,20 @@ inline Object errorObject(enum errorCode err)
|
|||
|
||||
#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);
|
||||
char* cursor = o->error->context;
|
||||
cursor += sprintf(cursor, "%s", context);
|
||||
if (fileName) {
|
||||
sprintf(cursor, " [33m%s:%d[0m", fileName, lineNo);
|
||||
}
|
||||
Object o = errorObject(code);
|
||||
sprintf(context + strlen(context), " [33m%s:%d[0m", fileName, lineNo);
|
||||
o.error->context = context;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline Object errorWithContextLineNo(enum errorCode code, const char* context, int lineNo, const char* fileName)
|
||||
{
|
||||
Object o = errorObject(code);
|
||||
if (context) {
|
||||
errorAddContext(&o, context, lineNo, fileName);
|
||||
}
|
||||
return o;
|
||||
char* copiedContext = malloc(sizeof(char) * ERR_LEN);
|
||||
strcpy(copiedContext, context);
|
||||
return errorWithAllocatedContextLineNo(code, copiedContext, lineNo, fileName);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
10
src/object.h
10
src/object.h
|
@ -10,6 +10,8 @@
|
|||
|
||||
#else
|
||||
|
||||
#define ERR_LEN 256
|
||||
|
||||
#ifdef DEBUG
|
||||
#define printd(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
|
@ -248,17 +250,17 @@ Object errorObject(enum errorCode err);
|
|||
|
||||
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
|
||||
#define errorWithContext(code, context) errorObject(code)
|
||||
#define errorAddContext(x, y, z, a) ;
|
||||
#define throw(_code, ...) return errorObject(_code)
|
||||
#else
|
||||
char ERROR_CONTEXT[128];
|
||||
#define throw(_code, ...) sprintf(ERROR_CONTEXT, __VA_ARGS__); return errorWithContext(_code, ERROR_CONTEXT)
|
||||
#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__)
|
||||
|
||||
void errorAddContext(Object* o, const char* context, int lineNo, const char* fileName);
|
||||
|
||||
#endif
|
||||
|
||||
struct Error noError();
|
||||
|
|
|
@ -50,16 +50,14 @@ Object evalStructArgs(const Object* symbol, const Object* fields, unused struct
|
|||
|
||||
int fieldCount = listLength(fields);
|
||||
struct StructDef def = {
|
||||
.name = malloc(sizeof(char) * (strlen(name) + 1)),
|
||||
.name = strdup(name),
|
||||
.fieldCount = fieldCount,
|
||||
.names = malloc(sizeof(char*) * fieldCount),
|
||||
};
|
||||
strcpy(def.name, name);
|
||||
|
||||
int i = 0;
|
||||
FOR_POINTER_IN_LIST(fields) {
|
||||
def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1));
|
||||
strcpy(def.names[i], POINTER->string);
|
||||
def.names[i] = strdup(POINTER->string);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -317,12 +315,14 @@ Object structAccess(Object* params, unused int length, unused struct Environment
|
|||
}
|
||||
if (isNumber(field)) {
|
||||
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]);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -429,6 +429,7 @@ Object parseBin(struct Slice* s)
|
|||
|
||||
struct InlinedFunction {
|
||||
Object (* func)(Object*, int, struct Environment*);
|
||||
|
||||
Object* arguments;
|
||||
int argCount;
|
||||
//struct Environment* env;
|
||||
|
@ -514,7 +515,11 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
parens--;
|
||||
}
|
||||
|
||||
if (parens == 0) {
|
||||
if (parens != 0) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
cleanObject(&obj);
|
||||
Object parsed = parse(tok).obj;
|
||||
if (parsed.type == TYPE_ERROR) {
|
||||
|
@ -525,6 +530,7 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (tok[i].text[0] == ')') {
|
||||
// Skip `tok` past end of list that just closed
|
||||
tok = &tok[i + 1];
|
||||
|
@ -536,7 +542,6 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
obj = eval(&parsed, env);
|
||||
cleanObject(&parsed);
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
title "Lambdas"
|
||||
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 "Multi-Statement" "(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 "AnonymousLambda" "\
|
||||
(map (fn (a) (* a a)) (5 6 7))" "( 25 36 49 )"
|
||||
check "FbnciSeq" "\
|
||||
|
@ -177,17 +176,17 @@ check "FbnciSeq" "\
|
|||
(if (< a 2) \
|
||||
a \
|
||||
(+ (fib (- a 1)) (fib (- a 2))) \
|
||||
)));\
|
||||
)))\
|
||||
(fib 11)" "89"
|
||||
check "Factorial" "\
|
||||
(def fac (fn (a) \
|
||||
(if (= a 1) \
|
||||
1 \
|
||||
(* a (fac (- a 1)) ) \
|
||||
)));\
|
||||
)))\
|
||||
(fac 11)" "39916800"
|
||||
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"
|
||||
check "Basic Cat" '(cat "Big" " Kitty")' "Big Kitty"
|
||||
|
|
40
src/tokens.c
40
src/tokens.c
|
@ -2,8 +2,6 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#define ERR_LEN 256
|
||||
|
||||
/*
|
||||
* Grammar:
|
||||
* token
|
||||
|
@ -42,11 +40,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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!input) {
|
||||
err->context = malloc(sizeof(char) * ERR_LEN);
|
||||
strcpy(err->context, "no input");
|
||||
err->context = strdup("no input");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -63,8 +68,8 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
|
||||
int parens = 0;
|
||||
while (input[i] != '\0') {
|
||||
int l = 1;
|
||||
if (isWhitespace(input[i]) || input[i] == ';') {
|
||||
int length = 1;
|
||||
if (isWhitespace(input[i])) {
|
||||
if (input[i] == '\n') {
|
||||
lineNumber++;
|
||||
}
|
||||
|
@ -77,10 +82,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
} else if (input[i] == ')') {
|
||||
parens--;
|
||||
if (parens < 0) {
|
||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
||||
err->code = MISMATCHED_PARENS;
|
||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||
strncpy(err->context, &input[start], ERR_LEN);
|
||||
buildErrFromInput(err, MISMATCHED_PARENS, i, input);
|
||||
//free(slices);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -104,12 +106,9 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
if (input[i] == '\n') {
|
||||
lineNumber++;
|
||||
}
|
||||
l++;
|
||||
length++;
|
||||
if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
|
||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
||||
err->code = UNEXPECTED_EOF;
|
||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||
strncpy(err->context, &input[start], ERR_LEN);
|
||||
buildErrFromInput(err, UNEXPECTED_EOF, i, input);
|
||||
//free(slices);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -120,25 +119,22 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
if (input[i] == '\n') {
|
||||
lineNumber++;
|
||||
}
|
||||
l++;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
while (!isWhitespace(input[++i]) && !isSingle(input[i]) && input[i] != '"' && input[i] != '\0') {
|
||||
l++;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
slices[slice].length = l;
|
||||
slices[slice].length = length;
|
||||
slice++;
|
||||
}
|
||||
|
||||
if (parens != 0) {
|
||||
err->context = malloc(sizeof(char) * ERR_LEN);
|
||||
err->code = MISMATCHED_PARENS;
|
||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||
strncpy(err->context, &input[start], ERR_LEN);
|
||||
buildErrFromInput(err, MISMATCHED_PARENS, i, input);
|
||||
//free(slices);
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue