diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-05-08 09:41:08 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:23:21 +0000 |
| commit | 99ca67938c0145db37182bdb709d9424a20dfee0 (patch) | |
| tree | 6df4e2b5fde650aa3c7e36893eb1780f932d56bd | |
| parent | release v0.1 (diff) | |
| download | alive-99ca67938c0145db37182bdb709d9424a20dfee0.tar.gz alive-99ca67938c0145db37182bdb709d9424a20dfee0.zip | |
wip new type system and refactoring
- Result -> RTNode
- Stream -> Result
- ValueStream -> SigStream
- EventStream -> EvtStream
| -rw-r--r-- | alv/ast.moon | 2 | ||||
| -rw-r--r-- | alv/base/init.moon | 15 | ||||
| -rw-r--r-- | alv/base/input.moon | 27 | ||||
| -rw-r--r-- | alv/base/match.moon | 29 | ||||
| -rw-r--r-- | alv/builtin.moon | 75 | ||||
| -rw-r--r-- | alv/cell.moon | 11 | ||||
| -rw-r--r-- | alv/copilot.moon | 8 | ||||
| -rw-r--r-- | alv/init.moon | 16 | ||||
| -rw-r--r-- | alv/invoke.moon | 27 | ||||
| -rw-r--r-- | alv/parsing.moon | 10 | ||||
| -rw-r--r-- | alv/result/base.moon (renamed from alv/stream/base.moon) | 14 | ||||
| -rw-r--r-- | alv/result/const.moon (renamed from alv/stream/value.moon) | 161 | ||||
| -rw-r--r-- | alv/result/evt.moon (renamed from alv/stream/event.moon) | 23 | ||||
| -rw-r--r-- | alv/result/init.moon | 21 | ||||
| -rw-r--r-- | alv/result/io.moon (renamed from alv/stream/io.moon) | 12 | ||||
| -rw-r--r-- | alv/result/sig.moon | 121 | ||||
| -rw-r--r-- | alv/rtnode.moon (renamed from alv/result.moon) | 28 | ||||
| -rw-r--r-- | alv/scope.moon | 25 | ||||
| -rw-r--r-- | alv/stream/init.moon | 18 | ||||
| -rw-r--r-- | alv/types.moon | 101 | ||||
| -rw-r--r-- | spec/cell_spec.moon | 18 | ||||
| -rw-r--r-- | spec/input_spec.moon | 25 | ||||
| -rw-r--r-- | spec/match_spec.moon | 11 | ||||
| -rw-r--r-- | spec/parsing_spec.moon | 53 | ||||
| -rw-r--r-- | spec/result/const_spec.moon | 149 | ||||
| -rw-r--r-- | spec/result/sig_spec.moon | 109 | ||||
| -rw-r--r-- | spec/rtnode_spec.moon (renamed from spec/result_spec.moon) | 71 | ||||
| -rw-r--r-- | spec/scope_spec.moon | 46 | ||||
| -rw-r--r-- | spec/value_spec.moon | 180 |
29 files changed, 845 insertions, 561 deletions
diff --git a/alv/ast.moon b/alv/ast.moon index 7090869..cff8947 100644 --- a/alv/ast.moon +++ b/alv/ast.moon @@ -1,7 +1,7 @@ ---- -- AST Node Interface. -- --- implemented by `ValueStream` and `Cell`. +-- implemented by `Constant` and `Cell`. -- -- @classmod AST diff --git a/alv/base/init.moon b/alv/base/init.moon index c37d85c..71e9cea 100644 --- a/alv/base/init.moon +++ b/alv/base/init.moon @@ -11,10 +11,11 @@ -- @see Input -- @see base.match.val -- @see base.match.evt --- @see ValueStream --- @see EventStream +-- @see Constant +-- @see SigStream +-- @see EvtStream -- @see IOStream --- @see Result +-- @see RTNode -- @see Error import Op from require 'alv.base.op' @@ -22,8 +23,8 @@ import Builtin from require 'alv.base.builtin' import FnDef from require 'alv.base.fndef' import Input from require 'alv.base.input' import val, evt from require 'alv.base.match' -import ValueStream, EventStream, IOStream from require 'alv.stream' -import Result from require 'alv.result' +import Constant, SigStream, EvtStream, IOStream from require 'alv.result' +import RTNode from require 'alv.rtnode' import Error from require 'alv.error' { @@ -34,6 +35,6 @@ import Error from require 'alv.error' :val, :evt -- redundant exports, to keep anything an extension might need in one import - :ValueStream, :EventStream, :IOStream - :Result, :Error + :Constant, :SigStream, :EvtStream, :IOStream + :RTNode, :Error } diff --git a/alv/base/input.moon b/alv/base/input.moon index fe01f88..dea91c9 100644 --- a/alv/base/input.moon +++ b/alv/base/input.moon @@ -2,8 +2,8 @@ -- Update scheduling policy for `Op` arguments. -- -- @classmod Input -import ValueStream, EventStream, IOStream from require 'alv.stream' -import Result from require 'alv.result' +import Constant, SigStream, EvtStream, IOStream from require 'alv.result' +import RTNode from require 'alv.rtnode' inherits = (klass, frm) -> assert klass, "cant find the ancestor of nil" @@ -53,7 +53,7 @@ class Input -- -- 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}. + -- `stream`:@{SigStream:dirty|dirty}. -- -- @treturn bool whether processing is necessary dirty: => @stream\dirty! @@ -77,7 +77,7 @@ class Input --- the current value -- - -- @tfield ValueStream stream + -- @tfield SigStream stream --- members -- @section members @@ -98,9 +98,9 @@ class Input -- Never marked dirty. Use this for input streams that are only read when -- another `Input` is dirty. -- - -- @tparam Stream|Result value + -- @tparam Stream|RTNode value @cold: (value) -> - if value.__class == Result + if value.__class == RTNode value = assert value.value, "Input from result without value!" ColdInput value @@ -108,15 +108,15 @@ class Input -- -- Behaviour depends on what kind of `Stream` `value` is: -- - -- - `ValueStream`: Marked dirty only if old and new `ValueStream` differ. - -- - `EventStream` and `IOStream`: Marked dirty only if the current - -- `EventStream` is dirty. + -- - `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|Result value + -- @tparam Stream|RTNode value @hot: (value) -> - if value.__class == Result + if value.__class == RTNode value = assert value.value, "Input from result without value!" InputType = match_parent value, mapping @@ -137,8 +137,9 @@ class IOInput extends Input io: true mapping = { - [ValueStream]: ValueInput - [EventStream]: Input + [Constant]: ColdInput + [SigStream]: ValueInput + [EvtStream]: Input [IOStream]: IOInput } diff --git a/alv/base/match.moon b/alv/base/match.moon index 62075c0..819b0b4 100644 --- a/alv/base/match.moon +++ b/alv/base/match.moon @@ -2,7 +2,7 @@ --- 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 +-- `Type`. It can match `SigStream`s and `EvtStream`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: @@ -21,12 +21,12 @@ -- - `-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) +-- pass a sequence of `RTNode`s. The method will either return the captured +-- `RTNode`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 +-- Recalling patterns will memorize the first RTNode they match, and +-- only match further RTNodes of the same type. For example -- -- arg = (val.num / val.str)! -- pattern = arg + arg @@ -45,14 +45,11 @@ -- -- @module base.match import Error from require 'alv.error' -import ValueStream, EventStream from require 'alv.stream' +import Primitive from require 'alv.types' local Repeat, Sequence, Choice, Optional -typestr = (result) -> - str = result\type! - str ..= '!' if result\metatype! == 'event' - str +typestr = (result) -> tostring result.value class Pattern match: (seq) => @@ -107,13 +104,17 @@ class Type extends Pattern capture: (seq, i) => return unless seq[i] type, mt = seq[i]\type!, seq[i]\metatype! - return unless @metatype == mt + if @metatype == 'event' + return unless mt == '!' + else + return if mt == '!' + match = if @type then type == @type else @remember type if match 1, seq[i] __tostring: => - str = @type or @metatype + str = tostring @type or @metatype str ..= '!' if @metatype == 'event' str @@ -272,7 +273,7 @@ class Optional extends Pattern -- @table val val = setmetatable {}, { __index: (key) => - with v = Type 'value', key + with v = Type 'value', Primitive key @[key] = v __call: (...) => Type 'value', ... @@ -290,7 +291,7 @@ val = setmetatable {}, { -- @table evt evt = setmetatable {}, { __index: (key) => - with v = Type 'event', key + with v = Type 'event', Primitive key @[key] = v __call: (...) => Type 'event', ... diff --git a/alv/builtin.moon b/alv/builtin.moon index c80e483..767d8e1 100644 --- a/alv/builtin.moon +++ b/alv/builtin.moon @@ -6,16 +6,17 @@ -- -- @module builtin import Builtin, Op, FnDef, Input, val, evt from require 'alv.base' -import ValueStream, LiteralValue from require 'alv.stream.value' +import Constant from require 'alv.result' import Error from require 'alv.error' -import Result from require 'alv.result' +import RTNode from require 'alv.rtnode' import Cell from require 'alv.cell' import Scope from require 'alv.scope' import Tag from require 'alv.tag' import op_invoke from require 'alv.invoke' +import Primitive from require 'alv.types' lfs = require 'lfs' -doc = ValueStream.meta +doc = Constant.meta meta: name: 'doc' summary: "Print documentation in console." @@ -36,11 +37,11 @@ doc = ValueStream.meta assert #tail == 1, "'doc' takes exactly one parameter" result = L\push tail[1]\eval, scope - with Result children: { def } + with RTNode children: { def } meta = result.value.meta L\print "(doc #{tail[1]}):\n#{format_meta meta}\n" -def = ValueStream.meta +def = Constant.meta meta: name: 'def' summary: "Declare symbols in current scope." @@ -63,9 +64,9 @@ Define the symbols `sym1`, `sym2`, … to resolve to the values of `val-expr1`, with val_expr\eval scope scope\set name, \make_ref! - Result :children + RTNode :children -use = ValueStream.meta +use = Constant.meta meta: name: 'use' summary: "Merge scopes into current scope." @@ -82,9 +83,9 @@ All arguments have to be evaltime constant." value = result\const! scope\use value\unwrap 'scope', "'use' only works on scopes" - Result! + RTNode! -require_ = ValueStream.meta +require_ = Constant.meta meta: name: 'require' summary: "Load a module." @@ -102,7 +103,7 @@ require_ = ValueStream.meta L\trace @, "loading module #{name}" COPILOT\require name -import_ = ValueStream.meta +import_ = Constant.meta meta: name: 'import' summary: "Require and define modules." @@ -120,9 +121,9 @@ current scope." name = child\unwrap 'sym' with COPILOT\require name scope\set name, \make_ref! - Result :children + RTNode :children -import_star = ValueStream.meta +import_star = Constant.meta meta: name: 'import*' summary: "Require and use modules." @@ -138,9 +139,9 @@ Requires modules `sym1`, `sym2`, … and merges them into the current scope." children = for i, child in ipairs tail with COPILOT\require child\unwrap 'sym' scope\use .value\unwrap 'scope' - Result :children + RTNode :children -export_ = ValueStream.meta +export_ = Constant.meta meta: name: 'export' summary: "Evaluate definitions in a new scope and return it." @@ -152,9 +153,9 @@ Evaluate `expr1`, `expr2`, … in a new Scope and return scope." eval: (scope, tail) => new_scope = Scope scope children = [expr\eval new_scope for expr in *tail] - Result :children, value: ValueStream.wrap new_scope + RTNode :children, value: Constant.wrap new_scope -export_star = ValueStream.meta +export_star = Constant.meta meta: name: 'export*' summary: "Export specific symbol definitions as a module/scope." @@ -179,9 +180,9 @@ Copies the containing scope if no symbols are given." with result = scope\get name new_scope\set name, result - Result :children, value: ValueStream.wrap new_scope + RTNode :children, value: Constant.wrap new_scope -fn = ValueStream.meta +fn = Constant.meta meta: name: 'fn' summary: "Declare a function." @@ -201,13 +202,13 @@ function is invoked." assert param.type == 'sym', "function parameter declaration has to be a symbol" param - Result value: with ValueStream.wrap FnDef param_symbols, body, scope + RTNode value: with Constant.wrap FnDef param_symbols, body, scope .meta = { summary: "(user defined function)" examples: { "(??? #{table.concat [p! for p in *param_symbols], ' '})" } } -defn = ValueStream.meta +defn = Constant.meta meta: name: 'defn' summary: "Define a function." @@ -229,16 +230,16 @@ function is invoked." assert param.type == 'sym', "function parameter declaration has to be a symbol" param - value = with ValueStream.wrap FnDef param_symbols, body, scope + value = 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, Result :value - Result! + scope\set name, RTNode :value + RTNode! -do_expr = ValueStream.meta +do_expr = Constant.meta meta: name: 'do' summary: "Evaluate multiple expressions in a new scope." @@ -250,9 +251,9 @@ Evaluate `expr1`, `expr2`, … and return the value of the last expression." eval: (scope, tail) => scope = Scope scope children = [expr\eval scope for expr in *tail] - Result :children, value: children[#children].value + RTNode :children, value: children[#children].value -if_ = ValueStream.meta +if_ = Constant.meta meta: name: 'if' summary: "Make an evaltime const choice." @@ -277,7 +278,7 @@ to `then-expr`, otherwise it is equivalent to `else-xpr` if given, or nil otherw elseif xelse xelse\eval scope -trace_ = ValueStream.meta +trace_ = Constant.meta meta: name: 'trace!' summary: "Trace an expression's value at evaltime." @@ -291,7 +292,7 @@ trace_ = ValueStream.meta with result = L\push tail[1]\eval, scope L\print "trace! #{tail[1]\stringify!}: #{result.value}" -trace = ValueStream.meta +trace = Constant.meta meta: name: 'trace' summary: "Trace an expression's values at runtime." @@ -313,13 +314,13 @@ trace = ValueStream.meta tag = @tag\clone Tag.parse '-1' inner = Cell tag, { - LiteralValue 'opdef', traceOp, 'trace' - ValueStream.str tostring tail[1] + Constant.literal (Primitive 'opdef'), traceOp, 'trace' + Constant.str tostring tail[1] tail[1] } inner\eval scope -print = ValueStream.meta +print = Constant.meta meta: name: 'print' summary: "Print string values." @@ -348,23 +349,23 @@ Scope.from_table { export: export_ 'export*': export_star - true: ValueStream.meta + true: Constant.meta meta: name: 'true' summary: "The boolean constant `true`." - value: ValueStream.bool true + value: Constant.bool true - false: ValueStream.meta + false: Constant.meta meta: name: 'false' summary: "The boolean constant `false`." - value: ValueStream.bool false + value: Constant.bool false - bang: ValueStream.meta + bang: Constant.meta meta: name: 'bang' summary: "A `bang` value-constant." - value: ValueStream 'bang', true + value: Constant 'bang', true :fn, :defn 'do': do_expr diff --git a/alv/cell.moon b/alv/cell.moon index 6d5e207..2e00195 100644 --- a/alv/cell.moon +++ b/alv/cell.moon @@ -5,9 +5,10 @@ -- nodes), a `Tag`, and optionally the internal whitespace as parsed. -- -- @classmod Cell -import ValueStream from require 'alv.stream' +import Constant from require 'alv.result' import Error from require 'alv.error' import op_invoke, fn_invoke from require 'alv.invoke' +import Primitive from require 'alv.types' import Tag from require 'alv.tag' local RootCell @@ -73,11 +74,11 @@ class Cell head = assert @head!, Error 'syntax', "cannot evaluate empty expr" head = (head\eval scope)\const! Builtin = switch head.type - when 'opdef' + when (Primitive 'opdef') op_invoke - when 'fndef' + when (Primitive 'fndef') fn_invoke - when 'builtin' + when (Primitive 'builtin') head\unwrap! else error Error 'type', "#{head} is not an opdef, fndef or builtin" @@ -157,7 +158,7 @@ class Cell -- @type RootCell class RootCell extends Cell - head: => ValueStream.sym 'do' + head: => Constant.sym 'do' tail: => @children clone: (parent) => diff --git a/alv/copilot.moon b/alv/copilot.moon index 7ef2134..d9b674f 100644 --- a/alv/copilot.moon +++ b/alv/copilot.moon @@ -6,8 +6,8 @@ lfs = require 'lfs' import Scope from require 'alv.scope' import Module from require 'alv.module' import Error from require 'alv.error' -import Result from require 'alv.result' -import ValueStream from require 'alv.stream' +import RTNode from require 'alv.rtnode' +import Constant from require 'alv.result' export COPILOT @@ -41,12 +41,12 @@ class Copilot --- require a module. -- @tparam string name - -- @treturn Result result + -- @treturn RTNode root require: (name) => Error.wrap "loading module '#{name}'", -> ok, lua = pcall require, "alv-lib.#{name}" if ok - Result value: ValueStream.wrap lua + RTNode value: Constant.wrap lua else assert @modules, "no current eval cycle?" if mod = @modules[name] diff --git a/alv/init.moon b/alv/init.moon index f2fed2f..95432f3 100644 --- a/alv/init.moon +++ b/alv/init.moon @@ -13,8 +13,9 @@ cycle = require 'alv.cycle' version = require 'alv.version' import Logger from require 'alv.logger' -import ValueStream, EventStream, IOStream from require 'alv.stream' -import Result from require 'alv.result' + +import Constant, SigStream, EvtStream, IOStream from require 'alv.result' +import RTNode from require 'alv.rtnode' import Scope from require 'alv.scope' import Error from require 'alv.error' import Registry, SimpleRegistry from require 'alv.registry' @@ -34,10 +35,11 @@ import Copilot from require 'alv.copilot' --- exports -- @table exports -- @tfield version version --- @tfield ValueStream ValueStream --- @tfield EventStream EventStream +-- @tfield Constant Constant +-- @tfield SigStream SigStream +-- @tfield EvtStream EvtStream -- @tfield IOStream IOStream --- @tfield Result Result +-- @tfield RTNode RTNode -- @tfield Cell Cell -- @tfield RootCell RootCell -- @tfield Scope Scope @@ -51,9 +53,9 @@ import Copilot from require 'alv.copilot' { :version - :ValueStream, :EventStream, :IOStream + :Constant, :SigStream, :EvtStream, :IOStream :Cell, :RootCell - :Result, :Scope, :Error + :RTNode, :Scope, :Error :Registry, :SimpleRegistry, :Tag diff --git a/alv/invoke.moon b/alv/invoke.moon index 439af49..4d9dfc9 100644 --- a/alv/invoke.moon +++ b/alv/invoke.moon @@ -2,10 +2,15 @@ -- Builtins for invoking `Op`s and `FnDef`s. -- -- @module invoke -import Result from require 'alv.result' +import RTNode from require 'alv.rtnode' import Builtin from require 'alv.base' import Scope from require 'alv.scope' import Error from require 'alv.error' +import Primitive from require 'alv.types' + +opdef = Primitive 'opdef' +fndef = Primitive 'fndef' +sym = Primitive 'sym' get_name = (value, raw) -> meta = if value.meta then value.meta.name @@ -34,7 +39,7 @@ class op_invoke extends Builtin @op = prev.op\fork! prev.forked = COPILOT.T else - def = @head\unwrap 'opdef', "cant op-invoke #{@head}" + def = @head\unwrap opdef, "cant op-invoke #{@head}" @op = def! --- `Builtin:destroy` implementation. @@ -50,11 +55,11 @@ class op_invoke extends Builtin -- checks if any of `op`:@{Op:all_inputs|all_inputs} are @{Input:dirty|dirty}, -- and if so, calls `op`:@{Op:tick|tick}. -- - -- The `Result` contains `op`, `Op.value` and all the `Result`s from the tail. + -- The `RTNode` contains `op`, `Op.value` and all the `RTNode`s from the tail. -- -- @tparam Scope scope the active scope -- @tparam {AST,...} tail the arguments to this expression - -- @treturn Result + -- @treturn RTNode eval: (scope, tail) => children = [L\push expr\eval, scope for expr in *tail] @@ -73,7 +78,7 @@ class op_invoke extends Builtin for input in @op\all_inputs! input\finish_setup! - Result :children, value: @op.out, op: @op + RTNode :children, value: @op.out, op: @op --- The `Op` instance. -- @@ -92,18 +97,18 @@ class fn_invoke extends Builtin -- `FnDef.body` with the prefix `Builtin.tag`, and `AST:eval`s it in the newly -- created `Scope`. -- - -- The `Result` contains the `Stream` from the cloned AST, and its children - -- are all the `Result`s from evaluating the tail as well as the cloned + -- The `RTNode` contains the `Stream` from the cloned AST, and its children + -- are all the `RTNode`s from evaluating the tail as well as the cloned -- `AST`s. -- -- @tparam Scope caller_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: (caller_scope, tail) => name = get_name @head, @cell\head! frame = "invoking function #{name} at [#{@tag}]" - fndef = @head\unwrap 'fndef', "cant fn-invoke #{@head}" + fndef = @head\unwrap fndef, "cant fn-invoke #{@head}" { :params, :body } = fndef if #params != #tail err = Error 'argument', "expected #{#params} arguments, found #{#tail}" @@ -113,7 +118,7 @@ class fn_invoke extends Builtin fn_scope = Scope fndef.scope, caller_scope children = for i=1,#params - name = params[i]\unwrap 'sym' + name = params[i]\unwrap sym with L\push tail[i]\eval, caller_scope fn_scope\set name, \make_ref! @@ -121,7 +126,7 @@ class fn_invoke extends Builtin result = Error.wrap frame, clone\eval, fn_scope table.insert children, result - Result :children, value: result.value + RTNode :children, value: result.value { :op_invoke, :fn_invoke diff --git a/alv/parsing.moon b/alv/parsing.moon index f9d6f98..9cc46d7 100644 --- a/alv/parsing.moon +++ b/alv/parsing.moon @@ -2,7 +2,7 @@ -- Lpeg Grammar for parsing `alive` code. -- -- @module parsing -import ValueStream from require 'alv.stream' +import Constant from require 'alv.result' import Cell from require 'alv.cell' import Tag from require 'alv.tag' import R, S, P, V, C, Ct from require 'lpeg' @@ -20,15 +20,15 @@ mspace = (comment + wc)^0 / 1 -- optional whitespace -- atoms digit = R '09' first = (R 'az', 'AZ') + S '-_+*/.!?=%' -sym = first * (first + digit)^0 / ValueStream\parse 'sym' +sym = first * (first + digit)^0 / Constant\parse 'sym' -strd = '"' * (C ((P '\\"') + (P '\\\\') + (1 - P '"'))^0) * '"' / ValueStream\parse 'str', '\"' -strq = "'" * (C ((P "\\'") + (P '\\\\') + (1 - P "'"))^0) * "'" / ValueStream\parse 'str', '\'' +strd = '"' * (C ((P '\\"') + (P '\\\\') + (1 - P '"'))^0) * '"' / Constant\parse 'str', '\"' +strq = "'" * (C ((P "\\'") + (P '\\\\') + (1 - P "'"))^0) * "'" / Constant\parse 'str', '\'' str = strd + strq int = digit^1 float = (digit^1 * '.' * digit^0) + (digit^0 * '.' * digit^1) -num = ((P '-')^-1 * (float + int)) / ValueStream\parse 'num' +num = ((P '-')^-1 * (float + int)) / Constant\parse 'num' atom = num + sym + str diff --git a/alv/stream/base.moon b/alv/result/base.moon index 37cc8a4..26af4b4 100644 --- a/alv/stream/base.moon +++ b/alv/result/base.moon @@ -1,7 +1,7 @@ ---- -- base Stream interface. -- --- implemented by `ValueStream`, `EventStream`, and `IOStream`. +-- implemented by `Constant`, `SigStream`, `EvtStream`, and `IOStream`. -- -- @classmod Stream @@ -9,7 +9,7 @@ class Stream --- Stream interface. -- -- Methods that have to be implemented by `Stream` implementations --- (`ValueStream`, `EventStream`, `IOStream`). +-- (`SigStream`, `EvtStream`, `IOStream`). -- -- @section interface @@ -25,6 +25,9 @@ class Stream -- @function fork -- @treturn Stream + __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: @@ -41,6 +44,13 @@ class Stream -- -- @tfield string type + --- the metatype string for this Stream. + -- + -- one of `=` (`Constant`), `~` (`SigStream`), + -- `!` (`EvtStream` and `IOStream`). + -- + -- @tfield string type + --- documentation metadata. -- -- an optional table containing metadata for error messages and diff --git a/alv/stream/value.moon b/alv/result/const.moon index 3409537..10bc943 100644 --- a/alv/stream/value.moon +++ b/alv/result/const.moon @@ -1,13 +1,19 @@ ---- --- Continuous stream of values. +-- Constant Value. -- --- Implements the `Stream` and `AST` intefaces. +-- Implements the `Stream` and `AST` inteface. -- --- @classmod ValueStream -import Stream from require 'alv.stream.base' -import Result from require 'alv.result' +-- @classmod Constant +import Stream from require 'alv.result.base' +import RTNode from require 'alv.rtnode' import Error from require 'alv.error' import scope, base from require 'alv.cycle' +import Primitive from require 'alv.types' + +num = Primitive 'num' +str = Primitive 'str' +sym = Primitive 'sym' +bool = Primitive 'bool' ancestor = (klass) -> assert klass, "cant find the ancestor of nil" @@ -15,22 +21,11 @@ ancestor = (klass) -> klass = klass.__parent klass -class ValueStream extends Stream ---- members --- @section members - - --- return whether this stream was changed in the current tick. +class Constant extends Stream + --- Whether this Result is dirty. -- - -- @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 + -- @tresult bool always `false`. + dirty: => false --- unwrap to the Lua type. -- @@ -47,67 +42,25 @@ class ValueStream extends Stream -- -- Used to insulate eval-cycles from each other. -- - -- @treturn ValueStream - fork: => - with ValueStream @type, @value, @raw - .updated = @updated + -- @treturn Constant + fork: => @ --- alias for `unwrap`. __call: (...) => @unwrap ... --- compare two values. -- - -- Compares two `ValueStream`s by comparing their types and their Lua values. + -- Compares two `SigStream`s by comparing their types and their Lua values. __eq: (other) => other.type == @type and other.value == @value - __tostring: => - value = if @meta.name - @meta.name - else if 'table' == (type @value) and rawget @value, '__base' - @value.__name - else - tostring @value - "<#{@@__name} #{@type}: #{value}>" - --- Stream metatype. -- - -- @tfield string metatype - metatype: 'value' - - --- 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 - -- - -- @tfield string type - - --- the wrapped Lua value. - -- @tfield any value - - --- documentation metadata. - -- - -- an optional table containing metadata for error messages and - -- documentation. The following keys are recognized: - -- - -- - `name`: optional name - -- - `summary`: single-line description (markdown) - -- - `examples`: optional list of single-line code examples - -- - `description`: optional full-text description (markdown) - -- - -- @tfield ?table meta + -- @tfield string metatype (`=`) + metatype: '=' --- AST interface -- --- `ValueStream` implements the `AST` interface. +-- `SignStream` implements the `AST` interface. -- @section ast --- evaluate this literal constant. @@ -117,12 +70,14 @@ class ValueStream extends Stream -- Resolves `sym`s in `scope` and returns a reference to them. -- -- @tparam Scope scope the scope to evaluate in - -- @treturn Result the evaluation result + -- @treturn RTNode the evaluation result eval: (scope) => + return RTNode value: @ if @literal + switch @type - when 'num', 'str' - Result value: @ - when 'sym' + when num, str + RTNode value: @ + when sym Error.wrap "resolving symbol '#{@value}'", scope\get, @value else error "cannot evaluate #{@}" @@ -132,17 +87,17 @@ class ValueStream extends Stream -- Throws an error if `raw` is not set. -- -- @treturn string the exact string this stream was parsed from - stringify: => assert @raw, "stringifying ValueStream that wasn't parsed" + stringify: => @raw --- clone this literal constant. -- - -- @treturn ValueStream self + -- @treturn SignStream self clone: (prefix) => @ --- static functions -- @section static - --- construct a new ValueStream. + --- construct a new Constant. -- -- @classmethod -- @tparam string type the type name @@ -157,9 +112,9 @@ class ValueStream extends Stream -- @tparam string sep the seperator char (only for `str`) @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 + 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 --- wrap a Lua value. -- @@ -167,7 +122,7 @@ class ValueStream extends Stream -- -- @tparam any val the value to wrap -- @tparam[opt] string name the name of this value (for error logging) - -- @treturn ValueStream + -- @treturn Constant @wrap: (val, name='(unknown)') -> typ = switch type val when 'number' then 'num' @@ -190,46 +145,52 @@ class ValueStream extends Stream error "#{name}: cannot wrap '#{val.__class.__name}' instance" else -- plain table - return ValueStream 'scope', scope.Scope.from_table val + val = scope.Scope.from_table val + 'scope' else error "#{name}: cannot wrap Lua type '#{type val}'" - ValueStream typ, val + Constant (Primitive typ), val --- create a constant number. - -- @tparam number num the number - -- @treturn ValueStream - @num: (num) -> ValueStream 'num', num, tostring num + -- @tparam number val the number + -- @treturn Constant + @num: (val) -> Constant num, val, tostring val --- create a constant string. - -- @tparam string str the string - -- @treturn ValueStream - @str: (str) -> ValueStream 'str', str, "'#{str}'" + -- @tparam string val the string + -- @treturn Constant + @str: (val) -> Constant str, val, "'#{val}'" --- create a constant symbol. - -- @tparam string sym the symbol - -- @treturn ValueStream - @sym: (sym) -> ValueStream 'sym', sym, sym + -- @tparam string val the symbol + -- @treturn Constant + @sym: (val) -> Constant sym, val, val --- create a constant boolean. - -- @tparam boolean bool the boolean - -- @treturn ValueStream - @bool: (bool) -> ValueStream 'bool', bool, tostring bool + -- @tparam boolean val the boolean + -- @treturn Constant + @bool: (val) -> Constant bool, val, tostring val + + --- create a forced-literal Constant. + -- + -- For internal use in `Builtin`s only. + -- + -- @treturn Constant + @literal: (...) -> + with Constant ... + .literal = true --- wrap and document a value. -- -- wraps `args.value` using `wrap`, then assigns `meta`. -- -- @tparam table args table with keys `value` and `meta` - -- @treturn ValueStream + -- @treturn Constant @meta: (args) -> - with ValueStream.wrap args.value + with Constant.wrap args.value .meta = args.meta if args.meta -class LiteralValue extends ValueStream - eval: => Result value: @ - { - :ValueStream - :LiteralValue + :Constant } diff --git a/alv/stream/event.moon b/alv/result/evt.moon index 16716be..0559a70 100644 --- a/alv/stream/event.moon +++ b/alv/result/evt.moon @@ -1,13 +1,10 @@ ---- -- Stream of momentary events. -- --- @classmod EventStream -import Stream from require 'alv.stream.base' -import Result from require 'alv.result' -import Error from require 'alv.error' -import scope, base from require 'alv.cycle' +-- @classmod EvtStream +import Stream from require 'alv.result.base' -class EventStream extends Stream +class EvtStream extends Stream --- members -- @section members @@ -44,19 +41,17 @@ class EventStream extends Stream -- -- Used to wrap insulate eval-cycles from each other. -- - -- @treturn EventStream + -- @treturn EvtStream fork: => @@ @type --- alias for `unwrap`. __call: (...) => @unwrap ... - - __tostring: => - "<#{@@__name} #{@type}>" + __tostring: => "<#{@type}#{@metatype} #{@type\pp @value}>" --- Stream metatype. -- - -- @tfield string metatype - metatype: 'event' + -- @tfield string metatype (`!`) + metatype: '!' --- the type name of the stream. -- @@ -89,12 +84,12 @@ class EventStream extends Stream --- static functions -- @section static - --- construct a new EventStream. + --- construct a new EvtStream. -- -- @classmethod -- @tparam string type the type name new: (type) => super type { - :EventStream + :EvtStream } diff --git a/alv/result/init.moon b/alv/result/init.moon new file mode 100644 index 0000000..aa7a115 --- /dev/null +++ b/alv/result/init.moon @@ -0,0 +1,21 @@ +---- +-- `Stream` interface and implementations. +-- +-- @see Stream +-- @see Constant +-- @see SigStream +-- @see EvtStream +-- @see IOStream +-- +-- @module stream +import Constant from require 'alv.result.const' +import SigStream from require 'alv.result.sig' +import EvtStream from require 'alv.result.evt' +import IOStream from require 'alv.result.io' + +{ + :Constant + :SigStream + :EvtStream + :IOStream +} diff --git a/alv/stream/io.moon b/alv/result/io.moon index e17daa8..b12322c 100644 --- a/alv/stream/io.moon +++ b/alv/result/io.moon @@ -4,12 +4,12 @@ -- Unlike other `Stream`s, this is not updated/set by an `Op` instace, but is -- continuously polled for changes by the runtime and may mark itself as -- *dirty* at any point in time. All runtime execution happens due to IOStream --- updates, which ripple through the `Result` tree. +-- updates, which ripple through the `RTNode` tree. -- -- @classmod IOStream -import EventStream from require 'alv.stream.event' +import EvtStream from require 'alv.result.evt' -class IOStream extends EventStream +class IOStream extends EvtStream --- IOStream interface. -- -- methods that have to be implemented by `IOStream` implementations. @@ -42,13 +42,13 @@ class IOStream extends EventStream -- via `Input.hot` should be notified (via `Op:tick`). May be called multiple -- times. May be called before `poll` on the first frame after construction. -- - -- If this is not overrided, the `EventStream` interface can be used, see - -- `EventStream.add`, `EventStream.unwrap`, and `EventStream.dirty`. + -- If this is not overriden, the `EvtStream` interface can be used, see + -- `EvtStream.add`, `EvtStream.unwrap`, and `EvtStream.dirty`. -- -- @function dirty -- @treturn bool whether processing is required - __inherited: (cls) => cls.__base.__tostring = @__tostring + __inherited: (cls) => cls.__base.__tostring or= @__tostring { :IOStream diff --git a/alv/result/sig.moon b/alv/result/sig.moon new file mode 100644 index 0000000..d7c18a3 --- /dev/null +++ b/alv/result/sig.moon @@ -0,0 +1,121 @@ +---- +-- Continuous stream of values. +-- +-- @classmod SigStream +import Stream from require 'alv.result.base' +import Primitive from require 'alv.types' + +class SigStream extends Stream +--- members +-- @section members + + --- return whether this stream 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. + -- + -- @tparam[opt] string type the type to check for + -- @tparam[optchain] string msg message to throw if type don't match + -- @treturn any `value` + unwrap: (type, msg) => + assert type == @type, msg or "#{@} is not a #{type}" if type + @value + + --- create a mutable copy of this stream. + -- + -- Used to insulate eval-cycles from each other. + -- + -- @treturn SigStream + fork: => + with @@ @type, @value + .updated = @updated + + --- alias for `unwrap`. + __call: (...) => @unwrap ... + + --- compare two values. + -- + -- 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 + -- + -- @tfield string type + + --- the wrapped Lua value. + -- @tfield any value + + --- documentation metadata. + -- + -- an optional table containing metadata for error messages and + -- documentation. The following keys are recognized: + -- + -- - `name`: optional name + -- - `summary`: single-line description (markdown) + -- - `examples`: optional list of single-line code examples + -- - `description`: optional full-text description (markdown) + -- + -- @tfield ?table meta + +--- static functions +-- @section static + + --- construct a new SigStream. + -- + -- @classmethod + -- @tparam string type the type name + -- @tparam any value the Lua value to be accessed through `unwrap` + new: (type, @value) => super type + + --- create a number stream. + -- @tparam number val the number + -- @treturn SigStream + @num: (val) -> SigStream Primitive'num', val + + --- create a string stream. + -- @tparam string val the string + -- @treturn SigStream + @str: (val) -> SigStream Primitive'str', val + + --- create a symbol stream. + -- @tparam string val the symbol + -- @treturn symbol + @sym: (val) -> SigStream Primitive'sym', val + + --- create a boolean stream. + -- @tparam boolean val the boolean + -- @treturn SigStream + @bool: (val) -> SigStream Primitive'bool', val + +{ + :SigStream +} diff --git a/alv/result.moon b/alv/rtnode.moon index 6f5ea28..dab4507 100644 --- a/alv/result.moon +++ b/alv/rtnode.moon @@ -1,15 +1,15 @@ ---- --- Result of evaluating an expression. +-- RTNode of evaluating an expression. -- --- `Result`s form a tree that controls execution order and message passing +-- `RTNode`s form a tree that controls execution order and message -- between `Op`s. -- --- @classmod Result -class Result +-- @classmod RTNode +class RTNode --- members -- @section members - --- return whether this Result's value is const. + --- return whether this RTNode's value is const. is_const: => not next @side_inputs --- assert value-constness and return the value. @@ -22,20 +22,20 @@ class Result --- assert this result has a value, return its type. -- @treturn string type: => - assert @value, "Result with value expected" + assert @value, "RTNode with value expected" @value.type --- assert this result has a value, returns its metatype. -- @treturn string `"value"` or `"event"` metatype: => - assert @value, "Result with value expected" + assert @value, "RTNode with value expected" @value.metatype --- create a copy of this result with value-copy semantics. -- the copy has the same @value and @side_inputs, but will not update -- anything on \tick. make_ref: => - with Result value: @value + with RTNode value: @value .side_inputs = @side_inputs --- poll all IOStream instances that are effecting this (sub)tree. @@ -73,7 +73,7 @@ class Result @op\tick! __tostring: => - buf = "<result=#{@value}" + buf = "<RT=#{@value}" buf ..= " #{@op}" if @op buf ..= " (#{#@children} children)" if #@children > 0 buf ..= ">" @@ -87,11 +87,11 @@ class Result -- -- @tfield ?Op op - --- list of child `Result`s from subexpressions + --- list of child `RTNode`s from subexpressions -- - -- @tfield {}|{Result,...} children + -- @tfield {}|{RTNode,...} children - --- cached mapping of all `Stream`/`Input` pairs affecting this Result. + --- cached mapping of all `Stream`/`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. @@ -101,7 +101,7 @@ class Result --- static functions -- @section static - --- create a new Result. + --- create a new RTNode. -- @classmethod -- @param params table with optional keys op, value, children. default: {} new: (params={}) => @@ -122,5 +122,5 @@ class Result @side_inputs[input.stream] = input { - :Result + :RTNode } diff --git a/alv/scope.moon b/alv/scope.moon index 6a0e2a5..575c36e 100644 --- a/alv/scope.moon +++ b/alv/scope.moon @@ -1,10 +1,11 @@ ---- --- Mapping from `sym`s to `Result`s. +-- Mapping from `sym`s to `RTNode`s. -- -- @classmod Scope -import ValueStream from require 'alv.stream' -import Result from require 'alv.result' +import Constant from require 'alv.result' +import RTNode from require 'alv.rtnode' import Error from require 'alv.error' +import Primitive from require 'alv.types' class Scope --- members @@ -12,21 +13,21 @@ class Scope --- set a Lua value in the scope. -- - -- wraps `val` in a `ValueStream` and `Result` before calling `set`. + -- wraps `val` in a `Constant` and `RTNode` before calling `set`. -- -- @tparam string key -- @tparam any val set_raw: (key, val) => - value = ValueStream.wrap val, key - @values[key] = Result :value + value = Constant.wrap val, key + @values[key] = RTNode :value - --- set a symbol to a `Result`. + --- set a symbol to a `RTNode`. -- -- @tparam string key - -- @tparam Result val + -- @tparam RTNode val set: (key, val) => L\trace "setting #{key} = #{val} in #{@}" - assert val.__class == Result, "expected #{key}=#{val} to be Result" + assert val.__class == RTNode, "expected #{key}=#{val} to be RTNode" assert val.value, Error 'type', "cannot define symbol to nil" assert not @values[key], Error 'type', "cannot redefine symbol '#{key}'!" @values[key] = val @@ -42,7 +43,7 @@ class Scope --- resolve a key in this Scope. -- -- @tparam string key the key to resolve - -- @treturn ?Result the value of the definition that was found, or `nil` + -- @treturn ?RTNode the value of the definition that was found, or `nil` get: (key) => L\debug "checking for #{key} in #{@}" if val = @values[key] @@ -56,7 +57,7 @@ class Scope child = @get start if not child error Error 'reference', "undefined symbol '#{start}'" - if child\type! != 'scope' + if child\type! != (Primitive 'scope') error Error 'reference', "'#{start}' is not a scope" child.value!\get rest, while_msg @@ -104,7 +105,7 @@ class Scope --- convert a Lua table to a Scope. -- -- `tbl` may contain more tables (or `Scope`s). - -- Uses `ValueStream.wrap` on the values recursively. + -- Uses `Constant.wrap` on the values recursively. -- -- @tparam table tbl the table to convert -- @treturn Scope diff --git a/alv/stream/init.moon b/alv/stream/init.moon deleted file mode 100644 index f9393b0..0000000 --- a/alv/stream/init.moon +++ /dev/null @@ -1,18 +0,0 @@ ----- --- `Stream` interface and implementations. --- --- @see Stream --- @see ValueStream --- @see EventStream --- @see IOStream --- --- @module stream -import ValueStream from require 'alv.stream.value' -import EventStream from require 'alv.stream.event' -import IOStream from require 'alv.stream.io' - -{ - :ValueStream - :EventStream - :IOStream -} diff --git a/alv/types.moon b/alv/types.moon new file mode 100644 index 0000000..3fcf722 --- /dev/null +++ b/alv/types.moon @@ -0,0 +1,101 @@ +-- what do i need types for? +-- +-- ## implementation side +-- argument specs - without values +-- output specs & output streams +-- - evt outputs are created without values, +-- - val outputs are created *with* values! +-- +-- ## language side +-- explicit casting + +-- Check whether two tables have all the same, +-- and *only the same* keys. +shared_shape = (a, b) -> + for key in pairs a + return false unless b[key] + + for key in pairs b + return false unless a[key] + + true + +same = (a, b) -> + return unless shared_shape a, b + for key, val in pairs a + return false unless val == b[key] + + true + +class Type + __eq: (a, b) -> + if a.__class == b.__class + a.__class.__base.__self_eq a, b + + __inherited: (cls) => + cls.__base.__self_eq = cls.__base.__eq + cls.__base.__eq = @__eq + +class Primitive extends Type + new: (@type) => + + pp: (value) => tostring value + + __eq: (other) => @type == other.type + __tostring: => @type + +class Struct extends Type + new: (@types) => + + --- create a new struct with a selection of keys + project: (keys) => + types = {} + for key in *keys + types[key] = @types[key] + @@ types + + pp: (value) => + inner = table.concat ["#{k}: #{@types[k]\pp v}" for k, v in pairs value], ', ' + "{#{inner}}" + + __eq: (other) => same @types, other.types + __tostring: => + inner = table.concat ["#{k}: #{v}" for k, v in pairs @types], ', ' + "{#{inner}}" + +class Array extends Type + new: (@size, @type) => + + pp: (value) => + inner = table.concat [@type\pp v for v in *value], ' ' + "[#{inner}]" + + __eq: (other) => @size == other.size and @type == other.type + __tostring: => "#{@type}[#{@size}]" + +" +bool = Primitive 'bool' +num = Primitive 'num' +str = Primitive 'str' + +vec3 = Array 3, num +noteevt = Struct { note: str, dur: num } + +assert.is.equal 'num[3]', tostring vec3 +assert.is.equal '{dur: num, note: str}', tostring noteevt + +assert.is.equal vec3 == Array 3, num +assert.not.equal vec3, Array 3, str +assert.is.equal noteevt, Struct { oct: num, note: str, dur: num } +assert.not.equal noteevt, Struct { oct: num, note: str, dur: str } + +print Constant bool, false +print SigStream vec3, { 0.5, 0.3, 0.7 } +print EvtStream noteevt +" + +{ + :Primitive + :Array + :Struct +} diff --git a/spec/cell_spec.moon b/spec/cell_spec.moon index 0b2ff64..de46245 100644 --- a/spec/cell_spec.moon +++ b/spec/cell_spec.moon @@ -1,15 +1,15 @@ import do_setup from require 'spec.test_setup' import Cell, RootCell from require 'alv.cell' -import ValueStream, Scope, Tag, SimpleRegistry, globals from require 'alv' +import Constant, Scope, Tag, SimpleRegistry, globals from require 'alv' import Copilot from require 'alv.copilot' setup do_setup hello_world = Cell.parse Tag.parse('2'), { - '', (ValueStream.sym 'hello'), ' ', (ValueStream.str 'world'), '' + '', (Constant.sym 'hello'), ' ', (Constant.str 'world'), '' } two_plus_two = Cell.parse Tag.parse('3'), { - '', (ValueStream.sym '+'), ' ', (ValueStream.num 2), ' ', (ValueStream.num 2), '' + '', (Constant.sym '+'), ' ', (Constant.num 2), ' ', (Constant.num 2), '' } describe 'Cell', -> @@ -18,8 +18,8 @@ describe 'Cell', -> with hello_world\clone parent it 'keeps children', -> assert.is.equal Cell, .__class - assert.is.equal (ValueStream.sym 'hello'), \head! - assert.is.same { ValueStream.str 'world' }, \tail! + assert.is.equal (Constant.sym 'hello'), \head! + assert.is.same { Constant.str 'world' }, \tail! it 'clones the tag', -> assert.is.equal hello_world.tag, .tag.original @@ -31,8 +31,8 @@ describe 'Cell', -> assert.has.error -> cell\eval globals it 'evaluates its head', -> - head = ValueStream.sym 'trace' - cell = Cell.parse { '', head, ' ', (ValueStream.sym 'true'), '' } + head = Constant.sym 'trace' + cell = Cell.parse { '', head, ' ', (Constant.sym 'true'), '' } s = spy.on head, 'eval' cell\eval globals @@ -45,10 +45,10 @@ describe 'RootCell', -> test 'head is always "do"', -> cell = Cell.parse_root {} - assert.is.equal (ValueStream.sym 'do'), cell\head! + assert.is.equal (Constant.sym 'do'), cell\head! cell = RootCell nil, { hello_world, two_plus_two } - assert.is.equal (ValueStream.sym 'do'), cell\head! + assert.is.equal (Constant.sym 'do'), cell\head! test 'tail is all children', -> cell = Cell.parse_root {} diff --git a/spec/input_spec.moon b/spec/input_spec.moon index 6ab4388..a8107ae 100644 --- a/spec/input_spec.moon +++ b/spec/input_spec.moon @@ -1,10 +1,13 @@ import do_setup from require 'spec.test_setup' -import Input, Result, ValueStream, EventStream, IOStream from require 'alv.base' +import Input, Result, SigStream, EvtStream, IOStream from require 'alv.base' +import Primitive from require 'alv.types' setup do_setup +my_io = Primitive 'my-io' + class MyIO extends IOStream - new: => super 'my-io' + new: => super my_io dirty: => @is_dirty basic_tests = (stream, input) -> @@ -22,7 +25,7 @@ basic_tests = (stream, input) -> assert.is.equal stream.metatype, input\metatype! describe 'Input.cold', -> - stream = ValueStream.num 1 + stream = SigStream.num 1 input = Input.cold stream basic_tests stream, input @@ -36,7 +39,7 @@ describe 'Input.cold', -> assert.is.false input\dirty! input\finish_setup! - new_input = Input.cold ValueStream.num 3 + new_input = Input.cold SigStream.num 3 new_input\setup input assert.is.false new_input\dirty! new_input.stream\set 4 @@ -44,8 +47,8 @@ describe 'Input.cold', -> input\finish_setup! describe 'Input.hot', -> - describe 'with EventStream', -> - stream = EventStream 'num' + describe 'with EvtStream', -> + stream = EvtStream Primitive 'num' input = Input.hot stream basic_tests stream, input @@ -53,7 +56,7 @@ describe 'Input.hot', -> it 'is marked for lifting', -> assert.is.nil input.io - it 'is dirty when the EventStream is dirty', -> + it 'is dirty when the EvtStream is dirty', -> assert.is.false input\dirty! assert.is.false stream\dirty! @@ -106,8 +109,8 @@ describe 'Input.hot', -> assert.is.true input\dirty! assert.is.true stream\dirty! - describe 'with ValueStream', -> - stream = ValueStream.num 1 + describe 'with SigStream', -> + stream = SigStream.num 1 local input describe 'at evaltime', -> @@ -120,7 +123,7 @@ describe 'Input.hot', -> input\finish_setup! it 'is dirty when different', -> - newval = ValueStream.num 2 + newval = SigStream.num 2 assert.is.false newval\dirty! newinput = Input.hot newval @@ -129,7 +132,7 @@ describe 'Input.hot', -> newinput\finish_setup! it 'is not dirty when equal', -> - newval = ValueStream.num! + newval = SigStream.num! newval\set 1 assert.is.true newval\dirty! diff --git a/spec/match_spec.moon b/spec/match_spec.moon index 52911db..91cee02 100644 --- a/spec/match_spec.moon +++ b/spec/match_spec.moon @@ -1,14 +1,15 @@ import val, evt from require 'alv.base.match' -import Result, ValueStream, EventStream from require 'alv' +import RTNode, SigStream, EvtStream from require 'alv' +import Primitive from require 'alv.types' mk_val = (type, const) -> - value = ValueStream type - with Result :value + value = SigStream Primitive type + with RTNode :value .side_inputs = { 'fake' } unless const mk_evt = (type, const) -> - value = EventStream type - with Result :value + value = EvtStream Primitive type + with RTNode :value .side_inputs = { 'fake' } unless const describe 'val and evt', -> diff --git a/spec/parsing_spec.moon b/spec/parsing_spec.moon index ecc8ff3..0486276 100644 --- a/spec/parsing_spec.moon +++ b/spec/parsing_spec.moon @@ -1,64 +1,53 @@ import space, atom, expr, explist, cell, program, comment from require 'alv.parsing' -import ValueStream from require 'alv' +import Constant from require 'alv' import Logger from require 'alv.logger' Logger\init 'silent' -verify_parse = (parser, str) -> - with assert parser\match str - assert.is.equal str, \stringify! +verify_parse = (parser, val) -> + with assert parser\match val + assert.is.equal val, \stringify! -verify_parse_nope = (parser, str) -> - with assert parser\match str - without_nope = str\match '^(.*) nope$' +verify_parse_nope = (parser, val) -> + with assert parser\match val + without_nope = val\match '^(.*) nope$' assert.is.equal without_nope, \stringify! describe 'atom parsing', -> test 'symbols', -> sym = verify_parse_nope atom, 'some-toast nope' - assert.is.equal 'sym', sym.type - assert.is.equal 'some-toast', sym\unwrap! - assert.is.equal 'some-toast', sym\stringify! + assert.is.equal (Constant.sym 'some-toast'), sym describe 'numbers', -> it 'parses ints', -> num = verify_parse_nope atom, '1234 nope' - assert.is.equal 'num', num.type - assert.is.equal 1234, num\unwrap! - assert.is.equal '1234', num\stringify! + assert.is.equal (Constant.num 1234), num it 'parses floats', -> num = verify_parse_nope atom, '0.123 nope' - assert.is.equal 'num', num.type - assert.is.equal 0.123, num\unwrap! + assert.is.equal (Constant.num 0.123), num num = verify_parse_nope atom, '.123 nope' - assert.is.equal 'num', num.type - assert.is.equal 0.123, num\unwrap! + assert.is.equal (Constant.num 0.123), num num = verify_parse_nope atom, '0. nope' - assert.is.equal 'num', num.type - assert.is.equal 0, num\unwrap! + assert.is.equal (Constant.num 0), num describe 'strings', -> it 'parses double-quote strings', -> str = verify_parse_nope atom, '"help some stuff!" nope' - assert.is.equal 'str', str.type - assert.is.equal 'help some stuff!', str\unwrap! + assert.is.equal (Constant.str 'help some stuff!'), str it 'parses single-quote strings', -> str = verify_parse_nope atom, "'help some stuff!' nope" - assert.is.equal 'str', str.type - assert.is.equal "help some stuff!", str\unwrap! + assert.is.equal (Constant.str "help some stuff!"), str it 'handles escapes', -> str = verify_parse_nope atom, '"string with \\"quote\\"s and \\\\" nope' - assert.is.equal 'str', str.type - assert.is.equal 'string with \"quote\"s and \\', str\unwrap! + assert.is.equal (Constant.str 'string with \"quote\"s and \\'), str str = verify_parse_nope atom, "'string with \\'quote\\'s and \\\\' nope" - assert.is.equal 'str', str.type - assert.is.equal "string with \'quote\'s and \\", str\unwrap! + assert.is.equal (Constant.str "string with \'quote\'s and \\"), str describe 'Cell', -> test 'basic parsing', -> @@ -66,9 +55,9 @@ describe 'Cell', -> "friend" )' assert.is.equal 3, #node.children - assert.is.equal (ValueStream.num 3), node.children[1] - assert.is.equal (ValueStream.sym 'ok-yes'), node.children[2] - assert.is.equal (ValueStream.str 'friend'), node.children[3] + assert.is.equal (Constant.num 3), node.children[1] + assert.is.equal (Constant.sym 'ok-yes'), node.children[2] + assert.is.equal (Constant.str 'friend'), node.children[3] test 'tag parsing', -> node = verify_parse cell, '([42]tagged 2)' @@ -89,8 +78,8 @@ describe 'RootCell parsing', -> node = verify_parse program, str assert.is.equal 2, #node.children - assert.is.equal (ValueStream.num 3), node.children[1] - assert.is.equal (ValueStream.sym 'ok-yes'), node.children[2] + assert.is.equal (Constant.num 3), node.children[1] + assert.is.equal (Constant.sym 'ok-yes'), node.children[2] it 'at the front of the string', -> verify ' 3\tok-yes' diff --git a/spec/result/const_spec.moon b/spec/result/const_spec.moon new file mode 100644 index 0000000..6bd7999 --- /dev/null +++ b/spec/result/const_spec.moon @@ -0,0 +1,149 @@ +import do_setup from require 'spec.test_setup' +import Constant, RTNode, Scope, SimpleRegistry from require 'alv' +import Op, Builtin from require 'alv.base' +import Primitive from require 'alv.types' + +class TestOp extends Op + new: (...) => super ... + +class TestBuiltin extends Builtin + new: (...) => + +setup do_setup + +describe 'Constant', -> + describe '.wrap', -> + it 'wraps numbers', -> + got = Constant.wrap 3 + assert.is.equal (Primitive 'num'), got.type + assert.is.equal 3, got.value + + it 'wraps strings', -> + got = Constant.wrap "im a happy string" + assert.is.equal (Primitive 'str'), got.type + assert.is.equal "im a happy string", got.value + + it 'wraps Constants', -> + pi = Constant.num 3.14 + got = Constant.wrap pi + + assert.is.equal pi, got + + it 'wraps Opdefs', -> + got = Constant.wrap TestOp + + assert.is.equal (Primitive 'opdef'), got.type + assert.is.equal TestOp, got.value + + it 'wraps Bultins', -> + got = Constant.wrap TestBuiltin + + assert.is.equal (Primitive 'builtin'), got.type + assert.is.equal TestBuiltin, got.value + + it 'wraps Scopes', -> + sub = Scope! + got = Constant.wrap sub + + assert.is.equal (Primitive 'scope'), got.type + assert.is.equal sub, got.value + + it 'wraps tables', -> + pi = Constant.num 3.14 + got = Constant.wrap { :pi } + + assert.is.equal (Primitive 'scope'), got.type + assert.is.equal pi, (got.value\get 'pi')\const! + + describe ':unwrap', -> + it 'returns the raw value!', -> + assert.is.equal 3.14, (Constant.num 3.14)\unwrap! + assert.is.equal 'hi', (Constant.str 'hi')\unwrap! + assert.is.equal 'hi', (Constant.sym 'hi')\unwrap! + + test 'can assert the type', -> + assert.is.equal 3.14, (Constant.num 3.14)\unwrap Primitive 'num' + assert.is.equal 'hi', (Constant.str 'hi')\unwrap Primitive 'str' + assert.is.equal 'hi', (Constant.sym 'hi')\unwrap Primitive 'sym' + assert.has_error -> (Constant.num 3.14)\unwrap Primitive 'sym' + assert.has_error -> (Constant.str 'hi')\unwrap Primitive 'num' + assert.has_error -> (Constant.sym 'hi')\unwrap Primitive 'str' + + test 'has __call shorthand', -> + assert.is.equal 3.14, (Constant.num 3.14)! + assert.is.equal 'hi', (Constant.str 'hi')! + assert.is.equal 'hi', (Constant.sym 'hi')! + assert.is.equal 3.14, (Constant.num 3.14) Primitive 'num' + assert.is.equal 'hi', (Constant.str 'hi') Primitive 'str' + assert.is.equal 'hi', (Constant.sym 'hi') Primitive 'sym' + assert.has_error -> (Constant.num 3.14) Primitive 'sym' + assert.has_error -> (Constant.str 'hi') Primitive 'num' + assert.has_error -> (Constant.sym 'hi') Primitive 'str' + + describe 'overrides __eq', -> + it 'compares the type', -> + val = Constant.num 3 + assert.is.equal (Constant.num 3), val + assert.not.equal (Constant.str '3'), val + + val = Constant.str 'hello' + assert.is.equal (Constant.str 'hello'), val + assert.not.equal (Constant.sym 'hello'), val + + it 'compares the value', -> + val = Constant.num 3 + assert.is.equal (Constant.num 3), val + assert.not.equal (Constant.num 4), val + + it ':dirty is always false', -> + val = Constant.num 3 + assert.is.false val\dirty! + + val.value = 4 + assert.is.false val\dirty! + + describe ':eval', -> + it 'turns numbers into consts', -> + assert_noop = (val) -> + assert.is.equal val, val\eval!\const! + + assert_noop Constant.num 2 + assert_noop Constant.str 'hello' + + 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" + + assert_eval = (sym, val) -> + const = Constant.sym sym + assert.is.equal val, (const\eval scope)\const! + + assert_eval 'number', Constant.num 3 + assert_eval 'hello', Constant.str "world" + assert_eval 'goodbye', Constant.sym "again" + + it ':clones literals as themselves', -> + assert_noop = (val) -> assert.is.equal val, val\clone! + + assert_noop Constant.num 2 + assert_noop Constant.str 'hello' + assert_noop Constant.sym 'world' + + describe ':fork', -> + it 'is equal to the original', -> + a = Constant.num 2 + b = Constant.str 'asdf' + c = Constant (Primitive 'weird'), {}, '(raw)' + + aa, bb, cc = a\fork!, b\fork!, c\fork! + assert.is.equal a, aa + assert.is.equal b, bb + assert.is.equal c, cc + + assert.is.false aa\dirty! + assert.is.false bb\dirty! + assert.is.false cc\dirty! + + assert.is.equal c.raw, cc.raw diff --git a/spec/result/sig_spec.moon b/spec/result/sig_spec.moon new file mode 100644 index 0000000..4bc0a67 --- /dev/null +++ b/spec/result/sig_spec.moon @@ -0,0 +1,109 @@ +import do_setup from require 'spec.test_setup' +import SigStream, RTNode, Scope, SimpleRegistry from require 'alv' +import Op, Builtin from require 'alv.base' +import Primitive from require 'alv.types' + +class TestOp extends Op + new: (...) => super ... + +class TestBuiltin extends Builtin + new: (...) => + +setup do_setup + +describe 'SigStream', -> + describe ':unwrap', -> + it 'returns the raw value!', -> + assert.is.equal 3.14, (SigStream.num 3.14)\unwrap! + assert.is.equal 'hi', (SigStream.str 'hi')\unwrap! + assert.is.equal 'hi', (SigStream.sym 'hi')\unwrap! + + test 'can assert the type', -> + assert.is.equal 3.14, (SigStream.num 3.14)\unwrap Primitive 'num' + assert.is.equal 'hi', (SigStream.str 'hi')\unwrap Primitive 'str' + assert.is.equal 'hi', (SigStream.sym 'hi')\unwrap Primitive 'sym' + assert.has_error -> (SigStream.num 3.14)\unwrap Primitive 'sym' + assert.has_error -> (SigStream.str 'hi')\unwrap Primitive 'num' + assert.has_error -> (SigStream.sym 'hi')\unwrap Primitive 'str' + + test 'has __call shorthand', -> + assert.is.equal 3.14, (SigStream.num 3.14)! + assert.is.equal 'hi', (SigStream.str 'hi')! + assert.is.equal 'hi', (SigStream.sym 'hi')! + assert.is.equal 3.14, (SigStream.num 3.14) Primitive 'num' + assert.is.equal 'hi', (SigStream.str 'hi') Primitive 'str' + assert.is.equal 'hi', (SigStream.sym 'hi') Primitive 'sym' + assert.has_error -> (SigStream.num 3.14) Primitive 'sym' + assert.has_error -> (SigStream.str 'hi') Primitive 'num' + assert.has_error -> (SigStream.sym 'hi') Primitive 'str' + + describe 'overrides __eq', -> + it 'compares the type', -> + val = SigStream.num 3 + assert.is.equal (SigStream.num 3), val + assert.not.equal (SigStream.str '3'), val + + val = SigStream.str 'hello' + assert.is.equal (SigStream.str 'hello'), val + assert.not.equal (SigStream.sym 'hello'), val + + it 'compares the value', -> + val = SigStream.num 3 + assert.is.equal (SigStream.num 3), val + assert.not.equal (SigStream.num 4), val + + describe ':set', -> + it 'sets the value', -> + val = SigStream.num 3 + assert.is.equal (SigStream.num 3), val + + val\set 4 + assert.is.equal (SigStream.num 4), val + assert.not.equal (SigStream.num 3), val + + it 'marks the value dirty', -> + val = SigStream.num 3 + assert.is.false val\dirty! + + val\set 4 + assert.is.true val\dirty! + + describe ':fork', -> + it 'is equal to the original', -> + a = SigStream.num 2 + b = SigStream.str 'asdf' + c = with SigStream 'weird', {}, '(raw)' + \set {} + + aa, bb, cc = a\fork!, b\fork!, c\fork! + assert.is.equal a, aa + assert.is.equal b, bb + assert.is.equal c, cc + + assert.is.false aa\dirty! + assert.is.false bb\dirty! + assert.is.true cc\dirty! + + assert.is.equal c.raw, cc.raw + + it 'isolates the original from the fork', -> + a = SigStream.num 3 + b = with SigStream 'weird', {}, '(raw)' + \set {} + + aa, bb = a\fork!, b\fork! + + bb\set {false} + + assert.is.same {}, b! + assert.is.same {false}, bb! + assert.is.true b\dirty! + assert.is.true bb\dirty! + + COPILOT\next_tick! + aa\set 4 + + assert.is.equal 3, a! + assert.is.equal 4, aa! + assert.is.false a\dirty! + assert.is.true aa\dirty! diff --git a/spec/result_spec.moon b/spec/rtnode_spec.moon index f7006f1..c4cf4e9 100644 --- a/spec/result_spec.moon +++ b/spec/rtnode_spec.moon @@ -1,44 +1,47 @@ import do_setup from require 'spec.test_setup' -import Result, Scope, SimpleRegistry from require 'alv' -import Input, Op, ValueStream, EventStream, IOStream from require 'alv.base' +import RTNode, Scope, SimpleRegistry from require 'alv' +import Input, Op, Constant, EvtStream, IOStream from require 'alv.base' +import Primitive from require 'alv.types' setup do_setup +num = Primitive 'num' +bang = Primitive 'bang' op_with_inputs = (inputs) -> with Op! \setup inputs if inputs result_with_sideinput = (value, input) -> - with Result :value + with RTNode :value .side_inputs = { [value]: input } class DirtyIO extends IOStream - new: => super 'dirty-io' + new: => super Primitive 'dirty-io' dirty: => true -describe 'Result', -> +describe 'RTNode', -> it 'wraps value, children', -> - value = ValueStream.num 3 + value = Constant.num 3 - a = Result! - b = Result! + a = RTNode! + b = RTNode! children = { a, b } - result = Result :value, :children + result = RTNode :value, :children assert.is.equal value, result.value assert.is.same children, result.children it ':type gets type and assets value', -> - result = Result value: ValueStream.num 2 - assert.is.equal 'num', result\type! + result = RTNode value: Constant.num 2 + assert.is.equal num, result\type! - result = Result! + result = RTNode! assert.has.error -> result\type! it ':is_const', -> - value = ValueStream.num 2 - pure = Result :value + value = Constant.num 2 + pure = RTNode :value impure = result_with_sideinput value, {} assert.is.true pure\is_const! @@ -49,10 +52,10 @@ describe 'Result', -> assert.has.error (-> impure\const 'test'), 'test' it ':make_ref', -> - value = ValueStream.num 2 + value = Constant.num 2 input = Input.hot value op = op_with_inputs { input } - thick = Result :value, :op, children: { Result!, Result! } + thick = RTNode :value, :op, children: { RTNode!, RTNode! } ref = thick\make_ref! assert ref @@ -62,43 +65,43 @@ describe 'Result', -> assert.is.nil ref.op it 'lifts up inputs from op', -> - event = ValueStream 'bang', false + event = Constant bang, false event_input = Input.hot event - value = ValueStream 'num', 4 + value = Constant num, 4 value_input = Input.hot value op = op_with_inputs { event_input, value_input } - result = Result op: op, :value + result = RTNode op: op, :value assert.is.equal op, result.op assert.is.same { [event]: event_input, [value]: value_input }, result.side_inputs it 'does not lift up op inputs that are also child values', -> - event = ValueStream 'bang', false + event = Constant bang, false event_input = Input.hot event - value = ValueStream 'num', 4 + value = Constant num, 4 value_input = Input.hot value op = op_with_inputs { event_input, value_input } - result = Result op: op, :value, children: { Result :value } + result = RTNode op: op, :value, children: { RTNode :value } assert.is.same { [event]: event_input }, result.side_inputs it 'lifts up side_inputs from children', -> - event_value = ValueStream 'bang', false + event_value = Constant bang, false event_input = Input.hot event_value - event = Result op: op_with_inputs { event_input } + event = RTNode op: op_with_inputs { event_input } assert.is.same { [event_value]: event_input }, event.side_inputs - value_value = ValueStream 'num', 4 + value_value = Constant num, 4 value_input = Input.hot value_value - value = Result op: op_with_inputs { value_input } + value = RTNode op: op_with_inputs { value_input } assert.is.same { [value_value]: value_input }, value.side_inputs - result = Result children: { event, value } + result = RTNode children: { event, value } assert.is.same { [event_value]: event_input, [value_value]: value_input }, result.side_inputs @@ -106,11 +109,11 @@ describe 'Result', -> local a_value, a_child, a_input local b_value, b_child, b_input before_each -> - a_value = EventStream 'num' + a_value = EvtStream num a_input = Input.hot a_value a_child = result_with_sideinput a_value, a_input - b_value = EventStream 'num' + b_value = EvtStream num b_input = Input.hot b_value b_child = result_with_sideinput b_value, b_input @@ -122,7 +125,7 @@ describe 'Result', -> a = spy.on a_child, 'tick' b = spy.on b_child, 'tick' - result = Result children: { a_child, b_child } + result = RTNode children: { a_child, b_child } result\tick! assert.spy(a).was_called_with match.ref a_child @@ -135,7 +138,7 @@ describe 'Result', -> a = spy.on a_child, 'tick' b = spy.on b_child, 'tick' - result = Result children: { a_child, b_child } + result = RTNode children: { a_child, b_child } result\tick! assert.spy(a).was_not_called! @@ -149,7 +152,7 @@ describe 'Result', -> op = op_with_inputs a: Input.hot a_value s = spy.on op, 'tick' - result = Result :op, children: { a_child, b_child } + result = RTNode :op, children: { a_child, b_child } result\tick! assert.spy(s).was_called_with match.ref op @@ -162,7 +165,7 @@ describe 'Result', -> op = op_with_inputs { Input.hot b_value } s = spy.on op, 'tick' - result = Result :op, children: { a_child, b_child } + result = RTNode :op, children: { a_child, b_child } result\tick! assert.spy(s).was_not_called! @@ -172,7 +175,7 @@ describe 'Result', -> io = DirtyIO! input = Input.hot io op = op_with_inputs { input } - result = Result :op + result = RTNode :op s = spy.on io, 'poll' assert.is.same { [io]: input }, result.side_inputs diff --git a/spec/scope_spec.moon b/spec/scope_spec.moon index beeeeac..405e9f8 100644 --- a/spec/scope_spec.moon +++ b/spec/scope_spec.moon @@ -1,4 +1,5 @@ -import Scope, ValueStream, Result from require 'alv' +import Scope, Constant, RTNode from require 'alv' +import Primitive from require 'alv.types' import Op from require 'alv.base' import Logger from require 'alv.logger' Logger\init 'silent' @@ -6,7 +7,12 @@ Logger\init 'silent' class TestOp extends Op new: (...) => super ... -wrap_res = (value) -> Result :value +wrap_res = (value) -> RTNode :value + +num = Primitive 'num' +str = Primitive 'str' +opdef = Primitive 'opdef' +scope_t = Primitive 'scope' describe 'Scope', -> describe 'constifies', -> @@ -16,18 +22,18 @@ describe 'Scope', -> scope\set_raw 'num', 3 got = (scope\get 'num')\const! - assert.is.equal 'num', got.type + assert.is.equal num, got.type assert.is.equal 3, got.value test 'strings', -> scope\set_raw 'str', "im a happy string" got = (scope\get 'str')\const! - assert.is.equal 'str', got.type + assert.is.equal str, got.type assert.is.equal "im a happy string", got.value test 'Values', -> - pi = ValueStream 'num', 3.14 + pi = Constant.num 3.14 scope\set_raw 'pi', pi assert.is.equal pi, (scope\get 'pi')\const! @@ -36,7 +42,7 @@ describe 'Scope', -> scope\set_raw 'test', TestOp got = (scope\get 'test')\const! - assert.is.equal 'opdef', got.type + assert.is.equal opdef, got.type assert.is.equal TestOp, got.value test 'Scopes', -> @@ -44,21 +50,21 @@ describe 'Scope', -> scope\set_raw 'sub', sub got = (scope\get 'sub')\const! - assert.is.equal 'scope', got.type + assert.is.equal scope_t, got.type assert.is.equal sub, got.value test 'tables', -> - pi = ValueStream 'num', 3.14 - scope\set_raw 'math', { :pi } + pi = Constant.num 3.14 + scope\set_raw 'math', { :pi } got = (scope\get 'math')\const! - assert.is.equal 'scope', got.type + assert.is.equal scope_t, got.type assert.is.equal Scope, got.value.__class assert.is.equal pi, (got.value\get 'pi')\const! assert.is.equal pi, (scope\get 'math/pi')\const! it 'wraps Values in from_table', -> - pi = ValueStream 'num', 3.14 + pi = Constant.num 3.14 scope = Scope.from_table { num: 3 str: "im a happy string" @@ -68,21 +74,21 @@ describe 'Scope', -> } got = (scope\get 'num')\const! - assert.is.equal 'num', got.type + assert.is.equal num, got.type assert.is.equal 3, got.value got = (scope\get 'str')\const! - assert.is.equal 'str', got.type + assert.is.equal str, got.type assert.is.equal "im a happy string", got.value assert.is.equal pi, (scope\get 'pi')\const! got = (scope\get 'test')\const! - assert.is.equal 'opdef', got.type + assert.is.equal opdef, got.type assert.is.equal TestOp, got.value got = (scope\get 'math')\const! - assert.is.equal 'scope', got.type + assert.is.equal scope_t, got.type assert.is.equal pi, (scope\get 'math/pi')\const! it 'gets from nested scopes', -> @@ -90,7 +96,7 @@ describe 'Scope', -> a = Scope! b = Scope! - pi = ValueStream 'num', 3.14 + pi = Constant.num 3.14 b\set_raw 'test', pi a\set_raw 'child', b root\set_raw 'deep', a @@ -98,8 +104,8 @@ describe 'Scope', -> assert.is.equal pi, (root\get 'deep/child/test')\const! describe 'can set symbols', -> - one = wrap_res ValueStream.num 1 - two = wrap_res ValueStream.num 2 + one = wrap_res Constant.num 1 + two = wrap_res Constant.num 2 scope = Scope! it 'disallows re-setting symbols', -> @@ -119,14 +125,14 @@ describe 'Scope', -> it 'allows access', -> got = (scope\get 'inherited')\const! - assert.is.equal 'str', got.type + assert.is.equal str, got.type assert.is.equal "inherited string", got.value it 'can be shadowed', -> scope\set_raw 'hidden', "overwritten" got = (scope\get 'hidden')\const! - assert.is.equal 'str', got.type + assert.is.equal str, got.type assert.is.equal "overwritten", got.value describe 'dynamic inheritance', -> diff --git a/spec/value_spec.moon b/spec/value_spec.moon deleted file mode 100644 index d81ed40..0000000 --- a/spec/value_spec.moon +++ /dev/null @@ -1,180 +0,0 @@ -import do_setup from require 'spec.test_setup' -import ValueStream, Result, Scope, SimpleRegistry from require 'alv' -import Op, Builtin from require 'alv.base' - -class TestOp extends Op - new: (...) => super ... - -class TestBuiltin extends Builtin - new: (...) => - -setup do_setup - -describe 'ValueStream', -> - describe '.wrap', -> - it 'wraps numbers', -> - got = ValueStream.wrap 3 - assert.is.equal 'num', got.type - assert.is.equal 3, got.value - - it 'wraps strings', -> - got = ValueStream.wrap "im a happy string" - assert.is.equal 'str', got.type - assert.is.equal "im a happy string", got.value - - it 'wraps Values', -> - pi = ValueStream 'num', 3.14 - got = ValueStream.wrap pi - - assert.is.equal pi, got - - it 'wraps Opdefs', -> - got = ValueStream.wrap TestOp - - assert.is.equal 'opdef', got.type - assert.is.equal TestOp, got.value - - it 'wraps Bultins', -> - got = ValueStream.wrap TestBuiltin - - assert.is.equal 'builtin', got.type - assert.is.equal TestBuiltin, got.value - - it 'wraps Scopes', -> - sub = Scope! - got = ValueStream.wrap sub - - assert.is.equal 'scope', got.type - assert.is.equal sub, got.value - - it 'wraps tables', -> - pi = ValueStream 'num', 3.14 - got = ValueStream.wrap { :pi } - - assert.is.equal 'scope', got.type - assert.is.equal pi, (got.value\get 'pi')\const! - - describe ':unwrap', -> - it 'returns the raw value!', -> - assert.is.equal 3.14, (ValueStream.num 3.14)\unwrap! - assert.is.equal 'hi', (ValueStream.str 'hi')\unwrap! - assert.is.equal 'hi', (ValueStream.sym 'hi')\unwrap! - - test 'can assert the type', -> - assert.is.equal 3.14, (ValueStream.num 3.14)\unwrap 'num' - assert.is.equal 'hi', (ValueStream.str 'hi')\unwrap 'str' - assert.is.equal 'hi', (ValueStream.sym 'hi')\unwrap 'sym' - assert.has_error -> (ValueStream.num 3.14)\unwrap 'sym' - assert.has_error -> (ValueStream.str 'hi')\unwrap 'num' - assert.has_error -> (ValueStream.sym 'hi')\unwrap 'str' - - test 'has __call shorthand', -> - assert.is.equal 3.14, (ValueStream.num 3.14)! - assert.is.equal 'hi', (ValueStream.str 'hi')! - assert.is.equal 'hi', (ValueStream.sym 'hi')! - assert.is.equal 3.14, (ValueStream.num 3.14) 'num' - assert.is.equal 'hi', (ValueStream.str 'hi') 'str' - assert.is.equal 'hi', (ValueStream.sym 'hi') 'sym' - assert.has_error -> (ValueStream.num 3.14) 'sym' - assert.has_error -> (ValueStream.str 'hi') 'num' - assert.has_error -> (ValueStream.sym 'hi') 'str' - - describe 'overrides __eq', -> - it 'compares the type', -> - val = ValueStream 'num', 3 - assert.is.equal (ValueStream.num 3), val - assert.not.equal (ValueStream.str '3'), val - - val = ValueStream 'str', 'hello' - assert.is.equal (ValueStream.str 'hello'), val - assert.not.equal (ValueStream.sym 'hello'), val - - it 'compares the value', -> - val = ValueStream 'num', 3 - assert.is.equal (ValueStream.num 3), val - assert.not.equal (ValueStream.num 4), val - - describe ':set', -> - it 'sets the value', -> - val = ValueStream 'num', 3 - assert.is.equal (ValueStream.num 3), val - - val\set 4 - assert.is.equal (ValueStream.num 4), val - assert.not.equal (ValueStream.num 3), val - - it 'marks the value dirty', -> - val = ValueStream 'num', 3 - assert.is.false val\dirty! - - val\set 4 - assert.is.true val\dirty! - - describe ':eval', -> - it 'turns numbers into consts', -> - assert_noop = (val) -> - assert.is.equal val, val\eval!\const! - - assert_noop ValueStream.num 2 - assert_noop ValueStream.str 'hello' - - it 'looks up symbols in the scope', -> - scope = with Scope! - \set 'number', Result value: ValueStream.num 3 - \set 'hello', Result value: ValueStream.str "world" - \set 'goodbye', Result value: ValueStream.sym "again" - - assert_eval = (sym, val) -> - const = ValueStream.sym sym - assert.is.equal val, (const\eval scope)\const! - - assert_eval 'number', ValueStream.num 3 - assert_eval 'hello', ValueStream.str "world" - assert_eval 'goodbye', ValueStream.sym "again" - - it ':clone sliterals as themselves', -> - assert_noop = (val) -> assert.is.equal val, val\clone! - - assert_noop ValueStream.num 2 - assert_noop ValueStream.str 'hello' - assert_noop ValueStream.sym 'world' - - describe ':fork', -> - it 'is equal to the original', -> - a = ValueStream.num 2 - b = ValueStream.str 'asdf' - c = with ValueStream 'weird', {}, '(raw)' - \set {} - - aa, bb, cc = a\fork!, b\fork!, c\fork! - assert.is.equal a, aa - assert.is.equal b, bb - assert.is.equal c, cc - - assert.is.false aa\dirty! - assert.is.false bb\dirty! - assert.is.true cc\dirty! - - assert.is.equal c.raw, cc.raw - - it 'isolates the original from the fork', -> - a = ValueStream.num 3 - b = with ValueStream 'weird', {}, '(raw)' - \set {} - - aa, bb = a\fork!, b\fork! - - bb\set {false} - - assert.is.same {}, b! - assert.is.same {false}, bb! - assert.is.true b\dirty! - assert.is.true bb\dirty! - - COPILOT\next_tick! - aa\set 4 - - assert.is.equal 3, a! - assert.is.equal 4, aa! - assert.is.false a\dirty! - assert.is.true aa\dirty! |
