diff --git a/src/Makefile b/src/Makefile index 598a053..eb4a050 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 exe = pl diff --git a/src/env.c b/src/env.c index aa1441d..edd49a3 100644 --- a/src/env.c +++ b/src/env.c @@ -10,6 +10,11 @@ #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* global() @@ -28,6 +33,239 @@ struct Dictionary { struct StructDef* structDefs; } 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(""); + 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(""); + 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) { if (!env) { @@ -43,15 +281,15 @@ Object fetchFromEnvironment(const char* name, struct Environment* env) } 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); break; } 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"); - 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) { - env->strings[i] = malloc(sizeof(char) * strlen(name) + 1); - strcpy(env->strings[i], name); - env->objects[i] = cloneObject(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, @@ -88,13 +326,11 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i outer->refs += 1; return *outer; } - env.strings = NULL; - env.objects = NULL; + env.elements = NULL; return env; } - env.strings = malloc(sizeof(char*) * (paramCount + 1)); - env.objects = malloc(sizeof(Object) * (paramCount + 1)); + env.elements = malloc(sizeof(struct EnvElement) * (paramCount + 1)); const Object* march = arg_forms; for (int i = 0; i < paramCount; i++) { @@ -105,7 +341,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i cleanObject(&newEnvObj); march = march ? march->forward : NULL; } - env.strings[paramCount] = NULL; + env.elements[paramCount].symbol = NULL; return env; } @@ -115,7 +351,7 @@ 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->strings[i] == NULL) { + 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) { @@ -123,10 +359,10 @@ void addToEnv(struct Environment* env, const char* name, const Object obj) return; } break; - } else if (strcmp(temp_env->strings[i], name) == 0) { + } else if (strcmp(temp_env->elements[i].symbol, name) == 0) { Object o = cloneObject(obj); - cleanObject(&temp_env->objects[i]); - temp_env->objects[i] = o; + cleanObject(&temp_env->elements[i].object); + temp_env->elements[i].object = o; return; } } @@ -137,66 +373,15 @@ void addToEnv(struct Environment* env, const char* name, const Object obj) const int inc = 5; const int old_size = env->capacity; env->capacity += inc; - env->strings = realloc(env->strings, sizeof(char*) * env->capacity); - env->objects = realloc(env->objects, sizeof(Object) * env->capacity); + env->elements = realloc(env->elements, sizeof(struct EnvElement) * env->capacity); 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); } -#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(""); - 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(""); - 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) { e->refs -= 1; @@ -207,18 +392,165 @@ void deleteEnv(struct Environment* e) deleteEnv(e->outer); } - if (e->strings) { + if (e->elements) { int i = 0; - while (e->strings[i]) { - free(e->strings[i]); - cleanObject(&e->objects[i]); + while (e->elements[i].symbol) { + free(e->elements[i].symbol); + cleanObject(&e->elements[i].object); i++; } - free(e->strings); - free(e->objects); + 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(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(""); + 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(""); + 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() { for (int i = 0; i < dictionary.structCount; i++) { @@ -231,27 +563,6 @@ void shredDictionary() 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 struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help, const char* const* tests, size_t testLength) @@ -333,11 +644,13 @@ void printColored(const char* code) } } -fn(help, "?", - "Gets a string with help text for the given function.\n" - "For example:\n" - " (? islist) => \"(islist (1 2 3)) => T\"" -) +Object segfault(Object* params, int length, struct Environment* env) +{ + int* p = NULL; + return numberObject(*p); +} + +Object help(Object* params, int length, struct Environment* env) { const char* symbol; if (!length || !params[0].string || params[0].string[0] == '\0') { @@ -421,115 +734,6 @@ int runTests(int detailed) } #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) { for (int i = 0; i < dictionary.structCount; i++) { diff --git a/src/env.h b/src/env.h index d850d85..e0b4322 100644 --- a/src/env.h +++ b/src/env.h @@ -2,13 +2,19 @@ #define ENVIRONMENT_H #include "object.h" +#include "hash.h" + +struct EnvElement { + char* symbol; + Object object; +}; struct Environment; struct Environment { - char** strings; - Object* objects; struct Environment* outer; - int capacity; + struct ObjectTable table; + // struct EnvElement* elements; // iterative + // int capacity; // iterative int refs; }; @@ -37,7 +43,7 @@ void shredDictionary(); struct Environment defaultEnv(); -struct Environment defaultEnvPreAllocated(char** strings, Object* objects); +struct Environment defaultEnvPreAllocated(struct EnvElement* elements); int getStructIndex(const char* name); @@ -49,4 +55,37 @@ void printColored(const char* code); 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 diff --git a/src/examples/lib.pbl b/src/examples/lib.pbl index eaf2b2e..0fb6a00 100644 --- a/src/examples/lib.pbl +++ b/src/examples/lib.pbl @@ -18,6 +18,16 @@ ; Cube a (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 (def max (fn (a b) (if (> a b) a b))) diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..6cff466 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,79 @@ +#include "hash.h" +#include "env.h" + +#include +#include + +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); +} \ No newline at end of file diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..55d4fb8 --- /dev/null +++ b/src/hash.h @@ -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 diff --git a/src/object.c b/src/object.c index e5515a6..fd4fe8f 100644 --- a/src/object.c +++ b/src/object.c @@ -627,7 +627,7 @@ Object cloneString(Object obj) } // 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; } diff --git a/src/object.h b/src/object.h index b9b7984..2ab775d 100644 --- a/src/object.h +++ b/src/object.h @@ -9,7 +9,6 @@ #define sprintf(_dest, args...) snprintf(_dest, 999, args) #else -#define xprintf(_dest, _format, ...) sprintf(_dest, _format, __VA_ARGS__) #ifdef DEBUG #define printd(...) printf(__VA_ARGS__) #else diff --git a/src/pebblisp.c b/src/pebblisp.c index 7317b02..4303b78 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -752,6 +752,7 @@ int main(int argc, const char* argv[]) } deleteEnv(&env); shredDictionary(); + // fprintf(stderr, "totalSearchDepth: %d of %d searches\n", getTotalSearchDepth(), getTotalSearches()); // fprintf(stderr, "\nHEAP-ALLOCATED OBJECTS: %d\n", getAllocations()); // fprintf(stderr, "TOTAL OBJECT.C ALLOC: %zu\n", getBytes()); }