Add simple object hashtable for env.
Currently has some issues with accessing parameters in recursive calls.
This commit is contained in:
parent
d625944e8d
commit
caaa6c53f6
|
@ -1,4 +1,4 @@
|
||||||
files = pebblisp.c tokens.c object.c env.c web.c plfunc.c
|
files = pebblisp.c tokens.c object.c env.c web.c plfunc.c hash.c
|
||||||
libs = -lreadline -lmicrohttpd
|
libs = -lreadline -lmicrohttpd
|
||||||
exe = pl
|
exe = pl
|
||||||
|
|
||||||
|
|
622
src/env.c
622
src/env.c
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
#define printd(...) ;
|
#define printd(...) ;
|
||||||
|
|
||||||
|
#define HASH_ENV
|
||||||
|
|
||||||
|
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help,
|
||||||
|
const char* const* tests, size_t testLength);
|
||||||
|
|
||||||
struct Environment* globalEnv;
|
struct Environment* globalEnv;
|
||||||
|
|
||||||
struct Environment* global()
|
struct Environment* global()
|
||||||
|
@ -28,6 +33,239 @@ struct Dictionary {
|
||||||
struct StructDef* structDefs;
|
struct StructDef* structDefs;
|
||||||
} dictionary;
|
} dictionary;
|
||||||
|
|
||||||
|
/// For any instances (e.g. segfault recovery) where defaultEnv() may be called
|
||||||
|
/// multiple times.
|
||||||
|
int helpInitialized = 0;
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
struct helpText {
|
||||||
|
const char* symbol;
|
||||||
|
const char* help;
|
||||||
|
const char* const* tests;
|
||||||
|
size_t testCount;
|
||||||
|
};
|
||||||
|
int currentHelp = 0;
|
||||||
|
struct helpText helpTexts[100];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct symFunc {
|
||||||
|
const char* sym;
|
||||||
|
|
||||||
|
Object (* func)(Object*, int, struct Environment*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func), _func ## Doc, _func ## Tests, array_length(_func ## Tests))
|
||||||
|
#else
|
||||||
|
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HASH_ENV // Hash-based env
|
||||||
|
Object* fetch(const char* name, struct Environment* env)
|
||||||
|
{
|
||||||
|
while (env) {
|
||||||
|
Object* object = getFromTable(&env->table, name);
|
||||||
|
if (object) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
env = env->outer;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object fetchFromEnvironment(const char* name, struct Environment* env)
|
||||||
|
{
|
||||||
|
Object* object = fetch(name, env);
|
||||||
|
if (object) {
|
||||||
|
return cloneObject(*object);
|
||||||
|
}
|
||||||
|
return errorWithContext(DID_NOT_FIND_SYMBOL, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||||
|
{
|
||||||
|
Object* existing = fetch(name, env);
|
||||||
|
if (existing) {
|
||||||
|
cleanObject(existing);
|
||||||
|
*existing = cloneObject(obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char* symbol = malloc(sizeof(char) * (strlen(name) + 1));
|
||||||
|
strcpy(symbol, name);
|
||||||
|
addToTable(&env->table, symbol, cloneObject(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Environment envForLambda(const Object* params, const Object* arg_forms, int paramCount,
|
||||||
|
struct Environment* outer)
|
||||||
|
{
|
||||||
|
if (outer) {
|
||||||
|
outer->refs += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Environment env = {
|
||||||
|
.outer = outer,
|
||||||
|
.table = buildTable(4),
|
||||||
|
.refs = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (paramCount == 0) {
|
||||||
|
if (outer) {
|
||||||
|
outer->refs += 1;
|
||||||
|
return *outer;
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Object* march = arg_forms;
|
||||||
|
for (int i = 0; i < paramCount; i++) {
|
||||||
|
const char* newObjName = itemAt(params, i)->string;
|
||||||
|
// Eval the `march` list
|
||||||
|
Object newEnvObj = march ? eval(march, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, newObjName);
|
||||||
|
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
|
||||||
|
cleanObject(&newEnvObj);
|
||||||
|
march = march ? march->forward : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteEnv(struct Environment* e)
|
||||||
|
{
|
||||||
|
e->refs -= 1;
|
||||||
|
if (e->refs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e->outer) {
|
||||||
|
deleteEnv(e->outer);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTable(&e->table);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Environment defaultEnv()
|
||||||
|
{
|
||||||
|
#ifndef STANDALONE
|
||||||
|
int helpInitialized = 0;
|
||||||
|
#endif
|
||||||
|
if (!helpInitialized) {
|
||||||
|
dictionary = (struct Dictionary) {
|
||||||
|
.structCount = 0,
|
||||||
|
.structCapacity = 8,
|
||||||
|
.structDefs = malloc(sizeof(struct StructDef) * 8),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Environment e = {
|
||||||
|
.table = buildTable(128),
|
||||||
|
.outer = NULL,
|
||||||
|
.refs = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct symFunc symFuncs[] = {
|
||||||
|
pf(def),
|
||||||
|
pf(add),
|
||||||
|
pf(sub),
|
||||||
|
pf(mul),
|
||||||
|
pf(dvi),
|
||||||
|
pf(mod),
|
||||||
|
pf(equ),
|
||||||
|
pf(greaterThan),
|
||||||
|
pf(lessThan),
|
||||||
|
pf(and),
|
||||||
|
pf(or),
|
||||||
|
pf(catObjects),
|
||||||
|
pf(filter),
|
||||||
|
pf(len),
|
||||||
|
pf(append),
|
||||||
|
pf(prepend),
|
||||||
|
pf(reduce),
|
||||||
|
pf(mapO),
|
||||||
|
pf(at),
|
||||||
|
#ifndef PBL_PLATFORM_APLITE
|
||||||
|
pf(rest),
|
||||||
|
pf(charAt),
|
||||||
|
pf(isNum),
|
||||||
|
pf(isList),
|
||||||
|
pf(isString),
|
||||||
|
pf(isErr),
|
||||||
|
pf(charVal),
|
||||||
|
pf(parseEvalO),
|
||||||
|
#endif
|
||||||
|
pf(structAccess),
|
||||||
|
pf(getTime),
|
||||||
|
#ifndef LOW_MEM
|
||||||
|
pf(reverse),
|
||||||
|
#endif
|
||||||
|
#ifdef WEBSERVER
|
||||||
|
pf(addGetRoute),
|
||||||
|
pf(addPostRoute),
|
||||||
|
pf(startServer),
|
||||||
|
#endif
|
||||||
|
#ifdef STANDALONE
|
||||||
|
pf(segfault),
|
||||||
|
pf(print),
|
||||||
|
pf(numToChar),
|
||||||
|
pf(printEnvO),
|
||||||
|
pf(systemCall),
|
||||||
|
pf(loadFile),
|
||||||
|
pf(cd),
|
||||||
|
pf(cwd),
|
||||||
|
pf(takeInput),
|
||||||
|
pf(readFileToObject),
|
||||||
|
pf(getEnvVar),
|
||||||
|
pf(help)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) {
|
||||||
|
addFunc(symFuncs[i].sym, symFuncs[i].func, &e, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
helpInitialized = 1;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printEnv(struct Environment* env, int printPointers)
|
||||||
|
{
|
||||||
|
if (!env) {
|
||||||
|
printf("NULL env\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("env->capacity = %lu\n", env->table.capacity);
|
||||||
|
printf("env->count = %lu\n", env->table.count);
|
||||||
|
|
||||||
|
for (int i = 0; i < env->table.capacity; i++) {
|
||||||
|
printf("[0m");
|
||||||
|
if (env->table.elements[i].symbol == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (printPointers) {
|
||||||
|
printf("[%d]: `%s` %p :: ", i, env->table.elements[i].symbol, env->table.elements[i].symbol);
|
||||||
|
} else {
|
||||||
|
printf("[%d]: `%s` :: ", i, env->table.elements[i].symbol);
|
||||||
|
}
|
||||||
|
printf("[0m");
|
||||||
|
if (env->table.elements[i].object.type == TYPE_STRING) {
|
||||||
|
printf("\"");
|
||||||
|
}
|
||||||
|
if (env->table.elements[i].object.type == TYPE_FUNC && !printPointers) {
|
||||||
|
printf("Native");
|
||||||
|
} else {
|
||||||
|
size_t length;
|
||||||
|
char* s = stringObj(&env->table.elements[i].object, &length);
|
||||||
|
printColored(s);
|
||||||
|
if (env->table.elements[i].object.type == TYPE_STRING) {
|
||||||
|
printf("\"");
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
Object fetchFromEnvironment(const char* name, struct Environment* env)
|
Object fetchFromEnvironment(const char* name, struct Environment* env)
|
||||||
{
|
{
|
||||||
if (!env) {
|
if (!env) {
|
||||||
|
@ -43,15 +281,15 @@ Object fetchFromEnvironment(const char* name, struct Environment* env)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < env->capacity; i++) {
|
for (int i = 0; i < env->capacity; i++) {
|
||||||
if (env->strings[i] == NULL) {
|
if (env->elements[i].symbol == NULL) {
|
||||||
printd("Try %d (NULL)\n", i);
|
printd("Try %d (NULL)\n", i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printd("Try %d (%s)\n", i, env->strings[i]);
|
printd("Try %d (%s)\n", i, env->strings[i]);
|
||||||
if (strcmp(name, env->strings[i]) == 0) {
|
if (strcmp(name, env->elements[i].symbol) == 0) {
|
||||||
printd("Returning!\n");
|
printd("Returning!\n");
|
||||||
return cloneObject(env->objects[i]);
|
return cloneObject(env->elements[i].object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,9 +303,9 @@ Object fetchFromEnvironment(const char* name, struct Environment* env)
|
||||||
|
|
||||||
void addToEnvAt(int i, struct Environment* env, const char* name, const Object obj)
|
void addToEnvAt(int i, struct Environment* env, const char* name, const Object obj)
|
||||||
{
|
{
|
||||||
env->strings[i] = malloc(sizeof(char) * strlen(name) + 1);
|
env->elements[i].symbol = malloc(sizeof(char) * strlen(name) + 1);
|
||||||
strcpy(env->strings[i], name);
|
strcpy(env->elements[i].symbol, name);
|
||||||
env->objects[i] = cloneObject(obj);
|
env->elements[i].object = cloneObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Environment envForLambda(const Object* params, const Object* arg_forms, int paramCount,
|
struct Environment envForLambda(const Object* params, const Object* arg_forms, int paramCount,
|
||||||
|
@ -88,13 +326,11 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i
|
||||||
outer->refs += 1;
|
outer->refs += 1;
|
||||||
return *outer;
|
return *outer;
|
||||||
}
|
}
|
||||||
env.strings = NULL;
|
env.elements = NULL;
|
||||||
env.objects = NULL;
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
env.strings = malloc(sizeof(char*) * (paramCount + 1));
|
env.elements = malloc(sizeof(struct EnvElement) * (paramCount + 1));
|
||||||
env.objects = malloc(sizeof(Object) * (paramCount + 1));
|
|
||||||
|
|
||||||
const Object* march = arg_forms;
|
const Object* march = arg_forms;
|
||||||
for (int i = 0; i < paramCount; i++) {
|
for (int i = 0; i < paramCount; i++) {
|
||||||
|
@ -105,7 +341,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i
|
||||||
cleanObject(&newEnvObj);
|
cleanObject(&newEnvObj);
|
||||||
march = march ? march->forward : NULL;
|
march = march ? march->forward : NULL;
|
||||||
}
|
}
|
||||||
env.strings[paramCount] = NULL;
|
env.elements[paramCount].symbol = NULL;
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +351,7 @@ void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||||
struct Environment* temp_env = env;
|
struct Environment* temp_env = env;
|
||||||
while (temp_env) {
|
while (temp_env) {
|
||||||
for (int i = 0; i < temp_env->capacity; i++) {
|
for (int i = 0; i < temp_env->capacity; i++) {
|
||||||
if (temp_env->strings[i] == NULL) {
|
if (temp_env->elements[i].symbol == NULL) {
|
||||||
// Add *new* item to env only if we're in the original scope,
|
// Add *new* item to env only if we're in the original scope,
|
||||||
// otherwise keep searching
|
// otherwise keep searching
|
||||||
if (temp_env == env) {
|
if (temp_env == env) {
|
||||||
|
@ -123,10 +359,10 @@ void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (strcmp(temp_env->strings[i], name) == 0) {
|
} else if (strcmp(temp_env->elements[i].symbol, name) == 0) {
|
||||||
Object o = cloneObject(obj);
|
Object o = cloneObject(obj);
|
||||||
cleanObject(&temp_env->objects[i]);
|
cleanObject(&temp_env->elements[i].object);
|
||||||
temp_env->objects[i] = o;
|
temp_env->elements[i].object = o;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,66 +373,15 @@ void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||||
const int inc = 5;
|
const int inc = 5;
|
||||||
const int old_size = env->capacity;
|
const int old_size = env->capacity;
|
||||||
env->capacity += inc;
|
env->capacity += inc;
|
||||||
env->strings = realloc(env->strings, sizeof(char*) * env->capacity);
|
env->elements = realloc(env->elements, sizeof(struct EnvElement) * env->capacity);
|
||||||
env->objects = realloc(env->objects, sizeof(Object) * env->capacity);
|
|
||||||
|
|
||||||
for (int j = 0; j < inc; j++) {
|
for (int j = 0; j < inc; j++) {
|
||||||
env->strings[old_size + j] = NULL;
|
env->elements[old_size + j].symbol = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
addToEnvAt(old_size, env, name, obj);
|
addToEnvAt(old_size, env, name, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STANDALONE
|
|
||||||
void printEnv(struct Environment* env, int printPointers)
|
|
||||||
{
|
|
||||||
if (!env) {
|
|
||||||
printf("NULL env\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printf("env->capacity = %d\n", env->capacity);
|
|
||||||
for (int i = 0; i < env->capacity; i++) {
|
|
||||||
printf("[0m");
|
|
||||||
if (env->strings[i] == NULL) {
|
|
||||||
printf("[%d]: NULL - End of Environment\n", i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (printPointers) {
|
|
||||||
printf("[%d]: `%s` %p :: ", i, env->strings[i], env->strings[i]);
|
|
||||||
} else {
|
|
||||||
printf("[%d]: `%s` :: ", i, env->strings[i]);
|
|
||||||
}
|
|
||||||
printf("[0m");
|
|
||||||
if (env->objects[i].type == TYPE_STRING) {
|
|
||||||
printf("\"");
|
|
||||||
}
|
|
||||||
if (env->objects[i].type == TYPE_FUNC && !printPointers) {
|
|
||||||
printf("Native");
|
|
||||||
} else {
|
|
||||||
size_t length;
|
|
||||||
char* s = stringObj(&env->objects[i], &length);
|
|
||||||
printColored(s);
|
|
||||||
if (env->objects[i].type == TYPE_STRING) {
|
|
||||||
printf("\"");
|
|
||||||
}
|
|
||||||
free(s);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void addFunc(const char* name,
|
|
||||||
Object (* func)(Object*, int, struct Environment*),
|
|
||||||
struct Environment* env,
|
|
||||||
int i)
|
|
||||||
{
|
|
||||||
Object o = newObject(TYPE_FUNC);
|
|
||||||
o.func = func;
|
|
||||||
addToEnvAt(i, env, name, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteEnv(struct Environment* e)
|
void deleteEnv(struct Environment* e)
|
||||||
{
|
{
|
||||||
e->refs -= 1;
|
e->refs -= 1;
|
||||||
|
@ -207,18 +392,165 @@ void deleteEnv(struct Environment* e)
|
||||||
deleteEnv(e->outer);
|
deleteEnv(e->outer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->strings) {
|
if (e->elements) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (e->strings[i]) {
|
while (e->elements[i].symbol) {
|
||||||
free(e->strings[i]);
|
free(e->elements[i].symbol);
|
||||||
cleanObject(&e->objects[i]);
|
cleanObject(&e->elements[i].object);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
free(e->strings);
|
free(e->elements);
|
||||||
free(e->objects);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Environment defaultEnvPreAllocated(struct EnvElement* elements)
|
||||||
|
{
|
||||||
|
#ifndef STANDALONE
|
||||||
|
int helpInitialized = 0;
|
||||||
|
#endif
|
||||||
|
if (!helpInitialized) {
|
||||||
|
dictionary = (struct Dictionary) {
|
||||||
|
.structCount = 0,
|
||||||
|
.structCapacity = 8,
|
||||||
|
.structDefs = malloc(sizeof(struct StructDef) * 8),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Environment e = {
|
||||||
|
.elements = elements,
|
||||||
|
.outer = NULL,
|
||||||
|
.capacity = MAX_ENV_ELM,
|
||||||
|
.refs = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct symFunc symFuncs[] = {
|
||||||
|
pf(def),
|
||||||
|
pf(add),
|
||||||
|
pf(sub),
|
||||||
|
pf(mul),
|
||||||
|
pf(dvi),
|
||||||
|
pf(mod),
|
||||||
|
pf(equ),
|
||||||
|
pf(greaterThan),
|
||||||
|
pf(lessThan),
|
||||||
|
pf(and),
|
||||||
|
pf(or),
|
||||||
|
pf(catObjects),
|
||||||
|
pf(filter),
|
||||||
|
pf(len),
|
||||||
|
pf(append),
|
||||||
|
pf(prepend),
|
||||||
|
pf(reduce),
|
||||||
|
pf(mapO),
|
||||||
|
pf(at),
|
||||||
|
#ifndef PBL_PLATFORM_APLITE
|
||||||
|
pf(rest),
|
||||||
|
pf(charAt),
|
||||||
|
pf(isNum),
|
||||||
|
pf(isList),
|
||||||
|
pf(isString),
|
||||||
|
pf(isErr),
|
||||||
|
pf(charVal),
|
||||||
|
pf(parseEvalO),
|
||||||
|
#endif
|
||||||
|
pf(structAccess),
|
||||||
|
pf(getTime),
|
||||||
|
#ifndef LOW_MEM
|
||||||
|
pf(reverse),
|
||||||
|
#endif
|
||||||
|
#ifdef WEBSERVER
|
||||||
|
pf(addGetRoute),
|
||||||
|
pf(addPostRoute),
|
||||||
|
pf(startServer),
|
||||||
|
#endif
|
||||||
|
#ifdef STANDALONE
|
||||||
|
pf(segfault),
|
||||||
|
pf(print),
|
||||||
|
pf(numToChar),
|
||||||
|
pf(printEnvO),
|
||||||
|
pf(systemCall),
|
||||||
|
pf(loadFile),
|
||||||
|
pf(cd),
|
||||||
|
pf(cwd),
|
||||||
|
pf(takeInput),
|
||||||
|
pf(readFileToObject),
|
||||||
|
pf(getEnvVar),
|
||||||
|
pf(help)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) {
|
||||||
|
addFunc(symFuncs[i].sym, symFuncs[i].func, &e, i);
|
||||||
|
}
|
||||||
|
for (int j = i; j < e.capacity; j++) {
|
||||||
|
e.elements[j].symbol = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CACHE
|
||||||
|
for (i = 0; i < CACHE_SIZE + 1; i++) {
|
||||||
|
cache[i] = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
helpInitialized = 1;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Environment defaultEnv()
|
||||||
|
{
|
||||||
|
return defaultEnvPreAllocated(malloc(sizeof(struct EnvElement) * MAX_ENV_ELM));
|
||||||
|
}
|
||||||
|
|
||||||
|
void printEnv(struct Environment* env, int printPointers)
|
||||||
|
{
|
||||||
|
if (!env) {
|
||||||
|
printf("NULL env\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("env->capacity = %d\n", env->capacity);
|
||||||
|
for (int i = 0; i < env->capacity; i++) {
|
||||||
|
printf("[0m");
|
||||||
|
if (env->elements[i].symbol == NULL) {
|
||||||
|
printf("[%d]: NULL - End of Environment\n", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (printPointers) {
|
||||||
|
printf("[%d]: `%s` %p :: ", i, env->elements[i].symbol, env->elements[i].symbol);
|
||||||
|
} else {
|
||||||
|
printf("[%d]: `%s` :: ", i, env->elements[i].symbol);
|
||||||
|
}
|
||||||
|
printf("[0m");
|
||||||
|
if (env->elements[i].object.type == TYPE_STRING) {
|
||||||
|
printf("\"");
|
||||||
|
}
|
||||||
|
if (env->elements[i].object.type == TYPE_FUNC && !printPointers) {
|
||||||
|
printf("Native");
|
||||||
|
} else {
|
||||||
|
size_t length;
|
||||||
|
char* s = stringObj(&env->elements[i].object, &length);
|
||||||
|
printColored(s);
|
||||||
|
if (env->elements[i].object.type == TYPE_STRING) {
|
||||||
|
printf("\"");
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void addFunc(const char* name,
|
||||||
|
Object (* func)(Object*, int, struct Environment*),
|
||||||
|
struct Environment* env,
|
||||||
|
int i)
|
||||||
|
{
|
||||||
|
Object o = newObject(TYPE_FUNC);
|
||||||
|
o.func = func;
|
||||||
|
// addToEnvAt(i, env, name, o);
|
||||||
|
addToEnv(env, name, o);
|
||||||
|
}
|
||||||
|
|
||||||
void shredDictionary()
|
void shredDictionary()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < dictionary.structCount; i++) {
|
for (int i = 0; i < dictionary.structCount; i++) {
|
||||||
|
@ -231,27 +563,6 @@ void shredDictionary()
|
||||||
free(dictionary.structDefs);
|
free(dictionary.structDefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct symFunc {
|
|
||||||
const char* sym;
|
|
||||||
|
|
||||||
Object (* func)(Object*, int, struct Environment*);
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef STANDALONE
|
|
||||||
struct helpText {
|
|
||||||
const char* symbol;
|
|
||||||
const char* help;
|
|
||||||
const char* const* tests;
|
|
||||||
size_t testCount;
|
|
||||||
};
|
|
||||||
int currentHelp = 0;
|
|
||||||
struct helpText helpTexts[100];
|
|
||||||
|
|
||||||
/// For any instances (e.g. segfault recovery) where defaultEnv() may be called
|
|
||||||
/// multiple times.
|
|
||||||
int helpInitialized = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help,
|
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help,
|
||||||
const char* const* tests, size_t testLength)
|
const char* const* tests, size_t testLength)
|
||||||
|
@ -333,11 +644,13 @@ void printColored(const char* code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn(help, "?",
|
Object segfault(Object* params, int length, struct Environment* env)
|
||||||
"Gets a string with help text for the given function.\n"
|
{
|
||||||
"For example:\n"
|
int* p = NULL;
|
||||||
" (? islist) => \"(islist (1 2 3)) => T\""
|
return numberObject(*p);
|
||||||
)
|
}
|
||||||
|
|
||||||
|
Object help(Object* params, int length, struct Environment* env)
|
||||||
{
|
{
|
||||||
const char* symbol;
|
const char* symbol;
|
||||||
if (!length || !params[0].string || params[0].string[0] == '\0') {
|
if (!length || !params[0].string || params[0].string[0] == '\0') {
|
||||||
|
@ -421,115 +734,6 @@ int runTests(int detailed)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fn(segfault, "seg",
|
|
||||||
"Induces a segfault."
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int* p = NULL;
|
|
||||||
return numberObject(*p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef STANDALONE
|
|
||||||
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func), _func ## Doc, _func ## Tests, array_length(_func ## Tests))
|
|
||||||
#else
|
|
||||||
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct Environment defaultEnvPreAllocated(char** strings, Object* objects)
|
|
||||||
{
|
|
||||||
#ifndef STANDALONE
|
|
||||||
int helpInitialized = 0;
|
|
||||||
#endif
|
|
||||||
if (!helpInitialized) {
|
|
||||||
dictionary = (struct Dictionary) {
|
|
||||||
.structCount = 0,
|
|
||||||
.structCapacity = 8,
|
|
||||||
.structDefs = malloc(sizeof(struct StructDef) * 8),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Environment e = {
|
|
||||||
.outer = NULL,
|
|
||||||
.strings = strings,
|
|
||||||
.objects = objects,
|
|
||||||
.capacity = MAX_ENV_ELM,
|
|
||||||
.refs = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct symFunc symFuncs[] = {
|
|
||||||
pf(def),
|
|
||||||
pf(add),
|
|
||||||
pf(sub),
|
|
||||||
pf(mul),
|
|
||||||
pf(dvi),
|
|
||||||
pf(mod),
|
|
||||||
pf(equ),
|
|
||||||
pf(greaterThan),
|
|
||||||
pf(lessThan),
|
|
||||||
pf(and),
|
|
||||||
pf(or),
|
|
||||||
pf(catObjects),
|
|
||||||
pf(filter),
|
|
||||||
pf(len),
|
|
||||||
pf(append),
|
|
||||||
pf(prepend),
|
|
||||||
pf(reduce),
|
|
||||||
pf(mapO),
|
|
||||||
pf(at),
|
|
||||||
#ifndef PBL_PLATFORM_APLITE
|
|
||||||
pf(rest),
|
|
||||||
pf(charAt),
|
|
||||||
pf(isNum),
|
|
||||||
pf(isList),
|
|
||||||
pf(isString),
|
|
||||||
pf(isErr),
|
|
||||||
pf(charVal),
|
|
||||||
pf(parseEvalO),
|
|
||||||
#endif
|
|
||||||
pf(structAccess),
|
|
||||||
pf(getTime),
|
|
||||||
#ifndef LOW_MEM
|
|
||||||
pf(reverse),
|
|
||||||
#endif
|
|
||||||
#ifdef WEBSERVER
|
|
||||||
pf(addGetRoute),
|
|
||||||
pf(addPostRoute),
|
|
||||||
pf(startServer),
|
|
||||||
#endif
|
|
||||||
#ifdef STANDALONE
|
|
||||||
pf(segfault),
|
|
||||||
pf(print),
|
|
||||||
pf(numToChar),
|
|
||||||
pf(printEnvO),
|
|
||||||
pf(systemCall),
|
|
||||||
pf(loadFile),
|
|
||||||
pf(cd),
|
|
||||||
pf(cwd),
|
|
||||||
pf(takeInput),
|
|
||||||
pf(readFileToObject),
|
|
||||||
pf(getEnvVar),
|
|
||||||
pf(help)
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) {
|
|
||||||
addFunc(symFuncs[i].sym, symFuncs[i].func, &e, i);
|
|
||||||
}
|
|
||||||
for (int j = i; j < e.capacity; j++) {
|
|
||||||
e.strings[j] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
helpInitialized = 1;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Environment defaultEnv()
|
|
||||||
{
|
|
||||||
return defaultEnvPreAllocated(malloc(sizeof(char*) * MAX_ENV_ELM), malloc(sizeof(Object) * MAX_ENV_ELM));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int getStructIndex(const char* name)
|
int getStructIndex(const char* name)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < dictionary.structCount; i++) {
|
for (int i = 0; i < dictionary.structCount; i++) {
|
||||||
|
|
47
src/env.h
47
src/env.h
|
@ -2,13 +2,19 @@
|
||||||
#define ENVIRONMENT_H
|
#define ENVIRONMENT_H
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
struct EnvElement {
|
||||||
|
char* symbol;
|
||||||
|
Object object;
|
||||||
|
};
|
||||||
|
|
||||||
struct Environment;
|
struct Environment;
|
||||||
struct Environment {
|
struct Environment {
|
||||||
char** strings;
|
|
||||||
Object* objects;
|
|
||||||
struct Environment* outer;
|
struct Environment* outer;
|
||||||
int capacity;
|
struct ObjectTable table;
|
||||||
|
// struct EnvElement* elements; // iterative
|
||||||
|
// int capacity; // iterative
|
||||||
|
|
||||||
int refs;
|
int refs;
|
||||||
};
|
};
|
||||||
|
@ -37,7 +43,7 @@ void shredDictionary();
|
||||||
|
|
||||||
struct Environment defaultEnv();
|
struct Environment defaultEnv();
|
||||||
|
|
||||||
struct Environment defaultEnvPreAllocated(char** strings, Object* objects);
|
struct Environment defaultEnvPreAllocated(struct EnvElement* elements);
|
||||||
|
|
||||||
int getStructIndex(const char* name);
|
int getStructIndex(const char* name);
|
||||||
|
|
||||||
|
@ -49,4 +55,37 @@ void printColored(const char* code);
|
||||||
|
|
||||||
int runTests(int detailed);
|
int runTests(int detailed);
|
||||||
|
|
||||||
|
int getTotalSearchDepth();
|
||||||
|
int getTotalSearches();
|
||||||
|
|
||||||
|
#define unused __attribute__((unused))
|
||||||
|
|
||||||
|
#define array_length(_array) (sizeof(_array) / sizeof((_array)[0]))
|
||||||
|
|
||||||
|
#define fnn(_name, _docs, ...) \
|
||||||
|
static const char * const _name ## Doc = _docs; \
|
||||||
|
unused static const char * const _name ## Tests[] = {__VA_ARGS__}; \
|
||||||
|
_Static_assert(array_length(_name ## Tests) % 2 == 0, "Array of test strings must have exactly one expected result for each test."); \
|
||||||
|
Object _name(Object* params, int length, struct Environment* env)
|
||||||
|
|
||||||
|
#define tfn(_name, _symbol, _type, _docs, ...) \
|
||||||
|
unused static int (*_name ## TypeChecks[])(Object) = UNPACK _type; \
|
||||||
|
static const char * const _name ## Symbol = _symbol; \
|
||||||
|
fnn(_name, _docs, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define fn(_name, _symbol, _docs, ...) \
|
||||||
|
static const char * const _name ## Symbol = _symbol; \
|
||||||
|
fnn(_name, _docs, __VA_ARGS__)
|
||||||
|
|
||||||
|
fn(segfault, "seg",
|
||||||
|
"Induces a segfault."
|
||||||
|
);
|
||||||
|
|
||||||
|
fn(help, "?",
|
||||||
|
"Gets a string with help text for the given function.\n"
|
||||||
|
"For example:\n"
|
||||||
|
" (? islist) => \"(islist (1 2 3)) => T\""
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,16 @@
|
||||||
; Cube a
|
; Cube a
|
||||||
(def cube (fn (a) (exp a 3)))
|
(def cube (fn (a) (exp a 3)))
|
||||||
|
|
||||||
|
(def fib_ (fn (a depth) (
|
||||||
|
(prnl (cat "n: " a))
|
||||||
|
(if (< a 2)
|
||||||
|
a
|
||||||
|
(+ (fib_ (- a 1) (+ 1 depth)) (fib_ (- a 2) (+ 1 depth)))
|
||||||
|
)
|
||||||
|
)))
|
||||||
|
|
||||||
|
(def fib (fn (a) ((fib a 0))))
|
||||||
|
|
||||||
; Return the larger of the two
|
; Return the larger of the two
|
||||||
(def max (fn (a b) (if (> a b) a b)))
|
(def max (fn (a b) (if (> a b) a b)))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "hash.h"
|
||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
#include <search.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static unsigned long hash(const char *str)
|
||||||
|
{
|
||||||
|
unsigned long hash = 5381;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = *str++)) {
|
||||||
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectTable buildTable(size_t capacity)
|
||||||
|
{
|
||||||
|
struct ObjectTable table = {
|
||||||
|
.count = 0,
|
||||||
|
.capacity = capacity,
|
||||||
|
.elements = malloc(sizeof(struct EnvElement) * capacity),
|
||||||
|
};
|
||||||
|
for (int i = 0; i < table.capacity; i++) {
|
||||||
|
table.elements[i].symbol = NULL;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param table
|
||||||
|
/// \param name Should be a new allocation
|
||||||
|
/// \param object Should already be cloned
|
||||||
|
void addToTable(struct ObjectTable* table, char* name, Object object)
|
||||||
|
{
|
||||||
|
size_t h = hash(name) % table->capacity;
|
||||||
|
while(table->elements[h].symbol) {
|
||||||
|
h = (h + 1) % table->capacity;
|
||||||
|
}
|
||||||
|
table->elements[h].symbol = name;
|
||||||
|
table->elements[h].object = object;
|
||||||
|
table->count += 1;
|
||||||
|
|
||||||
|
if (table->capacity < table->count * 2) {
|
||||||
|
struct ObjectTable newTable = buildTable(table->capacity * 2);
|
||||||
|
for (int i = 0; i < table->capacity; i++) {
|
||||||
|
if (table->elements[i].symbol) {
|
||||||
|
addToTable(&newTable, table->elements[i].symbol, table->elements[i].object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(table->elements);
|
||||||
|
*table = newTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object* getFromTable(struct ObjectTable* table, const char* name)
|
||||||
|
{
|
||||||
|
size_t h = hash(name) % table->capacity;
|
||||||
|
while(table->elements[h].symbol) {
|
||||||
|
if (strcmp(name, table->elements[h].symbol) == 0) {
|
||||||
|
return &table->elements[h].object;
|
||||||
|
}
|
||||||
|
h = (h + 1) % table->capacity;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteTable(struct ObjectTable* table)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < table->capacity; i++) {
|
||||||
|
if (table->elements[i].symbol) {
|
||||||
|
free(table->elements[i].symbol);
|
||||||
|
cleanObject(&table->elements[i].object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(table->elements);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef PEBBLISP_HASH_H
|
||||||
|
#define PEBBLISP_HASH_H
|
||||||
|
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
struct ObjectTable {
|
||||||
|
size_t count;
|
||||||
|
size_t capacity;
|
||||||
|
struct EnvElement* elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjectTable buildTable(size_t capacity);
|
||||||
|
|
||||||
|
void addToTable(struct ObjectTable* table, char* name, Object object);
|
||||||
|
|
||||||
|
Object* getFromTable(struct ObjectTable* table, const char* name);
|
||||||
|
|
||||||
|
void deleteTable(struct ObjectTable* table);
|
||||||
|
|
||||||
|
#endif //PEBBLISP_HASH_H
|
|
@ -627,7 +627,7 @@ Object cloneString(Object obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an Object with a deep copy of the given Object
|
// Returns an Object with a deep copy of the given Object
|
||||||
inline Object cloneOther(const Object src)
|
Object cloneOther(const Object src)
|
||||||
{
|
{
|
||||||
return src.other->clone ? src.other->clone(src.other) : src;
|
return src.other->clone ? src.other->clone(src.other) : src;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#define sprintf(_dest, args...) snprintf(_dest, 999, args)
|
#define sprintf(_dest, args...) snprintf(_dest, 999, args)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define xprintf(_dest, _format, ...) sprintf(_dest, _format, __VA_ARGS__)
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define printd(...) printf(__VA_ARGS__)
|
#define printd(...) printf(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -752,6 +752,7 @@ int main(int argc, const char* argv[])
|
||||||
}
|
}
|
||||||
deleteEnv(&env);
|
deleteEnv(&env);
|
||||||
shredDictionary();
|
shredDictionary();
|
||||||
|
// fprintf(stderr, "totalSearchDepth: %d of %d searches\n", getTotalSearchDepth(), getTotalSearches());
|
||||||
// fprintf(stderr, "\nHEAP-ALLOCATED OBJECTS: %d\n", getAllocations());
|
// fprintf(stderr, "\nHEAP-ALLOCATED OBJECTS: %d\n", getAllocations());
|
||||||
// fprintf(stderr, "TOTAL OBJECT.C ALLOC: %zu\n", getBytes());
|
// fprintf(stderr, "TOTAL OBJECT.C ALLOC: %zu\n", getBytes());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue