Mercurial > lbo > hg > ylisp
changeset 57:aff8b46c1fb9
doc: outline basic works of reference resolution and function calls
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 24 Aug 2019 10:12:56 +0200 |
parents | 1ac96e2f167c |
children | 06aa18744cb3 |
files | doc/execution.md src/func.h |
diffstat | 2 files changed, 51 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/execution.md Fri Aug 23 16:13:02 2019 +0200 +++ b/doc/execution.md Sat Aug 24 10:12:56 2019 +0200 @@ -2,11 +2,12 @@ ## Execution model. -The main execution model is stack-based interpretation of the parsed tree. - Names are scoped and visible in the scope they are defined in, after being defined, and in child scopes. +The execution runs on the tree of `yexpr_t` after some preprocessing, like +resolution of symbolic references (to values, functions, etc.). + ## Scoping. Every function call pushes an ID to the scope stack. The scope stack is used @@ -39,3 +40,49 @@ (print "The result is" (f1 5 x)) ``` + + +### Variable/reference resolution + +Symbols in the source code should be translated into numeric references (using +`yvalue_id_t`) to refer to value slots. This has the potential to +greatly enhance performance as referencing values does not invoke a potentially +expensive hash table lookup anymore but instead a cheap array dereference. + +The challenge is identifying each scope uniquely so that there are no reference +conflicts, but possibly also trying to recycle references. The current `value` +implementation doesn't support recycling. + +**Value allocation algorithm**: For uniquely allocating references using +`yvalue_create()/yvalue_resolve_or_create_symbol()`. + +The algorithm uses a stack of lists, each list represents the list of +already-allocated values in a scope, and for each new scope, a new list is +pushed onto the stack. Each `let` or `defn` results in pushing a new reference +to the list or redefining an existing one; each reference to a value results in +looking up the value in the top-most list, then the list below, etc. until a +reference could be found (at which point the symbolic reference is translated +into a numeric reference). + +A new scope is started by the start of a program, or one of a `defn`, `for`, +`let` s-expr. + +* Scan program tree + * Encounter symbolic reference (an ID)? -> Look up in stack of scope-lists by + walking each list in the stack until one is found. If none is found, this is + an error. + * Encounter one of `defn`, `for`, `let`: Push a new scope list onto the + stack. If `defn`, `let`: Push definition of the following function/value + into the list of the parent scope. + +TODO: Garbage collection, slot recycling (free-slot-list), reference counting? + +## Function calls + +A function is a stored `yexpr_t` tree value. Essentially the same as a normal +value, but with a few descriptions attached, like the number of arguments it +expects and the numeric references that it expects arguments in. Before calling, +expressions are copied into those references. + + +TODO: Pass-by-value copies value/duplicates reference
--- a/src/func.h Fri Aug 23 16:13:02 2019 +0200 +++ b/src/func.h Sat Aug 24 10:12:56 2019 +0200 @@ -18,6 +18,8 @@ /** * @brief Compiled function code. Functions are usually inserted in the global * value table and referenced there. + * + * TODO: Extend to allow reference capture for closures. */ typedef struct { yfunc_desc_t desc;