git.s-ol.nu alive / 8f68df2
rename base.match.val → base.match.sig s-ol 1 year, 8 months ago
19 changed file(s) with 120 addition(s) and 120 deletion(s). Raw diff Collapse all Expand all
1010 -- @see FnDef
1111 -- @see Input
1212 -- @see base.match.const
13 -- @see base.match.val
13 -- @see base.match.sig
1414 -- @see base.match.evt
1515 -- @see Constant
1616 -- @see SigStream
2828 import Builtin from require 'alv.base.builtin'
2929 import FnDef from require 'alv.base.fndef'
3030 import Input from require 'alv.base.input'
31 import const, val, evt from require 'alv.base.match'
31 import const, sig, evt from require 'alv.base.match'
3232 import Constant, SigStream, EvtStream, IOStream from require 'alv.result'
3333 import T, Primitive, Array, Struct from require 'alv.type'
3434 import RTNode from require 'alv.rtnode'
3939 :Builtin
4040 :FnDef
4141 :Input
42 :const, :val, :evt
42 :const, :sig, :evt
4343
4444 -- redundant exports, to keep anything an extension might need in one import
4545
88 -- `Repeat`, `Sequence`, `Choice`, and `Optional`. They can be used directly,
99 -- but there is also a number of shorthands for assembling patterns quickly:
1010 --
11 -- - `const()`, `val()` and `evt()`: Shorthands for `Type('='), Type('~'), Type('!')`
11 -- - `const()`, `sig()` and `evt()`: Shorthands for `Type('='), Type('~'), Type('!')`
1212 -- - `const.sym`: Shorthand for `Type('=', T.sym)`
13 -- - `val.num`: Shorthand for `Type('~', T.num)`
13 -- - `sig.num`: Shorthand for `Type('~', T.num)`
1414 -- - `evt.str`: Shorthand for `Type('!', T.str)`
1515 -- - `pat * 2`: Shorthand for `Repeat(pat, 1, 2)` (1-4 times `pat`)
1616 -- - `pat * 0`: Shorthand for `Repeat(pat, 1, nil)` (1-* times `pat`)
2828 -- Recalling patterns will memorize the first RTNode they match, and
2929 -- only match further RTNodes of the same type. For example
3030 --
31 -- arg = (val.num / val.str)!
31 -- arg = (sig.num / sig.str)!
3232 -- pattern = arg + arg
3333 --
3434 -- ...will match either two numbers or two strings, but not one number and one
3838 -- sequence of keys that are used instead of integers when constructing the
3939 -- capture table:
4040 --
41 -- pattern = (val.str + val.num):named('key', 'value')
41 -- pattern = (sig.str + sig.num):named('key', 'value')
4242 -- pattern:match(...)
4343 -- -- returns { {key='a', value=1}, {key='b', value=2}, ...}
4444 --
281281 -- Call or index with a string to obtain a `Type` instance.
282282 -- Call to obtain a wildcard pattern.
283283 --
284 -- val.str, val.num
285 -- val['vec3'], val(T.vec3)
286 -- val()
287 --
288 -- @table val
289 val = setmetatable {}, {
284 -- sig.str, sig.num
285 -- sig['vec3'], sig(T.vec3)
286 -- sig()
287 --
288 -- @table sig
289 sig = setmetatable {}, {
290290 __index: (key) =>
291291 with v = Type '~', T[key]
292292 @[key] = v
314314
315315 {
316316 :Type, :Repeat, :Sequence, :Choice, :Optional
317 :const, :val, :evt
317 :const, :sig, :evt
318318 }
44 -- documentation.
55 --
66 -- @module builtins
7 import Builtin, Op, PureOp, T, FnDef, Input, const, val, evt, Struct, Array
7 import Builtin, Op, PureOp, T, FnDef, Input, const, sig, evt, Struct, Array
88 from require 'alv.base'
99 import Constant from require 'alv.result'
1010 import Error from require 'alv.error'
328328
329329 value: class extends Op
330330 setup: (inputs) =>
331 value = (val.str / evt.str)\match inputs
331 value = (sig.str / evt.str)\match inputs
332332 super value: Input.hot value
333333
334334 tick: =>
360360 Since ~-streams cannot be emtpy, specifying an `initial` value is necessary."
361361 value: class extends Op
362362 setup: (inputs) =>
363 { event, initial } = (evt! + val!)\match inputs
363 { event, initial } = (evt! + sig!)\match inputs
364364 assert event\type! == initial\type!,
365365 Error 'argument', "~ arguments have to be of the same type"
366366
382382 - if `val` is a !-stream, emits a bang for each incoming event.
383383 - if `trig` is given, samples `sig` as a new event when `trig` arrives."
384384 value: class extends Op
385 pattern = (val! + evt.bang) / (val! / evt!)\rep(1,1)
385 pattern = (sig! + evt.bang) / (sig! / evt!)\rep(1,1)
386386 setup: (inputs) =>
387387 { sig, trig } = pattern\match inputs
388388 if trig
408408 description: "Produces an array of values."
409409
410410 value: do
411 any = val! / evt!
411 any = sig! / evt!
412412
413413 class extends PureOp
414414 pattern: any!*0
427427
428428 value: do
429429 key = const.str / const.sym
430 val = val! / evt!
430 val = sig! / evt!
431431 pair = (key + val)\named 'key', 'val'
432432
433433 class extends PureOp
446446 examples: { '(get val key [key2…])' }
447447
448448 value: class extends Op
449 pattern = (val! / evt!) + (const.str / const.sym / const.num)*0
449 pattern = (sig! / evt!) + (const.str / const.sym / const.num)*0
450450 setup: (inputs) =>
451451 { val, keys } = pattern\match inputs
452452 super val: Input.hot val
0 import PureOp, Constant, T, val, evt from require 'alv.base'
0 import PureOp, Constant, T, sig, evt from require 'alv.base'
11
22 all_same = (first, list) ->
33 for v in *list
1313 else
1414 true
1515
16 any = val! / evt!
16 any = sig! / evt!
1717
1818 class ReduceOp extends PureOp
1919 pattern: any\rep 2, nil
0 import PureOp, Constant, T, val, evt from require 'alv.base'
0 import PureOp, Constant, T, sig, evt from require 'alv.base'
11 unpack or= table.unpack
22
3 num = val.num / evt.num
3 num = sig.num / evt.num
44
55 class ReduceOp extends PureOp
66 pattern: num\rep 2, nil
0 import Constant, IOStream, Op, Input, T, Error, val from require 'alv.base'
0 import Constant, IOStream, Op, Input, T, Error, sig from require 'alv.base'
11 import RtMidiIn, RtMidiOut, RtMidi from require 'luartmidi'
22
33 bit = do
7070
7171 value: class extends PortOp
7272 setup: (inputs) =>
73 name = val.str\match inputs
73 name = sig.str\match inputs
7474 super inp: Input.hot name
7575
7676 output = Constant.meta
8181
8282 value: class extends PortOp
8383 setup: (inputs) =>
84 name = val.str\match inputs
84 name = sig.str\match inputs
8585 super out: Input.hot name
8686
8787 inout = Constant.meta
9292
9393 value: class extends PortOp
9494 setup: (inputs) =>
95 { inp, out } = (val.str + val.str)\match inputs
95 { inp, out } = (sig.str + sig.str)\match inputs
9696 super
9797 inp: Input.hot inp
9898 out: Input.hot out
0 import Constant, Op, Input, T, val, evt from require 'alv.base'
0 import Constant, Op, Input, T, sig, evt from require 'alv.base'
11 import apply_range, bit from require 'alv-lib.midi.core'
22 import bor, lshift from bit
33
2121 - (num) [ 0 - num["
2222
2323 value: class extends Op
24 num = val.num
25 pattern = -evt['midi/port'] + num + num + num + -num + -(val.str + num)
24 num = sig.num
25 pattern = -evt['midi/port'] + num + num + num + -num + -(sig.str + num)
2626 setup: (inputs, scope) =>
2727 { port, i, start, chan, steps, range } = pattern\match inputs
2828
6767 `start`). `steps` defaults to 8."
6868
6969 value: class extends Op
70 pattern = -evt['midi/port'] + val.num + val.num + val.num + -val.num
70 pattern = -evt['midi/port'] + sig.num + sig.num + sig.num + -sig.num
7171 setup: (inputs, scope) =>
7272 @out or= T.bool\mk_sig!
7373 @state or= {}
129129 `steps` defaults to 8."
130130
131131 value: class extends Op
132 pattern = -evt['midi/port'] + val.num + val.num + val.num + -val.num
132 pattern = -evt['midi/port'] + sig.num + sig.num + sig.num + -sig.num
133133 setup: (inputs, scope) =>
134134 @out or= T.bang\mk_evt!
135135 @state or= {}
0 import Constant, Op, Input, T, val, evt from require 'alv.base'
0 import Constant, Op, Input, T, sig, evt from require 'alv.base'
11 import input, output, inout, apply_range from require 'alv-lib.midi.core'
22
33 gate = Constant.meta
77 examples: { '(midi/gate [port] note [chan])' }
88
99 value: class extends Op
10 pattern = -evt['midi/port'] + val.num -val.num
10 pattern = -evt['midi/port'] + sig.num -sig.num
1111 setup: (inputs, scope) =>
1212 @out or= T.bool\mk_sig!
1313 { port, note, chan } = pattern\match inputs
3636 examples: { '(midi/trig [port] note [chan])' }
3737
3838 value: class extends Op
39 pattern = -evt['midi/port'] + val.num -val.num
39 pattern = -evt['midi/port'] + sig.num -sig.num
4040 setup: (inputs, scope) =>
4141 @out or= T.bang\mk_evt!
4242 { port, note, chan } = pattern\match inputs
6868 - (num) [ 0 - num["
6969
7070 value: class extends Op
71 pattern = -evt['midi/port'] + val.num + -val.num + -val.num
71 pattern = -evt['midi/port'] + sig.num + -sig.num + -sig.num
7272 setup: (inputs, scope) =>
7373 { port, cc, chan, range } = pattern\match inputs
7474 super
0 import Op, Constant, SigStream, Input, T, val, evt from require 'alv.base'
0 import Op, Constant, SigStream, Input, T, sig, evt from require 'alv.base'
11 import pack from require 'osc'
22 import dns, udp from require 'socket'
33
1010 examples: { '(osc/connect host port)' }
1111
1212 value: class extends Op
13 pattern = val.str + val.num
13 pattern = sig.str + sig.num
1414 setup: (inputs) =>
1515 @out or= SigStream T['udp/socket']
1616 { host, port } = pattern\match inputs
3737 - `path` is the OSC path to send the message to. It should be a string-value.
3838 - `evt` is the argument to send. It should be an event stream."
3939 value: class extends Op
40 pattern = -val['udp/socket'] + val.str + evt!
40 pattern = -sig['udp/socket'] + sig.str + evt!
4141 setup: (inputs, scope) =>
4242 { socket, path, value } = pattern\match inputs
4343 super
6666 - `val` is the value to Synchronize. It should be a value stream."
6767
6868 value: class extends Op
69 pattern = -val['udp/socket'] + val.str + val!
69 pattern = -sig['udp/socket'] + sig.str + sig!
7070 setup: (inputs, scope) =>
7171 { socket, path, value } = pattern\match inputs
7272 super
0 import Op, Constant, Input, val, evt from require 'alv.base'
0 import Op, Constant, Input, sig, evt from require 'alv.base'
11 import udp from require 'socket'
22
33 local conn
1919 conn or= udp!
2020 conn\sendto str, '127.0.0.1', 49161
2121
22 arg = val.num / val.str
22 arg = sig.num / sig.str
2323
2424 play = Constant.meta
2525 meta:
6868 description: "`effect` should be one of 'DIS', 'CHO', 'REV' or 'FEE'"
6969
7070 value: class extends Op
71 pattern = val.str + arg + arg
71 pattern = sig.str + arg + arg
7272 setup: (inputs) =>
7373 { which, a, b } = pattern\match inputs
7474 super {
0 import Constant, Error, Op, Input, T, Array, val, evt from require 'alv.base'
0 import Constant, Error, Op, Input, T, Array, sig, evt from require 'alv.base'
11
22 apply_range = (range, val) ->
33 if range\type! == T.str
2121 - 'deg' [ 0 - 360[
2222 - (num) [ 0 - num["
2323
24 pattern = -evt.bang + -(val.num / val.str)
24 pattern = -evt.bang + -(sig.num / sig.str)
2525
2626 num = Constant.meta
2727 meta:
0 import Constant, Op, Input, T, val, evt from require 'alv.base'
0 import Constant, Op, Input, T, sig, evt from require 'alv.base'
11
22 -- slower reference implementation
33 bjorklund = (n, k) ->
4545 When fed a num~ or num! stream, outputs a bang if the corresponding step is on."
4646
4747 value: class extends Op
48 pattern = (evt.bang / val.num / evt.num) + val.num + val.num
48 pattern = (evt.bang / sig.num / evt.num) + sig.num + sig.num
4949 setup: (inputs) =>
5050 { trig, n, k } = pattern\match inputs
5151
8888 When fed a num~ or num! stream, outputs a bang if the corresponding step is on."
8989
9090 value: class extends Op
91 pattern = (evt.bang / val.num / evt.num) + val.bool*0
91 pattern = (evt.bang / sig.num / evt.num) + sig.bool*0
9292 setup: (inputs) =>
9393 { trig, steps } = pattern\match inputs
9494
0 import Op, Constant, Input, val, evt from require 'alv.base'
0 import Op, Constant, Input, sig, evt from require 'alv.base'
11 import pack from require 'osc'
22 import dns, udp from require 'socket'
33
1717 - `trig` is the trigger signal. It should be a stream of bang-events.
1818 - `param` is the name of a synthdef parameter. It should be a string-value."
1919 value: class extends Op
20 pattern = -val['udp/socket'] + val.str + evt.bang + (val.str + val.num)\rep 0
20 pattern = -sig['udp/socket'] + sig.str + evt.bang + (sig.str + sig.num)\rep 0
2121 setup: (inputs, scope) =>
2222 { socket, synth, trig, ctrls } = pattern\match inputs
2323
5454 streams. Incoming events will cause a note to be played, while value changes
5555 will not."
5656 value: class extends Op
57 pattern = -val['udp/socket'] + val.str + (val.str + (val.num / evt.num))\rep 0
57 pattern = -sig['udp/socket'] + sig.str + (sig.str + (sig.num / evt.num))\rep 0
5858 setup: (inputs, scope) =>
5959 { socket, synth, trig, ctrls } = pattern\match inputs
6060
0 import PureOp, Constant, Input, T, val, evt from require 'alv.base'
0 import PureOp, Constant, Input, T, sig, evt from require 'alv.base'
11
2 any = val! / evt!
2 any = sig! / evt!
33
44 str = Constant.meta
55 meta:
0 import Constant, EvtStream, IOStream, Error, Op, Input, T, val, evt
0 import Constant, EvtStream, IOStream, Error, Op, Input, T, sig, evt
11 from require 'alv.base'
22 import monotime from require 'system'
33
3737 @out or= Clock!
3838
3939 setup: (inputs) =>
40 fps = (-val.num)\match inputs
40 fps = (-sig.num)\match inputs
4141 super fps: Input.hot fps or Constant.num 60
4242 @out.frametime = 1 / @inputs.fps!
4343
5959 super ...
6060 @out or= T.clock\mk_evt!
6161
62 pattern = -evt.clock + val.num + -val.str
62 pattern = -evt.clock + sig.num + -sig.str
6363 setup: (inputs, scope) =>
6464 { clock, scale } = pattern\match inputs
6565 super
9191 @out or= T.num\mk_sig!
9292
9393 default_wave = Constant.str 'sin'
94 pattern = -evt.clock + val.num + -val.str
94 pattern = -evt.clock + sig.num + -sig.str
9595 setup: (inputs, scope) =>
9696 { clock, freq, wave } = pattern\match inputs
9797 super
127127 @state or= 0
128128 @out or= T.num\mk_sig!
129129
130 pattern = -evt.clock + val.num + -val.num
130 pattern = -evt.clock + sig.num + -sig.num
131131 setup: (inputs, scope) =>
132132 { clock, period, max } = pattern\match inputs
133133 super
162162 @state or= { phase: 0, count: 0 }
163163 @out or= T.num\mk_sig @state.count
164164
165 pattern = -evt.clock + val.num
165 pattern = -evt.clock + sig.num
166166 setup: (inputs, scope) =>
167167 { clock, period } = pattern\match inputs
168168 super
194194 super ...
195195 @state or= 0
196196
197 pattern = -evt.clock + val.num + -val!
197 pattern = -evt.clock + sig.num + -sig!
198198 setup: (inputs, scope) =>
199199 { clock, period, evt } = pattern\match inputs
200200 super
228228 super ...
229229 @state or= { i: 1, t: 0 }
230230
231 pair = (val! + val.num)\named('value', 'delay')
232 pattern = -evt.clock + val.num + pair*0
231 pair = (sig! + sig.num)\named('value', 'delay')
232 pattern = -evt.clock + sig.num + pair*0
233233
234234 inputify = (step) ->
235235 {
0 import Constant, Op, Input, T, val, evt from require 'alv.base'
0 import Constant, Op, Input, T, sig, evt from require 'alv.base'
11
22 all_same = (list) ->
33 for v in *list[2,]
1818 (indexed starting from 0) is reproduced."
1919
2020 value: class extends Op
21 val_or_evt = (val! / evt!)!
22 pattern = (val.num / val.bool) + val_or_evt*0
21 val_or_evt = (sig! / evt!)!
22 pattern = (sig.num / sig.bool) + val_or_evt*0
2323 setup: (inputs) =>
2424 { i, values } = pattern\match inputs
2525
5454 value: class extends Op
5555 setup: (inputs) =>
5656 @out or= T.bang\mk_evt!
57 value = val.bool\match inputs
57 value = sig.bool\match inputs
5858 super value: Input.hot value
5959
6060 tick: =>
7878 scope, but might look up 'magic' dynamic symbols like `\*clock\*`.
7979
8080 #### argument parsing
81 Arguments should be parsed using `base.match`. The two exports `base.match.val`
81 Arguments should be parsed using `base.match`. The two exports `base.match.sig`
8282 and `base.match.evt` are used to build complex patterns that can parse and
8383 validate the Op arguments into complex structures (see the module documentation
8484 for more information).
8585
86 import val, evt from require 'alv.base'
87
88 pattern = evt.bang + val.str + val.num*3 + -evt!
86 import sig, evt from require 'alv.base'
87
88 pattern = evt.bang + sig.str + sig.num*3 + -evt!
8989 { trig, str, numbers, optional } = pattern\match inputs
9090
9191 This example matches first an `EvtStream` of type `bang`, then a `SigStream`
0 import const, val, evt from require 'alv.base.match'
0 import const, sig, evt from require 'alv.base.match'
11 import Op, Input from require 'alv.base'
22 import RTNode, T, Error from require 'alv'
33
1717 result = T[type]\mk_evt!
1818 RTNode :result, op: op_with_inputs { Input.hot result }
1919
20 describe 'val and evt', ->
20 describe 'sig and evt', ->
2121 describe 'type-less shorthand', ->
2222 it 'matches metatype', ->
2323 str = mk_val 'str'
2424 num = mk_val 'num'
25 assert.is.equal str, val!\match { str }
26 assert.is.equal num, val!\match { num }
25 assert.is.equal str, sig!\match { str }
26 assert.is.equal num, sig!\match { num }
2727 assert.has.error -> const!\match { str }
2828 assert.has.error -> const!\match { num }
2929 assert.has.error -> evt!\match { str }
3131
3232 str = mk_evt 'str'
3333 num = mk_evt 'num'
34 assert.has.error -> val!\match { str }
35 assert.has.error -> val!\match { num }
34 assert.has.error -> sig!\match { str }
35 assert.has.error -> sig!\match { num }
3636 assert.has.error -> const!\match { str }
3737 assert.has.error -> const!\match { num }
3838 assert.is.equal str, evt!\match { str }
4040
4141 str = mk_const 'str'
4242 num = mk_const 'num'
43 assert.is.equal str, val!\match { str }
44 assert.is.equal num, val!\match { num }
43 assert.is.equal str, sig!\match { str }
44 assert.is.equal num, sig!\match { num }
4545 assert.is.equal str, const!\match { str }
4646 assert.is.equal num, const!\match { num }
4747 assert.has.error -> evt!\match { str }
4848 assert.has.error -> evt!\match { num }
4949
5050 it 'can recall the type', ->
51 value = val!!
51 value = sig!!
5252 event = evt!!
5353 two_equal_values = value + value
5454 two_equal_events = event + event
7676 it 'stringifies well', ->
7777 assert.is.equal 'any=', tostring const!
7878 assert.is.equal 'any!', tostring evt!
79 assert.is.equal 'any~', tostring val!
79 assert.is.equal 'any~', tostring sig!
8080
8181 describe 'typed shorthand', ->
8282 it 'matches by metatype', ->
8383 str = mk_val 'str'
8484 num = mk_val 'num'
85 assert.is.equal str, val.str\match { str }
86 assert.is.equal num, val.num\match { num }
85 assert.is.equal str, sig.str\match { str }
86 assert.is.equal num, sig.num\match { num }
8787 assert.has.error -> const.str\match { str }
8888 assert.has.error -> const.num\match { num }
8989 assert.has.error -> evt.str\match { str }
9191
9292 str = mk_evt 'str'
9393 num = mk_evt 'num'
94 assert.has.error -> val.str\match { str }
95 assert.has.error -> val.num\match { num }
94 assert.has.error -> sig.str\match { str }
95 assert.has.error -> sig.num\match { num }
9696 assert.has.error -> const.str\match { str }
9797 assert.has.error -> const.num\match { num }
9898 assert.is.equal str, evt.str\match { str }
100100
101101 str = mk_const 'str'
102102 num = mk_const 'num'
103 assert.is.equal str, val.str\match { str }
104 assert.is.equal num, val.num\match { num }
103 assert.is.equal str, sig.str\match { str }
104 assert.is.equal num, sig.num\match { num }
105105 assert.is.equal str, const.str\match { str }
106106 assert.is.equal num, const.num\match { num }
107107 assert.has.error -> evt.str\match { str }
110110 it 'matches by type', ->
111111 str = mk_const 'str'
112112 num = mk_const 'num'
113 assert.is.equal str, val.str\match { str }
114 assert.is.equal num, val.num\match { num }
113 assert.is.equal str, sig.str\match { str }
114 assert.is.equal num, sig.num\match { num }
115115 assert.is.equal str, const.str\match { str }
116116 assert.is.equal num, const.num\match { num }
117 assert.has.error -> val.num\match { str }
118 assert.has.error -> val.str\match { num }
117 assert.has.error -> sig.num\match { str }
118 assert.has.error -> sig.str\match { num }
119119
120120 str = mk_val 'str'
121121 num = mk_val 'num'
122 assert.is.equal str, val.str\match { str }
123 assert.is.equal num, val.num\match { num }
122 assert.is.equal str, sig.str\match { str }
123 assert.is.equal num, sig.num\match { num }
124124 assert.has.error -> const.num\match { str }
125125 assert.has.error -> const.str\match { num }
126 assert.has.error -> val.num\match { str }
127 assert.has.error -> val.str\match { num }
126 assert.has.error -> sig.num\match { str }
127 assert.has.error -> sig.str\match { num }
128128
129129 str = mk_evt 'str'
130130 num = mk_evt 'num'
138138 it 'stringifies well', ->
139139 assert.is.equal 'str!', tostring evt.str
140140 assert.is.equal 'num!', tostring evt.num
141 assert.is.equal 'str~', tostring val.str
142 assert.is.equal 'num~', tostring val.num
141 assert.is.equal 'str~', tostring sig.str
142 assert.is.equal 'num~', tostring sig.num
143143 assert.is.equal 'str=', tostring const.str
144144 assert.is.equal 'num=', tostring const.num
145145
147147 str = mk_val 'str'
148148 num = mk_val 'num'
149149 bool = mk_val 'bool'
150 choice = val.str / val.num
150 choice = sig.str / sig.num
151151
152152 it 'matches either type', ->
153153 assert.is.equal str, choice\match { str }
166166 assert.has.error -> same\match { bool, bool }
167167
168168 it 'makes inner types recall', ->
169 same = (val! / evt!)!
169 same = (sig! / evt!)!
170170 same = same + same
171171 assert.is.same { str, str }, same\match { str, str }
172172 assert.is.same { num, num }, same\match { num, num }
181181 str = mk_val 'str'
182182 num = mk_val 'num'
183183 bool = mk_evt 'bool'
184 seq = val.str + val.num + evt.bool
184 seq = sig.str + sig.num + evt.bool
185185
186186 it 'matches all types in order', ->
187187 assert.is.same { str, num, bool }, seq\match { str, num, bool }
198198 assert.has.error -> seq\match { str, num, bool, bool }
199199
200200 it 'can handle optional children', ->
201 opt = -val.str + val.num
201 opt = -sig.str + sig.num
202202 assert.is.same { str, num }, opt\match { str, num }
203203 assert.is.same { nil, num }, opt\match { num }
204204 assert.has.error -> opt\match { str, str, num }
205205 assert.has.error -> opt\match { str, num, num }
206206
207207 it 'can handle repeat children', ->
208 rep = val.str + val.num*2
208 rep = sig.str + sig.num*2
209209 assert.is.same { str, {num} }, rep\match { str, num }
210210 assert.is.same { str, {num,num} }, rep\match { str, num, num }
211211 assert.has.error -> rep\match { str }
221221 times = (n, arg) -> return for i=1,n do arg
222222
223223 it '*x is [1,x[', ->
224 rep = val.str*3
224 rep = sig.str*3
225225 assert.has.error -> rep\match (times 0, str)
226226 assert.is.same (times 1, str), rep\match (times 1, str)
227227 assert.is.same (times 2, str), rep\match (times 2, str)
230230 assert.has.error -> rep\match (times 3, num)
231231
232232 it '*0 is [1,[', ->
233 rep = val.str*0
233 rep = sig.str*0
234234 assert.has.error -> rep\match (times 0, str)
235235 assert.is.same (times 1, str), rep\match (times 1, str)
236236 assert.is.same (times 2, str), rep\match (times 2, str)
238238 assert.has.error -> rep\match (times 3, num)
239239
240240 it '^x is [0,x[', ->
241 rep = val.str^3
241 rep = sig.str^3
242242 assert.is.same {}, rep\match {}
243243 assert.is.same (times 1, str), rep\match (times 1, str)
244244 assert.is.same (times 2, str), rep\match (times 2, str)
247247 assert.has.error -> rep\match (times 3, num)
248248
249249 it '^0 is [0,[', ->
250 rep = val.str^0
250 rep = sig.str^0
251251 assert.is.same {}, rep\match {}
252252 assert.is.same (times 1, str), rep\match (times 1, str)
253253 assert.is.same (times 2, str), rep\match (times 2, str)
255255 assert.has.error -> rep\match (times 3, num)
256256
257257 it ':rep(min, max) does anything else', ->
258 rep = val.str\rep 2, 2
258 rep = sig.str\rep 2, 2
259259 assert.has.error -> rep\match {}
260260 assert.has.error -> rep\match (times 1, str)
261261 assert.is.same (times 2, str), rep\match (times 2, str)
263263 assert.has.error -> rep\match (times 2, num)
264264
265265 it 'works with complex inner types', ->
266 rep = (val.num + val.str)\rep 2, 2
266 rep = (sig.num + sig.str)\rep 2, 2
267267 assert.has.error -> rep\match {}
268268 assert.has.error -> rep\match {num, str}
269269 assert.has.error -> rep\match {num, num}
272272 assert.has.error -> rep\match {num, str, num, str, num, str}
273273
274274 it 'stringifies well', ->
275 assert.is.equal 'str~{1-3}', tostring val.str*3
276 assert.is.equal 'str~{1-*}', tostring val.str*0
277 assert.is.equal 'str~{0-*}', tostring val.str^0
278 assert.is.equal 'str~{2-2}', tostring val.str\rep 2, 2
275 assert.is.equal 'str~{1-3}', tostring sig.str*3
276 assert.is.equal 'str~{1-*}', tostring sig.str*0
277 assert.is.equal 'str~{0-*}', tostring sig.str^0
278 assert.is.equal 'str~{2-2}', tostring sig.str\rep 2, 2
279279
280280 describe 'complex nesting', ->
281281 bang = mk_evt 'bang'
282282 str = mk_val 'str'
283283 num = mk_val 'num'
284284 num_c = mk_const 'num'
285 pattern = -evt.bang + val.num*4 +
286 (val.str + (val.num / val.str))\named('key', 'val')^0
285 pattern = -evt.bang + sig.num*4 +
286 (sig.str + (sig.num / sig.str))\named('key', 'val')^0
287287
288288 it 'just works', ->
289289 assert.is.same { bang, { num, num }, {} }, pattern\match { bang, num, num }
00 import do_setup, do_teardown, invoke_op from require 'spec.test_setup'
1 import PureOp, Input, T, val, evt from require 'alv.base'
1 import PureOp, Input, T, sig, evt from require 'alv.base'
22 import RTNode from require 'alv'
33
44 setup do_setup
55 teardown do_teardown
66
77 class TestPureOp extends PureOp
8 pattern: (val.num / val.str / evt.num)*3
8 pattern: (sig.num / sig.str / evt.num)*3
99 type: T.num
1010 tick: => @out\set 1
1111
8080 assert.has.error -> invoke_op TestPureOp, { (literal a), (literal b) }
8181
8282 it 'supports nested input patterns', ->
83 num = val.num / evt.num
83 num = sig.num / evt.num
8484 class NestedInputOp extends PureOp
85 pattern: (num + val.str)\named('a', 'b')\rep 2, 2
85 pattern: (num + sig.str)\named('a', 'b')\rep 2, 2
8686 type: T.num
8787 tick: => @out\set 1
8888
105105
106106 it 'supports dynamically generating the output type', ->
107107 class DynamicOp extends PureOp
108 pattern: val.num + (val! / evt!)
108 pattern: sig.num + (sig! / evt!)
109109 type: (inputs) => inputs[2]\type!
110110 tick: => @out\set @inputs[2]!
111111 typ = spy.on DynamicOp, 'type'