diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-05-08 11:41:56 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:23:21 +0000 |
| commit | bec1ebf1209c5a56ad4208d820222cb497b5f98c (patch) | |
| tree | 0663fbbd99d580b55b7aa611b415afd946b738bb | |
| parent | fix docs (diff) | |
| download | alive-bec1ebf1209c5a56ad4208d820222cb497b5f98c.tar.gz alive-bec1ebf1209c5a56ad4208d820222cb497b5f98c.zip | |
rename RTNode.value to RTNode.result (to match Result class)
| -rw-r--r-- | alv/ast.moon | 4 | ||||
| -rw-r--r-- | alv/base/builtin.moon | 6 | ||||
| -rw-r--r-- | alv/base/input.moon | 13 | ||||
| -rw-r--r-- | alv/base/match.moon | 10 | ||||
| -rw-r--r-- | alv/base/op.moon | 14 | ||||
| -rw-r--r-- | alv/builtin.moon | 42 | ||||
| -rw-r--r-- | alv/cell.moon | 2 | ||||
| -rw-r--r-- | alv/copilot.moon | 2 | ||||
| -rw-r--r-- | alv/invoke.moon | 10 | ||||
| -rw-r--r-- | alv/module.moon | 4 | ||||
| -rw-r--r-- | alv/registry.moon | 2 | ||||
| -rw-r--r-- | alv/result/base.moon | 44 | ||||
| -rw-r--r-- | alv/result/const.moon | 27 | ||||
| -rw-r--r-- | alv/result/evt.moon | 63 | ||||
| -rw-r--r-- | alv/result/init.moon | 6 | ||||
| -rw-r--r-- | alv/result/sig.moon | 60 | ||||
| -rw-r--r-- | alv/rtnode.moon | 49 | ||||
| -rw-r--r-- | alv/scope.moon | 8 | ||||
| -rw-r--r-- | docs/gen/layout.moon | 18 | ||||
| -rwxr-xr-x | docs/gen/module | 8 | ||||
| -rw-r--r-- | docs/internals/extensions.md | 49 | ||||
| -rw-r--r-- | spec/input_spec.moon | 2 | ||||
| -rw-r--r-- | spec/match_spec.moon | 21 | ||||
| -rw-r--r-- | spec/result/const_spec.moon | 6 | ||||
| -rw-r--r-- | spec/rtnode_spec.moon | 97 | ||||
| -rw-r--r-- | spec/scope_spec.moon | 40 |
26 files changed, 291 insertions, 316 deletions
diff --git a/alv/ast.moon b/alv/ast.moon index cff8947..b8c14e6 100644 --- a/alv/ast.moon +++ b/alv/ast.moon @@ -10,11 +10,11 @@ --- evaluate this AST Node. -- - -- Evaluate this node and return a `Result`. + -- Evaluate this node and return a `RTNode`. -- -- @function eval -- @tparam Scope scope the scope to evaluate in - -- @treturn Result the evaluation result + -- @treturn RTNode the evaluation result --- create a clone with its own identity. -- diff --git a/alv/base/builtin.moon b/alv/base/builtin.moon index f675207..5f46f37 100644 --- a/alv/base/builtin.moon +++ b/alv/base/builtin.moon @@ -31,7 +31,7 @@ class Builtin -- -- @tparam Scope scope the active scope -- @tparam {AST,...} tail the arguments to this expression - -- @treturn Result the result of this evaluation + -- @treturn RTNode the result of this evaluation eval: (scope, tail) => error "not implemented" --- free resources @@ -62,12 +62,12 @@ class Builtin -- 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`. + -- and return the `RTNode`. -- -- @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 + -- @treturn RTNode the result of evaluation @eval_cell: (cell, scope, head) => last = cell.tag\last! compatible = last and (last.__class == @) and last.head == head diff --git a/alv/base/input.moon b/alv/base/input.moon index dea91c9..a9f0e32 100644 --- a/alv/base/input.moon +++ b/alv/base/input.moon @@ -35,7 +35,7 @@ class Input --- create a new Input. -- -- @classmethod - -- @tparam Stream stream + -- @tparam Result stream new: (@stream) => assert @stream, "nil passed to Input: #{value}" @@ -98,26 +98,27 @@ class Input -- Never marked dirty. Use this for input streams that are only read when -- another `Input` is dirty. -- - -- @tparam Stream|RTNode value + -- @tparam Result|RTNode value @cold: (value) -> if value.__class == RTNode - value = assert value.value, "Input from result without value!" + value = assert value.result, "Input from node without result!" ColdInput value --- Create a `hot` `Input`. -- - -- Behaviour depends on what kind of `Stream` `value` is: + -- Behaviour depends on what kind of `Result` `value` is: -- + -- - `Constant`: treated like `cold`. -- - `SigStream`: Marked dirty only if old and new `SigStream` differ. -- - `EvtStream` and `IOStream`: Marked dirty only if the current -- `EvtStream` is dirty. -- -- This is the most common `Input` strategy. -- - -- @tparam Stream|RTNode value + -- @tparam Result|RTNode value @hot: (value) -> if value.__class == RTNode - value = assert value.value, "Input from result without value!" + value = assert value.result, "Input from node without result!" InputType = match_parent value, mapping assert InputType, "Input from unknown value: #{value}" diff --git a/alv/base/match.moon b/alv/base/match.moon index 3a2b3d5..926c970 100644 --- a/alv/base/match.moon +++ b/alv/base/match.moon @@ -49,14 +49,12 @@ import Primitive from require 'alv.type' local Repeat, Sequence, Choice, Optional -typestr = (result) -> tostring result.value - class Pattern match: (seq) => @reset! num, cap = @capture seq, 1 if num != #seq - args = table.concat [typestr arg for arg in *seq], ' ' + args = table.concat [arg.result\fulltype! for arg in *seq], ' ' msg = "couldn't match arguments (#{args}) against pattern #{@}" error Error 'argument', msg cap @@ -86,15 +84,15 @@ class Pattern cls.__base.__div or= @__div cls.__base.__unm or= @__unm ---- Base Stream Pattern. +--- Base Result Pattern. -- --- When instantiated with `type`, only succeeds for `Stream`s whose value and +-- When instantiated with `type`, only succeeds for `Result`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 +-- @function Type -- @tparam string metatype "value" or "event" -- @tparam ?string type type name class Type extends Pattern diff --git a/alv/base/op.moon b/alv/base/op.moon index b0a83dc..da90288 100644 --- a/alv/base/op.moon +++ b/alv/base/op.moon @@ -46,9 +46,9 @@ class Op -- -- @tfield table state - --- `Stream` instance representing this Op's computed output value. + --- `Result` instance representing this Op's computed output value. -- - -- Must be set to a `Stream` instance once `setup` finishes. Must not change + -- Must be set to a `Result` 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 @@ -56,7 +56,7 @@ class Op -- `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 + -- @tfield Result out --- table containing `Input`s to this Op. -- @@ -79,18 +79,18 @@ class Op -- -- @function new -- @classmethod - -- @tparam ?Stream out `out` + -- @tparam ?Result 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 + -- Called once every eval-cycle. `inputs` is a list of `RTNode`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 {RTNode,...} inputs a sequence of `RTNode`s -- @tparam Scope scope the active scope --- handle incoming events and update `out` (optional). @@ -120,7 +120,7 @@ class Op -- type is not known at this time. -- -- @classmethod - -- @tparam ?Stream out `out` + -- @tparam ?Result out `out` -- @tparam ?table state `state` new: (@out, @state) => diff --git a/alv/builtin.moon b/alv/builtin.moon index 58a1ecc..740da25 100644 --- a/alv/builtin.moon +++ b/alv/builtin.moon @@ -35,9 +35,9 @@ doc = Constant.meta eval: (scope, tail) => assert #tail == 1, "'doc' takes exactly one parameter" - result = L\push tail[1]\eval, scope + node = L\push tail[1]\eval, scope with RTNode children: { def } - meta = result.value.meta + meta = node.result.meta L\print "(doc #{tail[1]}):\n#{format_meta meta}\n" def = Constant.meta @@ -78,8 +78,8 @@ All arguments have to be evaltime constant." eval: (scope, tail) => L\trace "evaling #{@}" for child in *tail - result = L\push child\eval, scope - value = result\const! + node = L\push child\eval, scope + value = node\const! scope\use value\unwrap 'scope', "'use' only works on scopes" RTNode! @@ -96,8 +96,8 @@ require_ = Constant.meta L\trace "evaling #{@}" assert #tail == 1, "'require' takes exactly one parameter" - result = L\push tail[1]\eval, scope - name = result\const!\unwrap 'str' + node = L\push tail[1]\eval, scope + name = node\const!\unwrap 'str' L\trace @, "loading module #{name}" COPILOT\require name @@ -148,11 +148,11 @@ export_ = Constant.meta description: " Evaluate `expr1`, `expr2`, … in a new Scope and return scope." - value: class extends Builtin + value: class extends Builtin eval: (scope, tail) => new_scope = Scope scope children = [expr\eval new_scope for expr in *tail] - RTNode :children, value: Constant.wrap new_scope + RTNode :children, result: Constant.wrap new_scope export_star = Constant.meta meta: @@ -170,16 +170,16 @@ Copies the containing scope if no symbols are given." new_scope = Scope! children = if #tail == 0 - for k,result in pairs scope.values - new_scope\set k, result - result + for k,node in pairs scope.values + new_scope\set k, node + node else for child in *tail name = child\unwrap 'sym' - with result = scope\get name - new_scope\set name, result + with node = scope\get name + new_scope\set name, node - RTNode :children, value: Constant.wrap new_scope + RTNode :children, result: Constant.wrap new_scope fn = Constant.meta meta: @@ -201,7 +201,7 @@ function is invoked." assert param.type == 'sym', "function parameter declaration has to be a symbol" param - RTNode value: with Constant.wrap FnDef param_symbols, body, scope + RTNode result: with Constant.wrap FnDef param_symbols, body, scope .meta = { summary: "(user defined function)" examples: { "(??? #{table.concat [p! for p in *param_symbols], ' '})" } @@ -229,13 +229,13 @@ function is invoked." assert param.type == 'sym', "function parameter declaration has to be a symbol" param - value = with Constant.wrap FnDef param_symbols, body, scope + result = with Constant.wrap FnDef param_symbols, body, scope .meta = :name summary: "(user defined function)" examples: { "(#{name} #{table.concat [p! for p in *param_symbols], ' '})" } - scope\set name, RTNode :value + scope\set name, RTNode :result RTNode! do_expr = Constant.meta @@ -246,11 +246,11 @@ do_expr = Constant.meta description: " Evaluate `expr1`, `expr2`, … and return the value of the last expression." - value: class extends Builtin + value: class extends Builtin eval: (scope, tail) => scope = Scope scope children = [expr\eval scope for expr in *tail] - RTNode :children, value: children[#children].value + RTNode :children, result: children[#children].result if_ = Constant.meta meta: @@ -288,8 +288,8 @@ trace_ = Constant.meta L\trace "evaling #{@}" assert #tail == 1, "'trace!' takes exactly one parameter" - with result = L\push tail[1]\eval, scope - L\print "trace! #{tail[1]\stringify!}: #{result.value}" + with node = L\push tail[1]\eval, scope + L\print "trace! #{tail[1]\stringify!}: #{node.result}" trace = Constant.meta meta: diff --git a/alv/cell.moon b/alv/cell.moon index 933d292..a61f8de 100644 --- a/alv/cell.moon +++ b/alv/cell.moon @@ -69,7 +69,7 @@ class Cell -- then calls `Builtin:eval_cell` on it. -- -- @tparam Scope scope the scope to evaluate in - -- @treturn Result the evaluation result + -- @treturn RTNode the evaluation result eval: (scope) => head = assert @head!, Error 'syntax', "cannot evaluate empty expr" head = (head\eval scope)\const! diff --git a/alv/copilot.moon b/alv/copilot.moon index d9b674f..55e00c8 100644 --- a/alv/copilot.moon +++ b/alv/copilot.moon @@ -46,7 +46,7 @@ class Copilot Error.wrap "loading module '#{name}'", -> ok, lua = pcall require, "alv-lib.#{name}" if ok - RTNode value: Constant.wrap lua + RTNode result: Constant.wrap lua else assert @modules, "no current eval cycle?" if mod = @modules[name] diff --git a/alv/invoke.moon b/alv/invoke.moon index 03cf08e..0629b59 100644 --- a/alv/invoke.moon +++ b/alv/invoke.moon @@ -64,7 +64,7 @@ class op_invoke extends Builtin children = [L\push expr\eval, scope for expr in *tail] frame = "invoking op #{get_name @head, @cell\head!} at [#{@tag}]" - Error.wrap frame, @op\setup, [result for result in *children], scope + Error.wrap frame, @op\setup, [node for node in *children], scope any_dirty = false for input in @op\all_inputs! @@ -78,7 +78,7 @@ class op_invoke extends Builtin for input in @op\all_inputs! input\finish_setup! - RTNode :children, value: @op.out, op: @op + RTNode :children, result: @op.out, op: @op --- The `Op` instance. -- @@ -123,10 +123,10 @@ class fn_invoke extends Builtin fn_scope\set name, \make_ref! clone = body\clone @tag - result = Error.wrap frame, clone\eval, fn_scope + node = Error.wrap frame, clone\eval, fn_scope - table.insert children, result - RTNode :children, value: result.value + table.insert children, node + RTNode :children, result: node.result { :op_invoke, :fn_invoke diff --git a/alv/module.moon b/alv/module.moon index 8fc3ba7..7179ab6 100644 --- a/alv/module.moon +++ b/alv/module.moon @@ -67,8 +67,8 @@ class Module --- the last updated AST tree for this module. -- @tfield ?AST ast - --- the root Result of this module. - -- @tfield ?Result root + --- the runtime graph root of this module. + -- @tfield ?RTNode root { :Module diff --git a/alv/registry.moon b/alv/registry.moon index 1b24e9a..0d37a5c 100644 --- a/alv/registry.moon +++ b/alv/registry.moon @@ -2,8 +2,6 @@ -- `Tag` Registry. -- -- @classmod Registry -import Result from require 'alv.result' -import Error from require 'alv.error' class Registry --- internals for `Tag` diff --git a/alv/result/base.moon b/alv/result/base.moon index 26af4b4..bbbbeac 100644 --- a/alv/result/base.moon +++ b/alv/result/base.moon @@ -1,55 +1,45 @@ ---- --- base Stream interface. +-- base Result interface. -- -- implemented by `Constant`, `SigStream`, `EvtStream`, and `IOStream`. -- --- @classmod Stream +-- @classmod Result -class Stream ---- Stream interface. +class Result +--- Result interface. -- --- Methods that have to be implemented by `Stream` implementations +-- Methods that have to be implemented by `Result` implementations -- (`SigStream`, `EvtStream`, `IOStream`). -- -- @section interface - --- return whether this Stream was changed in the current tick. - -- + --- return whether this Result was changed in the current tick. -- @function dirty -- @treturn boolean - --- create a mutable copy of this Stream. + --- create a mutable copy of this Result. -- -- Used to insulate eval-cycles from each other. -- -- @function fork - -- @treturn Stream + -- @treturn Result __tostring: => "<#{@type}#{@metatype} #{@type\pp @value}>" __inherited: (cls) => cls.__base.__tostring or= @__tostring - --- the type name of this Stream's value. - -- - -- the following builtin typenames are used: - -- - -- - `str` - strings, `value` is a Lua string - -- - `sym` - symbols, `value` is a Lua string - -- - `num` - numbers, `value` is a Lua number - -- - `bool` - booleans, `value` is a Lua boolean - -- - `bang` - trigger signals, `value` is a Lua boolean - -- - `opdef` - `value` is an `Op` subclass - -- - `builtin` - `value` is a `Builtin` subclass - -- - `fndef` - `value` is a `FnDef` instance - -- - `scope` - `value` is a `Scope` instance - -- + --- the type name of this Result's value. -- @tfield string type - --- the metatype string for this Stream. + --- the metatype string for this Result. -- -- one of `=` (`Constant`), `~` (`SigStream`), -- `!` (`EvtStream` and `IOStream`). -- - -- @tfield string type + -- @tfield string metatype + + --- get the full typestring. + -- @treturn string `type .. metatype` + fulltype: => (tostring @type) .. @metatype --- documentation metadata. -- @@ -66,7 +56,7 @@ class Stream --- static functions -- @section static - --- construct a new Stream. + --- construct a new Result. -- -- @classmethod -- @tparam string type the type name @@ -74,5 +64,5 @@ class Stream new: (@type, @meta={}) => { - :Stream + :Result } diff --git a/alv/result/const.moon b/alv/result/const.moon index b9a7cf4..615e426 100644 --- a/alv/result/const.moon +++ b/alv/result/const.moon @@ -1,10 +1,10 @@ ---- -- Constant Value. -- --- Implements the `Stream` and `AST` inteface. +-- Implements the `Result` and `AST` inteface. -- -- @classmod Constant -import Stream from require 'alv.result.base' +import Result from require 'alv.result.base' import Primitive from require 'alv.type' import RTNode from require 'alv.rtnode' import Error from require 'alv.error' @@ -21,10 +21,14 @@ ancestor = (klass) -> klass = klass.__parent klass -class Constant extends Stream - --- Whether this Result is dirty. - -- - -- @treturn bool always `false`. +class Constant extends Result +--- Result interface +-- +-- `Constant` implements the `Result` interface. +-- @section result + + --- return whether this Result was changed in the current tick. + -- @treturn bool dirty: => false --- unwrap to the Lua type. @@ -53,14 +57,13 @@ class Constant extends Stream -- Compares two `SigStream`s by comparing their types and their Lua values. __eq: (other) => other.type == @type and other.value == @value - --- Stream metatype. - -- + --- Result metatype. -- @tfield string metatype (`=`) metatype: '=' --- AST interface -- --- `SignStream` implements the `AST` interface. +-- `Constant` implements the `AST` interface. -- @section ast --- evaluate this literal constant. @@ -72,11 +75,11 @@ class Constant extends Stream -- @tparam Scope scope the scope to evaluate in -- @treturn RTNode the evaluation result eval: (scope) => - return RTNode value: @ if @literal + return RTNode result: @ if @literal switch @type when num, str - RTNode value: @ + RTNode result: @ when sym Error.wrap "resolving symbol '#{@value}'", scope\get, @value else @@ -140,7 +143,7 @@ class Constant extends Stream switch ancestor val.__class when scope.Scope then 'scope' when base.FnDef then 'fndef' - when Stream then return val + when Result then return val else error "#{name}: cannot wrap '#{val.__class.__name}' instance" else diff --git a/alv/result/evt.moon b/alv/result/evt.moon index 0559a70..fdec85e 100644 --- a/alv/result/evt.moon +++ b/alv/result/evt.moon @@ -2,29 +2,18 @@ -- Stream of momentary events. -- -- @classmod EvtStream -import Stream from require 'alv.result.base' +import Result from require 'alv.result.base' -class EvtStream extends Stream ---- members --- @section members +class EvtStream extends Result +--- Result interface +-- +-- `EvtStream` implements the `Result` interface. +-- @section result - --- return whether this stream was changed in the current tick. - -- + --- return whether this Result was changed in the current tick. -- @treturn bool dirty: => @updated == COPILOT.T - --- push an event value into the stream. - -- - -- Marks this stream as dirty for the remainder of the current tick. - -- - -- @tparam any event - add: (event) => - if not @dirty! - @events = {} - - @updated = COPILOT.T - table.insert @events, event - --- get the sequence of current events (if any). -- -- Returns `events` if `dirty`, or an empty table otherwise. @@ -48,27 +37,13 @@ class EvtStream extends Stream __call: (...) => @unwrap ... __tostring: => "<#{@type}#{@metatype} #{@type\pp @value}>" - --- Stream metatype. - -- + --- the type name of this Result's value. + -- @tfield string type + + --- the metatype string for this Result. -- @tfield string metatype (`!`) metatype: '!' - --- the type name of the stream. - -- - -- the following builtin typenames are used: - -- - -- - `str` - strings, `value` is a Lua string - -- - `sym` - symbols, `value` is a Lua string - -- - `num` - numbers, `value` is a Lua number - -- - `bool` - booleans, `value` is a Lua boolean - -- - `bang` - trigger signals, `value` is a Lua boolean - -- - `opdef` - `value` is an `Op` subclass - -- - `builtin` - `value` is a `Builtin` subclass - -- - `fndef` - `value` is a `FnDef` instance - -- - `scope` - `value` is a `Scope` instance - -- - -- @tfield string type - --- documentation metadata. -- -- an optional table containing metadata for error messages and @@ -81,6 +56,22 @@ class EvtStream extends Stream -- -- @tfield ?table meta +--- members +-- @section members + + --- push an event value into the stream. + -- + -- Marks this stream as dirty for the remainder of the current tick. + -- + -- @tparam any event + add: (event) => + if not @dirty! + @events = {} + + @updated = COPILOT.T + table.insert @events, event + + --- static functions -- @section static diff --git a/alv/result/init.moon b/alv/result/init.moon index aa7a115..200e4e1 100644 --- a/alv/result/init.moon +++ b/alv/result/init.moon @@ -1,13 +1,13 @@ ---- --- `Stream` interface and implementations. +-- `Result` interface and implementations. -- --- @see Stream +-- @see Result -- @see Constant -- @see SigStream -- @see EvtStream -- @see IOStream -- --- @module stream +-- @module result import Constant from require 'alv.result.const' import SigStream from require 'alv.result.sig' import EvtStream from require 'alv.result.evt' diff --git a/alv/result/sig.moon b/alv/result/sig.moon index 6bcba65..8ca59b7 100644 --- a/alv/result/sig.moon +++ b/alv/result/sig.moon @@ -2,26 +2,19 @@ -- Continuous stream of values. -- -- @classmod SigStream -import Stream from require 'alv.result.base' +import Result from require 'alv.result.base' import Primitive from require 'alv.type' -class SigStream extends Stream ---- members --- @section members +class SigStream extends Result +--- Result interface +-- +-- `SigStream` implements the `Result` interface. +-- @section result - --- return whether this stream was changed in the current tick. - -- + --- return whether this Result was changed in the current tick. -- @treturn bool dirty: => @updated == COPILOT.T - --- update this stream's value. - -- - -- Marks this stream as dirty for the remainder of the current tick. - set: (value) => - if value != @value - @value = value - @updated = COPILOT.T - --- unwrap to the Lua type. -- -- Asserts `@type == type` if `type` is given. @@ -50,29 +43,12 @@ class SigStream extends Stream -- Compares two `SigStream`s by comparing their types and their Lua values. __eq: (other) => other.type == @type and other.value == @value - --- Stream metatype. - -- - -- @tfield string metatype (`~`) - metatype: '~' - - --- the type name of this stream. - -- - -- the following builtin typenames are used: - -- - -- - `str` - strings, `value` is a Lua string - -- - `sym` - symbols, `value` is a Lua string - -- - `num` - numbers, `value` is a Lua number - -- - `bool` - booleans, `value` is a Lua boolean - -- - `bang` - trigger signals, `value` is a Lua boolean - -- - `opdef` - `value` is an `Op` subclass - -- - `builtin` - `value` is a `Builtin` subclass - -- - `fndef` - `value` is a `FnDef` instance - -- - `scope` - `value` is a `Scope` instance - -- + --- the type name of this Result's value. -- @tfield string type - --- the wrapped Lua value. - -- @tfield any value + --- the metatype string for this Result. + -- @tfield string metatype (`~`) + metatype: '~' --- documentation metadata. -- @@ -86,6 +62,20 @@ class SigStream extends Stream -- -- @tfield ?table meta +--- members +-- @section members + + --- update this stream's value. + -- + -- Marks this stream as dirty for the remainder of the current tick. + set: (value) => + if value != @value + @value = value + @updated = COPILOT.T + + --- the wrapped Lua value. + -- @tfield any value + --- static functions -- @section static diff --git a/alv/rtnode.moon b/alv/rtnode.moon index dab4507..a8ebec3 100644 --- a/alv/rtnode.moon +++ b/alv/rtnode.moon @@ -9,33 +9,33 @@ class RTNode --- members -- @section members - --- return whether this RTNode's value is const. + --- return whether this RTNode's result is const. is_const: => not next @side_inputs - --- assert value-constness and return the value. + --- assert result-constness and return the result. -- @tparam[opt] string msg the error message to throw -- @treturn any const: (msg) => assert not (next @side_inputs), msg or "eval-time const expected" - @value + @result - --- assert this result has a value, return its type. + --- assert this result has a result, return its type. -- @treturn string type: => - assert @value, "RTNode with value expected" - @value.type + assert @result, "RTNode with result expected" + @result.type - --- assert this result has a value, returns its metatype. - -- @treturn string `"value"` or `"event"` + --- assert this result has a result, returns its metatype. + -- @treturn string `"result"` or `"event"` metatype: => - assert @value, "RTNode with value expected" - @value.metatype + assert @result, "RTNode with result expected" + @result.metatype - --- create a copy of this result with value-copy semantics. - -- the copy has the same @value and @side_inputs, but will not update + --- create a copy of this result with result-copy semantics. + -- the copy has the same @result and @side_inputs, but will not update -- anything on \tick. make_ref: => - with RTNode value: @value + with RTNode result: @result .side_inputs = @side_inputs --- poll all IOStream instances that are effecting this (sub)tree. @@ -73,15 +73,15 @@ class RTNode @op\tick! __tostring: => - buf = "<RT=#{@value}" + buf = "<RT=#{@result}" buf ..= " #{@op}" if @op buf ..= " (#{#@children} children)" if #@children > 0 buf ..= ">" buf - --- the `Stream` result + --- the `Result` result -- - -- @tfield ?Stream value + -- @tfield ?Result result --- an Op -- @@ -91,21 +91,21 @@ class RTNode -- -- @tfield {}|{RTNode,...} children - --- cached mapping of all `Stream`/`Input` pairs affecting this RTNode. + --- cached mapping of all `Result`/`Input` pairs affecting this RTNode. -- -- This is the union of all `children`s `side_inputs` and all `Input`s from - -- `op` that are not the `value` of any child. + -- `op` that are not the `result` of any child. -- - -- @tfield {[Stream]=Input,...} side_inputs + -- @tfield {[Result]=Input,...} side_inputs --- static functions -- @section static --- create a new RTNode. -- @classmethod - -- @param params table with optional keys op, value, children. default: {} + -- @param params table with optional keys op, result, children. default: {} new: (params={}) => - @value = params.value + @result = params.result @op = params.op @children = params.children or {} @@ -113,14 +113,17 @@ class RTNode for child in *@children for stream, input in pairs child.side_inputs @side_inputs[stream] = input - if child.value - is_child[child.value] = true + if child.result + is_child[child.result] = true if @op for input in @op\all_inputs! if input.io or not is_child[input.stream] @side_inputs[input.stream] = input + if @result and @result.metatype == '=' + assert not (next @side_inputs), "Const result has side_inputs" + { :RTNode } diff --git a/alv/scope.moon b/alv/scope.moon index c2c91e1..462d7a6 100644 --- a/alv/scope.moon +++ b/alv/scope.moon @@ -18,8 +18,8 @@ class Scope -- @tparam string key -- @tparam any val set_raw: (key, val) => - value = Constant.wrap val, key - @values[key] = RTNode :value + result = Constant.wrap val, key + @values[key] = RTNode :result --- set a symbol to a `RTNode`. -- @@ -28,7 +28,7 @@ class Scope set: (key, val) => L\trace "setting #{key} = #{val} in #{@}" assert val.__class == RTNode, "expected #{key}=#{val} to be RTNode" - assert val.value, Error 'type', "cannot define symbol to nil" + assert val.result, Error 'type', "cannot define symbol to nil" assert not @values[key], Error 'type', "cannot redefine symbol '#{key}'!" @values[key] = val @@ -59,7 +59,7 @@ class Scope error Error 'reference', "undefined symbol '#{start}'" if child\type! != (Primitive 'scope') error Error 'reference', "'#{start}' is not a scope" - child.value!\get rest, while_msg + child.result!\get rest, while_msg --- copy definitions from another scope. -- diff --git a/docs/gen/layout.moon b/docs/gen/layout.moon index ee0f359..60ee80d 100644 --- a/docs/gen/layout.moon +++ b/docs/gen/layout.moon @@ -16,14 +16,14 @@ render_meta = (meta) -> contents --- render an ALV Value to a HTML string -render = (name, value, prefix=nil, index=false) -> +-- render a Result to a HTML string +render = (name, result, prefix=nil, index=false) -> import div, label, code, ul, li, i, a, pre from dom id = if prefix then "#{prefix}/#{name}" else name - type = i value.type - assert value.meta, "#{id} doesn't have any metadata!" - summary = assert value.meta.summary, "#{id} doesn't have a summary!" + type = i tostring result.type + assert result.meta, "#{id} doesn't have any metadata!" + summary = assert result.meta.summary, "#{id} doesn't have a summary!" if index div { @@ -31,12 +31,12 @@ render = (name, value, prefix=nil, index=false) -> summary } else - content = switch value.type + content = switch tostring result.type when 'scope' - ul for k, result in opairs value!.values - li render k, result.value, id + ul for k, node in opairs result!.values + li render k, node.result, id else - render_meta value.meta + render_meta result.meta content.class = 'nest' div { diff --git a/docs/gen/module b/docs/gen/module index 4d8c18d..d726845 100755 --- a/docs/gen/module +++ b/docs/gen/module @@ -33,9 +33,9 @@ spit OUT, layout body: section { h2 (code name), ' module reference' h3 'index' - ul for key, res in opairs module.values - li render key, res.value, nil, true + ul for key, node in opairs module.values + li render key, node.result, nil, true h3 'details' - ul for key, res in opairs module.values - li render key, res.value + ul for key, node in opairs module.values + li render key, node.result } diff --git a/docs/internals/extensions.md b/docs/internals/extensions.md index 358aa7e..bc07e58 100644 --- a/docs/internals/extensions.md +++ b/docs/internals/extensions.md @@ -11,13 +11,13 @@ these are exported in the `base` module. ## documentation metadata The lua module should return a `Scope` or a table that will be converted using -`Scope.from_table`. All exports should be documented using `ValueStream.meta`, +`Scope.from_table`. All exports should be documented using `Constant.meta`, which attaches a `meta` table to the value that is used for error messages, documentation generation and [`(doc)`][builtins-doc]. - import ValueStream from require 'alv.base' + import Constant from require 'alv.base' - two = ValueStream.meta + two = Constant.meta meta: name: 'two' summary: "the number two" @@ -43,9 +43,9 @@ Most extensions will want to define a number of *Op*s to be used by the user. They are implemented by deriving from the `Op` class and implementing at least the `Op:setup` and `Op:tick` methods. - import ValueStream, Op, Input, evt from require 'alv.base' + import Constant, SigStream, Op, Input, evt from require 'alv.base' - total_sum = ValueStream.meta + total_sum = Constant.meta meta: name: 'total-sum' summary: "Keep a total of incoming numbers." @@ -56,7 +56,7 @@ the `Op:setup` and `Op:tick` methods. new: (...) => super ... @state or= { total: 0 } - @out or= ValueStream 'num', @state.total + @out or= SigStream 'num', @state.total setup: (inputs, scope) => num = evt.num\match inputs @@ -89,9 +89,9 @@ for more information). pattern = evt.bang + val.str + val.num*3 + -evt! { trig, str, numbers, optional } = pattern\match inputs -This example matches first an `EventStream` of type `bang`, then a `ValueStream` +This example matches first an `EvtStream` of type `bang`, then a `SigStream` of type `str`, followed by one, two or three `num`-values and finally an -optional argument `EventStream` of any type. `:match` will throw an error if it +optional argument `EvtStream` of any type. `:match` will throw an error if it couldn't (fully) match the arguments and otherwise return a structured mapping of the inputs. @@ -111,12 +111,12 @@ update when the value changes, it's enough to update only when the trigger input changes and simply read the value in that moment. *Hot* inputs on the other hand mark the input stream as a dependency for the -Op. Depending on the type of `Stream`, the semantics are a little different: +Op. Depending on the type of `Result`, the semantics are a little different: -- For `ValueStream`s, the Op updates whenever the current value changes. When +- For `SigStream`s, the Op updates whenever the current value changes. When an input stream is swapped out for another one at evaltime, but their values are momentarily equal, the input is not considered dirty. -- For `EventStream`s and `IOStream`s, the Op updates whenever the stream is +- For `EvtStream`s and `IOStream`s, the Op updates whenever the stream is dirty. There is no special handling when the stream is swapped out at evaltime. @@ -142,26 +142,29 @@ long as all 'leaf values' are `Input` instances. The following are both valid: values: { (Inputs.cold a), (Inputs.cold b), (Inputs.cold c) } #### output setup -When `Op:setup` finishes, `@out` has to be set to a `Stream` instance. The +When `Op:setup` finishes, `@out` has to be set to a `Result` instance. The instance can be created in `Op:setup`, or by overriding the constructor and delegating to the original one using `super`. In general setting it in the constructor is preferred, and it is only moved to `Op:setup` if the output type depends on the arguments received. -There are three types of `Stream`s that can be created: +There are four types of `Result`s that can be created: -- `ValueStream`s track *continuous values*. They can only have one value per - tick, and downstream Ops will not update when a *ValueStream* has been set - to the same value it already had. They are updated using `ValueStream:set`. -- `EventStream`s transmit *momentary events*. They can transmit multiple events - in a single tick. `EventStream`s do not keep a value set on the last tick on - the next tick. They are updated using `EventStream:add`. -- `IOStream`s are like `EventStream`s, but their `IOStream:poll` method is +- `SigStream`s track *continuous values*. They can only have one value per + tick, and downstream Ops will not update when a *SigStream* has been set + to the same value it already had. They are updated using `SigStream:set`. +- `EvtStream`s transmit *momentary events*. They can transmit multiple events + in a single tick. `EvtStream`s do not keep a value set on the last tick on + the next tick. They are updated using `EvtStream:add`. +- `IOStream`s are like `EvtStream`s, but their `IOStream:poll` method is polled by the event loop at the start of every tick. This gives them a chance to effectively create changes 'out of thin air' and kickstart the execution of the dataflow engine. All *runtime* execution is due to an `IOStream` becoming dirty somewhere. See the section on implementing `IOStream`s below for more information. +- `Constant`s do not change in-between evalcycles. Usually Ops do not output + `Constant`s directly, althrough `SigStream`s outputs are automatically + 'downgraded' to `Constant`s when the Op has no reactive inputs. ### Op:tick `Op:tick` is called whenever any of the inputs are *dirty*. This is where the @@ -179,7 +182,7 @@ familiar with the relevant internal interfaces (especially `AST`, `Result`, and `Scope`). ## defining `IOStream`s -`IOStream`s are `EventStream`s that can 'magically' create events out of +`IOStream`s are `EvtStream`s that can 'magically' create events out of nothing. They are the source of all processing in alv. Whenever you want to bring events into alv from an external protocol or application, an IOStream will be necessary. @@ -196,7 +199,7 @@ To implement a custom IOStream, create it as a class that inherits from the if math.random! < 0.1 @add true -In the constructor, you should call the super-constructor `EventStream.new` to +In the constructor, you should call the super-constructor `EvtStream.new` to set the event type. Often this will be a custom event that is only used inside your extension (such as e.g. the `midi/port` type in the [midi][modules-midi] module), but it can also be a primitive type like `'num'` in this example. In @@ -209,7 +212,7 @@ them this way in a real extension. ### using `IOStream`s There's a couple of ways IOStreams can be used and exposed to the user of your extension. You can either expose an instance of your IOStream directly -(documented using `ValueStream.meta`), or offer an Op that creates and returns +(documented using `SigStream.meta`), or offer an Op that creates and returns an instance in `Op.out` - that way the IOStream can be created only on demand and take parameters. It is also possible to not exepose the IOStream at all, and rather pass it as a hardcoded input into an Op's `Op.inputs`. diff --git a/spec/input_spec.moon b/spec/input_spec.moon index 371a3ee..8a8defe 100644 --- a/spec/input_spec.moon +++ b/spec/input_spec.moon @@ -12,7 +12,7 @@ class MyIO extends IOStream dirty: => @is_dirty basic_tests = (stream, input) -> - it 'gives access to the Stream', -> + it 'gives access to the Result', -> assert.is.equal stream, input.stream it 'forwards :unwrap', -> diff --git a/spec/match_spec.moon b/spec/match_spec.moon index e3483e3..1e2ce61 100644 --- a/spec/match_spec.moon +++ b/spec/match_spec.moon @@ -1,14 +1,14 @@ import val, evt from require 'alv.base.match' -import RTNode, Primitive, SigStream, EvtStream from require 'alv' +import RTNode, Primitive, SigStream, EvtStream, Error from require 'alv' mk_val = (type, const) -> - value = SigStream Primitive type - with RTNode :value + result = SigStream Primitive type + with RTNode :result .side_inputs = { 'fake' } unless const mk_evt = (type, const) -> - value = EvtStream Primitive type - with RTNode :value + result = EvtStream Primitive type + with RTNode :result .side_inputs = { 'fake' } unless const describe 'val and evt', -> @@ -224,11 +224,13 @@ describe 'complex nesting', -> bang = mk_evt 'bang' str = mk_val 'str' num = mk_val 'num' - pattern = -evt.bang + val.num*4 + (val.str + (val.num / val.str))\named('key', 'val')^0 + pattern = -evt.bang + val.num*4 + + (val.str + (val.num / val.str))\named('key', 'val')^0 it 'just works', -> assert.is.same { bang, { num, num }, {} }, pattern\match { bang, num, num } - assert.is.same { nil, { num }, { { key: str, val: num }, { key: str, val: str } } }, + assert.is.same { nil, { num }, { { key: str, val: num }, + { key: str, val: str } } }, pattern\match { num, str, num, str, str } assert.has.error -> pattern\match { num, str } assert.has.error -> pattern\match { bang, num, num, num, num, num, num } @@ -238,3 +240,8 @@ describe 'complex nesting', -> it 'stringifies well', -> assert.is.equal '(bang!? num{1-4} (str (num | str)){0-*})', tostring pattern + + it 'gives useful error feedback', -> + msg = "couldn't match arguments (num~ str~ bool~) against pattern #{pattern}" + err = Error 'argument', msg + assert.has.error (-> pattern\match { num, str, mk_val 'bool' }), err diff --git a/spec/result/const_spec.moon b/spec/result/const_spec.moon index 55d5175..31eec4e 100644 --- a/spec/result/const_spec.moon +++ b/spec/result/const_spec.moon @@ -111,9 +111,9 @@ describe 'Constant', -> it 'looks up symbols in the scope', -> scope = with Scope! - \set 'number', RTNode value: Constant.num 3 - \set 'hello', RTNode value: Constant.str "world" - \set 'goodbye', RTNode value: Constant.sym "again" + \set 'number', RTNode result: Constant.num 3 + \set 'hello', RTNode result: Constant.str "world" + \set 'goodbye', RTNode result: Constant.sym "again" assert_eval = (sym, val) -> const = Constant.sym sym diff --git a/spec/rtnode_spec.moon b/spec/rtnode_spec.moon index a842a74..a6cd63d 100644 --- a/spec/rtnode_spec.moon +++ b/spec/rtnode_spec.moon @@ -1,6 +1,7 @@ import do_setup from require 'spec.test_setup' import RTNode, Scope, SimpleRegistry from require 'alv' -import Primitive, Input, Op, Constant, EvtStream, IOStream from require 'alv.base' +import Primitive, Input, Op, Constant, SigStream, EvtStream, IOStream + from require 'alv.base' setup do_setup num = Primitive 'num' @@ -10,99 +11,99 @@ op_with_inputs = (inputs) -> with Op! \setup inputs if inputs -result_with_sideinput = (value, input) -> - with RTNode :value - .side_inputs = { [value]: input } +node_with_sideinput = (result, input) -> + with RTNode :result + .side_inputs = { [result]: input } class DirtyIO extends IOStream new: => super Primitive 'dirty-io' dirty: => true describe 'RTNode', -> - it 'wraps value, children', -> - value = Constant.num 3 + it 'wraps result, children', -> + result = Constant.num 3 a = RTNode! b = RTNode! children = { a, b } - result = RTNode :value, :children + node = RTNode :result, :children - assert.is.equal value, result.value - assert.is.same children, result.children + assert.is.equal result, node.result + assert.is.same children, node.children it ':type gets type and assets value', -> - result = RTNode value: Constant.num 2 - assert.is.equal num, result\type! + node = RTNode result: Constant.num 2 + assert.is.equal num, node\type! - result = RTNode! - assert.has.error -> result\type! + node = RTNode! + assert.has.error -> node\type! it ':is_const', -> - value = Constant.num 2 - pure = RTNode :value - impure = result_with_sideinput value, {} + result = Constant.num 2 + pure = RTNode :result + impure = node_with_sideinput result, {} assert.is.true pure\is_const! assert.is.false impure\is_const! - assert.is.equal value, pure\const! + assert.is.equal result, pure\const! assert.has.error -> impure\const! assert.has.error (-> impure\const 'test'), 'test' it ':make_ref', -> - value = Constant.num 2 - input = Input.hot value + result = SigStream.num 2 + input = Input.hot result op = op_with_inputs { input } - thick = RTNode :value, :op, children: { RTNode!, RTNode! } + thick = RTNode :result, :op, children: { RTNode!, RTNode! } ref = thick\make_ref! assert ref - assert.is.equal thick.value, ref.value + assert.is.equal thick.result, ref.result assert.is.same thick.side_inputs, ref.side_inputs assert.is.same {}, ref.children assert.is.nil ref.op it 'lifts up inputs from op', -> - event = Constant bang, false + event = EvtStream bang event_input = Input.hot event - value = Constant num, 4 + value = SigStream num, 4 value_input = Input.hot value op = op_with_inputs { event_input, value_input } - result = RTNode op: op, :value + node = RTNode op: op, result: value - assert.is.equal op, result.op + assert.is.equal op, node.op assert.is.same { [event]: event_input, [value]: value_input }, - result.side_inputs + node.side_inputs it 'does not lift up op inputs that are also child values', -> - event = Constant bang, false + event = EvtStream bang event_input = Input.hot event - value = Constant num, 4 - value_input = Input.hot value + result = SigStream num, 4 + value_input = Input.hot result op = op_with_inputs { event_input, value_input } - result = RTNode op: op, :value, children: { RTNode :value } + node = RTNode op: op, :result, children: { RTNode :result } - assert.is.same { [event]: event_input }, result.side_inputs + assert.is.same { [event]: event_input }, node.side_inputs it 'lifts up side_inputs from children', -> - event_value = Constant bang, false + event_value = EvtStream bang event_input = Input.hot event_value event = RTNode op: op_with_inputs { event_input } assert.is.same { [event_value]: event_input }, event.side_inputs - value_value = Constant num, 4 + value_value = SigStream num, 4 value_input = Input.hot value_value value = RTNode op: op_with_inputs { value_input } assert.is.same { [value_value]: value_input }, value.side_inputs - result = RTNode children: { event, value } + node = RTNode children: { event, value } assert.is.same { [event_value]: event_input, [value_value]: value_input }, - result.side_inputs + node.side_inputs describe ':tick', -> local a_value, a_child, a_input @@ -110,11 +111,11 @@ describe 'RTNode', -> before_each -> a_value = EvtStream num a_input = Input.hot a_value - a_child = result_with_sideinput a_value, a_input + a_child = node_with_sideinput a_value, a_input b_value = EvtStream num b_input = Input.hot b_value - b_child = result_with_sideinput b_value, b_input + b_child = node_with_sideinput b_value, b_input it 'updates children when a side_input is dirty', -> a_value\add 1 @@ -124,8 +125,8 @@ describe 'RTNode', -> a = spy.on a_child, 'tick' b = spy.on b_child, 'tick' - result = RTNode children: { a_child, b_child } - result\tick! + node = RTNode children: { a_child, b_child } + node\tick! assert.spy(a).was_called_with match.ref a_child assert.spy(b).was_called_with match.ref b_child @@ -137,8 +138,8 @@ describe 'RTNode', -> a = spy.on a_child, 'tick' b = spy.on b_child, 'tick' - result = RTNode children: { a_child, b_child } - result\tick! + node = RTNode children: { a_child, b_child } + node\tick! assert.spy(a).was_not_called! assert.spy(b).was_not_called! @@ -151,8 +152,8 @@ describe 'RTNode', -> op = op_with_inputs a: Input.hot a_value s = spy.on op, 'tick' - result = RTNode :op, children: { a_child, b_child } - result\tick! + node = RTNode :op, children: { a_child, b_child } + node\tick! assert.spy(s).was_called_with match.ref op @@ -164,8 +165,8 @@ describe 'RTNode', -> op = op_with_inputs { Input.hot b_value } s = spy.on op, 'tick' - result = RTNode :op, children: { a_child, b_child } - result\tick! + node = RTNode :op, children: { a_child, b_child } + node\tick! assert.spy(s).was_not_called! @@ -174,10 +175,10 @@ describe 'RTNode', -> io = DirtyIO! input = Input.hot io op = op_with_inputs { input } - result = RTNode :op + node = RTNode :op s = spy.on io, 'poll' - assert.is.same { [io]: input }, result.side_inputs - result\poll_io! + assert.is.same { [io]: input }, node.side_inputs + node\poll_io! assert.spy(s).was_called_with match.ref io diff --git a/spec/scope_spec.moon b/spec/scope_spec.moon index 4798391..7278b9e 100644 --- a/spec/scope_spec.moon +++ b/spec/scope_spec.moon @@ -6,7 +6,7 @@ Logger\init 'silent' class TestOp extends Op new: (...) => super ... -wrap_res = (value) -> RTNode :value +wrap_res = (result) -> RTNode :result num = Primitive 'num' str = Primitive 'str' @@ -21,36 +21,31 @@ describe 'Scope', -> scope\set_raw 'num', 3 got = (scope\get 'num')\const! - assert.is.equal num, got.type - assert.is.equal 3, got.value + assert.is.equal (Constant.num 3), got test 'strings', -> scope\set_raw 'str', "im a happy string" got = (scope\get 'str')\const! - assert.is.equal str, got.type - assert.is.equal "im a happy string", got.value + assert.is.equal (Constant.str "im a happy string"), got test 'Values', -> pi = Constant.num 3.14 scope\set_raw 'pi', pi - assert.is.equal pi, (scope\get 'pi')\const! test 'Opdefs', -> scope\set_raw 'test', TestOp got = (scope\get 'test')\const! - assert.is.equal opdef, got.type - assert.is.equal TestOp, got.value + assert.is.equal TestOp, got opdef test 'Scopes', -> sub = Scope! scope\set_raw 'sub', sub got = (scope\get 'sub')\const! - assert.is.equal scope_t, got.type - assert.is.equal sub, got.value + assert.is.equal sub, got scope_t test 'tables', -> pi = Constant.num 3.14 @@ -73,18 +68,15 @@ describe 'Scope', -> } got = (scope\get 'num')\const! - assert.is.equal num, got.type - assert.is.equal 3, got.value + assert.is.equal 3, got num got = (scope\get 'str')\const! - assert.is.equal str, got.type - assert.is.equal "im a happy string", got.value + assert.is.equal "im a happy string", got str assert.is.equal pi, (scope\get 'pi')\const! got = (scope\get 'test')\const! - assert.is.equal opdef, got.type - assert.is.equal TestOp, got.value + assert.is.equal TestOp, got opdef got = (scope\get 'math')\const! assert.is.equal scope_t, got.type @@ -124,15 +116,13 @@ describe 'Scope', -> it 'allows access', -> got = (scope\get 'inherited')\const! - assert.is.equal str, got.type - assert.is.equal "inherited string", got.value + assert.is.equal "inherited string", got str it 'can be shadowed', -> scope\set_raw 'hidden', "overwritten" got = (scope\get 'hidden')\const! - assert.is.equal str, got.type - assert.is.equal "overwritten", got.value + assert.is.equal "overwritten", got str describe 'dynamic inheritance', -> root = Scope! @@ -147,18 +137,18 @@ describe 'Scope', -> it 'follows a different parent', -> merged = Scope root, dyn_root - assert.is.equal 'normal', (merged\get 'normal').value! - assert.is.equal 'dynamic', (merged\get '*dynamic*').value! + assert.is.equal 'normal', (merged\get 'normal').result! + assert.is.equal 'dynamic', (merged\get '*dynamic*').result! it 'falls back to the immediate parent', -> merged = Scope root - assert.is.equal 'normal', (merged\get '*dynamic*').value! + assert.is.equal 'normal', (merged\get '*dynamic*').result! it 'looks in self first', -> merged = Scope root merged\set_raw '*dynamic*', 'merged' - assert.is.equal 'merged', (merged\get '*dynamic*').value! + assert.is.equal 'merged', (merged\get '*dynamic*').result! it 'can resolve nested', -> merged = Scope root, dyn_root - assert.is.equal 3, (merged\get '*nested*/value').value! + assert.is.equal 3, (merged\get '*nested*/value').result! |
