aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-02-07 19:08:03 +0000
committers-ol <s-ol@users.noreply.github.com>2020-02-07 19:08:03 +0000
commit64f212a9b219f5eb9c75723b627ac501afe1899f (patch)
treefecbdbd578443a286b9c37a7f77a07f0ff62676e /lib
parent50% of functions (diff)
downloadalive-64f212a9b219f5eb9c75723b627ac501afe1899f.tar.gz
alive-64f212a9b219f5eb9c75723b627ac501afe1899f.zip
new AST approach, testing
Diffstat (limited to 'lib')
-rw-r--r--lib/builtin.moon176
1 files changed, 92 insertions, 84 deletions
diff --git a/lib/builtin.moon b/lib/builtin.moon
index 440e553..96eb0f0 100644
--- a/lib/builtin.moon
+++ b/lib/builtin.moon
@@ -1,4 +1,4 @@
-import Macro, Const, Forward from require 'base'
+import Action, Const, Cell from require 'base'
import Scope from require 'scope'
-- (def sym1 val-expr1
@@ -8,33 +8,26 @@ import Scope from require 'scope'
--
-- if val-expr is a expand-time constant, defines a `Const`,
-- otherwise places a `Forward` for the expr
-class def extends Macro
- expand: (scope) =>
+class def extends Action
+ expand: (scope, tail) =>
L\trace "expanding #{@}"
- assert #@node > 2, "'def' requires at least 3 arguments"
- assert #@node % 2 == 1, "'def' requires an even number of arguments"
+ assert #tail > 1, "'def' requires at least 2 arguments"
+ assert #tail % 2 == 0, "'def' requires an even number of arguments"
L\push ->
- for i=2,#@node,2
- name, val_expr = @node[i], @node[i+1]
- assert name.atom_type == 'sym', "'def's argument ##{i} has to be a symbol"
- name = name\expand_quoted!\getc!
-
- scope\set name, val_expr\expand @node.scope
-
- -- @TODO: expand to Forward in Xpr:expand
- -- if val = val_expr\expand @node.scope
- -- -- expand-time constant
- -- scope\set name, val
- -- else
- -- -- patch-time expression
- -- scope\set name, Forward val_expr
+ for i=1,#tail,2
+ name, val_expr = tail[i], tail[i+1]
+ name = (name\quote scope, @registry)!\getc!
+ assert name.type == 'sym', "'def's argument ##{i} has to be a symbol"
+
+ scope\set name, val_expr\eval scope, @registry
+
nil
- patch: (map) =>
+ patch: (registry) =>
L\trace "patching #{@}"
for child in *@node[3,,2]
- L\push child\patch, map
+ L\push child\patch, registry
update: (dt) =>
L\trace "updating #{@}"
@@ -45,14 +38,12 @@ class def extends Macro
--
-- require a lua module and return its `Scope`
-- name-str has to be an expand-time constant
-class _require extends Macro
- expand: (scope) =>
+class require_mod extends Action
+ expand: (scope, tail) =>
L\trace "expanding #{@}"
- assert #@node == 2, "'require' takes only one parameter"
- for child in *@node[2,]
- L\push child\expand, @node.scope
+ assert #tail == 1, "'require' takes only one parameter"
- name = @node\tail!
+ name = L\push tail[1]\eval, scope, @registry
assert name.type == 'str', "'require' only works on strings"
L\trace @, "loading module #{name}"
@@ -63,87 +54,104 @@ class _require extends Macro
--
-- merge scopes into parent scope
-- scopes have to be expand-time constants
-class use extends Macro
- expand: (scope) =>
+class use extends Action
+ eval: (scope, tail) =>
L\trace "expanding #{@}"
- for child in *@node[2,]
- value = L\push child\expand, @node.scope
+ for child in *tail
+ value = L\push child\eval, scope, @registry
L\trace @, "merging #{value} into #{scope}"
assert value.type == 'scope', "'use' only works on scopes"
scope\use value\getc!
nil
--- ((fn ...) arg-expr1 [arg-expr2]...)
+-- (fn (p1 [p2]...) body-expr)
--
--- invoke a function
-class FunctionInvocation extends Macro
- new: (@node, @params, @body_tpl) =>
- super @node
+-- declare a function
+--
+-- pX are symbols that will resolve to a 'Forward' in the body
+class fn extends Action
+ class FnDef
+ new: (@params, @body) =>
- expand: (scope) =>
+ eval: (scope, tail) =>
L\trace "expanding #{@}"
- assert (#@params + 1) == #@node, "argument count mismatch in #{@node[1]}"
+ assert #tail == 2, "'fn' takes exactly two arguments"
+ { params, body } = tail
- for i=1,#@params
- param = @params[i]\getc!
- argument = @node[i+1]
- L\trace "EXPANDING ARG", argument
- @node.scope\set param, L\push argument\expand, scope
+ assert params.__class == Cell, "'fn's first argument has to be an expression"
+ param_symbols = for param in *params
+ assert param.type == 'sym', "function parameter declaration has to be a symbol"
+ param\quote scope, @registry
- @body = @body_tpl\clone @node.tag
- val = @body\expand @node.scope
- val
+ body = body\quote scope, @registry
+ Const 'fndef', FnDef param_symbols, body
- patch: (map) =>
- L\trace "patching #{@}:"
- for child in *@node[2,]
- L\push child\patch, map
+class op_invoke extends Action
+ patch: (head) =>
+ return true if head == @head
- @body\patch map
+ @op\destroy! if @op
- update: (dt) =>
- L\trace "updating #{@}:"
- @body\update dt
+ @head = head
+ assert @head.type == 'fndef', "cant op-invoke #{@head}"
+ @op = @head\getc!!
+
+ true
+
+ eval: (scope, tail) =>
+ args = [expr\eval scope, @registry for expr in *tail]
+ with @op
+ \patch unpack args
- for child in *@node[2,]
- L\push child\update, dt
+class fn_invoke extends Action
+ -- @TODO:
+ -- need to :patch() the case where the new head is a new fndef
+ -- but corresponds to the last head over time
- destroy: (dt) =>
- L\trace "destroying #{@}"
- @body.value\destroy! if @body.value
+ patch: (head) =>
+ return true if head == @head
- mt = { __call: (...) => @call ... }
- with_def: (params, body) ->
- call = (node) => FunctionInvocation node, params, body
- setmetatable { :call, __name: 'Invocation' }, mt
+ @head = head
--- (fn (p1 [p2]...) body-expr)
---
--- declare a function
---
--- pX are symbols that will resolve to a 'Forward' in the body
-class fn extends Macro
- expand: (scope) =>
- L\trace "expanding #{@}"
- assert #@node == 3, "'fn' takes exactly three arguments"
- params, body = @node[2], @node[3]
+ true
- assert params.type == 'Xpr', "'fn's first argument has to be an expression"
- param_symbols = for param in *params
- assert param.atom_type == 'sym', "function parameter declaration has to be a symbol"
- param\expand_quoted!
+ eval: (scope, tail) =>
+ assert @head.type == 'fndef', "cant fn-invoke #{@head}"
+ { :params, :body } = @head\getc!
- Const 'macrodef', FunctionInvocation.with_def param_symbols, body
+ assert #params == #tail, "argument count mismatch in #{@head}"
- patch: (map) =>
- L\trace "patching #{@}"
+ fn_scope = Scope @, scope
- update: (dt) =>
+ for i=1,#params
+ name = params[i]\getc!
+ argm = tail[i]
+ L\trace "EXPANDING ARG", argument
+ fn_scope\set name, L\push argm\eval, scope, @registry
+
+ body\expand fn_scope, @registry
+
+class do_expr extends Action
+ class DoWrapper
+ new: (@children) =>
+
+ update: (dt) =>
+ for child in *@children
+ child\update dt
+
+ get: => @children[#@children]\get!
+ getc: => @children[#@children]\getc!
+
+ eval: (scope, tail) =>
+ DoWrapper [expr\eval scope, @registry for expr in *tail]
{
- :def
- require: _require
- :use
+ 'op-invoke': op_invoke
+ 'fn-invoke': fn_invoke
+ 'do': do_expr
+
+ require: require_mod
+ :def, :use
:fn
}