1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
import TestPilot from require 'spec.test_setup'
import T, Constant, Scope from require 'alv'
describe "def", ->
COPILOT = TestPilot!
it "returns nothing", ->
with COPILOT\eval_once '(def _ 3)'
assert.is.true \is_const!
assert.is.nil .result
it "passes through side-effects", ->
with COPILOT\eval_once '
(import* time)
(def nonconst (every 0.5 "bang!"))'
assert.is.false \is_const!
assert.is.nil .result
assert.is.equal T.clock, (next .children[2].side_inputs).type
it "validates args", ->
err = assert.has.error -> COPILOT\eval_once '(def)'
assert.matches "requires at least 2 arguments", err
err = assert.has.error -> COPILOT\eval_once '(def a)'
assert.matches "requires at least 2 arguments", err
err = assert.has.error -> COPILOT\eval_once '(def a 1 b)'
assert.matches "requires an even number of arguments", err
err = assert.has.error -> COPILOT\eval_once '(def (+ 1 2) 3)'
assert.matches "name is not a symbol", err
it "cannot redefine symbols", ->
err = assert.has.error -> COPILOT\eval_once '
(def a 1
a 2)'
assert.matches "cannot redefine symbol", err
it "can hide symbols", ->
with COPILOT\eval_once '
(def a 1)
(do
(def a 2)
a)
a'
assert.is.true \is_const!
assert.is.equal (Constant.num 1), .result
assert.is.equal (Constant.num 2), .children[2].result
describe "export", ->
COPILOT = TestPilot!
it "returns a scope containing new defs", ->
with COPILOT\eval_once '(export)'
assert.is.true \is_const!
assert.is.equal T.scope, .result.type
assert.is.same {}, .result!.values
with COPILOT\eval_once '(export (def a 1 b 2))'
assert.is.true \is_const!
assert.is.equal T.scope, .result.type
assert.is.equal (Constant.num 1), .result!.values.a.result
assert.is.equal (Constant.num 2), .result!.values.b.result
it "passes through side-effects", ->
with COPILOT\eval_once '
(import* time)
(export
(def hello (every 0.5 "bang!"))
(every 0.5 42))'
assert.is.false \is_const!
assert.is.equal T.scope, .result.type
a = next .children[2].children[1].side_inputs
b = next .children[2].children[2].side_inputs
assert.is.truthy .side_inputs[a]
assert.is.truthy .side_inputs[b]
it "doesn't mutate the current scope", ->
with COPILOT\eval_once '
(def a 1)
(export
(def a 5)
(def b 2))
(export*)'
assert.is.true \is_const!
assert.is.equal T.scope, .result.type
assert.is.equal (Constant.num 1), .result!.values.a.result
assert.is.nil .result!.values.b
describe "export*", ->
COPILOT = TestPilot!
it "validates args", ->
err = assert.has.error -> COPILOT\eval_once '(export* (+ 1 2))'
assert.matches "arguments need to be symbols", err
err = assert.has.error -> COPILOT\eval_once '(export* 3)'
assert.matches "is not a sym", err
err = assert.has.error -> COPILOT\eval_once '(export* a)'
assert.matches "undefined symbol", err
describe "without args", ->
it "returns a scope containing all local defs", ->
with COPILOT\eval_once '(export*)'
assert.is.true \is_const!
assert.is.equal T.scope, .result.type
assert.is.same {}, .result!.values
with COPILOT\eval_once '
(def a 1 b "hello" c 3)
(export*)'
assert.is.true \is_const!
assert.is.equal T.scope, .result.type
assert.is.equal (Constant.num 1), .result!.values.a.result
assert.is.equal (Constant.str 'hello'), .result!.values.b.result
assert.is.equal (Constant.num 3), .result!.values.c.result
describe "with args", ->
it "returns a scope containing those defs", ->
with COPILOT\eval_once '
(def a 1 b "hello" c 3)
(export* a b)'
assert.is.true \is_const!
assert.is.equal T.scope, .result.type
assert.is.equal (Constant.num 1), .result!.values.a.result
assert.is.equal (Constant.str 'hello'), .result!.values.b.result
assert.is.nil .result!.values.c
describe "use", ->
COPILOT = TestPilot!
it "returns nothing", ->
with COPILOT\eval_once '(use (export))'
assert.is.true \is_const!
assert.is.nil .result
it "updates the current scope", ->
with COPILOT\eval_once '
(use (export
(def a 2)))
a'
assert.is.true \is_const!
assert.is.equal (Constant.num 2), .result
it "terms and conditions apply", ->
err = assert.has.error -> COPILOT\eval_once '
(def a 1)
(use
(export
(def a 5)
(def b 2)))'
assert.matches "cannot redefine symbol", err
|