septima-lang 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/src/ast-node.d.ts +103 -0
  2. package/dist/src/ast-node.js +156 -0
  3. package/dist/src/extract-message.d.ts +1 -0
  4. package/dist/src/extract-message.js +10 -0
  5. package/dist/src/fail-me.d.ts +1 -0
  6. package/dist/src/fail-me.js +11 -0
  7. package/dist/src/find-array-method.d.ts +15 -0
  8. package/dist/src/find-array-method.js +104 -0
  9. package/dist/src/find-string-method.d.ts +2 -0
  10. package/dist/src/find-string-method.js +88 -0
  11. package/dist/src/index.d.ts +1 -0
  12. package/dist/src/index.js +18 -0
  13. package/dist/src/location.d.ts +11 -0
  14. package/dist/src/location.js +3 -0
  15. package/dist/src/parser.d.ts +45 -0
  16. package/dist/src/parser.js +483 -0
  17. package/dist/src/result.d.ts +24 -0
  18. package/dist/src/result.js +29 -0
  19. package/dist/src/runtime.d.ts +28 -0
  20. package/dist/src/runtime.js +351 -0
  21. package/dist/src/scanner.d.ts +23 -0
  22. package/dist/src/scanner.js +88 -0
  23. package/dist/src/septima.d.ts +32 -0
  24. package/dist/src/septima.js +91 -0
  25. package/dist/src/should-never-happen.d.ts +1 -0
  26. package/dist/src/should-never-happen.js +9 -0
  27. package/dist/src/source-code.d.ts +19 -0
  28. package/dist/src/source-code.js +90 -0
  29. package/dist/src/stack.d.ts +11 -0
  30. package/dist/src/stack.js +19 -0
  31. package/dist/src/switch-on.d.ts +1 -0
  32. package/dist/src/switch-on.js +9 -0
  33. package/dist/src/symbol-table.d.ts +6 -0
  34. package/dist/src/symbol-table.js +3 -0
  35. package/dist/src/value.d.ts +128 -0
  36. package/dist/src/value.js +634 -0
  37. package/dist/tests/parser.spec.d.ts +1 -0
  38. package/dist/tests/parser.spec.js +35 -0
  39. package/dist/tests/septima-compute-module.spec.d.ts +1 -0
  40. package/dist/tests/septima-compute-module.spec.js +36 -0
  41. package/dist/tests/septima.spec.d.ts +1 -0
  42. package/dist/tests/septima.spec.js +845 -0
  43. package/dist/tests/value.spec.d.ts +1 -0
  44. package/dist/tests/value.spec.js +355 -0
  45. package/dist/tsconfig.tsbuildinfo +1 -0
  46. package/package.json +3 -3
  47. package/src/a.js +66 -0
  48. package/src/ast-node.ts +269 -0
  49. package/src/extract-message.ts +5 -0
  50. package/src/fail-me.ts +7 -0
  51. package/src/find-array-method.ts +115 -0
  52. package/src/find-string-method.ts +84 -0
  53. package/src/index.ts +1 -0
  54. package/src/location.ts +13 -0
  55. package/src/parser.ts +554 -0
  56. package/src/result.ts +45 -0
  57. package/src/runtime.ts +370 -0
  58. package/src/scanner.ts +106 -0
  59. package/src/septima.ts +121 -0
  60. package/src/should-never-happen.ts +4 -0
  61. package/src/source-code.ts +101 -0
  62. package/src/stack.ts +18 -0
  63. package/src/switch-on.ts +4 -0
  64. package/src/symbol-table.ts +7 -0
  65. package/src/value.ts +742 -0
  66. package/tests/parser.spec.ts +36 -0
  67. package/tests/septima-compute-module.spec.ts +41 -0
  68. package/tests/septima.spec.ts +921 -0
  69. package/tests/value.spec.ts +387 -0
  70. package/main.js +0 -1
@@ -0,0 +1,387 @@
1
+ import { Value } from '../src/value'
2
+
3
+ const err = () => {
4
+ throw new Error(`should not run`)
5
+ }
6
+
7
+ const fixed = (u: unknown) => () => Value.from(u)
8
+
9
+ const notFromHere = () => {
10
+ throw new Error('should not be called from this test')
11
+ }
12
+
13
+ describe('value', () => {
14
+ test('arithmetics', () => {
15
+ expect(Value.num(5).plus(Value.num(3)).export()).toEqual(8)
16
+ expect(Value.num(5).minus(Value.num(3)).export()).toEqual(2)
17
+ expect(Value.num(5).times(Value.num(3)).export()).toEqual(15)
18
+ expect(Value.num(14).over(Value.num(4)).export()).toEqual(3.5)
19
+ expect(Value.num(5).negate().export()).toEqual(-5)
20
+ expect(Value.num(-12).negate().export()).toEqual(12)
21
+ expect(Value.num(3).power(Value.num(4)).export()).toEqual(81)
22
+ expect(Value.num(2).power(Value.num(8)).export()).toEqual(256)
23
+ })
24
+ test('comparisons of numbers', () => {
25
+ expect(Value.num(5).order(Value.num(3)).export()).toEqual(1)
26
+ expect(Value.num(5).order(Value.num(4)).export()).toEqual(1)
27
+ expect(Value.num(5).order(Value.num(5)).export()).toEqual(0)
28
+ expect(Value.num(5).order(Value.num(6)).export()).toEqual(-1)
29
+ expect(Value.num(5).order(Value.num(7)).export()).toEqual(-1)
30
+ })
31
+ test('booleans', () => {
32
+ expect(Value.bool(true).export()).toEqual(true)
33
+ expect(Value.bool(false).export()).toEqual(false)
34
+ expect(Value.bool(false).not().export()).toEqual(true)
35
+ expect(Value.bool(true).not().export()).toEqual(false)
36
+ })
37
+ describe('boolean operators', () => {
38
+ test('or', () => {
39
+ expect(
40
+ Value.bool(false)
41
+ .or(() => Value.bool(false))
42
+ .export(),
43
+ ).toEqual(false)
44
+ expect(
45
+ Value.bool(false)
46
+ .or(() => Value.bool(true))
47
+ .export(),
48
+ ).toEqual(true)
49
+ expect(
50
+ Value.bool(true)
51
+ .or(() => Value.bool(false))
52
+ .export(),
53
+ ).toEqual(true)
54
+ expect(
55
+ Value.bool(true)
56
+ .or(() => Value.bool(true))
57
+ .export(),
58
+ ).toEqual(true)
59
+ })
60
+ test('and', () => {
61
+ expect(
62
+ Value.bool(false)
63
+ .and(() => Value.bool(false))
64
+ .export(),
65
+ ).toEqual(false)
66
+ expect(
67
+ Value.bool(false)
68
+ .and(() => Value.bool(true))
69
+ .export(),
70
+ ).toEqual(false)
71
+ expect(
72
+ Value.bool(true)
73
+ .and(() => Value.bool(false))
74
+ .export(),
75
+ ).toEqual(false)
76
+ expect(
77
+ Value.bool(true)
78
+ .and(() => Value.bool(true))
79
+ .export(),
80
+ ).toEqual(true)
81
+ })
82
+ })
83
+ test('comparisons of booleans', () => {
84
+ expect(Value.bool(false).order(Value.bool(false)).export()).toEqual(0)
85
+ expect(Value.bool(false).order(Value.bool(true)).export()).toEqual(-1)
86
+ expect(Value.bool(true).order(Value.bool(false)).export()).toEqual(1)
87
+ expect(Value.bool(true).order(Value.bool(true)).export()).toEqual(0)
88
+ })
89
+ test('strings', () => {
90
+ expect(Value.str('abc').export()).toEqual('abc')
91
+ expect(Value.str('').export()).toEqual('')
92
+ expect(Value.str('a').plus(Value.str('b')).export()).toEqual('ab')
93
+ expect(Value.str('').plus(Value.str('')).export()).toEqual('')
94
+ expect(Value.str('').plus(Value.str('xyz')).export()).toEqual('xyz')
95
+ expect(Value.str('pqr').plus(Value.str('')).export()).toEqual('pqr')
96
+ expect(Value.str('zxcvb').plus(Value.str('nm')).export()).toEqual('zxcvbnm')
97
+ })
98
+ test('comparisons of strings', () => {
99
+ expect(Value.str('e').order(Value.str('c')).export()).toEqual(1)
100
+ expect(Value.str('e').order(Value.str('d')).export()).toEqual(1)
101
+ expect(Value.str('e').order(Value.str('e')).export()).toEqual(0)
102
+ expect(Value.str('e').order(Value.str('f')).export()).toEqual(-1)
103
+ expect(Value.str('e').order(Value.str('g')).export()).toEqual(-1)
104
+ })
105
+ test('arrays', () => {
106
+ expect(Value.arr([Value.num(10), Value.num(20)]).export()).toEqual([10, 20])
107
+ expect(Value.arr([]).export()).toEqual([])
108
+ expect(Value.arr([Value.str('ab'), Value.num(500), Value.bool(true)]).export()).toEqual(['ab', 500, true])
109
+ })
110
+ test('objects', () => {
111
+ expect(Value.obj({ x: Value.num(10), y: Value.num(20) }).export()).toEqual({ x: 10, y: 20 })
112
+ expect(Value.obj({}).export()).toEqual({})
113
+ expect(Value.obj({ the: Value.str('ab'), quick: Value.num(500), brown: Value.bool(true) }).export()).toEqual({
114
+ the: 'ab',
115
+ quick: 500,
116
+ brown: true,
117
+ })
118
+ const o = Value.obj({ the: Value.str('ab'), quick: Value.num(500), brown: Value.bool(true) })
119
+ expect(o.access('the', notFromHere).export()).toEqual('ab')
120
+ expect(o.access('quick', notFromHere).export()).toEqual(500)
121
+ expect(o.access('brown', notFromHere).export()).toEqual(true)
122
+ expect(o.access(Value.str('quick'), notFromHere).export()).toEqual(500)
123
+ })
124
+ test('yells if access() is called with value which is neither string or num', () => {
125
+ const o = Value.obj({ the: Value.str('ab'), quick: Value.num(500), brown: Value.bool(true) })
126
+ expect(() => o.access(Value.arr([]), notFromHere).export()).toThrowError(
127
+ 'value type error: expected either num or str but found []',
128
+ )
129
+ expect(() => o.access(Value.bool(false), notFromHere).export()).toThrowError(
130
+ 'value type error: expected either num or str but found false',
131
+ )
132
+ expect(() => o.access(Value.obj({ x: Value.num(1) }), notFromHere).export()).toThrowError(
133
+ 'value type error: expected either num or str but found {"x":1}',
134
+ )
135
+ })
136
+ test('json', () => {
137
+ const v = Value.obj({ x: Value.num(1) })
138
+ expect(JSON.stringify(v)).toEqual('{"x":1}')
139
+ })
140
+ describe('ifElse', () => {
141
+ test('when applied to true evaluates the positive branch', () => {
142
+ expect(Value.bool(true).ifElse(fixed('yes'), fixed('no')).export()).toEqual('yes')
143
+ })
144
+ test('when applied to false evaluates the positive branch', () => {
145
+ expect(Value.bool(false).ifElse(fixed('yes'), fixed('no')).export()).toEqual('no')
146
+ })
147
+ test('errors if applied to a non-boolean', () => {
148
+ expect(() => Value.num(1).ifElse(fixed('yes'), fixed('no')).export()).toThrowError('expected bool but found 1')
149
+ })
150
+ })
151
+ describe('sink', () => {
152
+ const sink = Value.sink()
153
+ test('exported as undefined', () => {
154
+ expect(sink.export()).toEqual(undefined)
155
+ })
156
+ test('arithmetic operations on sink evaluate to sink', () => {
157
+ expect(sink.plus(Value.num(5)).export()).toEqual(undefined)
158
+ expect(sink.minus(Value.num(5)).export()).toEqual(undefined)
159
+ expect(sink.times(Value.num(5)).export()).toEqual(undefined)
160
+ expect(sink.over(Value.num(5)).export()).toEqual(undefined)
161
+ expect(sink.power(Value.num(5)).export()).toEqual(undefined)
162
+ expect(sink.modulo(Value.num(5)).export()).toEqual(undefined)
163
+ expect(sink.negate().export()).toEqual(undefined)
164
+
165
+ expect(Value.num(5).plus(sink).export()).toEqual(undefined)
166
+ expect(Value.num(5).minus(sink).export()).toEqual(undefined)
167
+ expect(Value.num(5).times(sink).export()).toEqual(undefined)
168
+ expect(Value.num(5).over(sink).export()).toEqual(undefined)
169
+ expect(Value.num(5).power(sink).export()).toEqual(undefined)
170
+ expect(Value.num(5).modulo(sink).export()).toEqual(undefined)
171
+ })
172
+ test('boolean operations on sink evaluate to sink', () => {
173
+ expect(sink.and(fixed(true)).export()).toEqual(undefined)
174
+ expect(sink.or(fixed(true)).export()).toEqual(undefined)
175
+ expect(sink.not().export()).toEqual(undefined)
176
+ })
177
+ test('when sink is the right-hand-side of a boolean expression, the result is sink only if the left-hand-side dictates so', () => {
178
+ expect(Value.bool(true).and(fixed(sink)).export()).toEqual(undefined)
179
+ expect(Value.bool(false).and(fixed(sink)).export()).toEqual(false)
180
+ expect(Value.bool(true).or(fixed(sink)).export()).toEqual(true)
181
+ expect(Value.bool(false).or(fixed(sink)).export()).toEqual(undefined)
182
+ })
183
+ test('ifElse with sink condition evaluates to sink', () => {
184
+ expect(sink.ifElse(fixed('y'), fixed('n')).export()).toEqual(undefined)
185
+ })
186
+ test('ifElse with sink positive expression evaluates to sink only if the condition is true', () => {
187
+ expect(Value.bool(true).ifElse(fixed(sink), fixed(-200)).export()).toEqual(undefined)
188
+ expect(Value.bool(false).ifElse(fixed(sink), fixed(-200)).export()).toEqual(-200)
189
+ })
190
+ test('ifElse with sink negative expression evaluates to sink only if the condition is false', () => {
191
+ expect(Value.bool(true).ifElse(fixed(-300), fixed(sink)).export()).toEqual(-300)
192
+ expect(Value.bool(false).ifElse(fixed(-300), fixed(sink)).export()).toEqual(undefined)
193
+ })
194
+ test('access to an attribute of a sink evaluates to sink', () => {
195
+ expect(sink.access('foo', notFromHere).export()).toEqual(undefined)
196
+ })
197
+ test('calling a sink evaluates to sink', () => {
198
+ expect(sink.call([], err).export()).toEqual(undefined)
199
+ })
200
+
201
+ test('applying .keys() to sink evaluates to sink', () => {
202
+ expect(sink.keys().export()).toEqual(undefined)
203
+ })
204
+ test('applying .entries() to sink evaluates to sink', () => {
205
+ expect(sink.entries().export()).toEqual(undefined)
206
+ })
207
+ test('applying .fromEntries() to sink evaluates to sink', () => {
208
+ expect(sink.fromEntries().export()).toEqual(undefined)
209
+ })
210
+ describe('unsink()', () => {
211
+ test('when applied to a non-sink value evaluates to it', () => {
212
+ expect(Value.num(5).unsink(fixed('x')).export()).toEqual(5)
213
+ })
214
+ test('when applied to a sink value evaluates to its argument', () => {
215
+ expect(Value.num(5).unsink(fixed('x')).export()).toEqual(5)
216
+ })
217
+ })
218
+ describe('comparisons', () => {
219
+ test('comparing a sink with itself evaluates to true', () => {
220
+ expect(sink.equalsTo(sink).export()).toEqual(true)
221
+ })
222
+
223
+ test('comparing a sink with other types evaluates to false', () => {
224
+ expect(sink.equalsTo(Value.arr([])).export()).toEqual(false)
225
+ expect(sink.equalsTo(Value.bool(false)).export()).toEqual(false)
226
+ expect(sink.equalsTo(Value.bool(true)).export()).toEqual(false)
227
+ expect(sink.equalsTo(Value.num(0)).export()).toEqual(false)
228
+ expect(sink.equalsTo(Value.num(5)).export()).toEqual(false)
229
+ expect(sink.equalsTo(Value.obj({})).export()).toEqual(false)
230
+ expect(sink.equalsTo(Value.str('')).export()).toEqual(false)
231
+ expect(sink.equalsTo(Value.str('s')).export()).toEqual(false)
232
+ })
233
+ test('erros when trying to order a sink with a non-sink', () => {
234
+ expect(() => sink.order(Value.arr([])).export()).toThrowError('Cannot compare a')
235
+ expect(() => sink.order(Value.bool(false)).export()).toThrowError('Cannot compare a')
236
+ expect(() => sink.order(Value.bool(true)).export()).toThrowError('Cannot compare a')
237
+ expect(() => sink.order(Value.num(0)).export()).toThrowError('Cannot compare a')
238
+ expect(() => sink.order(Value.num(5)).export()).toThrowError('Cannot compare a')
239
+ expect(() => sink.order(Value.obj({})).export()).toThrowError('Cannot compare a')
240
+ expect(() => sink.order(Value.str('')).export()).toThrowError('Cannot compare a')
241
+ expect(() => sink.order(Value.str('a')).export()).toThrowError('Cannot compare a')
242
+
243
+ expect(() => Value.arr([]).order(sink).export()).toThrowError('Cannot compare a')
244
+ expect(() => Value.bool(false).order(sink).export()).toThrowError('Cannot compare a')
245
+ expect(() => Value.bool(true).order(sink).export()).toThrowError('Cannot compare a')
246
+ expect(() => Value.num(0).order(sink).export()).toThrowError('Cannot compare a')
247
+ expect(() => Value.num(5).order(sink).export()).toThrowError('Cannot compare a')
248
+ expect(() => Value.obj({}).order(sink).export()).toThrowError('Cannot compare a')
249
+ expect(() => Value.str('').order(sink).export()).toThrowError('Cannot compare a')
250
+ expect(() => Value.str('a').order(sink).export()).toThrowError('Cannot compare a')
251
+ })
252
+ })
253
+ })
254
+ describe('type erros', () => {
255
+ const five = Value.num(1)
256
+ const t = Value.bool(true)
257
+ const f = Value.bool(false)
258
+
259
+ const check = (a: Value, b: Value | Value[], f: (lhs: Value, rhs: Value) => void) => {
260
+ const arr = Array.isArray(b) ? b : [b]
261
+ const r = /(^value type error: expected)|(^Cannot compare a )/
262
+ // /(^value type error: expected)|(^Type error: operator cannot be applied to operands of type)|(^Cannot compare when the left-hand-side value is of type)|(^Not a)/
263
+ for (const curr of arr) {
264
+ expect(() => f(a, curr)).toThrowError(r)
265
+ expect(() => f(curr, a)).toThrowError(r)
266
+ }
267
+ }
268
+
269
+ test('emits erros when numeric operations are applied to a boolean (either lhs or rhs)', () => {
270
+ check(five, t, (x, y) => x.plus(y))
271
+ check(five, t, (x, y) => x.minus(y))
272
+ check(five, t, (x, y) => x.times(y))
273
+ check(five, t, (x, y) => x.over(y))
274
+ check(five, t, (x, y) => x.power(y))
275
+ check(five, t, (x, y) => x.modulo(y))
276
+ check(five, t, (x, y) => x.order(y))
277
+ check(t, t, x => x.negate())
278
+ expect(1).toEqual(1) // make the linter happy
279
+ })
280
+ test('emits erros when boolean operations are applied to a number (either lhs or rhs)', () => {
281
+ check(five, f, (x, y) => x.or(() => y))
282
+ check(five, t, (x, y) => x.and(() => y))
283
+ check(five, five, x => x.not())
284
+ expect(1).toEqual(1) // make the linter happy
285
+ })
286
+ })
287
+ describe('foreign code calls', () => {
288
+ test('invokes the given function', () => {
289
+ const indexOf = Value.foreign(s => 'the quick brown fox jumps over the lazy dog'.indexOf(s.assertStr()))
290
+ expect(indexOf.call([Value.str('quick')], err).export()).toEqual(4)
291
+ })
292
+ })
293
+ describe('string operatios', () => {
294
+ test('.length', () => {
295
+ expect(Value.str('four scores AND seven').access('length', notFromHere).export()).toEqual(21)
296
+ })
297
+ test.each([
298
+ ['at', [Value.num(10)], 'e'],
299
+ ['at', [Value.num(-4)], 'v'],
300
+ ['charAt', [Value.num(10)], 'e'],
301
+ ['concat', [Value.str('years')], ' four scores AND seven years'],
302
+ ['endsWith', [Value.str('seven ')], true],
303
+ ['endsWith', [Value.str('years')], false],
304
+ ['includes', [Value.str('scores')], true],
305
+ ['includes', [Value.str('years')], false],
306
+ ['indexOf', [Value.str('e')], 10],
307
+ ['lastIndexOf', [Value.str('e')], 20],
308
+ ['match', [Value.str('r|f')], ['f']],
309
+ ['matchAll', [Value.str('r|f')], [['f'], ['r'], ['r']]],
310
+ ['padEnd', [Value.num(25), Value.str('#')], ' four scores AND seven ##'],
311
+ ['padStart', [Value.num(25), Value.str('#')], '## four scores AND seven '],
312
+ ['repeat', [Value.num(3)], ' four scores AND seven four scores AND seven four scores AND seven '],
313
+ ['replace', [Value.str('o'), Value.str('#')], ' f#ur scores AND seven '],
314
+ ['replaceAll', [Value.str('o'), Value.str('#')], ' f#ur sc#res AND seven '],
315
+ ['search', [Value.str('sco..s')], 6],
316
+ ['slice', [Value.num(13), Value.num(-7)], 'AND'],
317
+ ['split', [Value.str(' ')], ['', 'four', 'scores', 'AND', 'seven', '']],
318
+ ['startsWith', [Value.str(' four')], true],
319
+ ['startsWith', [Value.str('seven')], false],
320
+ ['substring', [Value.num(6), Value.num(12)], 'scores'],
321
+ ['substring', [Value.num(13), Value.num(-7)], ' four scores '],
322
+ ['toLowerCase', [], ' four scores and seven '],
323
+ ['toUpperCase', [], ' FOUR SCORES AND SEVEN '],
324
+ ['trim', [], 'four scores AND seven'],
325
+ ['trimEnd', [], ' four scores AND seven'],
326
+ ['trimStart', [], 'four scores AND seven '],
327
+ ])('provides the .%s() method', (name, args, expected) => {
328
+ const callee = Value.str(' four scores AND seven ').access(name, notFromHere)
329
+ const actual = callee.call(args, err)
330
+ expect(actual.export()).toEqual(expected)
331
+ })
332
+ })
333
+ describe('array operations', () => {
334
+ test('.length', () => {
335
+ expect(
336
+ Value.arr([Value.str('foo'), Value.str('bar'), Value.str('foo'), Value.str('goo')])
337
+ .access('length', notFromHere)
338
+ .export(),
339
+ ).toEqual(4)
340
+ })
341
+ test.each([
342
+ ['at', [Value.num(-1)], 'goo'],
343
+ ['at', [Value.num(4)], undefined],
344
+ ['concat', [Value.arr([Value.str('boo'), Value.str('poo')])], ['foo', 'bar', 'foo', 'goo', 'boo', 'poo']],
345
+ [
346
+ 'entries',
347
+ [],
348
+ [
349
+ [0, 'foo'],
350
+ [1, 'bar'],
351
+ [2, 'foo'],
352
+ [3, 'goo'],
353
+ ],
354
+ ],
355
+ // TODO(imaman): ['find', [Value.foreign(v => v.assertStr() === 'lorem ipsum')], ??]"",
356
+ ['includes', [Value.str('bar')], true],
357
+ ['includes', [Value.str('lorem-ipsum')], false],
358
+ ['indexOf', [Value.str('goo')], 3],
359
+ ['join', [Value.str('; ')], 'foo; bar; foo; goo'],
360
+ ['lastIndexOf', [Value.str('foo')], 2],
361
+ ['lastIndexOf', [Value.str('lorem ipsum')], -1],
362
+ ['reverse', [], ['goo', 'foo', 'bar', 'foo']],
363
+ ['slice', [Value.num(1), Value.num(2)], ['bar']],
364
+ ['slice', [Value.num(1), Value.num(3)], ['bar', 'foo']],
365
+ ['slice', [Value.num(2), Value.num(4)], ['foo', 'goo']],
366
+ ])('provides the .%s() method', (name, args, expected) => {
367
+ const input = Value.arr([Value.str('foo'), Value.str('bar'), Value.str('foo'), Value.str('goo')])
368
+ const before = JSON.parse(JSON.stringify(input))
369
+ const callee = input.access(name, notFromHere)
370
+ const actual = callee.call(args, err)
371
+ expect(actual.export()).toEqual(expected)
372
+ // Make sure the input array was not accidentally mutated.
373
+ expect(JSON.parse(JSON.stringify(input))).toEqual(before)
374
+ })
375
+ test('.flat() flattens', () => {
376
+ const input = Value.arr([Value.arr([Value.str('a'), Value.str('b')]), Value.str('c')])
377
+ const callee = input.access('flat', notFromHere)
378
+ const actual = callee.call([], err)
379
+ expect(actual.export()).toEqual(['a', 'b', 'c'])
380
+ })
381
+ })
382
+
383
+ test.todo('array.sort()')
384
+ test.todo('what happens when we get an undefined from a foreign call (like Array.get())')
385
+ test.todo('access to non-existing string method (a sad path test)')
386
+ test.todo('access to non-existing array method (a sad path test)')
387
+ })
package/main.js DELETED
@@ -1 +0,0 @@
1
- (()=>{"use strict";var e={166:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.span=t.show=void 0;const n=r(29),s=r(434);t.show=function e(t){if(Array.isArray(t))return t.map((t=>e(t))).join(", ");if("arrayLiteral"===t.tag)return`[${t.parts.map((t=>"element"===t.tag?e(t.v):"spread"===t.tag?`...${e(t.v)}`:void(0,n.shouldNeverHappen)(t))).join(", ")}]`;if("binaryOperator"===t.tag)return`(${e(t.lhs)} ${t.operator} ${e(t.rhs)})`;if("dot"===t.tag)return`${e(t.receiver)}.${e(t.ident)}`;if("export*"===t.tag)return"(export*)";if("ternary"===t.tag)return`${e(t.condition)} ? ${e(t.positive)} : ${e(t.negative)}`;if("functionCall"===t.tag)return`${e(t.callee)}(${e(t.actualArgs)})`;if("ident"===t.tag)return t.t.text;if("if"===t.tag)return`if (${e(t.condition)}) ${e(t.positive)} else ${e(t.negative)}`;if("indexAccess"===t.tag)return`${e(t.receiver)}[${e(t.index)}]`;if("lambda"===t.tag)return`fun (${e(t.formalArgs)}) ${e(t.body)}`;if("literal"===t.tag)return(0,s.switchOn)(t.type,{bool:()=>t.t.text,num:()=>t.t.text,sink:()=>"sink","sink!":()=>"sink!","sink!!":()=>"sink!!",str:()=>`'${t.t.text}'`});if("objectLiteral"===t.tag)return`{${t.parts.map((t=>"computedName"===t.tag?`[${e(t.k)}]: ${e(t.v)}`:"hardName"===t.tag?`${e(t.k)}: ${e(t.v)}`:"spread"===t.tag?`...${e(t.o)}`:void(0,n.shouldNeverHappen)(t))).join(", ")}}`;if("topLevelExpression"===t.tag){const r=t.definitions.map((t=>`let ${e(t.ident)} = ${e(t.value)}`)).join("; ");return`${r?r+";":""}${r&&t.computation?" ":""}${t.computation?e(t.computation):""}`}if("unaryOperator"===t.tag)return`${t.operator}${e(t.operand)}`;if("unit"===t.tag){const r=t.imports.map((t=>`import * as ${e(t.ident)} from '${t.pathToImportFrom.text}';`)).join("\n");return`${r?r+"\n":""}${e(t.expression)}`}(0,n.shouldNeverHappen)(t)},t.span=function e(t){const r=(e,t)=>({from:e.from,to:t.to}),s=e=>({from:e.location,to:{offset:e.location.offset+e.text.length-1}});if("arrayLiteral"===t.tag)return r(s(t.start),s(t.end));if("binaryOperator"===t.tag)return r(e(t.lhs),e(t.rhs));if("dot"===t.tag)return r(e(t.receiver),e(t.ident));if("functionCall"===t.tag)return r(e(t.callee),s(t.end));if("ident"===t.tag)return s(t.t);if("export*"===t.tag)return{from:{offset:0},to:{offset:0}};if("if"===t.tag)return r(e(t.condition),e(t.negative));if("indexAccess"===t.tag)return r(e(t.receiver),e(t.index));if("lambda"===t.tag)return r(s(t.start),e(t.body));if("ternary"===t.tag)return r(e(t.condition),e(t.negative));if("literal"===t.tag)return s(t.t);if("objectLiteral"===t.tag)return r(s(t.start),s(t.end));if("topLevelExpression"===t.tag){if(t.computation){const n=t.definitions.find(Boolean),o=e(t.computation);return r(n?s(n.start):o,o)}if(t.definitions.length){const n=t.definitions[0],o=t.definitions[t.definitions.length-1];return r(s(n.start),e(o.value))}return{from:{offset:0},to:{offset:0}}}if("unaryOperator"===t.tag)return r(s(t.operatorToken),e(t.operand));if("unit"===t.tag){const n=t.imports.find(Boolean),o=e(t.expression);return r(n?s(n.start):o,o)}(0,n.shouldNeverHappen)(t)}},883:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.extractMessage=void 0,t.extractMessage=function(e){return e.message}},465:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.failMe=void 0,t.failMe=function(e){if(!e)throw new Error("This expression must never be evaluated");throw new Error(`Bad value: ${e}`)}},855:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.findArrayMethod=void 0;const n=r(669);function s(e){const t=[];for(const r of e){const e=n.Value.from(r),s=e.unwrap();Array.isArray(s)?t.push(...s):t.push(e)}return t}t.findArrayMethod=function(e,t,r){const o=e=>(...t)=>r(e,t.map((e=>n.Value.from(e)))),i=e=>(...t)=>r(e,t.map((e=>n.Value.from(e)))).assertBool();if("at"===t)return n.Value.foreign((t=>e.at(t.assertNum())));if("concat"===t)return n.Value.foreign((t=>e.concat(t.assertArr())));if("entries"===t)return n.Value.foreign((()=>[...e.entries()]));if("every"===t)return n.Value.foreign((t=>e.every(i(t))));if("filter"===t)return n.Value.foreign((t=>e.filter(i(t))));if("find"===t)return n.Value.foreign((t=>e.find(i(t))));if("findIndex"===t)return n.Value.foreign((t=>e.findIndex(i(t))));if("flatMap"===t)return n.Value.foreign((t=>s(e.map(o(t)))));if("flat"===t)return n.Value.foreign((()=>s(e)));if("includes"===t)return n.Value.foreign((t=>e.some((e=>n.Value.from(e).equalsTo(t).isTrue()))));if("indexOf"===t)return n.Value.foreign((t=>e.findIndex((e=>n.Value.from(e).equalsTo(t).isTrue()))));if("join"===t)return n.Value.foreign((t=>e.join(t.assertStr())));if("lastIndexOf"===t)return n.Value.foreign((t=>{for(let r=e.length-1;r>=0;--r)if(n.Value.from(e[r]).equalsTo(t).isTrue())return r;return-1}));if("length"===t)return n.Value.num(e.length);if("map"===t)return n.Value.foreign((t=>e.map(o(t))));if("reverse"===t)return n.Value.foreign((()=>[...e].reverse()));if("reduce"===t)return n.Value.foreign(((t,r)=>e.reduce(o(t),r)));if("reduceRight"===t)return n.Value.foreign(((t,r)=>e.reduceRight(o(t),r)));if("slice"===t)return n.Value.foreign(((t,r)=>e.slice(t?.assertNum(),r?.assertNum())));if("some"===t)return n.Value.foreign((t=>e.some(i(t))));throw new Error(`Unrecognized array method: ${t}`)}},794:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.findStringMethod=void 0;const n=r(669);t.findStringMethod=function(e,t){const r=n.Value.toStringOrNumber(t);if("number"==typeof r)throw new Error("Index is of type number - not supported");if("at"===r)return n.Value.foreign((t=>e.at(t.assertNum())));if("charAt"===r)return n.Value.foreign((t=>e.charAt(t.assertNum())));if("concat"===r)return n.Value.foreign((t=>e.concat(t.assertStr())));if("endsWith"===r)return n.Value.foreign((t=>e.endsWith(t.assertStr())));if("includes"===r)return n.Value.foreign((t=>e.includes(t.assertStr())));if("indexOf"===r)return n.Value.foreign((t=>e.indexOf(t.assertStr())));if("lastIndexOf"===r)return n.Value.foreign((t=>e.lastIndexOf(t.assertStr())));if("length"===r)return n.Value.num(e.length);if("match"===r)return n.Value.foreign((t=>e.match(t.assertStr())));if("matchAll"===r)return n.Value.foreign((t=>[...e.matchAll(new RegExp(t.assertStr(),"g"))]));if("padEnd"===r)return n.Value.foreign(((t,r)=>e.padEnd(t.assertNum(),r?.assertStr())));if("padStart"===r)return n.Value.foreign(((t,r)=>e.padStart(t.assertNum(),r?.assertStr())));if("repeat"===r)return n.Value.foreign((t=>e.repeat(t.assertNum())));if("replace"===r)return n.Value.foreign(((t,r)=>e.replace(t.assertStr(),r.assertStr())));if("replaceAll"===r)return n.Value.foreign(((t,r)=>e.replaceAll(t.assertStr(),r.assertStr())));if("search"===r)return n.Value.foreign((t=>e.search(t.assertStr())));if("slice"===r)return n.Value.foreign(((t,r)=>e.slice(t?.assertNum(),r?.assertNum())));if("split"===r)return n.Value.foreign((t=>e.split(t.assertStr())));if("startsWith"===r)return n.Value.foreign((t=>e.startsWith(t.assertStr())));if("substring"===r)return n.Value.foreign(((t,r)=>e.substring(t.assertNum(),r?.assertNum())));if("toLowerCase"===r)return n.Value.foreign((()=>e.toLowerCase()));if("toUpperCase"===r)return n.Value.foreign((()=>e.toUpperCase()));if("trim"===r)return n.Value.foreign((()=>e.trim()));if("trimEnd"===r)return n.Value.foreign((()=>e.trimEnd()));if("trimStart"===r)return n.Value.foreign((()=>e.trimStart()));throw new Error(`Unrecognized string method: ${r}`)}},326:function(e,t,r){var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r);var s=Object.getOwnPropertyDescriptor(t,r);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,s)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__exportStar||function(e,t){for(var r in e)"default"===r||Object.prototype.hasOwnProperty.call(t,r)||n(t,e,r)};Object.defineProperty(t,"__esModule",{value:!0}),s(r(212),t)},270:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Parser=void 0;const n=r(166),s=r(434);t.Parser=class{constructor(e){this.scanner=e}parse(){const e=this.unit();if(!this.scanner.eof())throw new Error(`Loitering input ${this.scanner.sourceRef}`);return e}unit(){return{tag:"unit",imports:this.imports(),expression:this.expression("TOP_LEVEL")}}imports(){const e=[];for(;;){const t=this.scanner.consumeIf("import");if(!t)return e;this.scanner.consume("*"),this.scanner.consume("as");const r=this.identifier();this.scanner.consume("from");const o=this.maybePrimitiveLiteral();if(void 0===o)throw new Error(`Expected a literal ${this.scanner.sourceRef}`);const i=()=>{throw new Error(`Expected a string literal ${this.scanner.sourceCode.sourceRef((0,n.span)(o))}`)};(0,s.switchOn)(o.type,{bool:i,num:i,str:()=>{},sink:i,"sink!":i,"sink!!":i}),e.push({start:t,ident:r,pathToImportFrom:o.t}),this.scanner.consumeIf(";")}}definitions(e){const t=[];for(;;){if("NESTED"===e&&this.scanner.headMatches("export "))throw new Error(`non-top-level definition cannot be export ${this.scanner.sourceRef}`);let r=this.scanner.consumeIf("let ");if(r||"TOP_LEVEL"!==e||(r=this.scanner.consumeIf("export let ")),!r)return t;const n=this.identifier();this.scanner.consume("=");const s=this.lambda();if(t.push({start:r,ident:n,value:s}),this.scanner.consumeIf(";"),!this.scanner.headMatches("let "))return t}}expression(e="NESTED"){const t=this.definitions(e);if("TOP_LEVEL"===e&&this.scanner.eof())return{tag:"topLevelExpression",definitions:t};this.scanner.consumeIf("return");const r=this.lambda();return 0===t.length?r:{tag:"topLevelExpression",definitions:t,computation:r}}lambda(){const e=this.scanner.consumeIf("fun");if(!e)return this.arrowFunction();this.scanner.consume("(");const t=[];if(this.scanner.consumeIf(")"));else for(;;){const e=this.identifier();if(t.push(e),this.scanner.consumeIf(")"))break;this.scanner.consume(",")}return{tag:"lambda",start:e,formalArgs:t,body:this.expression()}}arrowFunction(){if(this.scanner.headMatches("(",")","=>")){const e=this.scanner.consume("(");return this.scanner.consume(")"),this.scanner.consume("=>"),{tag:"lambda",start:e,formalArgs:[],body:this.lambdaBody()}}if(this.scanner.headMatches(o,"=>")){const e=this.identifier();this.scanner.consume("=>");const t=this.lambdaBody();return{tag:"lambda",start:e.t,formalArgs:[e],body:t}}if(this.scanner.headMatches("(",o,")","=>")){const e=this.scanner.consume("("),t=this.identifier();return this.scanner.consume(")"),this.scanner.consume("=>"),{tag:"lambda",start:e,formalArgs:[t],body:this.lambdaBody()}}if(this.scanner.headMatches("(",o,",")){const e=this.scanner.consume("("),t=[];for(;;){const e=this.identifier();if(t.push(e),this.scanner.consumeIf(")"))break;this.scanner.consume(",")}return this.scanner.consume("=>"),{tag:"lambda",start:e,formalArgs:t,body:this.lambdaBody()}}return this.ifExpression()}lambdaBody(){if(this.scanner.consumeIf("{")){const e=this.expression();return this.scanner.consume("}"),e}return this.expression()}ifExpression(){if(!this.scanner.consumeIf("if"))return this.ternary();this.scanner.consume("(");const e=this.expression();this.scanner.consume(")");const t=this.expression();return this.scanner.consume("else"),{tag:"if",condition:e,positive:t,negative:this.expression()}}ternary(){const e=this.unsink();if(!this.scanner.consumeIf("? "))return e;const t=this.expression();return this.scanner.consume(":"),{tag:"ternary",condition:e,positive:t,negative:this.expression()}}unsink(){const e=this.or();return this.scanner.consumeIf("??")?{tag:"binaryOperator",operator:"??",lhs:e,rhs:this.unsink()}:e}or(){const e=this.and();return this.scanner.consumeIf("||")?{tag:"binaryOperator",operator:"||",lhs:e,rhs:this.or()}:e}and(){const e=this.equality();return this.scanner.consumeIf("&&")?{tag:"binaryOperator",operator:"&&",lhs:e,rhs:this.and()}:e}equality(){const e=this.comparison();return this.scanner.consumeIf("==")?{tag:"binaryOperator",operator:"==",lhs:e,rhs:this.equality()}:this.scanner.consumeIf("!=")?{tag:"binaryOperator",operator:"!=",lhs:e,rhs:this.equality()}:e}comparison(){const e=this.addition();return this.scanner.consumeIf(">=")?{tag:"binaryOperator",operator:">=",lhs:e,rhs:this.comparison()}:this.scanner.consumeIf("<=")?{tag:"binaryOperator",operator:"<=",lhs:e,rhs:this.comparison()}:this.scanner.consumeIf(">")?{tag:"binaryOperator",operator:">",lhs:e,rhs:this.comparison()}:this.scanner.consumeIf("<")?{tag:"binaryOperator",operator:"<",lhs:e,rhs:this.comparison()}:e}addition(){const e=this.multiplication();return this.scanner.consumeIf("+")?{tag:"binaryOperator",operator:"+",lhs:e,rhs:this.addition()}:this.scanner.consumeIf("-")?{tag:"binaryOperator",operator:"-",lhs:e,rhs:this.addition()}:e}multiplication(){const e=this.power();return this.scanner.consumeIf("*")?{tag:"binaryOperator",operator:"*",lhs:e,rhs:this.multiplication()}:this.scanner.consumeIf("/")?{tag:"binaryOperator",operator:"/",lhs:e,rhs:this.multiplication()}:this.scanner.consumeIf("%")?{tag:"binaryOperator",operator:"%",lhs:e,rhs:this.multiplication()}:e}power(){const e=this.unary();return this.scanner.consumeIf("**")?{tag:"binaryOperator",operator:"**",lhs:e,rhs:this.power()}:e}unary(){let e=this.scanner.consumeIf("!");return e?{tag:"unaryOperator",operand:this.unary(),operator:"!",operatorToken:e}:(e=this.scanner.consumeIf("+"),e?{tag:"unaryOperator",operand:this.unary(),operator:"+",operatorToken:e}:(e=this.scanner.consumeIf("-"),e?{tag:"unaryOperator",operand:this.unary(),operator:"-",operatorToken:e}:this.call()))}call(){const e=this.memberAccess();if(!this.scanner.consumeIf("("))return e;const{actualArgs:t,end:r}=this.actualArgList();return{tag:"functionCall",actualArgs:t,callee:e,end:r}}actualArgList(){const e=[],t=this.scanner.consumeIf(")");if(t)return{actualArgs:e,end:t};for(;;){const t=this.expression();e.push(t);let r=this.scanner.consumeIf(")");if(r)return{actualArgs:e,end:r};if(this.scanner.consume(","),r=this.scanner.consumeIf(")"),r)return{actualArgs:e,end:r}}}memberAccess(){let e=this.parenthesized();for(;;)if(this.scanner.consumeIf("."))e={tag:"dot",receiver:e,ident:this.identifier()};else if(this.scanner.consumeIf("["))e={tag:"indexAccess",receiver:e,index:this.expression()},this.scanner.consume("]");else{if(!this.scanner.consumeIf("("))return e;{const{actualArgs:t,end:r}=this.actualArgList();e={tag:"functionCall",actualArgs:t,callee:e,end:r}}}}parenthesized(){if(this.scanner.consumeIf("(")){const e=this.expression();return this.scanner.consume(")"),e}return this.literalOrIdent()}literalOrIdent(){const e=this.maybeLiteral()??this.maybeIdentifier();if(!e)throw new Error(`Unparsable input ${this.scanner.sourceRef}`);return e}maybeLiteral(){return this.maybePrimitiveLiteral()??this.maybeCompositeLiteral()}maybePrimitiveLiteral(){let e=this.scanner.consumeIf("sink!!")||this.scanner.consumeIf("undefined!!");return e?{tag:"literal",type:"sink!!",t:e}:(e=this.scanner.consumeIf("sink!")||this.scanner.consumeIf("undefined!"),e?{tag:"literal",type:"sink!",t:e}:(e=this.scanner.consumeIf("sink")||this.scanner.consumeIf("undefined"),e?{tag:"literal",type:"sink",t:e}:(e=this.scanner.consumeIf("true"),e?{tag:"literal",type:"bool",t:e}:(e=this.scanner.consumeIf("false"),e?{tag:"literal",type:"bool",t:e}:(e=this.scanner.consumeIf(/([0-9]*[.])?[0-9]+/),e?{tag:"literal",type:"num",t:e}:this.scanner.consumeIf('"',!1)?(e=this.scanner.consume(/[^"]*/),this.scanner.consume('"'),{tag:"literal",type:"str",t:e}):this.scanner.consumeIf("'",!1)?(e=this.scanner.consume(/[^']*/),this.scanner.consume("'"),{tag:"literal",type:"str",t:e}):void 0)))))}maybeCompositeLiteral(){let e=this.scanner.consumeIf("[");return e?this.arrayBody(e):(e=this.scanner.consumeIf("{"),e?this.objectBody(e):void 0)}arrayBody(e){const t=this.scanner.consumeIf("]");if(t)return{tag:"arrayLiteral",start:e,parts:[],end:t};const r=[];for(;;){if(this.scanner.consumeIf(",")){const t=this.scanner.consumeIf("]");if(t)return{tag:"arrayLiteral",start:e,parts:r,end:t};continue}if(this.scanner.consumeIf("..."))r.push({tag:"spread",v:this.expression()});else{const e=this.expression();r.push({tag:"element",v:e})}let t=this.scanner.consumeIf("]");if(t)return{tag:"arrayLiteral",start:e,parts:r,end:t};if(this.scanner.consume(","),t=this.scanner.consumeIf("]"),t)return{tag:"arrayLiteral",start:e,parts:r,end:t}}}objectBody(e){const t=this.scanner.consumeIf("}");if(t)return{tag:"objectLiteral",start:e,parts:[],end:t};const r=[];for(;;){if(this.scanner.consumeIf("..."))r.push({tag:"spread",o:this.expression()});else if(this.scanner.consumeIf("[")){const e=this.expression();this.scanner.consume("]"),this.scanner.consume(":");const t=this.expression();r.push({tag:"computedName",k:e,v:t})}else{const e=this.identifier();this.scanner.consume(":");const t=this.expression();r.push({tag:"hardName",k:e,v:t})}let t=this.scanner.consumeIf("}");if(t)return{tag:"objectLiteral",start:e,parts:r,end:t};if(this.scanner.consume(","),t=this.scanner.consumeIf("}"),t)return{tag:"objectLiteral",start:e,parts:r,end:t}}}identifier(){const e=this.maybeIdentifier();if(!e)throw new Error(`Expected an identifier ${this.scanner.sourceRef}`);return e}maybeIdentifier(){const e=this.scanner.consumeIf(o);if(e)return{tag:"ident",t:e}}};const o=/[a-zA-Z][0-9A-Za-z_]*/},351:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ResultSinkImpl=void 0,t.ResultSinkImpl=class{constructor(e,t){this.sink=e,this.sourceCode=t,this.tag="sink"}get where(){return this.sink.span()}get trace(){const e=this.sink.trace();if(e)return this.sourceCode.formatTrace(e)}get symbols(){return this.sink.symbols()?.export()}get message(){return`Evaluated to sink: ${this.trace??this.sourceCode.sourceRef(this.where)}`}}},257:function(e,t,r){var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r);var s=Object.getOwnPropertyDescriptor(t,r);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,s)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&n(t,e,r);return s(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.Runtime=void 0;const i=r(166),a=r(883),u=r(465),c=r(29),l=o(r(884)),f=r(434),h=r(669);class p{constructor(e,t,r){this.symbol=e,this.placeholder=t,this.earlier=r}lookup(e){if(this.symbol===e){const e=this.placeholder.destination;if(void 0===e)throw new Error(`Unresolved definition: ${this.symbol}`);return e}return this.earlier.lookup(e)}export(){const e=this.earlier.export();return e[this.symbol]=this.placeholder.destination?.export()??(0,u.failMe)(`Unbounded symbol: ${this.symbol}`),e}exportValue(){const e=this.earlier.exportValue();return e[this.symbol]=this.placeholder.destination??(0,u.failMe)(`Unbounded symbol: ${this.symbol}`),e}}class d{lookup(e){throw new Error(`Symbol ${e} was not found`)}export(){return{}}exportValue(){return{}}}t.Runtime=class{constructor(e,t="quiet",r,n,s){this.root=e,this.verbosity=t,this.preimports=r,this.getAstOf=n,this.args=s,this.stack=void 0}buildInitialSymbolTable(e){const t=new d,r=h.Value.foreign((e=>e.keys())),n=h.Value.foreign((e=>e.entries())),s=h.Value.foreign((e=>e.fromEntries()));let o=new p("Object",{destination:h.Value.obj({keys:r,entries:n,fromEntries:s})},t);e&&(o=new p("args",{destination:h.Value.from(this.args)},o));for(const[e,t]of Object.entries(this.preimports))o=new p(e,{destination:t},o);return o}compute(){try{return{value:this.evalNode(this.root,this.buildInitialSymbolTable(!0))}}catch(e){const t=[];for(let e=this.stack;e;e=e?.next)t.push(e.ast);return{expressionTrace:t,errorMessage:(0,a.extractMessage)(e),stack:e.stack}}}evalNode(e,t){this.stack=l.push(e,this.stack);let r=this.evalNodeImpl(e,t);return r.isSink()&&!r.span()&&(r=r.bindToSpan((0,i.span)(e))),(0,f.switchOn)(this.verbosity,{quiet:()=>{},trace:()=>{console.log(`output of <|${(0,i.show)(e)}|> is ${JSON.stringify(r)} // ${e.tag}`)}}),this.stack=l.pop(this.stack),r}importDefinitions(e){const t=this.getAstOf(e),r=t.expression,n=t.imports;if("arrayLiteral"===r.tag||"binaryOperator"===r.tag||"dot"===r.tag||"export*"===r.tag||"functionCall"===r.tag||"ident"===r.tag||"if"===r.tag||"ternary"===r.tag||"indexAccess"===r.tag||"lambda"===r.tag||"literal"===r.tag||"objectLiteral"===r.tag||"unaryOperator"===r.tag||"unit"===r.tag)return h.Value.obj({});if("topLevelExpression"===r.tag){const e={tag:"unit",imports:n,expression:{tag:"topLevelExpression",definitions:r.definitions,computation:{tag:"export*"}}};return this.evalNode(e,this.buildInitialSymbolTable(!1))}(0,c.shouldNeverHappen)(r)}evalNodeImpl(e,t){if("unit"===e.tag){let r=t;for(const t of e.imports){const e=this.importDefinitions(t.pathToImportFrom.text);r=new p(t.ident.t.text,{destination:e},r)}return this.evalNode(e.expression,r)}if("topLevelExpression"===e.tag){let r=t;for(const t of e.definitions){const e=t.ident.t.text,n={destination:void 0};r=new p(e,n,r);const s=this.evalNode(t.value,r);n.destination=s}return e.computation?this.evalNode(e.computation,r):h.Value.str("")}if("export*"===e.tag)return h.Value.obj(t.exportValue());if("binaryOperator"===e.tag){const r=this.evalNode(e.lhs,t);if("||"===e.operator)return r.or((()=>this.evalNode(e.rhs,t)));if("&&"===e.operator)return r.and((()=>this.evalNode(e.rhs,t)));if("??"===e.operator)return r.unsink((()=>this.evalNode(e.rhs,t)));const n=this.evalNode(e.rhs,t);if("!="===e.operator)return r.equalsTo(n).not();if("=="===e.operator)return r.equalsTo(n);if("<="===e.operator)return r.order(n).isToZero("<=");if("<"===e.operator)return r.order(n).isToZero("<");if(">="===e.operator)return r.order(n).isToZero(">=");if(">"===e.operator)return r.order(n).isToZero(">");if("%"===e.operator)return r.modulo(n);if("*"===e.operator)return r.times(n);if("**"===e.operator)return r.power(n);if("+"===e.operator)return r.plus(n);if("-"===e.operator)return r.minus(n);if("/"===e.operator)return r.over(n);(0,c.shouldNeverHappen)(e.operator)}if("unaryOperator"===e.tag){const r=this.evalNode(e.operand,t);if("!"===e.operator)return r.not();if("+"===e.operator)return h.Value.num(0).plus(r);if("-"===e.operator)return r.negate();(0,c.shouldNeverHappen)(e.operator)}if("ident"===e.tag)return t.lookup(e.t.text);if("literal"===e.tag){if("bool"===e.type)return h.Value.bool("true"===e.t.text);if("num"===e.type)return h.Value.num(Number(e.t.text));if("sink!!"===e.type)return h.Value.sink(void 0,this.stack,t);if("sink!"===e.type)return h.Value.sink(void 0,this.stack);if("sink"===e.type)return h.Value.sink();if("str"===e.type)return h.Value.str(e.t.text);(0,c.shouldNeverHappen)(e.type)}if("arrayLiteral"===e.tag){const r=[];for(const n of e.parts)if("element"===n.tag)r.push(this.evalNode(n.v,t));else if("spread"===n.tag){const e=this.evalNode(n.v,t);r.push(...e.assertArr())}else(0,c.shouldNeverHappen)(n);return h.Value.arr(r)}if("objectLiteral"===e.tag){const r=e.parts.flatMap((e=>{if("hardName"===e.tag)return[[e.k.t.text,this.evalNode(e.v,t)]];if("computedName"===e.tag)return[[this.evalNode(e.k,t).assertStr(),this.evalNode(e.v,t)]];if("spread"===e.tag){const r=this.evalNode(e.o,t);return Object.entries(r.assertObj())}(0,c.shouldNeverHappen)(e)}));return h.Value.obj(Object.fromEntries(r))}if("lambda"===e.tag)return h.Value.lambda(e,t);if("functionCall"===e.tag){const r=e.actualArgs.map((e=>this.evalNode(e,t))),n=this.evalNode(e.callee,t);return this.call(n,r)}if("if"===e.tag||"ternary"===e.tag)return this.evalNode(e.condition,t).ifElse((()=>this.evalNode(e.positive,t)),(()=>this.evalNode(e.negative,t)));if("dot"===e.tag){const r=this.evalNode(e.receiver,t);if(null==r)throw new Error(`Cannot access attribute .${e.ident.t.text} of ${r}`);return r.access(e.ident.t.text,((e,t)=>this.call(e,t)))}if("indexAccess"===e.tag){const r=this.evalNode(e.receiver,t),n=this.evalNode(e.index,t);return r.access(n,((e,t)=>this.call(e,t)))}(0,c.shouldNeverHappen)(e)}call(e,t){return e.call(t,((e,r,n)=>{if(e.length>t.length)throw new Error(`Arg list length mismatch: expected ${e.length} but got ${t.length}`);const s=e.reduce(((e,r,n)=>new p(r,{destination:t[n]},e)),n);return this.evalNode(r,s)}))}}},756:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Scanner=void 0;class r{constructor(e,t=0){this.sourceCode=e,this.offset=t,0===this.offset&&this.eatWhitespace()}get sourceRef(){return this.sourceCode.sourceRef(this.sourceCode.expandToEndOfLine({offset:this.offset}))}curr(){return this.sourceCode.input.substring(this.offset)}eatWhitespace(){for(;;)if(!this.consumeIf(/\s*/,!1)){if(!this.consumeIf("//",!1))return;this.consume(/[^\n]*/,!1)}}eof(){return this.offset>=this.sourceCode.input.length}synopsis(){const e=this.curr();let t=e.substring(0,20);return t.length!==e.length&&(t=`${t}...`),{position:this.offset,lookingAt:t}}headMatches(...e){const t=new r(this.sourceCode,this.offset);for(const r of e)if(void 0===t.consumeIf(r,!0))return!1;return!0}consume(e,t=!0){const r=this.match(e);if(void 0===r)throw new Error(`Expected ${e} ${this.sourceRef}`);const n=this.offset;return this.offset+=r.length,t&&this.eatWhitespace(),{location:{offset:n},text:r}}consumeIf(e,t=!0){if(this.match(e))return this.consume(e,t)}match(e){if("string"==typeof e)return this.curr().startsWith(e)?e:void 0;const t=this.curr().match(e);return t&&0===t.index?t[0]:void 0}}t.Scanner=r},212:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.parse=t.Septima=void 0;const n=r(270),s=r(351),o=r(257),i=r(756),a=r(29),u=r(893);class c{static run(e,t,r={}){const n=t?.onSink??(e=>{throw new Error(e.message)}),s=(new c).compute(e,{},"quiet",r);return"ok"===s.tag?s.value:"sink"===s.tag?n(s):void(0,a.shouldNeverHappen)(s)}constructor(){}computeModule(e,t,r){const n=t(e),o=new u.SourceCode(n),i=this.computeImpl(o,"quiet",{},t,r);return i.isSink()?new s.ResultSinkImpl(i,o):{value:i.export(),tag:"ok"}}compute(e,t={},r="quiet",n){const o={};for(const[e,n]of Object.entries(t)){const t=new u.SourceCode(n),i=this.computeImpl(t,r,{},void 0,{});if(i.isSink()){const r=new s.ResultSinkImpl(i,t);throw new Error(`preimport (${e}) evaluated to sink: ${r.message}`)}o[e]=i}const i=new u.SourceCode(e),a=this.computeImpl(i,r,o,void 0,n);return a.isSink()?new s.ResultSinkImpl(a,i):{value:a.export(),tag:"ok"}}computeImpl(e,t,r,s,a){const u=new i.Scanner(e),c=l(new n.Parser(u)),f=new o.Runtime(c,t,r,(e=>{if(!s)throw new Error("cannot read modules");return l(s(e))}),a).compute();if(f.value)return f.value;const h=`${f.errorMessage} when evaluating:\n${e.formatTrace(f.expressionTrace)}`;throw new Error(h)}}function l(e){return("string"==typeof e?new n.Parser(new i.Scanner(new u.SourceCode(e))):e).parse()}t.Septima=c,t.parse=l},29:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.shouldNeverHappen=void 0,t.shouldNeverHappen=function(e){throw new Error(`This should never happen ${e}`)}},893:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SourceCode=void 0;const n=r(166);t.SourceCode=class{constructor(e){this.input=e}formatTrace(e){return` ${e.map((e=>this.sourceRef((0,n.span)(e)))).reverse().join("\n ")}`}sourceRefOfLocation(e){return this.sourceRef(this.expandToEndOfLine(e))}sourceRef(e){return e?`at ${this.formatSpan(e)} ${this.interestingPart(e)}`:"at <unknown location>"}formatSpan(e){const t=this.resolveLocation(e.from),r=this.resolveLocation(e.to);return t.line===r.line?`(${t.line+1}:${t.col+1}..${r.col+1})`:`(${t.line+1}:${t.col+1}..${r.line+1}:${r.col+1})`}interestingPart(e){const t=this.resolveLocation(e.from),r=this.resolveLocation(e.to),n=e=>e.replace(/^[\n]*/,"").replace(/[\n]*$/,""),s=this.lineAt(e.from);if(t.line!==r.line)return`${n(s).substring(0,80)}...`;const o=n(s.substring(t.col,r.col+1));return o.length<=80?o:`${o.substring(0,80)}...`}resolveLocation(e){const t=this.input.slice(0,e.offset);let r=0;for(let e=0;e<t.length;++e)"\n"===t[e]&&(r+=1);let n=0;for(let e=t.length-1;e>=0&&"\n"!==t[e];--e,++n);return{line:r,col:n}}expandToEndOfLine(e){let t=this.input.indexOf("\n",e.offset);return t<0&&(t=this.input.length-1),{from:e,to:{offset:t}}}lineAt(e){const t=this.input.lastIndexOf("\n",e.offset)+1,r=this.expandToEndOfLine(e).to;return this.input.substring(t,r.offset+1)}}},884:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.empty=t.pop=t.push=void 0,t.push=function(e,t){return{ast:e,next:t}},t.pop=function(e){if(void 0===e)throw new Error("Cannot pop from an empty stack");return e.next},t.empty=function(){}},434:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.switchOn=void 0,t.switchOn=function(e,t){return(0,t[e])()}},669:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Value=void 0;const n=r(166),s=r(465),o=r(855),i=r(794),a=r(29),u=r(434);function c(e){return JSON.stringify(e)}const l=(e,...t)=>(r,n,s)=>{if(0===t.length)throw new Error(`value type error: expected ${e} but found ${c(s)}`);throw new Error(`value type error: expected either ${t.join(", ")} or ${e} but found ${c(s)}`)};function f(e,t){const r=e.inner;if("arr"===r.tag)return t.arr(r.val,r.tag,e);if("bool"===r.tag)return t.bool(r.val,r.tag,e);if("foreign"===r.tag)return t.foreign(r.val,r.tag,e);if("lambda"===r.tag)return t.lambda(r.val,r.tag,e);if("num"===r.tag)return t.num(r.val,r.tag,e);if("obj"===r.tag)return t.obj(r.val,r.tag,e);if("sink"===r.tag){if(!t.sink)throw new Error("Cannot evaluate a sink value");return t.sink(r.val,r.tag,e)}if("str"===r.tag)return t.str(r.val,r.tag,e);(0,a.shouldNeverHappen)(r)}function h(e,t){return e.isSink()?e:p.from(f(e,t))}class p{constructor(e){this.inner=e}static bool(e){return new p({val:e,tag:"bool"})}static num(e){return new p({val:e,tag:"num"})}static sink(e,t,r){return new p({val:void 0,tag:"sink",...e?{span:e}:{},...t?{trace:t}:{},...r?{symbols:r}:{}})}static str(e){return new p({val:e,tag:"str"})}static arr(e){return new p({val:e,tag:"arr"})}static obj(e){return new p({val:e,tag:"obj"})}static lambda(e,t){return new p({val:{ast:e,table:t},tag:"lambda"})}static foreign(e){return new p({tag:"foreign",val:e})}isSink(){return"sink"===this.inner.tag}unwrap(){return this.inner.val}assertBool(){const e=l("bool");return f(this,{arr:e,bool:e=>e,foreign:e,lambda:e,num:e,obj:e,sink:e,str:e})}assertNum(){const e=l("num");return f(this,{arr:e,bool:e,foreign:e,lambda:e,num:e=>e,obj:e,sink:e,str:e})}assertStr(){const e=l("str");return f(this,{arr:e,bool:e,foreign:e,lambda:e,num:e,obj:e,sink:e,str:e=>e})}assertArr(){const e=l("arr");return f(this,{arr:e=>e,bool:e,foreign:e,lambda:e,num:e,obj:e,sink:e,str:e})}assertObj(){const e=l("obj");return f(this,{arr:e,bool:e,foreign:e,lambda:e,num:e,obj:e=>e,sink:e,str:e})}assertLambda(){const e=l("lambda");return f(this,{arr:e,bool:e,foreign:e,lambda:e=>e,num:e,obj:e,sink:e,str:e})}isLambda(){return"lambda"===this.inner.tag}ifElse(e,t){const r=l("bool");return h(this,{arr:r,bool:r=>r?e():t(),foreign:r,lambda:r,num:r,obj:r,str:r})}bindToSpan(e){const t=this.inner;if("sink"!==t.tag)throw new Error(`Not supported on type ${this.inner.tag}`);return p.sink(e,t.trace,t.symbols)}trace(){const e=this.inner;if("sink"!==e.tag)return;const t=[];for(let r=e.trace;void 0!==r;r=r?.next)t.push(r.ast);return 0===t.length?void 0:t}symbols(){const e=this.inner;if("sink"===e.tag)return e.symbols}span(){const e=this.inner;if("sink"===e.tag)return e.span}or(e){const t=l("bool");return h(this,{arr:t,bool:r=>r||h(e(),{arr:t,bool:e=>e,foreign:t,lambda:t,num:t,obj:t,str:t}),foreign:t,lambda:t,num:t,obj:t,str:t})}and(e){const t=l("bool");return h(this,{arr:t,bool:r=>r&&h(e(),{arr:t,bool:e=>e,foreign:t,lambda:t,num:t,obj:t,str:t}),foreign:t,lambda:t,num:t,obj:t,str:t})}unsink(e){return this.isSink()?e():this}equalsTo(e){if(this.inner.tag!==e.inner.tag)return p.bool(!1);const t=JSON.stringify(this.inner.val)===JSON.stringify(e.inner.val);return p.bool(t)}not(){const e=l("bool");return h(this,{arr:e,bool:e=>!e,foreign:e,lambda:e,num:e,obj:e,str:e})}binaryNumericOperator(e,t,r){const n=l("num");return h(e,{arr:n,bool:n,foreign:n,lambda:n,num:e=>h(t,{arr:n,bool:n,foreign:n,lambda:n,num:t=>r(e,t),obj:n,str:n}),obj:n,str:n})}plus(e){const t=l("num");return h(this,{arr:t,bool:t,foreign:t,lambda:t,num:r=>h(e,{arr:t,bool:t,foreign:t,lambda:t,num:e=>r+e,obj:t,str:t}),obj:t,str:t=>h(e,{arr:e=>t+e,bool:e=>t+e,foreign:e=>t+e,lambda:e=>t+e,num:e=>t+e,obj:e=>t+e,str:e=>t+e})})}minus(e){return this.binaryNumericOperator(this,e,((e,t)=>e-t))}times(e){return this.binaryNumericOperator(this,e,((e,t)=>e*t))}power(e){return this.binaryNumericOperator(this,e,((e,t)=>e**t))}over(e){return this.binaryNumericOperator(this,e,((e,t)=>e/t))}modulo(e){return this.binaryNumericOperator(this,e,((e,t)=>e%t))}negate(){return p.num(0).minus(this)}isToZero(e){const t=l("num");return h(this,{arr:t,bool:t,foreign:t,lambda:t,num:t=>(0,u.switchOn)(e,{"<":()=>p.bool(t<0),"<=":()=>p.bool(t<=0),"==":()=>p.bool(0==t),"!=":()=>p.bool(0!==t),">=":()=>p.bool(t>=0),">":()=>p.bool(t>0)}),obj:t,str:t})}isTrue(){const e=l("bool");return f(this,{arr:e,bool:e=>e,foreign:e,lambda:e,num:e,obj:e,sink:e,str:e})}isZero(){const e=l("num");return f(this,{arr:e,bool:e,foreign:e,lambda:e,num:e=>0===e,obj:e,sink:e,str:e})}order(e){const t=(e,t)=>{throw new Error(`Cannot compare a value of type ${t}`)};if(this.inner.tag!==e.inner.tag)throw new Error(`Cannot compare a ${this.inner.tag} value with a value of another type (${e.inner.tag})`);return h(this,{arr:t,bool:t=>{const r=e.assertBool();return t&&!r?1:!t&&r?-1:0},foreign:t,lambda:t,num:()=>{const t=this.minus(e).assertNum();return t<0?-1:t>0?1:0},obj:t,str:t=>{const r=e.assertStr(),n=t.localeCompare(r);return n<0?-1:n>0?1:0}})}static toStringOrNumber(e){if("string"==typeof e)return e;const t=l("str","num");return f(e,{arr:t,bool:t,foreign:t,lambda:t,num:e=>e,obj:t,sink:t,str:e=>e})}access(e,t){const r=l("obj","str","arr");return h(this,{arr:r=>{if("string"==typeof e)return(0,o.findArrayMethod)(r,e,t);const n=e.assertNum();if(n<0||n>r.length)throw new Error(`array index (${n}) is out of bounds (length = ${r.length})`);return r[n]},bool:r,foreign:r,lambda:r,num:r,obj:t=>t[p.toStringOrNumber(e)],str:t=>(0,i.findStringMethod)(t,e)})}call(e,t){const r=l("lambda","foreign");return h(this,{arr:r,bool:r,foreign:t=>d(t(...e)),lambda:e=>t(e.ast.formalArgs.map((e=>e.t.text)),e.ast.body,e.table),num:r,obj:r,str:r})}keys(){const e=l("obj");return h(this,{arr:e,bool:e,foreign:e,lambda:e,num:e,obj:e=>Object.keys(e),str:e})}entries(){const e=l("obj");return h(this,{arr:e,bool:e,foreign:e,lambda:e,num:e,obj:e=>Object.entries(e),str:e})}fromEntries(){const e=l("arr");return h(this,{arr:t=>Object.fromEntries(t.map((t=>f(t,{arr:e=>(2===e.length||(0,s.failMe)("each entry must be a [key, value] pair"),[e[0].assertStr(),e[1]]),bool:e,foreign:e,lambda:e,num:e,obj:e,sink:e,str:e})))),bool:e,foreign:e,lambda:e,num:e,obj:e,str:e})}toString(){return this.inner.val?.toString()??"sink"}toJSON(){const e=t=>f(t,{arr:t=>t.map((t=>e(t))),bool:e=>e,foreign:e=>e.toString(),lambda:e=>(0,n.show)(e.ast),num:e=>e,obj:t=>Object.fromEntries(Object.entries(t).map((([t,r])=>[t,e(r)]))),sink:()=>{},str:e=>e});return e(this)}export(){return this.toJSON()}static from(e){return d(e)}}function d(e){if(e instanceof p)return e;if("boolean"==typeof e)return p.bool(e);if("number"==typeof e)return p.num(e);if("string"==typeof e)return p.str(e);if(Array.isArray(e))return p.arr(e.map((e=>d(e))));if(void 0===e)return p.sink();if(e&&"object"==typeof e)return p.obj(Object.fromEntries(Object.entries(e).map((([e,t])=>[e,d(t)]))));throw new Error(`cannot convert ${JSON.stringify(e)} to Value`)}t.Value=p}},t={};!function r(n){var s=t[n];if(void 0!==s)return s.exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,r),o.exports}(326)})();