diff --git a/src/env.c b/src/env.c index 4f3ecb3..4b6ea51 100644 --- a/src/env.c +++ b/src/env.c @@ -237,7 +237,10 @@ struct Environment defaultEnv() pf(getEnvVar), pf(async), pf(await), - pf(help) + pf(help), + pf(buildHashTable), + pf(addToHashTable), + pf(getFromHashTable) #endif }; diff --git a/src/env.h b/src/env.h index d2390c9..f652090 100644 --- a/src/env.h +++ b/src/env.h @@ -61,20 +61,6 @@ void printColored(const char* code); int runTests(int detailed, int specificTest); -#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 fn(_name, _symbol, _docs, ...) \ -static const char * const _name ## Symbol = _symbol; \ -fnn(_name, _docs, __VA_ARGS__) - fn(segfault, "seg", "Induces a segfault." ); diff --git a/src/examples/forbble2.pbl b/src/examples/forbble2.pbl index df9f5dd..54b0c08 100644 --- a/src/examples/forbble2.pbl +++ b/src/examples/forbble2.pbl @@ -30,7 +30,7 @@ (stkadd bottom) ))) -(def words (fn (text) ( +(def get-words (fn (text) ( (split text " ") ))) @@ -46,27 +46,40 @@ (prnl (pop)) ))) -(def fmap (fn (word) ( - ;(prnl (cat "fmap: " word)) - - (if (= "swap" word) (swap) - (if (= "??" word) (pstack) - (if (= "+" word) (twop +) - (if (= "-" word) (twop -) - (if (= "/" word) (twop /) - (if (= "*" word) (twop *) - (if (= "." word) (loud-pop) - (stkadd (eval word)) - ))))))) +(def compile (fn (words) ( + (def name (at 0 words)) + (set words (rest words)) + (def name ()) ))) -(def repl (fn () ( - (def z (inp "plf:> ")) - (if (= z "q") () ( - (for-each fmap (words z)) - (prn nl) - (repl) +(def _fmap (fn (words) ( + ;(prnl (cat "fmap: " word)) + (def word (at 0 words)) + + (if (iserr word) () ( + (if (= ":" word) (compile (words)) + (if (= "swap" word) (swap) + (if (= "??" word) (pstack) + (if (= "+" word) (twop +) + (if (= "-" word) (twop -) + (if (= "/" word) (twop /) + (if (= "*" word) (twop *) + (if (= "." word) (loud-pop) + (stkadd (eval word)) + )))))))) + (_fmap (rest words)) )) ))) -(repl) +(def fmap (fn (text) ( + (def words (get-words text)) + (_fmap words) +))) + +; Override the normal REPL prompt +(set prompt "plf:> ") +(set preprocess (fn (text) ( + (fmap text) + (prn nl) + "" ; Have the underlying REPL do nothing +))) \ No newline at end of file diff --git a/src/hash.c b/src/hash.c index 2ea5010..34a8413 100644 --- a/src/hash.c +++ b/src/hash.c @@ -2,6 +2,7 @@ #include "env.h" #include +#include size_t addStripped(struct ObjectTable* table, char* name, struct StrippedObject object); @@ -130,6 +131,7 @@ size_t addStripped(struct ObjectTable* table, char* name, struct StrippedObject while (table->elements[h].symbol) { h = (h + 1) % table->capacity; } + eprintf("adding at %d: `%s`\n", h, name); table->elements[h].symbol = name; table->elements[h].object = object; table->count += 1; @@ -147,3 +149,43 @@ size_t addToTable(struct ObjectTable* table, char* name, Object object) .type = object.type, }); } + +#ifdef STANDALONE + +Object buildHashTable(Object* params, int length, struct Environment* env) +{ + long capacity = 16; + if (length > 0 && params[0].type == TYPE_NUMBER) { + capacity = params[0].number; + } + Object table = newObject(TYPE_HASH_TABLE); + table.table = malloc(sizeof(struct ObjectTableObject)); + table.table->table = buildTable(capacity); + table.table->refs = 2; + return table; +} + +Object addToHashTable(Object* params, int length, struct Environment* env) +{ + Object table = params[0]; + Object name = params[1]; + Object add = params[2]; + eprintf("Adding `%s`\n", name.string); + addToTable(&table.table->table, name.string, cloneObject(add)); + return numberObject(0); +} + +Object getFromHashTable(Object* params, int length, struct Environment* env) +{ + struct ObjectTable* table = ¶ms[0].table->table; + for (int i = 0; i < table->capacity; i++) { + eprintf("[%d] %s\n", i, table->elements[i].symbol); + } + struct StrippedObject* fetched = getFromTable(¶ms[0].table->table, params[1].string); + if (fetched) { + return deStrip(*fetched); + } + throw(DID_NOT_FIND_SYMBOL, "Hash table does not contain %s", params[1].string); +} + +#endif \ No newline at end of file diff --git a/src/hash.h b/src/hash.h index 0331227..0f9c39d 100644 --- a/src/hash.h +++ b/src/hash.h @@ -20,4 +20,25 @@ struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name) void deleteTable(struct ObjectTable* table); +#ifdef STANDALONE + +struct ObjectTableObject { + struct ObjectTable table; + int refs; +}; + +fn(buildHashTable, "table", + "Create a hash table object." +); + +fn(addToHashTable, "h-insert", + "Insert into a hash table object." +); + +fn(getFromHashTable, "h-get", + "Get a value from a hash table object." +); + +#endif + #endif //PEBBLISP_HASH_H diff --git a/src/object.c b/src/object.c index 41f3fd2..7e6b8f1 100644 --- a/src/object.c +++ b/src/object.c @@ -262,6 +262,9 @@ int stringNObj(struct string* s, const Object* obj) case TYPE_STATIC_FUNC: appendf(s, "STATIC FUNC"); break; + case TYPE_HASH_TABLE: + appendf(s, "HASH TABLE"); + break; case TYPE_STRUCT: stringStruct(s, obj); break; @@ -358,6 +361,7 @@ const char* getTypeName(const Object* obj) SIMPLE_TYPE(TYPE_STATIC_FUNC); SIMPLE_TYPE(TYPE_SYMBOL); SIMPLE_TYPE(TYPE_STRING); + SIMPLE_TYPE(TYPE_HASH_TABLE); SIMPLE_TYPE(TYPE_PROMISE); SIMPLE_TYPE(TYPE_OTHER); SIMPLE_TYPE(TYPE_ERROR); @@ -422,6 +426,13 @@ void cleanObject(Object* target) case TYPE_SLIST: deleteList(target); break; + case TYPE_HASH_TABLE: + target->table->refs -= 1; + if (!target->table->refs) { + deleteTable(&target->table->table); + free(target->table); + } + break; case TYPE_LAMBDA: target->lambda->refs -= 1; if (!target->lambda->refs) { @@ -627,6 +638,7 @@ inline int isValidType(const Object test) case TYPE_SYMBOL: case TYPE_LAMBDA: case TYPE_STRING: + case TYPE_HASH_TABLE: case TYPE_PROMISE: case TYPE_OTHER: case TYPE_ERROR: @@ -674,8 +686,12 @@ inline Object cloneObject(const Object src) return errorWithContext(getErrorCode(src), src.error->context); case TYPE_OTHER: return cloneOther(src); + case TYPE_HASH_TABLE: + src.table->refs += 1; + return src; case TYPE_STATIC_FUNC: src.staticF->refs += 1; + return src; case TYPE_BOOL: case TYPE_NUMBER: case TYPE_FUNC: diff --git a/src/object.h b/src/object.h index c3e2234..9333707 100644 --- a/src/object.h +++ b/src/object.h @@ -40,6 +40,45 @@ #define SIMPLE_ERRORS #endif +#define unused __attribute__((unused)) + +#define array_length(_array) (sizeof(_array) / sizeof((_array)[0])) + +#define UNPACK(...) __VA_ARGS__ + +#ifdef STANDALONE +#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 expect(_checker) {.checkFunc = (_checker), .name = #_checker} +#define returns(_checker) {.checkFunc = (_checker), .name = #_checker} +#define anyType {.checkFunc = NULL, .name = "AnyType"} + +#define tfn(_name, _symbol, _type, _docs, ...) \ +unused static struct TypeCheck _name ## TypeChecks[] = 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__) + +#else +#define fnn(_name, _docs, ...) \ +Object _name(Object* params, int length, struct Environment* env) + +#define tfn(_name, _symbol, _type, _docs, ...) \ +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__) +#endif + enum errorCode { MISMATCHED_PARENS, NULL_ENV, @@ -73,6 +112,7 @@ typedef enum Type { TYPE_SYMBOL, TYPE_LAMBDA, TYPE_STRING, + TYPE_HASH_TABLE, TYPE_PROMISE, TYPE_OTHER, TYPE_ERROR @@ -85,6 +125,7 @@ struct Environment; struct Promise; struct Other; struct StaticFunction; +struct ObjectTableObject; struct Error { enum errorCode code; char* context; @@ -106,6 +147,7 @@ struct Object { struct StaticFunction* staticF; struct Other* other; struct Promise* promise; + struct ObjectTableObject* table; #ifdef SIMPLE_ERRORS enum errorCode error; #else diff --git a/src/pebblisp.c b/src/pebblisp.c index 74b6925..ccef47b 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -310,6 +310,7 @@ Object eval(const Object* obj, struct Environment* env) case TYPE_STRING: case TYPE_STRUCT: case TYPE_SLIST: + case TYPE_HASH_TABLE: case TYPE_PROMISE: return cloneObject(*obj); diff --git a/src/pebblisp.h b/src/pebblisp.h index 2819aec..5370614 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -6,51 +6,12 @@ #include "env.h" #include "object.h" -#define unused __attribute__((unused)) - -#define array_length(_array) (sizeof(_array) / sizeof((_array)[0])) - -#define UNPACK(...) __VA_ARGS__ - -#ifdef STANDALONE -#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) - struct TypeCheck { int (* checkFunc)(Object); const char* name; }; -#define expect(_checker) {.checkFunc = (_checker), .name = #_checker} -#define returns(_checker) {.checkFunc = (_checker), .name = #_checker} -#define anyType {.checkFunc = NULL, .name = "AnyType"} - -#define tfn(_name, _symbol, _type, _docs, ...) \ -unused static struct TypeCheck _name ## TypeChecks[] = 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__) - -#else -#define fnn(_name, _docs, ...) \ -Object _name(Object* params, int length, struct Environment* env) - -#define tfn(_name, _symbol, _type, _docs, ...) \ -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__) -#endif - #define trueObject() boolObject(1) #define falseObject() boolObject(0)