aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-02-02 18:34:18 +0000
committers-ol <s-ol@users.noreply.github.com>2020-02-02 18:35:58 +0000
commit1fb8e4b2e621128e043ae4091f3e25d56b9d7cc2 (patch)
tree9b95ff4e17784aaee4c14372741f2a65d76d02fb
parentadd logger (diff)
downloadalive-1fb8e4b2e621128e043ae4091f3e25d56b9d7cc2.tar.gz
alive-1fb8e4b2e621128e043ae4091f3e25d56b9d7cc2.zip
clean out old patching implementation
-rw-r--r--ast.moon57
-rw-r--r--base.moon47
-rw-r--r--lib/builtin.moon70
-rw-r--r--lib/debug.moon2
-rw-r--r--logger.moon2
-rw-r--r--registry.moon91
-rw-r--r--scope.moon18
-rw-r--r--test.alv2
8 files changed, 158 insertions, 131 deletions
diff --git a/ast.moon b/ast.moon
index 99b200a..a1e10ad 100644
--- a/ast.moon
+++ b/ast.moon
@@ -12,16 +12,15 @@ hash = (tbl) ->
class ASTNode
-- first pass (outin):
- -- * expand macros
- -- * define scoped values
- -- * evaluate references
+ -- * expand macros (mutate scopes)
+ -- * resolve symbols
expand: (scope) =>
-- second pass (inout):
- -- * setup OPs (spawn/patch)
- link: =>
+ -- * setup expressions (spawn/patch)
+ patch: (prev) =>
-class Atom
+class Atom extends ASTNode
type: 'Atom'
new: (@raw, @atom_type) =>
@@ -42,7 +41,7 @@ class Atom
else
error "unknown atom type: '#{@atom_type}'"
- link: =>
+ @value
_walk: => coroutine.yield @type, @
@@ -65,7 +64,7 @@ class Atom
__tostring: =>
"<Atom#{hash @} #{@stringify!}>"
-class Xpr
+class Xpr extends ASTNode
type: 'Xpr'
-- either:
@@ -86,21 +85,45 @@ class Xpr
@white[i/2] = parts[i+1]
expand: (scope) =>
- head = @[1]
- head\expand scope
+ @[1]\expand scope
+ head = @head!
@scope = Scope @, scope
- if head.value.type == 'macro'
- macro = head.value\getc!
- macro scope, @
- else
- for child in *@[2,]
- child\expand scope
+ switch head.type
+ when 'macrodef'
+ Macrodef = head\getc!
+ @macro = Macrodef @
+ @value = @macro\expand scope
+ else
+ for child in *@[2,]
+ child\expand @scope
+
+ @value
- link: =>
+ patch: (prev) =>
head = @head!
+ compatible = prev and
+ prev.value and
+ prev\head! == head
+
+ if @macro
+ -- forward for macros
+ prev.value\destroy! if prev and prev.value
+ @macro\patch!
+ elseif compatible
+ -- continued existance
+ @value = prev.value
+ @value\setup @tail!
+ else
+ -- destroy + recreate
+ prev.value\destroy! if prev and prev.value
+ @value = head\getc!\spawn @tail!
+
+ update: (dt) =>
+ @value\update dt
+
head: => @[1].value
tail: => unpack [p.value for p in *@[2,]]
diff --git a/base.moon b/base.moon
index 72dd62f..334431c 100644
--- a/base.moon
+++ b/base.moon
@@ -1,37 +1,62 @@
import is_object from require 'moon'
class Const
- types = { sym: true, scope: true, str: true, num: true, op: true, opdef: true, macro: true }
+ types = {
+ sym: true
+ scope: true
+ str: true
+ num: true
+ op: true
+ opdef: true
+ macrodef: true
+ }
new: (@type, @value) =>
assert types[@type], "invalid Const type: #{@type}"
get: => @value
getc: => @value
- __tostring: => "<#{@type}: #{@value}>"
+ destroy: =>
-class Op
- new: (@node) =>
- @setup @node\tail!
+ __tostring: =>
+ value = if @type\match 'def$' then @value.__name else @value
+ "<#{@type}: #{value}>"
- patch: (next) =>
- @node = next
- @setup @node\tail!
+class Op
+ new: (...) =>
+ @setup ...
update: (dt) =>
get: => @value
getc: =>
- print "WARN: stream to constant", debug.traceback!
+ L\warn "stream #{@} cast to constant"
@value
destroy: =>
__tostring: => "<op: #{@@__name}>"
- __inherited: (cls) =>
- cls.__base.__tostring = @__tostring
+ __inherited: (cls) => cls.__base.__tostring = @__tostring
+
+ spawn: (Opdef, ...) ->
+ Opdef ...
+
+class Macro
+ new: (@node) =>
+ -- print "creating Macro #{@@__name}", debug.traceback!
+
+ -- forwarded from ASTNode
+ expand: (scope) =>
+
+ -- forwarded from ASTNode
+ -- note: if prev_value is passed, it has to be :destroy'ed or returned
+ patch: (prev_value) => prev_value
+
+ __tostring: => "<macro: #{@@__name}>"
+ __inherited: (cls) => cls.__base.__tostring = @__tostring
{
:Const
:Op
+ :Macro
}
diff --git a/lib/builtin.moon b/lib/builtin.moon
index e7586da..369c3b3 100644
--- a/lib/builtin.moon
+++ b/lib/builtin.moon
@@ -1,29 +1,51 @@
-import Const from require 'base'
+import Macro, Const from require 'base'
import Scope from require 'scope'
-module = {
- def: (scope, xpr) ->
- assert #xpr > 2, "'def' requires at least 3 arguments"
- assert #xpr % 2 == 1, "'def' requires an even number of arguments"
- for i=2,#xpr,2
- assert xpr[i].atom_type == 'sym', "'def's argument ##{i} has to be a symbol"
- xpr[i+1]\expand xpr.scope
- scope\set xpr[i].raw, xpr[i+1].value
-
- use: (scope, xpr) ->
- for value in *xpr[2,]
- value\expand xpr.scope
- assert value.value.type == 'scope', "'use' only works on scopes"
- scope\use value.value\getc!
-
- require: (scope, xpr) ->
- assert #xpr == 2, "'require' takes only one parameter"
-
- xpr[2]\expand xpr.scope
- name = xpr[2].value
+class def extends Macro
+ expand: (scope) =>
+ assert #@node > 2, "'def' requires at least 3 arguments"
+ assert #@node % 2 == 1, "'def' requires an even number of arguments"
+
+ L\trace @
+ L\push ->
+ for i=2,#@node,2
+ name, val = @node[i], @node[i+1]
+ assert name.atom_type == 'sym', "'def's argument ##{i} has to be a symbol"
+ val\expand @node.scope
+ scope\set name.raw, val.value
+
+ nil
+
+class _require extends Macro
+ expand: (scope) =>
+ assert #@node == 2, "'require' takes only one parameter"
+
+ L\trace @
+ L\push ->
+ for child in *@node[2,]
+ child\expand @node.scope
+
+ name = @node\tail!
assert name.type == 'str', "'require' only works on strings"
- xpr.value = Const 'scope', Scope.from_table require "lib.#{name\getc!}"
-}
+ L\trace @, "loading module #{name}"
+ scope = Scope.from_table require "lib.#{name\getc!}"
+ Const 'scope', scope
+
+class use extends Macro
+ expand: (scope) =>
+ L\trace @
+ L\push ->
+ for child in *@node[2,]
+ value = child\expand @node.scope
+ L\trace @, "merging #{value} into #{scope}"
+ assert value.type == 'scope', "'use' only works on scopes"
+ scope\use value\getc!
-{ k, Const 'macro', v for k, v in pairs module }
+ nil
+
+{
+ :def
+ require: _require
+ :use
+}
diff --git a/lib/debug.moon b/lib/debug.moon
index c2d0d52..3b5df47 100644
--- a/lib/debug.moon
+++ b/lib/debug.moon
@@ -5,7 +5,7 @@ class out extends Op
@name = name\getc!
update: =>
- print "#{@name} << ", @chld\get!
+ L\print "@name", @chld\get!
{
:out
diff --git a/logger.moon b/logger.moon
index 9a4ca19..b1daa92 100644
--- a/logger.moon
+++ b/logger.moon
@@ -11,7 +11,7 @@ class Logger
}
mklog = (max_level) ->
- new: (level='log') =>
+ new: (level='trace') =>
@level = levels[level] or level
@prefix = ' '
diff --git a/registry.moon b/registry.moon
index 7268f6d..bb33916 100644
--- a/registry.moon
+++ b/registry.moon
@@ -8,87 +8,48 @@ class Registry
@map = {}
- add_module: (name) =>
- @globals\set_raw name, require "lib.#{name}"
-
--
gentag: => #@map + 1
- patch: (sexpr) =>
- old = @map[sexpr.tag]
- @map[sexpr.tag] = sexpr
-
- if not old
- @spawn_expr sexpr
- else
- @patch_expr sexpr, old
- sexpr.tag
-
- patch_root: (@root) =>
- seen = {}
- to_tag = {}
-
+ retag: (@root) =>
scope = Scope @root, @globals
+
+ -- first pass (outin):
+ -- * expand macros (mutate scopes)
+ -- * resolve symbols
for child in *@root
child\expand scope
- for typ, node in @root\walk 'inout', false
- node\link!
-
+ -- second pass (inout):
+ -- * tag untagged exprs
+ -- * destroy orphaned exprs
+ seen = {}
+ to_tag = for typ, node in @root\walk 'inout', false
continue unless typ == 'Xpr'
- sexpr = node
- if not sexpr.tag
- @spawn_expr sexpr
- table.insert to_tag, sexpr
- else
- tag = @patch sexpr
- seen[tag] = true
+ if node.tag
+ seen[node.tag] = true
+ continue
- for sexpr in *to_tag
- tag = @gentag!
- sexpr.tag = tag
- @map[tag] = sexpr
- seen[tag] = true
+ node
for tag, expr in pairs @map
if not seen[tag]
- @destroy_expr expr
+ expr.value\destroy! if expr.value
@map[tag] = nil
- spawn_expr: (sexpr) =>
- head = sexpr\head!
- return if head.type == 'macro'
-
- def = head\getc!
- if sexpr.tag
- print "respawning [#{sexpr.tag}]: '#{def}'"
- else
- print "spawning '#{def}'"
-
- sexpr.value = def sexpr
-
- patch_expr: (new, old) =>
- head = new\head!
-
- if head\getc! == old\head!\getc!
- -- same function, can be patched
- return if head.type == 'macro'
-
- print "patching [#{new.tag}]"
- new.value = old.value
- new.value\patch new
- else
- -- different function
- @spawn_expr new
-
- destroy_expr: (sexpr) =>
- head = sexpr\head!
- return if head.type == 'macro'
+ for sexpr in *to_tag
+ tag = @gentag!
+ sexpr.tag = tag
+ @map[tag] = sexpr
- sexpr.value\destroy!
- print "destroying [#{sexpr.tag}]"
+ link: =>
+ -- third pass (inout):
+ -- * patch expressions (spawn/patch)
+ for typ, node in @root\walk 'inout', false
+ L\trace "patching #{node}"
+ node\patch @map[node.tag]
--
@@ -103,6 +64,6 @@ class Registry
ok, err = xpcall sexpr.value.update, tb, sexpr.value, dt
if not ok
- print "@#{sexpr}: #{err}"
+ L\error "while updating #{sexpr}: #{err}"
:Registry
diff --git a/scope.moon b/scope.moon
index 3033fe2..2ca81b4 100644
--- a/scope.moon
+++ b/scope.moon
@@ -1,4 +1,4 @@
-import Const, Op from require 'base'
+import Const, Op, Macro from require 'base'
ancestor = (klass) ->
assert klass, "cant find the ancestor of nil"
@@ -10,25 +10,21 @@ local Scope
constify = (val, key) ->
typ = switch type val
- when 'number'
- 'num'
- when 'string'
- 'str'
+ when 'number' then 'num'
+ when 'string' then 'str'
when 'table'
if base = rawget val, '__base'
-- a class
switch ancestor val
- when Op
- 'opdef'
+ when Op then 'opdef'
+ when Macro then 'macrodef'
else
error "#{key}: cannot constify klass '#{val.__name}'"
elseif klass = val.__class
-- an instance
switch ancestor klass
- when Op
- 'op'
- when Scope
- 'scope'
+ when Op then 'op'
+ when Scope then 'scope'
when Const
return val
else
diff --git a/test.alv b/test.alv
index f84e43c..fea479d 100644
--- a/test.alv
+++ b/test.alv
@@ -1,7 +1,7 @@
([2]use ([1]require 'math'))
([4]use ([3]require 'osc'))
([6]use ([5]require 'time'))
-
+
([8]out '127.0.0.1' 9000 '/param/radius/set' ([11]mix 0.3 0.5 ([7]lfo 1.8)))
([10]out '127.0.0.1' 9000 '/param/offset/set' ([13]+ ([9]lfo 0.2 'sin')
([12]lfo 0.5 'sin')))