Handle all HASHLESS details in hash.c
This commit is contained in:
parent
4d215b1b79
commit
4baf7e011b
277
src/env.c
277
src/env.c
|
@ -57,8 +57,6 @@ struct symFunc {
|
||||||
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func))
|
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HASHLESS_ENV // Hash-based env
|
|
||||||
|
|
||||||
Object* fetch(const char* name, struct Environment* env)
|
Object* fetch(const char* name, struct Environment* env)
|
||||||
{
|
{
|
||||||
while (env) {
|
while (env) {
|
||||||
|
@ -261,281 +259,6 @@ void printEnv(struct Environment* env, int printPointers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
Object fetchFromEnvironment(const char* name, struct Environment* env)
|
|
||||||
{
|
|
||||||
if (!env) {
|
|
||||||
return errorObject(NULL_ENV);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env->capacity == 0) {
|
|
||||||
if (env->outer) {
|
|
||||||
return fetchFromEnvironment(name, env->outer);
|
|
||||||
} else {
|
|
||||||
return errorObject(EMPTY_ENV);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < env->capacity; i++) {
|
|
||||||
if (env->elements[i].symbol == NULL) {
|
|
||||||
printd("Try %d (NULL)\n", i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printd("Try %d (%s)\n", i, env->strings[i]);
|
|
||||||
if (strcmp(name, env->elements[i].symbol) == 0) {
|
|
||||||
printd("Returning!\n");
|
|
||||||
return cloneObject(env->elements[i].object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printd("Trying outer %p\n", env->outer);
|
|
||||||
if (env->outer) {
|
|
||||||
return fetchFromEnvironment(name, env->outer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorWithContext(DID_NOT_FIND_SYMBOL, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToEnvAt(int i, struct Environment* env, const char* name, const Object obj)
|
|
||||||
{
|
|
||||||
env->elements[i].symbol = malloc(sizeof(char) * strlen(name) + 1);
|
|
||||||
strcpy(env->elements[i].symbol, name);
|
|
||||||
env->elements[i].object = 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,
|
|
||||||
.capacity = paramCount,
|
|
||||||
.refs = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (paramCount == 0) {
|
|
||||||
if (outer) {
|
|
||||||
outer->refs += 1;
|
|
||||||
return *outer;
|
|
||||||
}
|
|
||||||
env.elements = NULL;
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
|
|
||||||
env.elements = malloc(sizeof(struct EnvElement) * (paramCount + 1));
|
|
||||||
|
|
||||||
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);
|
|
||||||
addToEnvAt(i, &env, newObjName, newEnvObj); // Could use eval_forms?
|
|
||||||
cleanObject(&newEnvObj);
|
|
||||||
march = march ? march->forward : NULL;
|
|
||||||
}
|
|
||||||
env.elements[paramCount].symbol = NULL;
|
|
||||||
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToEnv(struct Environment* env, const char* name, const Object obj)
|
|
||||||
{
|
|
||||||
struct Environment* temp_env = env;
|
|
||||||
while (temp_env) {
|
|
||||||
for (int i = 0; i < temp_env->capacity; i++) {
|
|
||||||
if (temp_env->elements[i].symbol == NULL) {
|
|
||||||
// Add *new* item to env only if we're in the original scope,
|
|
||||||
// otherwise keep searching
|
|
||||||
if (temp_env == env) {
|
|
||||||
addToEnvAt(i, env, name, obj);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else if (strcmp(temp_env->elements[i].symbol, name) == 0) {
|
|
||||||
Object o = cloneObject(obj);
|
|
||||||
cleanObject(&temp_env->elements[i].object);
|
|
||||||
temp_env->elements[i].object = o;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
temp_env = temp_env->outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
printd("Reallocating environment\n");
|
|
||||||
const int inc = 5;
|
|
||||||
const int old_size = env->capacity;
|
|
||||||
env->capacity += inc;
|
|
||||||
env->elements = realloc(env->elements, sizeof(struct EnvElement) * env->capacity);
|
|
||||||
|
|
||||||
for (int j = 0; j < inc; j++) {
|
|
||||||
env->elements[old_size + j].symbol = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
addToEnvAt(old_size, env, name, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteEnv(struct Environment* e)
|
|
||||||
{
|
|
||||||
e->refs -= 1;
|
|
||||||
if (e->refs) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (e->outer) {
|
|
||||||
deleteEnv(e->outer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->elements) {
|
|
||||||
int i = 0;
|
|
||||||
while (e->elements[i].symbol) {
|
|
||||||
free(e->elements[i].symbol);
|
|
||||||
cleanObject(&e->elements[i].object);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
free(e->elements);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(chars),
|
|
||||||
pf(matches),
|
|
||||||
pf(slen),
|
|
||||||
pf(substring),
|
|
||||||
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(async),
|
|
||||||
pf(await),
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
void addFunc(const char* name,
|
||||||
Object (* func)(Object*, int, struct Environment*),
|
Object (* func)(Object*, int, struct Environment*),
|
||||||
struct Environment* env,
|
struct Environment* env,
|
||||||
|
|
105
src/hash.c
105
src/hash.c
|
@ -3,18 +3,6 @@
|
||||||
|
|
||||||
#include <string.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 buildTable(size_t capacity)
|
||||||
{
|
{
|
||||||
struct ObjectTable table = {
|
struct ObjectTable table = {
|
||||||
|
@ -28,11 +16,32 @@ struct ObjectTable buildTable(size_t capacity)
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
void deleteTable(struct ObjectTable* table)
|
||||||
/// \param table
|
{
|
||||||
/// \param name Should be a new allocation
|
for (int i = 0; i < table->capacity; i++) {
|
||||||
/// \param object Should already be cloned
|
if (table->elements[i].symbol) {
|
||||||
void addToTable(struct ObjectTable* table, char* name, Object object)
|
free(table->elements[i].symbol);
|
||||||
|
cleanObject(&table->elements[i].object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(table->elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HASHLESS_ENV
|
||||||
|
|
||||||
|
static unsigned long hash(const char* str, struct ObjectTable* table)
|
||||||
|
{
|
||||||
|
unsigned long hash = 5381;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = *str++)) {
|
||||||
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash % table->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void extendTable(struct ObjectTable* table)
|
||||||
{
|
{
|
||||||
if (table->capacity < (table->count + 1) * 2) {
|
if (table->capacity < (table->count + 1) * 2) {
|
||||||
struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4);
|
struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4);
|
||||||
|
@ -44,14 +53,6 @@ void addToTable(struct ObjectTable* table, char* name, Object object)
|
||||||
free(table->elements);
|
free(table->elements);
|
||||||
*table = newTable;
|
*table = newTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object* getFromTable(struct ObjectTable* table, const char* name)
|
Object* getFromTable(struct ObjectTable* table, const char* name)
|
||||||
|
@ -59,7 +60,7 @@ Object* getFromTable(struct ObjectTable* table, const char* name)
|
||||||
if (table->capacity == 0) {
|
if (table->capacity == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
size_t h = hash(name) % table->capacity;
|
size_t h = hash(name, table);
|
||||||
while (table->elements[h].symbol) {
|
while (table->elements[h].symbol) {
|
||||||
if (strcmp(name, table->elements[h].symbol) == 0) {
|
if (strcmp(name, table->elements[h].symbol) == 0) {
|
||||||
return &table->elements[h].object;
|
return &table->elements[h].object;
|
||||||
|
@ -69,13 +70,53 @@ Object* getFromTable(struct ObjectTable* table, const char* name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteTable(struct ObjectTable* table)
|
#else
|
||||||
|
|
||||||
|
void extendTable(struct ObjectTable* table)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < table->capacity; i++) {
|
if (table->count == (table->capacity - 1)) {
|
||||||
if (table->elements[i].symbol) {
|
struct EnvElement* oldElements = table->elements;
|
||||||
free(table->elements[i].symbol);
|
size_t oldCapacity = table->capacity;
|
||||||
cleanObject(&table->elements[i].object);
|
table->capacity *= 2;
|
||||||
|
table->elements = malloc(sizeof(struct EnvElement) * table->capacity);
|
||||||
|
for (int i = 0; i < oldCapacity; i++) {
|
||||||
|
table->elements[i] = oldElements[i];
|
||||||
|
}
|
||||||
|
for (size_t i = oldCapacity; i < table->capacity; i++) {
|
||||||
|
table->elements[i].symbol = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(table->elements);
|
}
|
||||||
|
|
||||||
|
Object* getFromTable(struct ObjectTable* table, const char* name)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < table->count; i++) {
|
||||||
|
if (strcmp(name, table->elements[i].symbol) == 0) {
|
||||||
|
return &table->elements[i].object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long hash(unused const char* str, struct ObjectTable* table)
|
||||||
|
{
|
||||||
|
return table->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param table
|
||||||
|
/// \param name Should be a new allocation
|
||||||
|
/// \param object Should already be cloned
|
||||||
|
void addToTable(struct ObjectTable* table, char* name, Object object)
|
||||||
|
{
|
||||||
|
extendTable(table);
|
||||||
|
size_t h = hash(name, table);
|
||||||
|
while (table->elements[h].symbol) {
|
||||||
|
h = (h + 1) % table->capacity;
|
||||||
|
}
|
||||||
|
table->elements[h].symbol = name;
|
||||||
|
table->elements[h].object = object;
|
||||||
|
table->count += 1;
|
||||||
}
|
}
|
Loading…
Reference in New Issue