aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-05-08 09:41:08 +0000
committers-ol <s+removethis@s-ol.nu>2025-03-02 14:23:21 +0000
commit99ca67938c0145db37182bdb709d9424a20dfee0 (patch)
tree6df4e2b5fde650aa3c7e36893eb1780f932d56bd
parentrelease v0.1 (diff)
downloadalive-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.moon2
-rw-r--r--alv/base/init.moon15
-rw-r--r--alv/base/input.moon27
-rw-r--r--alv/base/match.moon29
-rw-r--r--alv/builtin.moon75
-rw-r--r--alv/cell.moon11
-rw-r--r--alv/copilot.moon8
-rw-r--r--alv/init.moon16
-rw-r--r--alv/invoke.moon27
-rw-r--r--alv/parsing.moon10
-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.moon21
-rw-r--r--alv/result/io.moon (renamed from alv/stream/io.moon)12
-rw-r--r--alv/result/sig.moon121
-rw-r--r--alv/rtnode.moon (renamed from alv/result.moon)28
-rw-r--r--alv/scope.moon25
-rw-r--r--alv/stream/init.moon18
-rw-r--r--alv/types.moon101
-rw-r--r--spec/cell_spec.moon18
-rw-r--r--spec/input_spec.moon25
-rw-r--r--spec/match_spec.moon11
-rw-r--r--spec/parsing_spec.moon53
-rw-r--r--spec/result/const_spec.moon149
-rw-r--r--spec/result/sig_spec.moon109
-rw-r--r--spec/rtnode_spec.moon (renamed from spec/result_spec.moon)71
-rw-r--r--spec/scope_spec.moon46
-rw-r--r--spec/value_spec.moon180
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!