Start work on hash-table objects.
This commit is contained in:
parent
4ea3b1d36d
commit
8e30b24e8f
|
@ -237,7 +237,10 @@ struct Environment defaultEnv()
|
|||
pf(getEnvVar),
|
||||
pf(async),
|
||||
pf(await),
|
||||
pf(help)
|
||||
pf(help),
|
||||
pf(buildHashTable),
|
||||
pf(addToHashTable),
|
||||
pf(getFromHashTable)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
14
src/env.h
14
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."
|
||||
);
|
||||
|
|
|
@ -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
|
||||
)))
|
42
src/hash.c
42
src/hash.c
|
@ -2,6 +2,7 @@
|
|||
#include "env.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
21
src/hash.h
21
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
|
||||
|
|
16
src/object.c
16
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:
|
||||
|
|
42
src/object.h
42
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue