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(getEnvVar),
|
||||||
pf(async),
|
pf(async),
|
||||||
pf(await),
|
pf(await),
|
||||||
pf(help)
|
pf(help),
|
||||||
|
pf(buildHashTable),
|
||||||
|
pf(addToHashTable),
|
||||||
|
pf(getFromHashTable)
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
14
src/env.h
14
src/env.h
|
@ -61,20 +61,6 @@ void printColored(const char* code);
|
||||||
|
|
||||||
int runTests(int detailed, int specificTest);
|
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",
|
fn(segfault, "seg",
|
||||||
"Induces a segfault."
|
"Induces a segfault."
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
(stkadd bottom)
|
(stkadd bottom)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(def words (fn (text) (
|
(def get-words (fn (text) (
|
||||||
(split text " ")
|
(split text " ")
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
@ -46,27 +46,40 @@
|
||||||
(prnl (pop))
|
(prnl (pop))
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(def fmap (fn (word) (
|
(def compile (fn (words) (
|
||||||
;(prnl (cat "fmap: " word))
|
(def name (at 0 words))
|
||||||
|
(set words (rest words))
|
||||||
(if (= "swap" word) (swap)
|
(def name ())
|
||||||
(if (= "??" word) (pstack)
|
|
||||||
(if (= "+" word) (twop +)
|
|
||||||
(if (= "-" word) (twop -)
|
|
||||||
(if (= "/" word) (twop /)
|
|
||||||
(if (= "*" word) (twop *)
|
|
||||||
(if (= "." word) (loud-pop)
|
|
||||||
(stkadd (eval word))
|
|
||||||
)))))))
|
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(def repl (fn () (
|
(def _fmap (fn (words) (
|
||||||
(def z (inp "plf:> "))
|
;(prnl (cat "fmap: " word))
|
||||||
(if (= z "q") () (
|
(def word (at 0 words))
|
||||||
(for-each fmap (words z))
|
|
||||||
(prn nl)
|
(if (iserr word) () (
|
||||||
(repl)
|
(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 "env.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
size_t addStripped(struct ObjectTable* table, char* name, struct StrippedObject object);
|
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) {
|
while (table->elements[h].symbol) {
|
||||||
h = (h + 1) % table->capacity;
|
h = (h + 1) % table->capacity;
|
||||||
}
|
}
|
||||||
|
eprintf("adding at %d: `%s`\n", h, name);
|
||||||
table->elements[h].symbol = name;
|
table->elements[h].symbol = name;
|
||||||
table->elements[h].object = object;
|
table->elements[h].object = object;
|
||||||
table->count += 1;
|
table->count += 1;
|
||||||
|
@ -147,3 +149,43 @@ size_t addToTable(struct ObjectTable* table, char* name, Object object)
|
||||||
.type = object.type,
|
.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);
|
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
|
#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:
|
case TYPE_STATIC_FUNC:
|
||||||
appendf(s, "STATIC FUNC");
|
appendf(s, "STATIC FUNC");
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HASH_TABLE:
|
||||||
|
appendf(s, "HASH TABLE");
|
||||||
|
break;
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
stringStruct(s, obj);
|
stringStruct(s, obj);
|
||||||
break;
|
break;
|
||||||
|
@ -358,6 +361,7 @@ const char* getTypeName(const Object* obj)
|
||||||
SIMPLE_TYPE(TYPE_STATIC_FUNC);
|
SIMPLE_TYPE(TYPE_STATIC_FUNC);
|
||||||
SIMPLE_TYPE(TYPE_SYMBOL);
|
SIMPLE_TYPE(TYPE_SYMBOL);
|
||||||
SIMPLE_TYPE(TYPE_STRING);
|
SIMPLE_TYPE(TYPE_STRING);
|
||||||
|
SIMPLE_TYPE(TYPE_HASH_TABLE);
|
||||||
SIMPLE_TYPE(TYPE_PROMISE);
|
SIMPLE_TYPE(TYPE_PROMISE);
|
||||||
SIMPLE_TYPE(TYPE_OTHER);
|
SIMPLE_TYPE(TYPE_OTHER);
|
||||||
SIMPLE_TYPE(TYPE_ERROR);
|
SIMPLE_TYPE(TYPE_ERROR);
|
||||||
|
@ -422,6 +426,13 @@ void cleanObject(Object* target)
|
||||||
case TYPE_SLIST:
|
case TYPE_SLIST:
|
||||||
deleteList(target);
|
deleteList(target);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HASH_TABLE:
|
||||||
|
target->table->refs -= 1;
|
||||||
|
if (!target->table->refs) {
|
||||||
|
deleteTable(&target->table->table);
|
||||||
|
free(target->table);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TYPE_LAMBDA:
|
case TYPE_LAMBDA:
|
||||||
target->lambda->refs -= 1;
|
target->lambda->refs -= 1;
|
||||||
if (!target->lambda->refs) {
|
if (!target->lambda->refs) {
|
||||||
|
@ -627,6 +638,7 @@ inline int isValidType(const Object test)
|
||||||
case TYPE_SYMBOL:
|
case TYPE_SYMBOL:
|
||||||
case TYPE_LAMBDA:
|
case TYPE_LAMBDA:
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
|
case TYPE_HASH_TABLE:
|
||||||
case TYPE_PROMISE:
|
case TYPE_PROMISE:
|
||||||
case TYPE_OTHER:
|
case TYPE_OTHER:
|
||||||
case TYPE_ERROR:
|
case TYPE_ERROR:
|
||||||
|
@ -674,8 +686,12 @@ inline Object cloneObject(const Object src)
|
||||||
return errorWithContext(getErrorCode(src), src.error->context);
|
return errorWithContext(getErrorCode(src), src.error->context);
|
||||||
case TYPE_OTHER:
|
case TYPE_OTHER:
|
||||||
return cloneOther(src);
|
return cloneOther(src);
|
||||||
|
case TYPE_HASH_TABLE:
|
||||||
|
src.table->refs += 1;
|
||||||
|
return src;
|
||||||
case TYPE_STATIC_FUNC:
|
case TYPE_STATIC_FUNC:
|
||||||
src.staticF->refs += 1;
|
src.staticF->refs += 1;
|
||||||
|
return src;
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
|
|
42
src/object.h
42
src/object.h
|
@ -40,6 +40,45 @@
|
||||||
#define SIMPLE_ERRORS
|
#define SIMPLE_ERRORS
|
||||||
#endif
|
#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 {
|
enum errorCode {
|
||||||
MISMATCHED_PARENS,
|
MISMATCHED_PARENS,
|
||||||
NULL_ENV,
|
NULL_ENV,
|
||||||
|
@ -73,6 +112,7 @@ typedef enum Type {
|
||||||
TYPE_SYMBOL,
|
TYPE_SYMBOL,
|
||||||
TYPE_LAMBDA,
|
TYPE_LAMBDA,
|
||||||
TYPE_STRING,
|
TYPE_STRING,
|
||||||
|
TYPE_HASH_TABLE,
|
||||||
TYPE_PROMISE,
|
TYPE_PROMISE,
|
||||||
TYPE_OTHER,
|
TYPE_OTHER,
|
||||||
TYPE_ERROR
|
TYPE_ERROR
|
||||||
|
@ -85,6 +125,7 @@ struct Environment;
|
||||||
struct Promise;
|
struct Promise;
|
||||||
struct Other;
|
struct Other;
|
||||||
struct StaticFunction;
|
struct StaticFunction;
|
||||||
|
struct ObjectTableObject;
|
||||||
struct Error {
|
struct Error {
|
||||||
enum errorCode code;
|
enum errorCode code;
|
||||||
char* context;
|
char* context;
|
||||||
|
@ -106,6 +147,7 @@ struct Object {
|
||||||
struct StaticFunction* staticF;
|
struct StaticFunction* staticF;
|
||||||
struct Other* other;
|
struct Other* other;
|
||||||
struct Promise* promise;
|
struct Promise* promise;
|
||||||
|
struct ObjectTableObject* table;
|
||||||
#ifdef SIMPLE_ERRORS
|
#ifdef SIMPLE_ERRORS
|
||||||
enum errorCode error;
|
enum errorCode error;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -310,6 +310,7 @@ Object eval(const Object* obj, struct Environment* env)
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
case TYPE_SLIST:
|
case TYPE_SLIST:
|
||||||
|
case TYPE_HASH_TABLE:
|
||||||
case TYPE_PROMISE:
|
case TYPE_PROMISE:
|
||||||
return cloneObject(*obj);
|
return cloneObject(*obj);
|
||||||
|
|
||||||
|
|
|
@ -6,51 +6,12 @@
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
#include "object.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 {
|
struct TypeCheck {
|
||||||
int (* checkFunc)(Object);
|
int (* checkFunc)(Object);
|
||||||
|
|
||||||
const char* name;
|
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 trueObject() boolObject(1)
|
||||||
|
|
||||||
#define falseObject() boolObject(0)
|
#define falseObject() boolObject(0)
|
||||||
|
|
Loading…
Reference in New Issue