diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-02-02 18:34:18 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-02-02 18:35:58 +0000 |
| commit | 1fb8e4b2e621128e043ae4091f3e25d56b9d7cc2 (patch) | |
| tree | 9b95ff4e17784aaee4c14372741f2a65d76d02fb | |
| parent | add logger (diff) | |
| download | alive-1fb8e4b2e621128e043ae4091f3e25d56b9d7cc2.tar.gz alive-1fb8e4b2e621128e043ae4091f3e25d56b9d7cc2.zip | |
clean out old patching implementation
| -rw-r--r-- | ast.moon | 57 | ||||
| -rw-r--r-- | base.moon | 47 | ||||
| -rw-r--r-- | lib/builtin.moon | 70 | ||||
| -rw-r--r-- | lib/debug.moon | 2 | ||||
| -rw-r--r-- | logger.moon | 2 | ||||
| -rw-r--r-- | registry.moon | 91 | ||||
| -rw-r--r-- | scope.moon | 18 | ||||
| -rw-r--r-- | test.alv | 2 |
8 files changed, 158 insertions, 131 deletions
@@ -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,]] @@ -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 @@ -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 @@ -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'))) |
