diff options
author | kartofen <mladenovnasko0@gmail.com> | 2024-09-08 20:02:06 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2024-09-08 20:02:06 +0300 |
commit | f60047d4b013eb7f75ad4f5c63eda63153a4bf8e (patch) | |
tree | 2a3e9fd5fc1eb07b7e06797f74f5e7a31c313159 | |
parent | 4308cd4abe5a75fb8410df929eac687cbd04032b (diff) |
value is now opaque
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | src/lexer.h | 2 | ||||
-rw-r--r-- | src/main.c | 58 | ||||
-rw-r--r-- | src/mempool.h | 8 | ||||
-rw-r--r-- | src/value.c | 64 | ||||
-rw-r--r-- | src/value.h | 15 |
6 files changed, 84 insertions, 66 deletions
@@ -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); @@ -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); |