aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2024-09-08 20:02:06 +0300
committerkartofen <mladenovnasko0@gmail.com>2024-09-08 20:02:06 +0300
commitf60047d4b013eb7f75ad4f5c63eda63153a4bf8e (patch)
tree2a3e9fd5fc1eb07b7e06797f74f5e7a31c313159
parent4308cd4abe5a75fb8410df929eac687cbd04032b (diff)
value is now opaque
-rw-r--r--README.md3
-rw-r--r--src/lexer.h2
-rw-r--r--src/main.c58
-rw-r--r--src/mempool.h8
-rw-r--r--src/value.c64
-rw-r--r--src/value.h15
6 files changed, 84 insertions, 66 deletions
diff --git a/README.md b/README.md
index 59ef04b..8170398 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,9 @@
-### nlisp
+g### nlisp
A simple lisp/scheme interpreter
#### TODO
-* totally opaque value_t (maybe add add something with tagged pointers)
* hamt for allocations
* reduce allocations
diff --git a/src/lexer.h b/src/lexer.h
index 6a14050..632811e 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -60,6 +60,8 @@ struct lexer {
size_t acc_idx;
};
+#define lexer_get_line(lexer) ((lexer)->line)
+
lexer_t lexer_create(FILE *fp);
void lexer_destroy(lexer_t lexer);
int lexer_clear_line(lexer_t lexer);
diff --git a/src/main.c b/src/main.c
index 8baaa94..9c59c56 100644
--- a/src/main.c
+++ b/src/main.c
@@ -65,7 +65,7 @@ static void print_value(value_t value)
char buf[256] = {0};
value_string(value, sizeof(buf), buf);
info("%-12s %s", value ?
- value_type_string[value->type] : "VALUE", buf);
+ value_type_string[vvalue_type(value)] : "VALUE", buf);
}
static void print_toklist(struct toklist *toklist)
@@ -239,7 +239,7 @@ int main(int argc, char **argv)
if(val == VALUE_EMPTY) {
if(!repl_flag) {
- printf("%s:%zu: FAILED\n", filename, lexer->line);
+ printf("%s:%zu: FAILED\n", filename, lexer_get_line(lexer));
break;
} else {
printf("=> FAILED\n");
@@ -250,7 +250,7 @@ int main(int argc, char **argv)
value_string(val, sizeof(buf), buf);
if(!repl_flag) {
- printf("%s:%zu: %s\n", filename, lexer->line, buf);
+ printf("%s:%zu: %s\n", filename, lexer_get_line(lexer), buf);
} else {
printf("=> %s\n", buf);
}
@@ -277,9 +277,9 @@ static char *str_alloc_copy(char *src)
}
#define HAS_ENOUGH_ARGS(proc, type, argc, fail) \
- if(argc != proc->value.type.argc) { \
+ if(argc != vvalue_##type(proc).argc) { \
err("Wrong number of arguemnts, expected %zu, but got %zu", \
- proc->value.type.argc, argc); \
+ vvalue_##type(proc).argc, argc); \
fail; \
}
@@ -333,18 +333,18 @@ value_t apply(env_t env, value_t proc, size_t argc, value_t *argv)
{
if(proc == VALUE_EMPTY) return value_copy(global_nil);
- switch(proc->type) {
+ switch(vvalue_type(proc)) {
case VALUE_PROC:
HAS_ENOUGH_ARGS(proc, proc, argc, return VALUE_EMPTY);
- return apply_lambda(&proc->value.proc, argv);
+ return apply_lambda(&vvalue_proc(proc), argv);
case VALUE_MACRO:
HAS_ENOUGH_ARGS(proc, proc, argc, return VALUE_EMPTY);
- return apply_macro(env, &proc->value.proc, argv);
+ return apply_macro(env, &vvalue_proc(proc), argv);
case VALUE_PROC_BUILTIN:
HAS_ENOUGH_ARGS(proc, proc_builtin, argc, return VALUE_EMPTY);
- return proc->value.proc_builtin.proc(argv);
+ return vvalue_proc_builtin(proc).proc(argv);
default:
- err("'%s' is not a procedure", value_type_string[proc->type]);
+ err("'%s' is not a procedure", value_type_string[vvalue_type(proc)]);
return VALUE_EMPTY;
}
}
@@ -591,11 +591,11 @@ value_t evaluate_if(env_t env, struct tctx *tctx)
// goto exit;
// }
- ERR_Z(cond->type == VALUE_INT,
+ ERR_Z(vvalue_type(cond) == VALUE_INT,
err("expected condition to evaluate to VALUE_INT");
goto exit);
- if(cond->value.num) {
+ if(vvalue_num(cond)) {
TOKEN_NEXT(tctx);
ret = evaluate_expr(env, tctx);
@@ -635,7 +635,7 @@ value_t evaluate_defmacro(env_t env, struct tctx *tctx)
tctx->token->type = TOKEN_LAMBDA;
ERR_Z(lambda = evaluate_lambda(env, tctx), goto fail);
- lambda->type = VALUE_MACRO;
+ value_set_type(lambda, VALUE_MACRO);
// TOKEN_MATCH(tctx, TOKEN_RP, goto fail);
@@ -759,7 +759,7 @@ value_t quote_sexp(env_t env, struct tctx *tctx, bool is_quasi)
goto exit);
*rightmost = new_cons;
- rightmost = &new_cons->value.cons.right;
+ rightmost = &vvalue_cons(new_cons).right;
TOKEN_NEXT(tctx);
}
@@ -811,10 +811,10 @@ static int toklist_expr(struct tctx *tctx, struct toklist **toklist)
if(TOKEN(tctx)->type == TOKEN_LP) depth++;
else if(TOKEN(tctx)->type == TOKEN_RP) depth--;
-
+
// printf("%zu\n", depth);
// print_token(TOKEN(tctx));
-
+
if(toklist)
token_clone(&tokens[tokens_len++], TOKEN(tctx));
@@ -835,40 +835,40 @@ static struct toklist *value_to_toklist(value_t value)
{
struct token token = {0};
- switch(value->type) {
+ switch(vvalue_type(value)) {
case VALUE_ATOM:
// fix me
- if(strcmp(value->value.atom, "lambda") == 0) {
+ if(strcmp(vvalue_atom(value), "lambda") == 0) {
SET_TOKEN_TYPE(&token, TOKEN_LAMBDA);
break;
- } else if(strcmp(value->value.atom, "if") == 0) {
+ } else if(strcmp(vvalue_atom(value), "if") == 0) {
SET_TOKEN_TYPE(&token, TOKEN_IF);
break;
- } else if(strcmp(value->value.atom, "quote") == 0) {
+ } else if(strcmp(vvalue_atom(value), "quote") == 0) {
SET_TOKEN_TYPE(&token, TOKEN_QUOTE_FORM);
break;
- } else if(strcmp(value->value.atom, "'") == 0) {
+ } else if(strcmp(vvalue_atom(value), "'") == 0) {
SET_TOKEN_TYPE(&token, TOKEN_QUOTE);
break;
}
SET_TOKEN_TYPE(&token, TOKEN_ID);
SET_TOKEN_VALUE(&token, id,
- str_alloc_copy(value->value.atom));
+ str_alloc_copy(vvalue_atom(value)));
break;
case VALUE_STR:
SET_TOKEN_TYPE(&token, TOKEN_STR);
SET_TOKEN_VALUE(&token, str,
- str_alloc_copy(value->value.str));
+ str_alloc_copy(vvalue_atom(value)));
break;
case VALUE_INT:
SET_TOKEN_TYPE(&token, TOKEN_INT);
- SET_TOKEN_VALUE(&token, num, value->value.num);
+ SET_TOKEN_VALUE(&token, num, vvalue_num(value));
break;
case VALUE_CONS:
return cons_to_toklist(value);
default:
- err("Cant turn '%s' to a token", value_type_string[value->type]);
+ err("Cant turn '%s' to a token", value_type_string[vvalue_type(value)]);
return NULL;
}
@@ -894,15 +894,15 @@ static struct toklist *cons_to_toklist(value_t value)
ADD_TOKEN(tail, TOKEN_LP);
while(1) {
- value_t left = value->value.cons.left;
- value = value->value.cons.right;
+ value_t left = vvalue_cons(value).left;
+ value = vvalue_cons(value).right;
struct toklist *new = NULL;
ERR_Z(new = value_to_toklist(left), goto fail);
ADD_TOKLIST(tail, new);
- if(value->type == VALUE_NIL) break;
- if(value->type != VALUE_CONS) {
+ if(vvalue_type(value) == VALUE_NIL) break;
+ if(vvalue_type(value) != VALUE_CONS) {
ADD_TOKEN(tail, TOKEN_DOT);
ERR_Z(new = value_to_toklist(value), goto fail);
diff --git a/src/mempool.h b/src/mempool.h
index 7d065f5..bca1e31 100644
--- a/src/mempool.h
+++ b/src/mempool.h
@@ -2,7 +2,7 @@
#define MEMPOOL_H
/* To generate use MEMPOOL_GENERATE(id, type, cap), where functions
- * _mempool_allocate() and _mempool_free(type *obj) will be prefixed with id
+ * _mempool_allocate() and _mempool_free(type *obj) will be prefixed with <id>
* and can be used to allocate objects of type <type> with <cap> objects in
* each block
*/
@@ -10,7 +10,7 @@
#define for_each_block(id, b, head) \
for(struct id##_block *b = (head), *next = NULL; \
b && (next = b->next, 1); b = next)
-#define get_last_block(b) \
+#define get_last_block(b) \
while((b)->next != NULL) (b) = (b)->next
#define MEMPOOL_GENERATE(id, type, cap) \
@@ -31,9 +31,9 @@
static inline void *_##id##_mempool_init_block(struct id##_block *b) \
{ \
b->next = NULL; \
- for(size_t i = 0; i < cap; i++) \
+ for(size_t i = 0; i < cap; i++) \
b->chunks[i].next = &b->chunks[i+1]; \
- b->chunks[cap-1].next = NULL; \
+ b->chunks[cap-1].next = NULL; \
\
return b->chunks; \
} \
diff --git a/src/value.c b/src/value.c
index c72c4a2..94a7acd 100644
--- a/src/value.c
+++ b/src/value.c
@@ -19,26 +19,26 @@ const char * const value_type_string[] = {
#define FN(fn, ...) return fn(buf, buf_sz, __VA_ARGS__)
#define VALUE_STRING_TABLE(X, v, buf, buf_sz) \
X(VALUE_NIL, FN(snprintf, "(nil)")) \
- X(VALUE_ATOM, FN(snprintf, "%s", VALUE(v).atom)) \
- X(VALUE_STR, FN(snprintf, "%s", VALUE(v).str)) \
- X(VALUE_INT, FN(snprintf, "%d", VALUE(v).num)) \
- X(VALUE_CONS, FN(cons_print, &VALUE(v).cons)) \
- X(VALUE_PROC, FN(proc_print, &VALUE(v).proc)) \
- X(VALUE_MACRO, FN(proc_print, &VALUE(v).proc)) \
+ X(VALUE_ATOM, FN(snprintf, "%s", vvalue_atom(v))) \
+ X(VALUE_STR, FN(snprintf, "%s", vvalue_str(v))) \
+ X(VALUE_INT, FN(snprintf, "%d", vvalue_num(v))) \
+ X(VALUE_CONS, FN(cons_print, &vvalue_cons(v))) \
+ X(VALUE_PROC, FN(proc_print, &vvalue_proc(v))) \
+ X(VALUE_MACRO, FN(proc_print, &vvalue_proc(v))) \
X(VALUE_PROC_BUILTIN, \
- FN(snprintf, "%p", *(void **)&VALUE(v).proc_builtin.proc))
+ FN(snprintf, "%p", *(void **)&vvalue_proc_builtin(v).proc))
-#define NOREFS(value) (--(value)->refs == 0)
+#define NOREFS(value) (value_dec_refs(value) == 0)
#define VALUE_DESTROY_TABLE(X, v) \
X(VALUE_NIL, (void)NOREFS(v)) \
- X(VALUE_ATOM, if(NOREFS(v)) free(VALUE(v).atom)) \
- X(VALUE_STR, if(NOREFS(v)) free(VALUE(v).str)) \
+ X(VALUE_ATOM, if(NOREFS(v)) free(vvalue_atom(v))) \
+ X(VALUE_STR, if(NOREFS(v)) free(vvalue_str(v))) \
X(VALUE_INT, (void)NOREFS(v)) \
X(VALUE_CONS, (void)NOREFS(v); \
- value_destroy(VALUE(v).cons.left); \
- value_destroy(VALUE(v).cons.right)) \
- X(VALUE_PROC, if(NOREFS(v)) proc_destroy(&VALUE(v).proc)) \
- X(VALUE_MACRO, if(NOREFS(v)) proc_destroy(&VALUE(v).proc)) \
+ value_destroy(vvalue_cons(v).left); \
+ value_destroy(vvalue_cons(v).right)) \
+ X(VALUE_PROC, if(NOREFS(v)) proc_destroy(&vvalue_proc(v))) \
+ X(VALUE_MACRO, if(NOREFS(v)) proc_destroy(&vvalue_proc(v))) \
X(VALUE_PROC_BUILTIN, (void)NOREFS(v))
#define CREATE(vtype, value) return value_create(vtype, value)
@@ -63,32 +63,35 @@ const char * const value_type_string[] = {
X(VALUE_MACRO, proc) \
X(VALUE_PROC_BUILTIN, proc_builtin)
+// #define value_alloc() malloc(sizeof(struct value))
+// #define value_dealloc(v) free(v)
+#define value_alloc() value_mempool_allocate()
+#define value_free(v) value_mempool_free(v)
+
static char *str_alloc_copy(char *src);
static int cons_print(char *buf, size_t buf_sz, struct cons *cons);
static int proc_print(char *buf, size_t buf_sz, struct proc *proc);
-
static void proc_destroy(struct proc *proc);
-#define MEMBER_COPY(vtype, member) \
- case vtype: memcpy(&_value->value.member, value, \
- sizeof(_value->value.member)); \
+#define MEMBER_COPY(vtype, member) \
+ case vtype: memcpy(&vvalue_##member(_value), value, \
+ sizeof(vvalue_##member(_value))); \
break;
value_t value_create(enum value_type type, void *value)
{
- // value_t _value = malloc(sizeof(*_value));
- value_t _value = value_mempool_allocate();
- _value->type = type;
+ value_t _value = value_alloc();
+ value_set_type(_value, type);
switch(type) {
VALUE_MEMBER_TABLE(MEMBER_COPY);
default: break;
}
- _value->refs = 1;
+ value_set_refs(_value, 1);
return _value;
}
@@ -101,9 +104,8 @@ void value_destroy(value_t value)
VALUE_DESTROY_TABLE(CASE_APPLY, value);
}
- if(value->refs == 0)
- value_mempool_free(value);
- // free(value);
+ if(vvalue_refs(value) == 0)
+ value_free(value);
}
value_t value_from_token(struct token *token)
@@ -122,11 +124,11 @@ value_t value_copy(value_t value)
{
if(!value) return value;
- value->refs++;
+ value_inc_refs(value);
- if(value->type == VALUE_CONS) {
- value_copy(value->value.cons.left);
- value_copy(value->value.cons.right);
+ if(vvalue_type(value) == VALUE_CONS) {
+ value_copy(vvalue_cons(value).left);
+ value_copy(vvalue_cons(value).right);
}
return value;
@@ -168,13 +170,13 @@ static int cons_print(char *buf, size_t buf_sz, struct cons *cons)
SET_VALUE_STRING(cons->left);
value_t right = cons->right;
- while(right->type == VALUE_CONS) {
+ while(vvalue_type(right) == VALUE_CONS) {
SET_CHAR(' ');
SET_VALUE_STRING(right->value.cons.left);
right = right->value.cons.right;
}
- if(right->type != VALUE_NIL) {
+ if(vvalue_type(right) != VALUE_NIL) {
SET_CHAR(' ');
SET_CHAR('.');
SET_CHAR(' ');
diff --git a/src/value.h b/src/value.h
index 264e083..f5f66d3 100644
--- a/src/value.h
+++ b/src/value.h
@@ -57,6 +57,21 @@ struct value {
size_t refs;
};
+#define vvalue_type(v) ((v)->type)
+#define vvalue_refs(v) ((v)->refs)
+
+#define vvalue_atom(v) ((v)->value.atom)
+#define vvalue_str(v) ((v)->value.str)
+#define vvalue_num(v) ((v)->value.num)
+#define vvalue_cons(v) ((v)->value.cons)
+#define vvalue_proc(v) ((v)->value.proc)
+#define vvalue_proc_builtin(v) ((v)->value.proc_builtin)
+
+#define value_set_type(v, type) (vvalue_type(v) = type)
+#define value_set_refs(v, refs) (vvalue_refs(v) = refs)
+#define value_inc_refs(v) (++vvalue_refs(v))
+#define value_dec_refs(v) (--vvalue_refs(v))
+
value_t value_create(enum value_type type, void * value);
void value_destroy(value_t value);