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;