X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=src%2Feval.c;h=253c8ec45f1833f9d3e39edf909f09819d5f6349;hb=refs%2Fheads%2Fmaster;hp=e563fdfd3acd91eab0048e537b7d7a1aba039b7f;hpb=6c1eef40f411ff4eec7a3f7599a81be7fae07e2a;p=muddle-interpreter.git diff --git a/src/eval.c b/src/eval.c index e563fdf..253c8ec 100644 --- a/src/eval.c +++ b/src/eval.c @@ -16,14 +16,17 @@ License along with this file. If not, see . */ +#include "alloc.h" #include "eval.h" +#include "oblist.h" -#include "alloc.h" +#include // globals for now extern object ret; extern frame *cf; extern object *cst; +extern vector_object globals; void push_frame (void (*fn) (), tuple_object args, void (*cont) ()) @@ -34,7 +37,7 @@ push_frame (void (*fn) (), tuple_object args, void (*cont) ()) // allocate new frame, make current frame *prev = cf; cf = (frame *) cst; - cst += sizeof (frame) / sizeof (object); + cst = (object *) (cf + 1); // set new frame's frametop cf->cont = new_subr (fn); @@ -55,8 +58,16 @@ pop_frame () // TODO: replace with PUSH_ARG interface? #define END_LOCALS() do { cf->prevcst = cst; } while (0) #define CALL_THEN(fn, args, cont) do { push_frame(fn, args, cont); return; } while (0) +#define CALL_THEN_RET(fn, args) CALL_THEN(fn, args, pop_frame) +#define CALL_THEN_RECUR(f, args) do { push_frame(f, args, cf->cont.val.fn); return; } while (0) #define TAILCALL(fn) do { cf->cont = fn; return; } while (0) +static inline bool +NO_LOCALS () +{ + return cst == (object *) (cf + 1); +} + /* uint32_t len = 0; pool_object *x = POOL_OBJECT(o->head); @@ -80,6 +91,10 @@ generic calls must perform wrapping // * FSUBR: call impl // * complex FUNCTION: call impl +static object *gval (atom_object * var); + +static void subr_NTH (); + // Upon initial entry, `cf->args.body[0]` is the FORM, and // `ret` is the result of evaluating the FORM's first position. // Typically, the first position will be an ATOM, which is @@ -92,13 +107,51 @@ call () { switch (ret.type) { - /* - case EVALTYPE_ATOM: - break; - case EVALTYPE_FIX32: - case EVALTYPE_FIX64: - break; - */ + case EVALTYPE_ATOM: + { + object *val = gval (&ret.atom); + if (!val) + { + // TODO: lvalue lookup + assert (0 && "attempted to call unbound symbol"); + } + END_LOCALS (); + pool_ptr p = as_list (&cf->args.body[0])->val.head; + assert (p); + p = POOL_OBJECT (p)->rest; + object *args = cst; + uint32_t argct = 0; + while (p) + { + argct++; + (cst++)->pool = *POOL_OBJECT (p); + p = POOL_OBJECT (p)->rest; + } + if (val->type == EVALTYPE_SUBR) + CALL_THEN_RET (val->subr.val.fn, new_tuple (args, argct)); + if (val->type == EVALTYPE_FIX32 || val->type == EVALTYPE_FIX64) + { + pool_ptr p = as_list (&cf->args.body[0])->val.head; + object * args = cst; + *cst++ = *val; + cst++->pool = *POOL_OBJECT (POOL_OBJECT (p)->rest); + assert (!POOL_OBJECT (POOL_OBJECT (p)->rest)->rest); + CALL_THEN_RET (subr_NTH, new_tuple (args, 2)); + } + assert (0 && "I don't know how to call that"); + break; + } + case EVALTYPE_FIX32: + case EVALTYPE_FIX64: + { + pool_ptr p = as_list (&cf->args.body[0])->val.head; + object * args = cst; + *cst++ = ret; + assert (POOL_OBJECT (p)->rest); + cst++->pool = *POOL_OBJECT (POOL_OBJECT (p)->rest); + assert (!POOL_OBJECT (POOL_OBJECT (p)->rest)->rest); + CALL_THEN_RET (subr_NTH, new_tuple (args, 2)); + } default: assert (0 && "I don't know how to call that"); } @@ -111,25 +164,25 @@ eval_rest () // store result of previous call pool_object *prev_res = as_pool (&ret); list_object *tail = as_list (&cf->locals[1]); - *POOL_OBJECT (tail->head) = (pool_object) + *POOL_OBJECT (tail->val.head) = (pool_object) { - .type = prev_res->type,.rest = tail->head + 1,.val = prev_res->val}; + .type = prev_res->type,.rest = tail->val.head + 1,.val = prev_res->val}; // advance input and output assert (cf->args.len == 1); list_object *args = as_list (&cf->args.body[0]); - assert (args->head); - args->head = POOL_OBJECT (args->head)->rest; - if (!args->head) + assert (args->val.head); + args->val.head = POOL_OBJECT (args->val.head)->rest; + if (!args->val.head) { - POOL_OBJECT (tail->head)->rest = 0; + POOL_OBJECT (tail->val.head)->rest = 0; RETURN (cf->locals[0]); } - tail->head++; + tail->val.head++; // eval next element END_LOCALS (); - CALL_THEN (eval, new_tuple ((object *) POOL_OBJECT (args->head), 1), + CALL_THEN (eval, new_tuple ((object *) POOL_OBJECT (args->val.head), 1), eval_rest); } @@ -141,11 +194,12 @@ eval () { case EVALTYPE_FIX32: case EVALTYPE_FIX64: + case EVALTYPE_ATOM: RETURN (cf->args.body[0]); case EVALTYPE_LIST: // Handle `head` now; then iterate on `.rest`. - if (!cf->args.body[0].list.head) + if (!cf->args.body[0].list.val.head) RETURN (cf->args.body[0]); // locals: { list_object list, list_object tail } cst += 2; @@ -157,11 +211,11 @@ eval () END_LOCALS (); CALL_THEN (eval, new_tuple ((object *) - POOL_OBJECT (cf->args.body[0].list.head), 1), + POOL_OBJECT (cf->args.body[0].list.val.head), 1), eval_rest); case EVALTYPE_FORM: // `<>` is a special case. - if (!cf->args.body[0].list.head) + if (!cf->args.body[0].list.val.head) { cf->args.body[0].type = EVALTYPE_FALSE; RETURN (cf->args.body[0]); @@ -170,12 +224,224 @@ eval () END_LOCALS (); CALL_THEN (eval, new_tuple ((object *) - POOL_OBJECT (cf->args.body[0].list.head), 1), - call); + POOL_OBJECT (cf->args.body[0].list.val.head), + 1), call); /* - case EVALTYPE_VECTOR: TAILCALL(eval_vector); - */ + case EVALTYPE_VECTOR: TAILCALL(eval_vector); + */ default: assert (0 && "I don't know how to eval that"); } } + +inline static object * +create_global_binding (uvector_object oblist, const char *pname) +{ + object *p = stack_push (&globals); + stack_push (&globals)->atom = + oblist_find_or_insert (root, pname, strlen (pname)); + return p; +} + +#include "atom.h" +#include "print.h" +#include + +static void +subr_root () +{ + ret.uvector = root; + pop_frame (); +} + +static void +do_gval () +{ + if (cf->args.len != 1) + assert (0 && "error: GVAL expects arity 1"); + if (cf->args.body[0].type != EVALTYPE_ATOM) + fprintf (stderr, "error: GVAL of a evaltype=%x\n", cf->args.body[0].type); + atom_object *atomos = as_atom (&cf->args.body[0]); + object *pv = gval (atomos); + if (!pv) + assert (0 && "error: GVAL of unbound"); + ret = *pv; + pop_frame (); +} + +static void +subr_gval () +{ + assert (cf->args.len == 1); + END_LOCALS (); + object *args = cst; + *(cst++) = cf->args.body[0]; + CALL_THEN (eval, new_tuple (args, 1), do_gval); +} + +static void +do_setg () +{ + assert (cf->args.len == 2); + atom_object *name = as_atom (&cf->args.body[0]); + *create_global_binding (root, atom_pname (*name)) = ret; + pop_frame (); +} + +static void +do_setg1 () +{ + assert (cf->args.len == 2); + // save result of previous + cf->args.body[0] = ret; + END_LOCALS (); + object *args = cst; + *(cst++) = cf->args.body[1]; + CALL_THEN (eval, new_tuple (args, 1), do_setg); +} + +static void +subr_setg () +{ + assert (cf->args.len == 2); + END_LOCALS (); + object *args = cst; + *(cst++) = cf->args.body[0]; + CALL_THEN (eval, new_tuple (args, 1), do_setg1); +} + +static void +subr_quote () +{ + assert (cf->args.len == 1); + ret = cf->args.body[0]; + pop_frame (); +} + +static void +appl_list () +{ + // TODO: deal with non-poolable objects in arguments + ret.list = + new_list (pool_copy_array ((pool_object *) cf->args.body, cf->args.len)); + pop_frame (); +} + +static bool +eval_arg () +{ + uint32_t next_to_eval = NO_LOCALS ()? (cst++)->fix32 = new_fix32 (0), 0 + : ++as_fix32 (&cf->locals[0])->val.n; + END_LOCALS (); + if (next_to_eval > 1) + cf->args.body[next_to_eval - 1] = ret; + if (next_to_eval < cf->args.len) + { + object *args = cst; + *(cst++) = cf->args.body[next_to_eval]; + push_frame (eval, new_tuple (args, 1), cf->cont.val.fn); + return true; + } + return false; +} + +static void +subr_list () +{ + eval_arg ()? : appl_list (); +} + +static void +appl_add () +{ + fix64_object result = new_fix64 (0); + for (int i = 0; i < cf->args.len; i++) + { + switch (cf->args.body[i].type) + { + case EVALTYPE_FIX32: + // fallthough: a fix32 is stored the same way as its fix64 + case EVALTYPE_FIX64: + result.val.n += cf->args.body[i].fix64.val.n; + break; + default: + assert (0 && "don't know how to add that"); + } + } + ret.fix64 = result; + pop_frame (); +} + +static void +subr_add () +{ + eval_arg ()? : appl_add (); +} + +static void appl_NTH () +{ + assert (cf->args.len == 2); + int ix; + switch (cf->args.body[0].type) + { + case EVALTYPE_FIX32: + case EVALTYPE_FIX64: + ix = cf->args.body[0].fix64.val.n; + assert ((uint64_t)ix == cf->args.body[0].fix64.val.n); + break; + default: + assert (0 && "tried to NTH a strange index type?"); + } + switch (cf->args.body[1].type) + { + case EVALTYPE_VECTOR: + assert (ix < cf->args.body[1].vector.val.len); + RETURN (HEAP_OBJECT (cf->args.body[1].vector.val.body)[ix]); + case EVALTYPE_UVECTOR: + assert (ix < cf->args.body[1].uvector.val.len); + RETURN (uv_get (&cf->args.body[1].uvector, ix)); + case EVALTYPE_LIST: + { + pool_ptr p = cf->args.body[1].list.val.head; + for (int i=0; irest; + } + assert (p); + RETURN (*(object*)POOL_OBJECT (p)); + } + } + assert (0 && "tried to NTH a strange collection type?"); +} + +void subr_NTH () +{ + eval_arg ()? : appl_NTH (); +} + +void +init_standard_env () +{ + create_global_binding (root, "ROOT")->subr = new_subr (subr_root); + create_global_binding (root, "GVAL")->subr = new_subr (subr_gval); + create_global_binding (root, "SETG")->subr = new_subr (subr_setg); + create_global_binding (root, "QUOTE")->subr = new_subr (subr_quote); + create_global_binding (root, "LIST")->subr = new_subr (subr_list); + create_global_binding (root, "+")->subr = new_subr (subr_add); + create_global_binding (root, "NTH")->subr = new_subr (subr_NTH); +} + +object * +gval (atom_object * var) +{ + object *gvals = HEAP_OBJECT (globals.val.body); + for (int i = 0; i < globals.val.len / 2; i++) + { + // TODO: need proper atom comparison once multiple OBLISTs active + if (as_atom (&gvals[i * 2])->val.body == var->val.body) + { + return &gvals[i * 2 + 1]; + } + } + return 0; +}