diff options
Diffstat (limited to 'core/base')
| -rw-r--r-- | core/base/builtin.moon | 96 | ||||
| -rw-r--r-- | core/base/fndef.moon | 26 | ||||
| -rw-r--r-- | core/base/init.moon | 39 | ||||
| -rw-r--r-- | core/base/input.moon | 146 | ||||
| -rw-r--r-- | core/base/match.moon | 302 | ||||
| -rw-r--r-- | core/base/op.moon | 168 |
6 files changed, 0 insertions, 777 deletions
diff --git a/core/base/builtin.moon b/core/base/builtin.moon deleted file mode 100644 index fd36c69..0000000 --- a/core/base/builtin.moon +++ /dev/null @@ -1,96 +0,0 @@ ----- --- Builtin / Special Form evaluation Strategy (`builtin`). --- --- Responsible for quoting/evaluating subexpressions, instantiating and setting --- up `Op`s, updating the current `Scope`, etc. --- See `builtin` and `invoke` for examples. --- --- @classmod Builtin - -class Builtin ---- Builtin interface. --- --- methods that have to be implemented by `Builtin` implementations. --- @section interface - - --- create a new instance. - -- - -- @tparam Cell cell the Cell to evaluate - -- @tparam Value head the (`AST:eval`d) `head` of the Cell to evaluate - new: (@cell, @head) => - @tag = @cell.tag - @tag\register @ - - --- perform the actual evaluation. - -- - -- Implementations should: - -- - -- - eval or quote `tail` values - -- - perform scope effects - -- - wrap all child-results - -- - -- @tparam Scope scope the active scope - -- @tparam {AST,...} tail the arguments to this expression - -- @treturn Result the result of this evaluation - eval: (scope, tail) => error "not implemented" - - --- free resources - destroy: => - - --- setup or copy state from previous instance of same type. - -- - -- `prev` is only passed if Builtin types of prev and current expression match. - -- Otherwise, or when no previous expression exists, `nil` is passed. - -- - -- @tparam ?Builtin prev the previous Builtin instance - setup: (prev) => - - --- the `Cell` this Builtin was created for. - -- @tfield Cell cell - - --- the evaluated head of `cell`. - -- @tfield AST head - - --- the identity of `cell`. - -- @tfield Tag tag - ---- static functions --- @section static - - --- create and setup a `Builtin` for a given tag, then evaluate it. - -- - -- Create a new instance using `tag` and `head` and call `setup` on it. - -- If a previous instance with the same `tag` exists and has the same `head`, - -- it pass it to `setup`. Register the `Builtin` with `tag`, evaluate it - -- and return the `Result`. - -- - -- @tparam Cell cell the `Cell` being evaluated - -- @tparam Scope scope the active scope - -- @tparam Value head the (`AST:eval`d) head of the `Cell` being evaluated - -- @treturn Result the result of evaluation - @eval_cell: (cell, scope, head) => - last = cell.tag\last! - compatible = last and (last.__class == @) and last.head == head - - L\trace if compatible - "reusing #{last} for #{cell.tag} <#{@__name} #{head}>" - else if last - "replacing #{last} with new #{cell.tag} <#{@__name} #{head}>" - else - "initializing #{cell.tag} <#{@__name} #{head}>" - - builtin = @ cell, head - if compatible - builtin\setup last - else - last\destroy! if last - builtin\setup nil - - builtin\eval scope, cell\tail! - - __tostring: => "<#{@@__name} #{@head}>" - __inherited: (cls) => cls.__base.__tostring = @__tostring - -{ - :Builtin -} diff --git a/core/base/fndef.moon b/core/base/fndef.moon deleted file mode 100644 index b79ad85..0000000 --- a/core/base/fndef.moon +++ /dev/null @@ -1,26 +0,0 @@ ----- --- user-function definition (`fndef`). --- --- When called, expands to its body with params bound to the fn arguments (see --- `invoke.fn_invoke`). --- --- @classmod FnDef - -class FnDef ---- static functions --- @section static - - --- create a new instance - -- - -- @classmethod - -- @tparam {Value,...} params (`AST:quote`d) naming the function parameters - -- @tparam AST body (`AST:quote`d) expression the function evaluates to - -- @tparam Scope scope the lexical scope the function was defined in (closure) - new: (@params, @body, @scope) => - - __tostring: => - "(fn (#{table.concat [p\stringify! for p in *@params], ' '}) ...)" - -{ - :FnDef -} diff --git a/core/base/init.moon b/core/base/init.moon deleted file mode 100644 index 9153f79..0000000 --- a/core/base/init.moon +++ /dev/null @@ -1,39 +0,0 @@ ----- --- Base definitions for extensions. --- --- This module exports the following classes and tables that extension modules --- may need: --- --- @module base --- @see Op --- @see Builtin --- @see FnDef --- @see Input --- @see base.match.val --- @see base.match.evt --- @see ValueStream --- @see EventStream --- @see IOStream --- @see Result --- @see Error - -import Op from require 'core.base.op' -import Builtin from require 'core.base.builtin' -import FnDef from require 'core.base.fndef' -import Input from require 'core.base.input' -import val, evt from require 'core.base.match' -import ValueStream, EventStream, IOStream from require 'core.stream' -import Result from require 'core.result' -import Error from require 'core.error' - -{ - :Op - :Builtin - :FnDef - :Input - :val, :evt - - -- redundant exports, to keep anything an extension might need in one import - :ValueStream, :EventStream, :IOStream - :Result, :Error -} diff --git a/core/base/input.moon b/core/base/input.moon deleted file mode 100644 index bcf188e..0000000 --- a/core/base/input.moon +++ /dev/null @@ -1,146 +0,0 @@ ----- --- Update scheduling policy for `Op` arguments. --- --- @classmod Input -import ValueStream, EventStream, IOStream from require 'core.stream' -import Result from require 'core.result' - -inherits = (klass, frm) -> - assert klass, "cant find the ancestor of nil" - return true if klass == frm - while klass.__parent - return true if klass.__parent == frm - klass = klass.__parent - false - -match_parent = (inst, map) -> - klass = assert inst and inst.__class, "not an instance" - if key = map[klass] - return key - - while klass.__parent - if key = map[klass.__parent] - return key - - klass = klass.__parent - -local ColdInput, ValueInput, IOInput, mapping - -class Input ---- Input interface. --- --- Methods that have to be implemented by `Input` implementations. --- @section interface - - --- create a new Input. - -- - -- @classmethod - -- @tparam Stream stream - new: (@stream) => - assert @stream, "nil passed to Input: #{value}" - - --- copy state from old instance (optional). - -- - -- called by `Op:setup` with another `Input` instance or `nil` once this instance is - -- registered. Must prepare this instance for `dirty`. - -- - -- May enter a 'setup state' that is exited using `finish_setup`. - -- - -- @tparam ?Input prev previous `Input` intance or nil - setup: (prev) => - - --- whether this input requires processing (optional). - -- - -- must return a boolean indicating whether `Op`s that refer to this instance - -- should be notified (via `Op:tick`). If not overwritten, delegates to - -- `stream`:@{ValueStream:dirty|dirty}. - -- - -- @treturn bool whether processing is necessary - dirty: => @stream\dirty! - - --- leave setup state (optional). - -- - -- called after the `Op` has completed (or skipped) its first `Op:tick` after - -- `Op:setup`. Must prepare this instance for dataflow operation. - finish_setup: => - - --- unwrap to Lua value (optional). - -- - -- @treturn any the raw Lua value - unwrap: => @stream\unwrap! - - --- return the type name of this `Input` (optional). - type: => @stream.type - - --- return the metatype name of this `Input` (optional). - metatype: => @stream.metatype - - --- the current value - -- - -- @tfield ValueStream stream - ---- members --- @section members - - --- alias for `unwrap`. - __call: => @stream\unwrap! - - __tostring: => "#{@@__name}:#{@stream}" - __inherited: (cls) => - cls.__base.__call = @__call - cls.__base.__tostring = @__tostring - ---- static functions --- @section static - - --- Create a `cold` `Input`. - -- - -- Never marked dirty. Use this for input streams that are only read when - -- another `Input` is dirty. - -- - -- @tparam Stream|Result value - @cold: (value) -> - if value.__class == Result - value = assert value.value, "Input from result without value!" - ColdInput value - - --- Create a `hot` `Input`. - -- - -- Behaviour depends on what kind of `Stream` `value` is: - -- - -- - `ValueStream`: Marked dirty for the eval-tick if old and new `ValueStream` differ. - -- - `EventStream` and `IOStream`: Marked dirty only if the current `EventStream` is dirty. - -- - -- This is the most common `Input` strategy. - -- - -- @tparam Stream|Result value - @hot: (value) -> - if value.__class == Result - value = assert value.value, "Input from result without value!" - - InputType = match_parent value, mapping - assert InputType, "Input from unknown value: #{value}" - InputType value - -class ColdInput extends Input - dirty: => false - -class ValueInput extends Input - setup: (old) => @dirty_setup = not old or @stream != old.stream - finish_setup: => @dirty_setup = nil - dirty: => - return @dirty_setup if @dirty_setup != nil - @stream\dirty! - -class IOInput extends Input - io: true - -mapping = { - [ValueStream]: ValueInput - [EventStream]: Input - [IOStream]: IOInput -} - -{ - :Input -} diff --git a/core/base/match.moon b/core/base/match.moon deleted file mode 100644 index 700b50d..0000000 --- a/core/base/match.moon +++ /dev/null @@ -1,302 +0,0 @@ ------ ---- Pattern capturing for Op argument parsing. --- --- There is only one basic buildings block for assembling patterns: --- `Type`. It can match `ValueStream`s and `EventStream`s depending on its --- metatype argument and can take an optional type name to match as an argument. --- --- In addition to this primitive, the following modifiers are available: --- `Repeat`, `Sequence`, `Choice`, and `Optional`. They can be used directly, --- but there is also a number of shorthands for assembling patterns quickly: --- --- - `val()` and `evt()`: Shorthands for `Type('value')` and `Type('event')` --- - `val.num`: Shorthand for `Type('value', 'num')` --- - `evt.str`: Shorthand for `Type('event', 'str')` --- - `pat * 2`: Shorthand for `Repeat(pat, 1, 2)` (1-4 times `pat`) --- - `pat * 0`: Shorthand for `Repeat(pat, 1, nil)` (1-* times `pat`) --- - `pat ^ 2`: Shorthand for `Repeat(pat, 0, 2)` (0-4 times `pat`) --- - `pat ^ 0`: Shorthand for `Repeat(pat, 0, nil)` (0-* times `pat`) --- - `a + b + … + z`: Shorthand for `Sequence{ a, b, ..., z }` --- - `a / b / … / z`: Shorthand for `Choice{ a, b, ..., z }` --- - `-pat`: Shorthand for `Optional(pat)` --- --- To perform the actual matching, call the `:match` method on a pattern and --- pass a sequence of `Result`s. The method will either return the captured --- `Result`s (or a table structuring them) --- --- Any ambiguous pattern can be set to 'recall mode' by invoking it. --- Recalling patterns will memorize the first Result they match, and --- only match further Results of the same type. For example --- --- arg = (val.num / val.str)! --- pattern = arg + arg --- --- ...will match either two numbers or two strings, but not one number and one --- string. Recalling works on `Choice` and `Type` patterns. `Type` patterns --- without a type (`val!` and `evt!`) always behave like this. --- --- On `Sequence` patterns, a special method `:named` exists. It takes a --- sequence of keys that are used instead of integers when constructing the --- capture table: --- --- pattern = (val.str + val.num):named('key', 'value') --- pattern:match(...) --- -- returns { {key='a', value=1}, {key='b', value=2}, ...} --- --- @module base.match -import Error from require 'core.error' -import ValueStream, EventStream from require 'core.stream' - -local Repeat, Sequence, Choice, Optional - -typestr = (result) -> - str = result\type! - str ..= '!' if result\metatype! == 'event' - str - -class Pattern - match: (seq) => - @reset! - num, cap = @capture seq, 1 - if num != #seq - args = table.concat [typestr arg for arg in *seq], ' ' - msg = "couldn't match arguments (#{args}) against pattern #{@}" - error Error 'argument', msg - cap - - remember: (key) => - return true unless @recall - - @recalled or= key - @recalled == key - - rep: (min, max) => Repeat @, min, max - - reset: => @recalled = nil - - __call: => @ - __mul: (num) => Repeat @, 1, if num != 0 then num - __pow: (num) => Repeat @, 0, if num != 0 then num - __add: (other) => Sequence { @, other } - __div: (other) => Choice { @, other } - __unm: => Optional @ - - __inherited: (cls) => - cls.__base.__call or= @__call - cls.__base.__mul or= @__mul - cls.__base.__pow or= @__pow - cls.__base.__add or= @__add - cls.__base.__div or= @__div - cls.__base.__unm or= @__unm - ---- Base Stream Pattern. --- --- When instantiated with `type`, only succeeds for `Stream`s whose value and --- meta types match. --- --- Otherwise, matches Streams based only on `metatype` for the first match, but --- using both afterwards (recall mode). --- --- @function Stream --- @tparam string metatype "value" or "event" --- @tparam ?string type type name -class Type extends Pattern - new: (@metatype, @type) => - @recall = not @type - - capture: (seq, i) => - return unless seq[i] - type, mt = seq[i]\type!, seq[i]\metatype! - return unless @metatype == mt - match = if @type then type == @type else @remember type - if match - 1, seq[i] - - __tostring: => - str = @type or @metatype - str ..= '!' if @metatype == 'event' - str - ---- Repeat a pattern. --- --- Matches a given `inner` pattern as many times as possible, within the given --- minimum/maximum counts. Matching this pattern results in a sequence of the --- individual captures produced by the inner pattern. --- --- @function Repeat --- @tparam Pattern inner the original pattern --- @tparam ?number min minimum amount of repetitions --- @tparam ?number max maximum amount of repetitions (default infinite) -class Repeat extends Pattern - new: (@inner, @min, @max) => - - capture: (seq, i) => - take, all = 0, {} - while true - num, cap = @inner\capture seq, i+take - break unless num - - take += num - table.insert all, cap - - break if @max and take >= @max - - return if @min and take < @min - return if @max and take > @max - - take, all - - reset: => - @inner\reset! - - __call: => - @@ @inner!, @min, @max - - __tostring: => - min = @min or '0' - max = @max or '*' - "#{@inner}{#{min}-#{max}}" - ---- Match multiple patterns in order. --- --- Matches the inner patterns in order, only succeeds if all of them match. --- Captures the individual captures produced by the inner patterns in a --- sequence, or table with keys specified in `keys` or using the `:named(...)` --- modifier. --- --- @function Sequence --- @tparam {Pattern,...} elements the inner patterns --- @tparam ?{string,...} keys the keys to use when capturing matches -class Sequence extends Pattern - new: (@elements, @keys) => - - capture: (seq, i) => - take, all = 0, {} - for key, elem in ipairs @elements - num, cap = elem\capture seq, i+take - return unless num - - take += num - key = @keys[key] if @keys - all[key] = cap - - take, all - - reset: => - for elem in *@elements - elem\reset! - - named: (...) => - @@ [e for e in *@elements], { ... } - - __call: => - @@ [e! for e in *@elements] - - __add: (other) => - elements = [e for e in *@elements] - table.insert elements, other - @@ elements - - __tostring: => - core = table.concat [tostring e for e in *@elements], ' ' - "(#{core})" - ---- Match one of multiple options. --- --- Matches using the first matching pattern in `elements` and returns its --- captured value. Supports recalling the matched subpattern. --- --- @function Choice --- @tparam {Pattern,...} elements the inner patterns --- @tparam ?{string,...} keys the keys to use when capturing matches -class Choice extends Pattern - new: (@elements, @recall=false) => - - capture: (seq, i) => - for key, elem in ipairs @elements - num, cap = elem\capture seq, i - if num and @remember key - return num, cap - - reset: => - super! - for elem in *@elements - elem\reset! - - __call: => - @@ [e! for e in *@elements], true - - __div: (other) => - elements = [e for e in *@elements] - table.insert elements, other - @@ elements - - __tostring: => - core = table.concat [tostring e for e in *@elements], ' | ' - "(#{core})" - ---- Optionally match a pattern. --- --- Matches using the first matching pattern in `elements` and returns its --- captured value. Supports recalling the matched subpattern. --- --- @function Optional --- @tparam {Pattern,...} elements the inner patterns --- @tparam ?{string,...} keys the keys to use when capturing matches -class Optional extends Pattern - new: (@inner) => - - capture: (seq, i) => - num, cap = @inner\capture seq, i - num or 0, cap - - reset: => - @inner\reset! - - __call: => - @@ @inner! - - __unm: => @ - - __tostring: => "#{@inner}?" - ---- `Value` shorthands. --- --- Call or index with a string to obtain a `Type` instance. --- Call to obtain a wildcard pattern. --- --- val.str, val.num --- val['vec3'], val('vec3') --- val() --- --- @table val -val = setmetatable {}, { - __index: (key) => - with v = Type 'value', key - @[key] = v - - __call: (...) => Type 'value', ... -} - ---- `Event` shorthands. --- --- Call or index with a string to obtain an `Type` instance. --- Call to obtain a wildcard pattern. --- --- evt.bang, evt.str, evt.num --- evt['midi/message'], evt('midi/message') --- evt() --- --- @table evt -evt = setmetatable {}, { - __index: (key) => - with v = Type 'event', key - @[key] = v - - __call: (...) => Type 'event', ... -} - -{ - :Type, :Repeat, :Sequence, :Choice, :Optional - :val, :evt -} diff --git a/core/base/op.moon b/core/base/op.moon deleted file mode 100644 index b0a83dc..0000000 --- a/core/base/op.moon +++ /dev/null @@ -1,168 +0,0 @@ ----- --- Persistent expression Operator. --- --- @classmod Op - -deepcopy = (val) -> - switch type val - when 'number', 'string', 'boolean', 'nil' - val - when 'table' - assert (not getmetatable {}), "state should only contain simple tables!" - {(deepcopy k), (deepcopy v) for k,v in pairs val} - else - error "state cannot contain values of type '#{type val}'" - -class Op ---- members --- @section members - - do_yield = (table) -> - for k, v in pairs table - if v.__class - coroutine.yield v - else - do_yield v - --- yield all `Input`s from the (potentially nested) `inputs` table - -- - -- @treturn iterator iterator over `inputs` - all_inputs: => coroutine.wrap -> do_yield @inputs - - --- create a mutable copy of this Op. - -- - -- Used to wrap insulate eval-cycles from each other. The copy does not have - -- `inputs` set, since it is expected that this is (re)set in `setup`. - -- - -- @treturn Op - fork: => - out = if @out then @out\fork! - state = if @state then deepcopy @state - @@ out, state - - --- internal state of this Op. - -- - -- This may be any simple Lua value, including Lua tables, as long as it has - -- no metatables, multiple references/loops, userdata etc. - -- - -- @tfield table state - - --- `Stream` instance representing this Op's computed output value. - -- - -- Must be set to a `Stream` instance once `setup` finishes. Must not change - -- type, be removed or replaced outside of `new` and `setup`. If it is a - -- `ValueStream`, it should have a value assigned via `set` or the - -- constructor once `tick` is called the first time. If `out`'s value is not - -- initialized in `new` or `setup`, the implementation must make sure - -- `tick``(true)` is called at least on the first eval-cycle the Op goes - -- through, e.g. by using an `Input.hot` with a `ValueStream`. - -- - -- @tfield Stream out - - --- table containing `Input`s to this Op. - -- - -- The `inputs` table can be nested with string or integer keys, - -- but all leaf-entries must be `Input` instances. It must not contain loops - -- or instances of other classes. - -- - -- @tfield {Input,...} inputs - ---- Op interface. --- --- methods that have to be implemented by `Op` implementations. --- @section interface - - --- construct a new instance. - -- - -- The optional parameters `out` and `state` are used by `fork` to duplicate - -- an instance. If the constructor is overriden, these parameters must be - -- forwarded to the superconstructor unchanged. - -- - -- @function new - -- @classmethod - -- @tparam ?Stream out `out` - -- @tparam ?table state `state` - - --- parse arguments and patch self. - -- - -- Called once every eval-cycle. `inputs` is a list of `Result`s that are the - -- argument to this op. The `inputs` have to be wrapped in `Input` instances - -- to define update behaviour. Use `base.match` to parse them, then delegate to - -- `super:setup` to patch the `Input` instances. - -- - -- @function setup - -- @tparam {Result,...} inputs a sequence of `Result`s - -- @tparam Scope scope the active scope - - --- handle incoming events and update `out` (optional). - -- - -- Called once per frame if any `Input`s are dirty. Some `Input`s may have - -- special behaviour immediately after `setup` that can cause them to become - -- dirty at eval-time. In this case, an eval-time tick is executed. You can - -- detect this using the `setup` parameter. - -- - -- `tick` is called after `setup`. `tick` is not called immediately after - -- `setup` if no `inputs` are dirty. Update `out` here. - -- - -- @tparam bool setup whether this is an eval-time tick - tick: => - - --- called when the Op is destroyed (optional). - destroy: => - ---- implementation utilities. --- --- super-methods and utilities for use by implementations. --- @section super - - --- if `type` is passed, an output stream is instantiated. - -- if `init` is passed, the stream is initialized to that Lua value. - -- it is okay not to use this and create the output stream in :setup() if the - -- type is not known at this time. - -- - -- @classmethod - -- @tparam ?Stream out `out` - -- @tparam ?table state `state` - new: (@out, @state) => - - do_setup = (old, cur) -> - for k, cur_val in pairs cur - old_val = old and old[k] - - -- are these inputs or nested tables? - cur_plain = cur_val and not cur_val.__class - old_plain = old_val and not old_val.__class - - if cur_plain and old_plain - -- both are tables, recurse - do_setup old_val, cur_val - elseif not (cur_plain or old_plain) - -- both are streams (or nil), setup them - cur_val\setup old_val - --- setup previous `inputs`, if any, with the new inputs, and write them to - -- `inputs`. The `inputs` table can be nested with string or integer keys, - -- but all leaf-entries must be `Input` instances. It must not contain loops - -- or instances of other classes. - -- - -- @tparam table inputs table of `Input`s - setup: (inputs) => - old_inputs = @inputs - @inputs = inputs - do_setup old_inputs, @inputs - - do_unwrap = (value) -> - if value.__class - value\unwrap! - else - {k, do_unwrap v for k,v in pairs value} - --- `\unwrap` all `Input`s in `@inputs` and return a table with the same - -- shape. - -- - -- @treturn table the values of all `Input`s - unwrap_all: => do_unwrap @inputs - - __tostring: => "<op: #{@@__name}>" - __inherited: (cls) => cls.__base.__tostring = @__tostring - -{ - :Op -} |
