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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
|
----
-- Builtin `Action`s and `Op`s.
--
-- Please see the [reference](../../reference/index.html#builtins) for
-- documentation.
--
-- @module builtin
import Action, Op, FnDef, Input, val from require 'core.base'
import ValueStream, LiteralValue from require 'core.stream.value'
import Result from require 'core.result'
import Cell from require 'core.cell'
import Scope from require 'core.scope'
import Tag from require 'core.tag'
import op_invoke from require 'core.invoke'
doc = ValueStream.meta
meta:
name: 'doc'
summary: "Print documentation in console."
examples: { '(doc sym)' }
description: "Print the documentation for `sym` to the console"
value: class extends Action
format_meta = =>
str = @summary
if @examples
for example in *@examples
str ..= '\n' .. example
if @description
str ..= '\n' .. @description\match '^\n*(.+)\n*$'
str
eval: (scope, tail) =>
assert #tail == 1, "'doc' takes exactly one parameter"
result = L\push tail[1]\eval, scope
with Result children: { def }
meta = result.value.meta
L\print "(doc #{tail[1]}):\n#{format_meta meta}\n"
def = ValueStream.meta
meta:
name: 'def'
summary: "Declare symbols in current scope."
examples: { '(def sym1 val-expr1 [sym2 val-expr2…])' }
description: "
Define the symbols `sym1`, `sym2`, … to resolve to the values of `val-expr1`,
`val-expr2`, …."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail > 1, "'def' requires at least 2 arguments"
assert #tail % 2 == 0, "'def' requires an even number of arguments"
children = L\push ->
return for i=1,#tail,2
name, val_expr = tail[i], tail[i+1]
name = (name\quote scope)\unwrap 'sym'
with val_expr\eval scope
scope\set name, \make_ref!
Result :children
use = ValueStream.meta
meta:
name: 'use'
summary: "Merge scopes into current scope."
examples: { '(use scope1 [scope2…])' }
description: "
Copy all symbol definitions from `scope1`, `scope2`, … to the current scope.
All arguments have to be evaltime constant."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
for child in *tail
result = L\push child\eval, scope
value = result\const!
scope\use value\unwrap 'scope', "'use' only works on scopes"
Result!
require_ = ValueStream.meta
meta:
name: 'require'
summary: "Load a module."
examples: { '(require name)' }
description: "Load a module and return its scope."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail == 1, "'require' takes exactly one parameter"
result = L\push tail[1]\eval, scope
name = result\const!
L\trace @, "loading module #{name}"
scope = ValueStream.wrap require "lib.#{name\unwrap 'str'}"
Result :value
import_ = ValueStream.meta
meta:
name: 'import'
summary: "Require and define modules."
examples: { '(import sym1 [sym2…])' }
description: "
Requires modules `sym1`, `sym2`, … and define them as `sym1`, `sym2`, … in the
current scope."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail > 0, "'import' requires at least one arguments"
for child in *tail
name = (child\quote scope)\unwrap 'sym'
value = ValueStream.wrap require "lib.#{name}"
scope\set name, Result :value -- (require "lib.#{name})\unwrap 'scope'
Result!
import_star = ValueStream.meta
meta:
name: 'import*'
summary: "Require and use modules."
examples: { '(import* sym1 [sym2…])' }
description: "
Requires modules `sym1`, `sym2`, … and merges them into the current scope."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail > 0, "'import' requires at least one arguments"
for child in *tail
name = (child\quote scope)\unwrap 'sym'
value = ValueStream.wrap require "lib.#{name}"
scope\use value\unwrap 'scope' -- (require "lib.#{name}")\unwrap 'scope'
Result!
fn = ValueStream.meta
meta:
name: 'fn'
summary: "Declare a function."
examples: { '(fn (p1 [p2…]) body-expr)' }
description: "
The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
function is invoked."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail == 2, "'fn' takes exactly two arguments"
{ params, body } = tail
assert params.__class == Cell, "'fn's first argument has to be an expression"
param_symbols = for param in *params.children
assert param.type == 'sym', "function parameter declaration has to be a symbol"
param\quote scope
body = body\quote scope
Result value: with ValueStream.wrap FnDef param_symbols, body, scope
.meta = {
summary: "(user defined function)"
examples: { "(??? #{table.concat [p! for p in *param_symbols], ' '})" }
}
defn = ValueStream.meta
meta:
name: 'defn'
summary: "Define a function."
examples: { '(defn name-sym (p1 [p2…]) body-expr)' }
description: "
Declare a function and define it as `name-sym` in the current scope.
The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
function is invoked."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail == 3, "'defn' takes exactly three arguments"
{ name, params, body } = tail
name = (name\quote scope)\unwrap 'sym'
assert params.__class == Cell, "'defn's second argument has to be an expression"
param_symbols = for param in *params.children
assert param.type == 'sym', "function parameter declaration has to be a symbol"
param\quote scope
body = body\quote scope
value = with ValueStream.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!
do_expr = ValueStream.meta
meta:
name: 'do_expr'
summary: "Evaluate multiple expressions in a new scope."
examples: { '(do expr1 [expr2…])' }
description: "
Evaluate `expr1`, `expr2`, … and return the value of the last expression."
value: class extends Action
eval: (scope, tail) =>
scope = Scope scope
Result children: [expr\eval scope for expr in *tail]
if_ = ValueStream.meta
meta:
name: 'if'
summary: "Make an evaltime const choice."
examples: { '(if bool then-expr [else-expr])' }
description: "
`bool` has to be an evaltime constant. If it is truthy, this expression is equivalent
to `then-expr`, otherwise it is equivalent to `else-xpr` if given, or nil otherwise."
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail >= 2, "'if' needs at least two parameters"
assert #tail <= 3, "'if' needs at most three parameters"
{ xif, xthen, xelse } = tail
xif = L\push xif\eval, scope
xif = xif\const!\unwrap!
if xif
xthen\eval scope
elseif xelse
xelse\eval scope
trace_ = ValueStream.meta
meta:
name: 'trace!'
summary: "Trace an expression's value at evaltime."
examples: { '(trace! expr)' }
value: class extends Action
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail == 1, "'trace!' takes exactly one parameter"
with result = L\push tail[1]\eval, scope
L\print "trace! #{tail[1]\stringify!}: #{result.value}"
trace = ValueStream.meta
meta:
name: 'trace'
summary: "Trace an expression's values at runtime."
examples: { '(trace expr)' }
value: class extends Action
class traceOp extends Op
setup: (inputs) =>
super
prefix: Input.cold inputs[1]
value: Input.hot inputs[2]
tick: =>
L\print "trace #{@inputs.prefix!}: #{@inputs.value.stream}"
eval: (scope, tail) =>
L\trace "evaling #{@}"
assert #tail == 1, "'trace!' takes exactly one parameter"
tag = @tag\clone Tag.parse '-1'
inner = Cell tag, {
LiteralValue 'opdef', traceOp, 'trace'
ValueStream.str tostring tail[1]
tail[1]
}
inner\eval scope
print = ValueStream.meta
meta:
name: 'print'
summary: "Print string values."
examples: { '(print str)' }
value: class extends Op
setup: (inputs) =>
value = val.str\match inputs
super value: Input.hot value
tick: => print @inputs.value!
{
:doc
:trace, 'trace!': trace_, :print
:def, :use
require: require_
import: import_
'import*': import_star
true: ValueStream.meta
meta:
name: 'true'
summary: "The boolean constant `true`."
value: ValueStream.bool true
false: ValueStream.meta
meta:
name: 'false'
summary: "The boolean constant `false`."
value: ValueStream.bool false
bang: ValueStream.meta
meta:
name: 'bang'
summary: "A `bang` value-constant."
value: ValueStream 'bang', true
:fn, :defn
'do': do_expr
if: if_
}
|