diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-02-10 14:30:03 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-02-10 14:31:39 +0000 |
| commit | 2174e57f3626b95b69eeb543f1d11ee867b67a63 (patch) | |
| tree | 28e4483952928d5babe04b57cb57bad1da723128 | |
| parent | switch from luaposix to luasystem (diff) | |
| download | alive-2174e57f3626b95b69eeb543f1d11ee867b67a63.tar.gz alive-2174e57f3626b95b69eeb543f1d11ee867b67a63.zip | |
reorganization
| -rw-r--r-- | base.moon | 258 | ||||
| -rw-r--r-- | core/base.moon | 69 | ||||
| -rw-r--r-- | core/cell.moon | 85 | ||||
| -rw-r--r-- | core/const.moon | 106 | ||||
| -rw-r--r-- | core/init.moon | 13 | ||||
| -rw-r--r-- | core/invoke.moon | 79 | ||||
| -rw-r--r-- | core/scope.moon (renamed from scope.moon) | 8 | ||||
| -rw-r--r-- | lib/builtin.moon | 3 | ||||
| -rw-r--r-- | lib/debug.moon | 2 | ||||
| -rw-r--r-- | lib/gui.moon | 2 | ||||
| -rw-r--r-- | lib/math.moon | 2 | ||||
| -rw-r--r-- | lib/osc.moon | 2 | ||||
| -rw-r--r-- | lib/time.moon | 2 | ||||
| -rw-r--r-- | lib/util.moon | 2 | ||||
| -rw-r--r-- | parsing.moon | 2 | ||||
| -rw-r--r-- | registry.moon | 3 | ||||
| -rw-r--r-- | spec/cell_spec.moon | 7 | ||||
| -rw-r--r-- | spec/const_spec.moon | 3 | ||||
| -rw-r--r-- | spec/parsing_spec.moon | 2 | ||||
| -rw-r--r-- | spec/registry_spec.moon | 2 | ||||
| -rw-r--r-- | spec/scope_spec.moon | 3 |
21 files changed, 370 insertions, 285 deletions
diff --git a/base.moon b/base.moon deleted file mode 100644 index bfdf7da..0000000 --- a/base.moon +++ /dev/null @@ -1,258 +0,0 @@ -import Scope from require 'scope' - -unpack or= table.unpack - -ancestor = (klass) -> - assert klass, "cant find the ancestor of nil" - while klass.__parent - klass = klass.__parent - klass - -class Op --- common - new: => - -- (...) => @setup ... - - get: => @value - getc: => - L\warn "stream #{@} cast to constant" - @value - --- Value interface - update: => - - destroy: => - --- static - __tostring: => "<op: #{@@__name}>" - __inherited: (cls) => cls.__base.__tostring = @__tostring - - spawn: (Opdef, ...) -> - Opdef ... - -class Action --- common - new: (head, @tag, @registry) => - @patch head - - register: => - @tag = @registry\register @, @tag - --- AST interface - -- * eval args - -- * perform scope effects - -- * patch nested exprs - -- * return runtime-tree value - eval: (scope, tail) => error "not implemented" - - -- free resources - destroy: => - - -- update this instance for :eavl() with new head - -- if :patch() returns false, this instance is :destroy'ed and recreated instead - -- must *not* return false when called after :new() - -- only considered if Action types match - patch: (head) => - if head == @head - true - - @head = head - --- static - @get_or_create: (ActionType, head, tag, registry) -> - last = tag and registry\prev tag - compatible = last and - (last.__class == ActionType) and - (last\patch head) and - last - - if not compatible - last\destroy! if last - compatible = ActionType head, tag, registry - - with compatible - \register! - - __tostring: => "<action: #{@@__name}>" - __inherited: (cls) => cls.__base.__tostring = @__tostring - -class Const - types = { - sym: true - str: true - num: true - scope: true - op: true - opdef: true - fndef: true - builtin: true - } - - new: (@type, @value, @raw) => - assert types[@type], "invalid Const type: #{@type}" - --- Value interface - get: (type) => - assert not type or type == @type, "#{@} is not a #{type}" - @value - - getc: (type) => - assert not type or type == @type, "#{@} is not a #{type}" - @value - - update: (dt) => - switch @type - when 'op' - @value\update dt - --- AST interface - eval: (scope) => - switch @type - when 'num', 'str' - @ - when 'sym' - assert (scope\get @value), "undefined reference to symbol '#{@value}'" - else - error "cannot evaluate #{@}" - - quote: => @ - - stringify: => @raw - --- static - __tostring: => - value = if @type == 'opdef' or @type == 'builtin' then @value.__name else @value - "<#{@type}: #{value}>" - - __eq: (other) => - other.type == @type and other.value == @value - - unescape = (str) -> str\gsub '\\([\'"\\])', '%1' - - @parse: (type, sep) => - switch type - when 'num' then (match) -> @ 'num', (tonumber match), match - when 'sym' then (match) -> @ 'sym', match, match - when 'str' then (match) -> @ 'str', (unescape match), sep .. match .. sep - - @num: (num) -> Const 'num', num, tostring num - @str: (str) -> Const 'str', str, "'#{str}'" - @sym: (sym) -> Const 'sym', sym, sym - @empty: -> Const 'str', '', "''" - - @wrap: (val, name='(unknown)') -> - typ = switch type val - when 'number' then 'num' - when 'string' then 'str' - when 'table' - if base = rawget val, '__base' - -- a class - switch ancestor val - when Op then 'opdef' - when Action then 'builtin' - else - error "#{name}: cannot wrap class '#{val.__name}'" - elseif val.__class - -- an instance - switch ancestor val.__class - when Op then 'op' - when Scope then 'scope' - when Const - return val - else - error "#{name}: cannot wrap '#{val.__class.__name}' instance" - else - -- plain table - return Const 'scope', Scope.from_table val - else - error "#{name}: cannot wrap Lua type '#{type val}'" - - Const typ, val - -local builtin -class Cell --- common - new: (@tag, @children, @white) => - if not @white - @white = ['' for i=1,#@children+1] - - builtin or= require 'lib.builtin' - - head: => @children[1] - tail: => [c for c in *@children[2,]] - --- AST interface - eval: (scope, registry) => - head = @head!\eval scope, registry - Action = switch head.type - when 'opdef' - -- scope\get 'op-invoke' - builtin['op-invoke'] - when 'fndef' - -- scope\get 'fn-invoke' - builtin['fn-invoke'] - when 'builtin' - head\getc! - else - error "cannot evaluate expr with head #{head}" - - action = Action\get_or_create head, @tag, registry - @tag or= action.tag - action\eval scope, @tail! - - quote: (scope, registry) => - @tag = registry\register @, @tag - children = [child\quote scope, registry for child in *@children] - @ - - stringify: (depth=-1) => - buf = '' - buf ..= if depth > 0 then ' ' else @white[0] - if depth == 0 - buf ..= '...' - else - for i, child in ipairs @children - buf ..= child\stringify depth - 1 - buf ..= if depth > 0 then ' ' else @white[i] - - tag = if @tag then "[#{@tag\stringify!}]" else '' - '(' .. tag .. buf .. ')' - --- static - __tostring: => @stringify 2 - - parse_args = (tag, parts) -> - if not parts - parts, tag = tag, nil - - children, white = {}, { [0]: parts[1] } - - for i = 2,#parts,2 - children[i/2] = parts[i] - white[i/2] = parts[i+1] - - tag, children, white - @parse: (...) => - tag, children, white = parse_args ... - @ tag, children, white - -class RootCell extends Cell - head: => Const.sym 'do' - tail: => @children - - stringify: => - buf = '' - buf ..= @white[0] - - for i, child in ipairs @children - buf ..= child\stringify! - buf ..= @white[i] - - buf - -{ - :Op - :Const - :Action - :Cell, :RootCell -} diff --git a/core/base.moon b/core/base.moon new file mode 100644 index 0000000..1805bea --- /dev/null +++ b/core/base.moon @@ -0,0 +1,69 @@ +class Op +-- common + new: => + -- (...) => @setup ... + + get: => @value + getc: => + L\warn "stream #{@} cast to constant" + @value + +-- Value interface + update: => + + destroy: => + +-- static + __tostring: => "<op: #{@@__name}>" + __inherited: (cls) => cls.__base.__tostring = @__tostring + + spawn: (Opdef, ...) -> + Opdef ... + +class Action +-- common + new: (head, @tag, @registry) => + @patch head + + register: => + @tag = @registry\register @, @tag + +-- AST interface + -- * eval args + -- * perform scope effects + -- * patch nested exprs + -- * return runtime-tree value + eval: (scope, tail) => error "not implemented" + + -- free resources + destroy: => + + -- update this instance for :eavl() with new head + -- if :patch() returns false, this instance is :destroy'ed and recreated instead + -- must *not* return false when called after :new() + -- only considered if Action types match + patch: (head) => + if head == @head + true + + @head = head + +-- static + @get_or_create: (ActionType, head, tag, registry) -> + last = tag and registry\prev tag + compatible = last and + (last.__class == ActionType) and + (last\patch head) and + last + + if not compatible + last\destroy! if last + compatible = ActionType head, tag, registry + + with compatible + \register! + + __tostring: => "<action: #{@@__name}>" + __inherited: (cls) => cls.__base.__tostring = @__tostring + +:Op, :Action diff --git a/core/cell.moon b/core/cell.moon new file mode 100644 index 0000000..199c4c3 --- /dev/null +++ b/core/cell.moon @@ -0,0 +1,85 @@ +import Const from require 'core.const' +import op_invoke, fn_invoke from require 'core.invoke' + +class Cell +-- common + new: (@tag, @children, @white) => + if not @white + @white = ['' for i=1,#@children+1] + + head: => @children[1] + tail: => [c for c in *@children[2,]] + +-- AST interface + eval: (scope, registry) => + head = @head!\eval scope, registry + Action = switch head.type + when 'opdef' + -- scope\get 'op-invoke' + op_invoke + when 'fndef' + -- scope\get 'fn-invoke' + fn_invoke + when 'builtin' + head\getc! + else + error "cannot evaluate expr with head #{head}" + + action = Action\get_or_create head, @tag, registry + @tag or= action.tag + action\eval scope, @tail! + + quote: (scope, registry) => + tag = registry\register @, @tag + children = [child\quote scope, registry for child in *@children] + Cell tag, children, @white + + stringify: (depth=-1) => + buf = '' + buf ..= if depth > 0 then '' else @white[0] + if depth == 0 + buf ..= '...' + else + for i, child in ipairs @children + buf ..= child\stringify depth - 1 + buf ..= if depth > 0 then ' ' else @white[i] + + if depth > 0 + buf = buf\sub 1, #buf - 1 + + tag = if @tag then "[#{@tag\stringify!}]" else '' + '(' .. tag .. buf .. ')' + +-- static + __tostring: => @stringify 2 + + parse_args = (tag, parts) -> + if not parts + parts, tag = tag, nil + + children, white = {}, { [0]: parts[1] } + + for i = 2,#parts,2 + children[i/2] = parts[i] + white[i/2] = parts[i+1] + + tag, children, white + @parse: (...) => + tag, children, white = parse_args ... + @ tag, children, white + +class RootCell extends Cell + head: => Const.sym 'do' + tail: => @children + + stringify: => + buf = '' + buf ..= @white[0] + + for i, child in ipairs @children + buf ..= child\stringify! + buf ..= @white[i] + + buf + +:Cell, :RootCell diff --git a/core/const.moon b/core/const.moon new file mode 100644 index 0000000..564ab53 --- /dev/null +++ b/core/const.moon @@ -0,0 +1,106 @@ +import Op, Action from require 'core.base' + +local Scope +load_ = -> + import Scope from require 'core.scope' + +ancestor = (klass) -> + assert klass, "cant find the ancestor of nil" + while klass.__parent + klass = klass.__parent + klass + +class Const + types = { + sym: true + str: true + num: true + scope: true + op: true + opdef: true + fndef: true + builtin: true + } + + new: (@type, @value, @raw) => + assert types[@type], "invalid Const type: #{@type}" + +-- Value interface + get: (type) => + assert not type or type == @type, "#{@} is not a #{type}" + @value + + getc: (type) => + assert not type or type == @type, "#{@} is not a #{type}" + @value + + update: (dt) => + switch @type + when 'op' + @value\update dt + +-- AST interface + eval: (scope) => + switch @type + when 'num', 'str' + @ + when 'sym' + assert (scope\get @value), "undefined reference to symbol '#{@value}'" + else + error "cannot evaluate #{@}" + + quote: => @ + + stringify: => @raw + +-- static + __tostring: => + value = if @type == 'opdef' or @type == 'builtin' then @value.__name else @value + "<#{@type}: #{value}>" + + __eq: (other) => + other.type == @type and other.value == @value + + unescape = (str) -> str\gsub '\\([\'"\\])', '%1' + + @parse: (type, sep) => + switch type + when 'num' then (match) -> @ 'num', (tonumber match), match + when 'sym' then (match) -> @ 'sym', match, match + when 'str' then (match) -> @ 'str', (unescape match), sep .. match .. sep + + @num: (num) -> Const 'num', num, tostring num + @str: (str) -> Const 'str', str, "'#{str}'" + @sym: (sym) -> Const 'sym', sym, sym + @empty: -> Const 'str', '', "''" + + @wrap: (val, name='(unknown)') -> + typ = switch type val + when 'number' then 'num' + when 'string' then 'str' + when 'table' + if base = rawget val, '__base' + -- a class + switch ancestor val + when Op then 'opdef' + when Action then 'builtin' + else + error "#{name}: cannot wrap class '#{val.__name}'" + elseif val.__class + -- an instance + switch ancestor val.__class + when Op then 'op' + when Scope then 'scope' + when Const + return val + else + error "#{name}: cannot wrap '#{val.__class.__name}' instance" + else + -- plain table + return Const 'scope', Scope.from_table val + else + error "#{name}: cannot wrap Lua type '#{type val}'" + + Const typ, val + +:Const, :load_ diff --git a/core/init.moon b/core/init.moon new file mode 100644 index 0000000..713f326 --- /dev/null +++ b/core/init.moon @@ -0,0 +1,13 @@ +import Op, Action from require 'core.base' + +import Const, load_ from require 'core.const' +import Scope from require 'core.scope' +load_! + +import Cell, RootCell from require 'core.cell' + +{ + :Const, :Cell, :RootCell + :Op, :Action + :Scope +} diff --git a/core/invoke.moon b/core/invoke.moon new file mode 100644 index 0000000..78c40a2 --- /dev/null +++ b/core/invoke.moon @@ -0,0 +1,79 @@ +import Const from require 'core.const' +import Action from require 'core.base' +import Scope from require 'core.scope' + +class UpdateChildren + new: (@children) => + + update: (dt) => + for child in *@children + L\trace "updating #{child}" + L\push child\update, dt + + get: => @children[#@children]\get! + getc: => @children[#@children]\getc! + + __tostring: => '<forwarder>' + +class op_invoke extends Action + patch: (head) => + return true if head == @head + + @op\destroy! if @op + + @head = head + assert @head.type == 'opdef', "cant op-invoke #{@head}" + @op = @head\getc!! + + true + + eval: (scope, tail) => + args = [expr\eval scope, @registry for expr in *tail] + -- Const 'op', with @op + with @op + \setup unpack args + +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 + + patch: (head) => + return true if head == @head + + @head = head + + true + + eval: (scope, tail) => + assert @head.type == 'fndef', "cant fn-invoke #{@head}" + { :params, :body } = @head\getc! + + assert #params == #tail, "argument count mismatch in #{@head}" + + fn_scope = Scope @, scope + + for i=1,#params + name = params[i]\getc! + argm = tail[i] + fn_scope\set name, L\push argm\eval, scope, @registry + + body\eval fn_scope, @registry + +class do_expr extends Action + class DoWrapper + new: (@children) => + + update: (dt) => + for child in *@children + L\push child\update, dt + + get: => @children[#@children]\get! + getc: => @children[#@children]\getc! + + __tostring: => '<dowrapper>' + + eval: (scope, tail) => + UpdateChildren [(expr\eval scope, @registry) or Const.empty! for expr in *tail] + +:op_invoke, :fn_invoke diff --git a/scope.moon b/core/scope.moon index 7378dd5..a840ba7 100644 --- a/scope.moon +++ b/core/scope.moon @@ -1,9 +1,7 @@ -local Const +import Const from require 'core.const' class Scope new: (@node, @parent) => - import Const from require 'base' - @values = {} set_raw: (key, val) => @values[key] = Const.wrap val, key @@ -54,6 +52,4 @@ class Scope buf ..= ">" buf -{ - :Scope -} +:Scope diff --git a/lib/builtin.moon b/lib/builtin.moon index 5c3d7d4..b4d6dc7 100644 --- a/lib/builtin.moon +++ b/lib/builtin.moon @@ -1,5 +1,4 @@ -import Action, Const, Cell from require 'base' -import Scope from require 'scope' +import Const, Cell, Action, Scope from require 'core' class UpdateChildren new: (@children) => diff --git a/lib/debug.moon b/lib/debug.moon index f87b06a..6888d89 100644 --- a/lib/debug.moon +++ b/lib/debug.moon @@ -1,4 +1,4 @@ -import Op from require 'base' +import Op from require 'core' class out extends Op setup: (name, @chld) => diff --git a/lib/gui.moon b/lib/gui.moon index 37df233..69c97a3 100644 --- a/lib/gui.moon +++ b/lib/gui.moon @@ -1,5 +1,5 @@ { graphics: lg } = love -import Op from require 'base' +import Op from require 'core' import Registry from require 'registry' import Copilot from require 'copilot' diff --git a/lib/math.moon b/lib/math.moon index 0a514a6..ca7321c 100644 --- a/lib/math.moon +++ b/lib/math.moon @@ -1,4 +1,4 @@ -import Op from require 'base' +import Op from require 'core' unpack or= table.unpack class BinOp extends Op diff --git a/lib/osc.moon b/lib/osc.moon index 02e3ade..a2c992b 100644 --- a/lib/osc.moon +++ b/lib/osc.moon @@ -1,4 +1,4 @@ -import Op from require 'base' +import Op from require 'core' import pack, unpack from require 'osc' import dns, udp from require 'socket' diff --git a/lib/time.moon b/lib/time.moon index 22457bb..567b16f 100644 --- a/lib/time.moon +++ b/lib/time.moon @@ -1,4 +1,4 @@ -import Op, Const from require 'base' +import Const, Op from require 'core' class lfo extends Op tau = math.pi * 2 diff --git a/lib/util.moon b/lib/util.moon index 5079b1b..ed643aa 100644 --- a/lib/util.moon +++ b/lib/util.moon @@ -1,4 +1,4 @@ -import Op from require 'base' +import Op from require 'core' class pick extends Op setup: (@i, ...) => diff --git a/parsing.moon b/parsing.moon index ba1f02e..91ad260 100644 --- a/parsing.moon +++ b/parsing.moon @@ -1,4 +1,4 @@ -import Const, Cell, RootCell from require 'base' +import Const, Cell, RootCell from require 'core' import R, S, P, V, C, Ct from require 'lpeg' -- whitespace diff --git a/registry.moon b/registry.moon index 70955cb..51fa187 100644 --- a/registry.moon +++ b/registry.moon @@ -1,5 +1,4 @@ -import Scope from require 'scope' -import Const from require 'base' +import Const, Scope from require 'core' class Registry new: () => diff --git a/spec/cell_spec.moon b/spec/cell_spec.moon index 2b0860c..6ec9fc8 100644 --- a/spec/cell_spec.moon +++ b/spec/cell_spec.moon @@ -1,5 +1,4 @@ -import Cell, RootCell, Const from require 'base' -import Scope from require 'scope' +import Cell, RootCell, Const, Scope from require 'core' import Registry from require 'registry' import Logger from require 'logger' Logger.init 'silent' @@ -7,7 +6,6 @@ Logger.init 'silent' hello_world = Cell nil, { (Const.sym 'hello'), (Const.str 'world') } two_plus_two = Cell nil, { (Const.sym '+'), (Const.num 2), (Const.num 2) } - describe 'Cell', -> describe 'quoting', -> it 'quotes children', -> @@ -38,7 +36,8 @@ describe 'Cell', -> reg = mock register: => root\quote nil, reg - (assert.spy reg.register).was.called_with reg, root, (Const.num 2) + (assert.spy reg.register).was.called! + (assert.spy reg.register).was.called_with reg, match._, Const.num 2 describe 'evaluation', -> registry = Registry! diff --git a/spec/const_spec.moon b/spec/const_spec.moon index 4e4028f..4def3a6 100644 --- a/spec/const_spec.moon +++ b/spec/const_spec.moon @@ -1,5 +1,4 @@ -import Const, Op, Action from require 'base' -import Scope from require 'scope' +import Const, Op, Action, Scope from require 'core' import Logger from require 'logger' Logger.init 'silent' diff --git a/spec/parsing_spec.moon b/spec/parsing_spec.moon index 4bd5067..c405245 100644 --- a/spec/parsing_spec.moon +++ b/spec/parsing_spec.moon @@ -1,5 +1,5 @@ import space, atom, expr, explist, cell, program, comment from require 'parsing' -import Const from require 'base' +import Const from require 'core' import Logger from require 'logger' Logger.init 'silent' diff --git a/spec/registry_spec.moon b/spec/registry_spec.moon index 53a406c..de79744 100644 --- a/spec/registry_spec.moon +++ b/spec/registry_spec.moon @@ -1,5 +1,5 @@ import Registry from require 'registry' -import Const from require 'base' +import Const from require 'core' mk = -> mock destroy: => diff --git a/spec/scope_spec.moon b/spec/scope_spec.moon index 97bc436..9e7ab80 100644 --- a/spec/scope_spec.moon +++ b/spec/scope_spec.moon @@ -1,5 +1,4 @@ -import Op, Const from require 'base' -import Scope from require 'scope' +import Scope, Const, Op from require 'core' import Logger from require 'logger' Logger.init 'silent' |
