Start dropping support for semicolon separators.

Simplify some error functions.
Oh, right. strdup() exists.
This commit is contained in:
Sage Vaillancourt 2022-04-14 00:31:51 -04:00
parent e326af38f8
commit 3f4d8fd7af
8 changed files with 76 additions and 81 deletions

View File

@ -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;

View File

@ -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;
} }

View File

@ -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), " %s:%d", fileName, lineNo);
cursor += sprintf(cursor, "%s", context); o.error->context = context;
if (fileName) { return o;
sprintf(cursor, " %s:%d", 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

View File

@ -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();

View File

@ -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++;
} }

View File

@ -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"

View File

@ -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;
} }

View File

@ -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;