Mercurial > lbo > hg > ylisp
changeset 83:b86bc111f4a4
built-ins: Refactor let and other built-in functionality
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Mon, 26 Aug 2019 10:06:52 +0200 |
parents | 7f331aa5abd1 |
children | 6a42872a9f81 |
files | doc/execution.md src/CMakeLists.txt src/built-ins.c src/built-ins.h src/eval.h src/types.h |
diffstat | 6 files changed, 50 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/execution.md Mon Aug 26 09:41:13 2019 +0200 +++ b/doc/execution.md Mon Aug 26 10:06:52 2019 +0200 @@ -120,6 +120,11 @@ All this logic happens within `yeval()`; it binds arguments when calling functions and handles the return value. +Built-in functions are called with arguments on the call stack. Those arguments +are shallow copies from the expressions, so built-ins should not modify them +except where it's guaranteed not to have side effects (scalar values, for +example). + ## Evaluation -> see `yeval()` in `eval.h`.
--- a/src/CMakeLists.txt Mon Aug 26 09:41:13 2019 +0200 +++ b/src/CMakeLists.txt Mon Aug 26 10:06:52 2019 +0200 @@ -11,6 +11,7 @@ ADD_LIBRARY(core STATIC atom.c built-ins.c + eval.c expr.c func.c value.c)
--- a/src/built-ins.c Mon Aug 26 09:41:13 2019 +0200 +++ b/src/built-ins.c Mon Aug 26 10:06:52 2019 +0200 @@ -6,6 +6,13 @@ // TODO: Write standard library! +/** + * @brief Type of a built-in function called during execution. + * + * The functions return a yexpr_t of which the caller assumes ownership. + */ +typedef yexpr_t (*ybuiltin_fn)(yeval_state_t* state); + struct ybuiltin_id_mapping { const char* id; YBUILTIN_TYPE builtin; @@ -57,30 +64,48 @@ static void nothing(void){}; -/// Expects a reference and a value on the stack. They may not depend on other -/// references except for functions, i.e. should have been copied using -/// `yexpr_copy()` (which is the convention for calling functions anyway). +/// Expects a list expression starting with built-in "let" on the stack. /// /// Returns an UNDEF expression by default, or an EXCEPTION if something went /// wrong. -yexpr_t ybuiltin_fn_let(yvec_t* call_stack) { - yexpr_t ref, val; - if (!yvec_pop(call_stack, &val)) goto notenoughfail; - if (!yvec_pop(call_stack, &ref)) goto notenoughfail; +yexpr_t ybuiltin_fn_let(yeval_state_t* state) { + yexpr_t let, *ref, *val; + size_t counter = 0; + yvec_t* letlist = &let.value.list; + + if (!yvec_pop(&state->call_stack, &let)) goto notenoughfail; + if (let.typ != YEXPR_LIST) goto badexprfail; + if (let.value.list.len < 3) goto notenoughfail; + + yexpr_t let_id = *YVEC_AT(letlist, counter++, yexpr_t); + if (let_id.typ != YEXPR_BUILTIN || let_id.value.builtin != YBUILTIN_LET) + goto badexprfail; - if (ref.typ != YEXPR_REF || val.typ == YEXPR_UNDEF) goto typefail; - yvalue_t newvalue = {.typ = YVALUE_EXPR, .value.expr = val}; - yvalue_set(ref.value.ref, &newvalue); + ref = YVEC_AT(letlist, counter++, yexpr_t); + val = YVEC_AT(letlist, counter++, yexpr_t); + if (ref->typ != YEXPR_REF || val->typ == YEXPR_UNDEF) goto typefail; + + yvalue_t newvalue = { + .typ = YVALUE_EXPR, + .value.expr = yeval(state, val, /* in_place= */ false)}; + yvalue_set(ref->value.ref, &newvalue); return yexpr_new(); + +badexprfail: + return ybuiltin_type_error( + YBUILTIN_LET, ystr_new("BUG: not a let expression on stack"), &let); + notenoughfail: return ybuiltin_type_error( - YBUILTIN_LET, ystr_new("BUG: not enough arguments on call stack"), - NULL); + YBUILTIN_LET, + ystr_new("BUG: not enough arguments on call stack or to builtin"), + &let); + typefail: nothing(); yexpr_t args = yexpr_new(); - yexpr_init_or_extend(&args, ref); - yexpr_init_or_extend(&args, val); + yexpr_init_or_extend(&args, *ref); + yexpr_init_or_extend(&args, *val); yexpr_t exc = ybuiltin_type_error( YBUILTIN_LET, ystr_new( @@ -102,8 +127,8 @@ return YBUILTIN_ENUM_STR[t]; } -yexpr_t ybuiltin_run(YBUILTIN_TYPE t, yvec_t* call_stack) { +yexpr_t ybuiltin_run(YBUILTIN_TYPE t, yeval_state_t* state) { assert((t * sizeof(ybuiltin_fn)) < sizeof(YBUILTIN_FNS)); - return YBUILTIN_FNS[t](call_stack); + return YBUILTIN_FNS[t](state); }
--- a/src/built-ins.h Mon Aug 26 09:41:13 2019 +0200 +++ b/src/built-ins.h Mon Aug 26 10:06:52 2019 +0200 @@ -1,6 +1,7 @@ #ifndef src_built_ins_h #define src_built_ins_h +#include <src/eval.h> #include <src/expr.h> #include <src/types.h> @@ -20,7 +21,7 @@ /** * @brief Run a built-in function. The caller assumes ownership of the returned value. */ -yexpr_t ybuiltin_run(YBUILTIN_TYPE t, yvec_t* call_stack); +yexpr_t ybuiltin_run(YBUILTIN_TYPE t, yeval_state_t* state); /** * @}
--- a/src/eval.h Mon Aug 26 09:41:13 2019 +0200 +++ b/src/eval.h Mon Aug 26 10:06:52 2019 +0200 @@ -1,6 +1,7 @@ #ifndef src_eval_h #define src_eval_h +#include <src/types.h> #include <src/base/vec.h> /**
--- a/src/types.h Mon Aug 26 09:41:13 2019 +0200 +++ b/src/types.h Mon Aug 26 10:06:52 2019 +0200 @@ -117,13 +117,6 @@ typedef struct yexpr_t yexpr_t; /** - * @brief Type of a built-in function called during execution. - * - * The functions return a yexpr_t of which the caller assumes ownership. - */ -typedef yexpr_t (*ybuiltin_fn)(yvec_t* call_stack); - -/** * @} */ #endif