septima-lang 0.0.5 → 0.0.7

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 (72) hide show
  1. package/main.js +1 -0
  2. package/package.json +3 -3
  3. package/dist/src/ast-node.d.ts +0 -98
  4. package/dist/src/ast-node.js +0 -139
  5. package/dist/src/extract-message.d.ts +0 -1
  6. package/dist/src/extract-message.js +0 -10
  7. package/dist/src/fail-me.d.ts +0 -1
  8. package/dist/src/fail-me.js +0 -11
  9. package/dist/src/find-array-method.d.ts +0 -15
  10. package/dist/src/find-array-method.js +0 -104
  11. package/dist/src/find-string-method.d.ts +0 -2
  12. package/dist/src/find-string-method.js +0 -88
  13. package/dist/src/index.d.ts +0 -1
  14. package/dist/src/index.js +0 -18
  15. package/dist/src/location.d.ts +0 -11
  16. package/dist/src/location.js +0 -3
  17. package/dist/src/parser.d.ts +0 -44
  18. package/dist/src/parser.js +0 -458
  19. package/dist/src/result.d.ts +0 -24
  20. package/dist/src/result.js +0 -29
  21. package/dist/src/runtime.d.ts +0 -27
  22. package/dist/src/runtime.js +0 -343
  23. package/dist/src/scanner.d.ts +0 -23
  24. package/dist/src/scanner.js +0 -88
  25. package/dist/src/septima.d.ts +0 -32
  26. package/dist/src/septima.js +0 -91
  27. package/dist/src/should-never-happen.d.ts +0 -1
  28. package/dist/src/should-never-happen.js +0 -9
  29. package/dist/src/source-code.d.ts +0 -19
  30. package/dist/src/source-code.js +0 -90
  31. package/dist/src/stack.d.ts +0 -11
  32. package/dist/src/stack.js +0 -19
  33. package/dist/src/switch-on.d.ts +0 -1
  34. package/dist/src/switch-on.js +0 -9
  35. package/dist/src/symbol-table.d.ts +0 -6
  36. package/dist/src/symbol-table.js +0 -3
  37. package/dist/src/value.d.ts +0 -128
  38. package/dist/src/value.js +0 -634
  39. package/dist/tests/parser.spec.d.ts +0 -1
  40. package/dist/tests/parser.spec.js +0 -31
  41. package/dist/tests/septima-compute-module.spec.d.ts +0 -1
  42. package/dist/tests/septima-compute-module.spec.js +0 -30
  43. package/dist/tests/septima.spec.d.ts +0 -1
  44. package/dist/tests/septima.spec.js +0 -774
  45. package/dist/tests/value.spec.d.ts +0 -1
  46. package/dist/tests/value.spec.js +0 -355
  47. package/dist/tsconfig.tsbuildinfo +0 -1
  48. package/jest-output.json +0 -1
  49. package/src/a.js +0 -66
  50. package/src/ast-node.ts +0 -249
  51. package/src/extract-message.ts +0 -5
  52. package/src/fail-me.ts +0 -7
  53. package/src/find-array-method.ts +0 -115
  54. package/src/find-string-method.ts +0 -84
  55. package/src/index.ts +0 -1
  56. package/src/location.ts +0 -13
  57. package/src/parser.ts +0 -526
  58. package/src/result.ts +0 -45
  59. package/src/runtime.ts +0 -360
  60. package/src/scanner.ts +0 -106
  61. package/src/septima.ts +0 -114
  62. package/src/should-never-happen.ts +0 -4
  63. package/src/source-code.ts +0 -101
  64. package/src/stack.ts +0 -18
  65. package/src/switch-on.ts +0 -4
  66. package/src/symbol-table.ts +0 -7
  67. package/src/value.ts +0 -742
  68. package/tests/parser.spec.ts +0 -30
  69. package/tests/septima-compute-module.spec.ts +0 -33
  70. package/tests/septima.spec.ts +0 -839
  71. package/tests/value.spec.ts +0 -387
  72. package/tsconfig.json +0 -11
@@ -1,839 +0,0 @@
1
- import { Septima } from '../src/septima'
2
-
3
- /**
4
- * Runs a Septima program for testing purposes. If the program evaluates to `sink` an `undefined` is
5
- * returned.
6
- * @param input the Septima program to run
7
- */
8
- function run(input: string) {
9
- return Septima.run(input, { onSink: () => undefined })
10
- }
11
-
12
- /**
13
- * Runs a Septima program for testing purposes. The program is expected to evaluate to `sink`. Throws an exception if
14
- * this expectation is not met.
15
- * @param input the Septima program to run
16
- */
17
- function runSink(input: string) {
18
- const septima = new Septima()
19
- const res = septima.compute(input)
20
-
21
- if (res.tag !== 'sink') {
22
- throw new Error(`Not a sink: ${res.value}`)
23
- }
24
- return res
25
- }
26
-
27
- describe('septima', () => {
28
- test('basics', () => {
29
- expect(run(`5`)).toEqual(5)
30
- expect(() => run(`6 789`)).toThrowError(`Loitering input at (1:3..5) 789`)
31
- expect(run(`3.14`)).toEqual(3.14)
32
- })
33
- test('an optional return keyword can be placed before the result', () => {
34
- expect(run(`return 5`)).toEqual(5)
35
- expect(run(`return 3.14`)).toEqual(3.14)
36
- })
37
-
38
- test('booleans', () => {
39
- expect(run(`true`)).toEqual(true)
40
- expect(run(`false`)).toEqual(false)
41
- expect(run(`!true`)).toEqual(false)
42
- expect(run(`!false`)).toEqual(true)
43
- expect(run(`!!true`)).toEqual(true)
44
- expect(run(`!!false`)).toEqual(false)
45
-
46
- expect(run(`true||true`)).toEqual(true)
47
- expect(run(`true||false`)).toEqual(true)
48
- expect(run(`false||true`)).toEqual(true)
49
- expect(run(`false||false`)).toEqual(false)
50
-
51
- expect(run(`true && true`)).toEqual(true)
52
- expect(run(`true && false`)).toEqual(false)
53
- expect(run(`false && true`)).toEqual(false)
54
- expect(run(`false && false`)).toEqual(false)
55
- })
56
-
57
- test('arithmetics', () => {
58
- expect(run(`8*2`)).toEqual(16)
59
- expect(run(`3+1`)).toEqual(4)
60
- expect(run(`20-3`)).toEqual(17)
61
- expect(run(`48/6`)).toEqual(8)
62
- expect(run(`(1+4)*6`)).toEqual(30)
63
- expect(run(`1+4*6`)).toEqual(25)
64
- expect(run(`20%6`)).toEqual(2)
65
- expect(run(`20%8`)).toEqual(4)
66
- expect(run(`40%15`)).toEqual(10)
67
- expect(run(`6**3`)).toEqual(216)
68
- expect(run(`6**4`)).toEqual(1296)
69
- expect(run(`2*3**4`)).toEqual(162)
70
- expect(run(`(2*3)**4`)).toEqual(1296)
71
-
72
- expect(run(`8/0`)).toEqual(Infinity)
73
- expect(run(`(-4) ** 0.5`)).toEqual(NaN)
74
-
75
- expect(() => run(`!5`)).toThrowError(`value type error: expected bool but found 5`)
76
- expect(() => run(`!0`)).toThrowError(`value type error: expected bool but found 0`)
77
- expect(() => run(`!!0`)).toThrowError(`value type error: expected bool but found 0`)
78
- expect(() => run(`!!4`)).toThrowError(`value type error: expected bool but found 4`)
79
- })
80
-
81
- test('error message specifies the location in the file', () => {
82
- expect(() => run(`7+\n6+\n5+4+3+!2`)).toThrowError(`value type error: expected bool but found 2`)
83
-
84
- const expected = [
85
- `value type error: expected num but found "zxcvbnm" when evaluating:`,
86
- ` at (1:1..21) 9 * 8 * 'zxcvbnm' * 7`,
87
- ` at (1:1..21) 9 * 8 * 'zxcvbnm' * 7`,
88
- ` at (1:5..21) 8 * 'zxcvbnm' * 7`,
89
- ` at (1:10..21) zxcvbnm' * 7`,
90
- ].join('\n')
91
-
92
- expect(() => run(`9 * 8 * 'zxcvbnm' * 7`)).toThrowError(expected)
93
- })
94
-
95
- test('equality', () => {
96
- expect(run(`3==4`)).toEqual(false)
97
- expect(run(`3==3`)).toEqual(true)
98
- expect(run(`3!=4`)).toEqual(true)
99
- expect(run(`3!=3`)).toEqual(false)
100
- })
101
-
102
- test('comparison', () => {
103
- expect(run(`3>2`)).toEqual(true)
104
- expect(run(`3>3`)).toEqual(false)
105
- expect(run(`3>4`)).toEqual(false)
106
-
107
- expect(run(`3>=2`)).toEqual(true)
108
- expect(run(`3>=3`)).toEqual(true)
109
- expect(run(`3>=4`)).toEqual(false)
110
-
111
- expect(run(`3<=2`)).toEqual(false)
112
- expect(run(`3<=3`)).toEqual(true)
113
- expect(run(`3<=4`)).toEqual(true)
114
-
115
- expect(run(`3<2`)).toEqual(false)
116
- expect(run(`3<3`)).toEqual(false)
117
- expect(run(`3<4`)).toEqual(true)
118
- })
119
-
120
- test('combined arithmetics and logical expressions', () => {
121
- expect(run(`(5 + 3 > 6) && (10*20 > 150)`)).toEqual(true)
122
- expect(run(`(5 + 3 > 9) && (10*20 > 150)`)).toEqual(false)
123
- expect(run(`(5 + 3 > 6) && (10*20 > 201)`)).toEqual(false)
124
- expect(run(`(5 + 3 > 9) && (10*20 > 201)`)).toEqual(false)
125
- })
126
-
127
- test('the rhs of a logical-or expression is evaluated only if lhs is false', () => {
128
- expect(run(`true || x`)).toEqual(true)
129
- expect(() => run(`false || x`)).toThrowError('Symbol x was not found')
130
- })
131
- test('the rhs of a logical-and expression is evaluated only if lhs is true', () => {
132
- expect(run(`false && x`)).toEqual(false)
133
- expect(() => run(`true && x`)).toThrowError('Symbol x was not found')
134
- })
135
-
136
- test('eats whitespace', () => {
137
- expect(run(` 8 * 2 `)).toEqual(16)
138
- expect(run(`3 + 1`)).toEqual(4)
139
- expect(run(`20 - 3`)).toEqual(17)
140
- expect(run(`48 / 6`)).toEqual(8)
141
- expect(run(`(1 + 4 ) *7`)).toEqual(35)
142
- })
143
-
144
- describe('unary expressions', () => {
145
- test('+', () => {
146
- expect(run(`+7`)).toEqual(7)
147
- expect(run(`3*+7`)).toEqual(21)
148
- expect(run(`3 * +7`)).toEqual(21)
149
- })
150
- test('errors if + is applied to non-number', () => {
151
- expect(() => run(`+true`)).toThrowError('expected num but found true')
152
- expect(() => run(`+[]`)).toThrowError('expected num but found []')
153
- expect(() => run(`+{}`)).toThrowError('expected num but found {}')
154
- expect(() => run(`+(fun (x) x*2)`)).toThrowError('expected num but found "fun (x) (x * 2)"')
155
- expect(() => run(`+'abc'`)).toThrowError(`expected num but found "abc"`)
156
- })
157
- test('-', () => {
158
- expect(run(`-7`)).toEqual(-7)
159
- expect(run(`3+-7`)).toEqual(-4)
160
- expect(run(`3*-7`)).toEqual(-21)
161
- expect(run(`-3*-7`)).toEqual(21)
162
- expect(run(`3 + -7`)).toEqual(-4)
163
- expect(run(`3 * -7`)).toEqual(-21)
164
- expect(run(`-3 * -7`)).toEqual(21)
165
- })
166
- })
167
-
168
- describe('strings', () => {
169
- test('can be specified via the double-quotes notation', () => {
170
- expect(run(`""`)).toEqual('')
171
- expect(run(`"ab"`)).toEqual('ab')
172
- expect(run(`"ab" + "cd"`)).toEqual('abcd')
173
- })
174
- test('can be specified via the single-quotes notation', () => {
175
- expect(run(`''`)).toEqual('')
176
- expect(run(`'ab'`)).toEqual('ab')
177
- expect(run(`'ab' + 'cd'`)).toEqual('abcd')
178
- })
179
- test('does not trim leading/trailing whitespace', () => {
180
- expect(run(`' ab'`)).toEqual(' ab')
181
- expect(run(`'ab '`)).toEqual('ab ')
182
- expect(run(`' '`)).toEqual(' ')
183
- expect(run(`' ab '`)).toEqual(' ab ')
184
- expect(run(`" ab"`)).toEqual(' ab')
185
- expect(run(`"ab "`)).toEqual('ab ')
186
- expect(run(`" "`)).toEqual(' ')
187
- expect(run(`" ab "`)).toEqual(' ab ')
188
- })
189
- test('supports string methods', () => {
190
- expect(run(`'bigbird'.substring(3, 7)`)).toEqual('bird')
191
- expect(run(`'bigbird'.indexOf('g')`)).toEqual(2)
192
- expect(run(`'ab-cde-fghi-jkl'.split('-')`)).toEqual(['ab', 'cde', 'fghi', 'jkl'])
193
- expect(run(`let s = ' ab cd '; [s.trimStart(), s.trimEnd(), s.trim()]`)).toEqual([
194
- 'ab cd ',
195
- ' ab cd',
196
- 'ab cd',
197
- ])
198
- })
199
- test('supports optional arguments of string methods', () => {
200
- expect(run(`'bigbird'.substring(5)`)).toEqual('rd')
201
- })
202
- })
203
- describe('let', () => {
204
- test('binds values to variables', () => {
205
- expect(run(`let x = 5; x+3`)).toEqual(8)
206
- expect(run(`let x = 5; let y = 20; x*y+4`)).toEqual(104)
207
- })
208
- test('do not need the trailing semicolon', () => {
209
- expect(run(`let x = 5 x+3`)).toEqual(8)
210
- expect(run(`let x = 5 let y = 20 x*y+4`)).toEqual(104)
211
- })
212
- test('fails if the variable was not defined', () => {
213
- expect(() => run(`let x = 5; x+y`)).toThrowError('Symbol y was not found')
214
- })
215
-
216
- test('parenthsized expression can have let defintions', () => {
217
- expect(
218
- run(`
219
- let x = 5;
220
- let y = 20;
221
-
222
- x*y+(let n = 4; n*7)`),
223
- ).toEqual(128)
224
- expect(
225
- run(`
226
- let x = 5;
227
- let y = 20;
228
-
229
- x*y+(let n = 4; let o = 7; o*n)`),
230
- ).toEqual(128)
231
- })
232
-
233
- test('inner expressions can access variables from enclosing scopes', () => {
234
- expect(
235
- run(`
236
- let x = 5;
237
- let y = 20;
238
-
239
- x*y+(let n = 4; n+x)`),
240
- ).toEqual(109)
241
- })
242
- test('definitions from inner scopes overshadow definitions from outer scopes', () => {
243
- expect(
244
- run(`
245
- let x = 5;
246
- let y = 20;
247
-
248
- x*y+(let n = 4; let x = 200; n+x)`),
249
- ).toEqual(304)
250
- })
251
- test('the body of a definition can reference an earlier definition from the same scope', () => {
252
- expect(run(`let x = 10; let y = x*2; y*2`)).toEqual(40)
253
- })
254
- test('the body of a definition cannot reference a latter definition from the same scope', () => {
255
- expect(() => run(`let y = x*2; let x = 10; y*2`)).toThrowError(`Symbol x was not found`)
256
- })
257
- test('the body of a definition cannot reference itself', () => {
258
- expect(() => run(`let x = 10; let y = if (x > 0) y else x; y*2`)).toThrowError(`Unresolved definition: y`)
259
- })
260
- test('uses lexical scoping (and not dynamic scoping)', () => {
261
- const actual = run(`let x = (let a = 1; a+1); let y = (let a=100; x+1); y`)
262
- expect(actual).toEqual(3)
263
- })
264
- test('definitions go out of scope', () => {
265
- expect(() => run(`let x = (let a = 1; a+1); a+100`)).toThrowError('Symbol a was not found')
266
- })
267
- })
268
-
269
- describe('arrays', () => {
270
- test('array literals are specified via the enclosing brackets notation ([])', () => {
271
- expect(run(`["ab", 5]`)).toEqual(['ab', 5])
272
- expect(run(`[]`)).toEqual([])
273
- })
274
- test('allow a dangling comma', () => {
275
- expect(run(`[,]`)).toEqual([])
276
- expect(run(`[,,]`)).toEqual([])
277
- expect(run(`[246,]`)).toEqual([246])
278
- expect(run(`[246,531,]`)).toEqual([246, 531])
279
- })
280
- test('individual elements of an array can be accessed via the [<index>] notation', () => {
281
- expect(run(`let a = ['sun', 'mon', 'tue', 'wed']; a[1]`)).toEqual('mon')
282
- })
283
- test('the <index> value at the [<index>] notation can be a computed value', () => {
284
- expect(run(`let a = ['sun', 'mon', 'tue', 'wed']; let f = fun(n) n-5; [a[3-1], a[18/6], a[f(5)]]`)).toEqual([
285
- 'tue',
286
- 'wed',
287
- 'sun',
288
- ])
289
- })
290
- })
291
-
292
- describe('objects', () => {
293
- describe('literals', () => {
294
- test('are specified via JSON format', () => {
295
- expect(run(`{}`)).toEqual({})
296
- expect(run(`{a: 1}`)).toEqual({ a: 1 })
297
- expect(run(`{a: 1, b: 2}`)).toEqual({ a: 1, b: 2 })
298
- expect(run(`{a: "A", b: "B", c: "CCC"}`)).toEqual({ a: 'A', b: 'B', c: 'CCC' })
299
- })
300
- test('allow a dangling comma', () => {
301
- expect(run(`{a: 1,}`)).toEqual({ a: 1 })
302
- expect(run(`{a: 1, b: 2,}`)).toEqual({ a: 1, b: 2 })
303
- expect(run(`{a: "A", b: "B", c: "CCC",}`)).toEqual({ a: 'A', b: 'B', c: 'CCC' })
304
- })
305
- test('a dangling comma in an empty object is not allowed', () => {
306
- expect(() => run(`{,}`)).toThrowError('Expected an identifier at (1:2..3) ,}')
307
- })
308
- test('supports computed attributes names via the [<expression>]: <value> notation', () => {
309
- expect(run(`{["a" + 'b']: 'a-and-b'}`)).toEqual({ ab: 'a-and-b' })
310
- })
311
- })
312
- describe('attributes', () => {
313
- test('can be accessed via the .<ident> notation', () => {
314
- expect(run(`let x = {a: 3, b: 4}; x.a`)).toEqual(3)
315
- expect(run(`let x = {a: 3, b: 4}; x.a * x.b`)).toEqual(12)
316
- expect(run(`let x = {a: 3, b: {x: {Jan: 1, Feb: 2, May: 5}, y: 300}}; [x.b.x.Jan, x.b.x.May, x.b.y]`)).toEqual([
317
- 1, 5, 300,
318
- ])
319
- expect(run(`let x = {a: 3, calendar: ["A"] }; x.calendar`)).toEqual(['A'])
320
- expect(
321
- run(
322
- `let x = {a: 3, calendar: {months: { Jan: 1, Feb: 2, May: 5}, days: ["Mon", "Tue", "Wed" ] } }; [x.calendar.months, x.calendar.days]`,
323
- ),
324
- ).toEqual([{ Jan: 1, Feb: 2, May: 5 }, ['Mon', 'Tue', 'Wed']])
325
- })
326
- test('can be accessed via the [<name>] notation', () => {
327
- expect(run(`let x = {a: 3, b: 4}; x['a']`)).toEqual(3)
328
- expect(run(`let x = {a: 3, b: 4}; [x['a'], x["b"]]`)).toEqual([3, 4])
329
- expect(run(`let x = {a: 3, b: {x: {Jan: 1, Feb: 2, May: 5}, y: 300}}; x["b"]['x']["May"]`)).toEqual(5)
330
- })
331
- test('supports chains of attribute accesses mixing the .<ident> and the [<name>] notations', () => {
332
- expect(run(`let o = {b: {x: {M: 5}}}; [o["b"].x["M"], o.b["x"].M, o.b.x["M"]]`)).toEqual([5, 5, 5])
333
- })
334
- test('supports chains of calls to nested attributes which are lambda expressions', () => {
335
- expect(run(`let o = {a: fun () { b: fun () { c: fun () { d: 'x' }}}}; o.a().b().c().d`)).toEqual('x')
336
- expect(run(`let o = {a: fun () { b: { c: fun () { d: 'x' }}}}; o.a().b.c().d`)).toEqual('x')
337
- })
338
- test('the <name> value at the [<name>] notation can be a computed value', () => {
339
- expect(run(`let q = fun (x) x + "eb"; let o = {Jan: 1, Feb: 2, May: 5}; [o["Ja" + 'n'], o[q('F')]]`)).toEqual([
340
- 1, 2,
341
- ])
342
- })
343
- })
344
- })
345
-
346
- describe('spread operator in objects', () => {
347
- test('shallow copies an object into an object literal', () => {
348
- expect(run(`let o = {a: 1, b: 2}; {...o}`)).toEqual({ a: 1, b: 2 })
349
- })
350
- test('can be combined with hard-coded (literal) attributes', () => {
351
- expect(run(`let o = {a: 1}; {...o, b: 2}`)).toEqual({ a: 1, b: 2 })
352
- expect(run(`let o = {b: 2}; {...o, a: 1, ...o}`)).toEqual({ a: 1, b: 2 })
353
- })
354
- test('can be used multiple times inside a single object literal', () => {
355
- expect(run(`let o1 = {b: 2}; let o2 = {c: 3}; {a: 1, ...o1, ...o2, d: 4}`)).toEqual({
356
- a: 1,
357
- b: 2,
358
- c: 3,
359
- d: 4,
360
- })
361
- })
362
- test('overrides attributes to its left', () => {
363
- expect(run(`let o = {b: 2}; {a: 100, b: 200, c: 300, ...o}`)).toEqual({ a: 100, b: 2, c: 300 })
364
- })
365
- test('overridden by attributes to its right', () => {
366
- expect(run(`let o = {a: 1, b: 2, c: 3}; {...o, b: 200}`)).toEqual({ a: 1, b: 200, c: 3 })
367
- })
368
- test('can be mixed with computed attribute names', () => {
369
- expect(run(`let o = {ab: 'anteater'}; {...o, ['c' + 'd']: 'cat'}`)).toEqual({ ab: 'anteater', cd: 'cat' })
370
- })
371
- test('errors if applied to a non-object value', () => {
372
- expect(() => run(`let o = ['a']; {...o}`)).toThrowError(`value type error: expected obj but found ["a"]`)
373
- expect(() => run(`let o = true; {...o}`)).toThrowError('value type error: expected obj but found true')
374
- expect(() => run(`let o = 5; {...o}`)).toThrowError('value type error: expected obj but found 5')
375
- expect(() => run(`let o = 'a'; {...o}`)).toThrowError('value type error: expected obj but found "a"')
376
- })
377
- })
378
-
379
- describe('spread operator in arrays', () => {
380
- test('shallow copies an array into an array literal', () => {
381
- expect(run(`let a = ['x', 'y']; [...a]`)).toEqual(['x', 'y'])
382
- })
383
- test('can be mixed with array elements', () => {
384
- expect(run(`let a = ['x', 'y']; ['p', ...a, 'q']`)).toEqual(['p', 'x', 'y', 'q'])
385
- })
386
- test('can be used multiple times inside an array literal', () => {
387
- expect(run(`let a1 = ['x', 'y']; let a2 = ['z']; ['p', ...a1, 'q', ...a2, 'r']`)).toEqual([
388
- 'p',
389
- 'x',
390
- 'y',
391
- 'q',
392
- 'z',
393
- 'r',
394
- ])
395
- })
396
- test('errors if applied to a non-array value', () => {
397
- expect(() => run(`let a = true; [...a]`)).toThrowError('value type error: expected arr but found true')
398
- expect(() => run(`let a = 5; [...a]`)).toThrowError('value type error: expected arr but found 5')
399
- expect(() => run(`let a = {x: 1}; [...a]`)).toThrowError(`value type error: expected arr but found {"x":1}`)
400
- expect(() => run(`let a = 'a'; [...a]`)).toThrowError('value type error: expected arr but found "a"')
401
- })
402
- })
403
-
404
- describe('if', () => {
405
- test('returns the value of the first branch if the condition is true', () => {
406
- expect(run(`if (4 > 3) 200 else -100`)).toEqual(200)
407
- })
408
- test('evaluates the first branch only if the condition is true', () => {
409
- expect(() => run(`if (true) x else -100`)).toThrowError('Symbol x was not found')
410
- expect(run(`if (false) x else -100`)).toEqual(-100)
411
- })
412
- test('returns the value of the second branch if the condition is false', () => {
413
- expect(run(`if (4 < 3) 200 else -100`)).toEqual(-100)
414
- })
415
- test('evaluates the second branch only if the condition is false', () => {
416
- expect(() => run(`if (false) 200 else x`)).toThrowError('Symbol x was not found')
417
- expect(run(`if (true) 200 else x`)).toEqual(200)
418
- })
419
- test('yells if conditions is not boolean', () => {
420
- expect(() => run(`if (5+8) 200 else -100`)).toThrowError('value type error: expected bool but found 13')
421
- })
422
- })
423
-
424
- describe('lambda expressions', () => {
425
- test('binds the value of the actual arg to the formal arg', () => {
426
- expect(run(`(fun(a) 2*a)(3)`)).toEqual(6)
427
- expect(run(`(fun(a, b) a*a-b*b)(3,4)`)).toEqual(-7)
428
- expect(run(`(fun(a, b) a*a-b*b)(4,3)`)).toEqual(7)
429
- })
430
- test('can be stored in a variable', () => {
431
- expect(run(`let triple = (fun(a) 3*a); triple(100) - triple(90)`)).toEqual(30)
432
- expect(run(`let triple = fun(a) 3*a; triple(100) - triple(90)`)).toEqual(30)
433
- })
434
- describe('arrow function notation', () => {
435
- test('a single formal argument does not need to be surrounded with parenthesis', () => {
436
- expect(run(`let triple = a => 3*a; triple(100)`)).toEqual(300)
437
- })
438
- test('(a) => <expression>', () => {
439
- expect(run(`let triple = (a) => 3*a; triple(100)`)).toEqual(300)
440
- })
441
- test('() => <expression>', () => {
442
- expect(run(`let five = () => 5; five()`)).toEqual(5)
443
- })
444
- test('(a,b) => <expression>', () => {
445
- expect(run(`let conc = (a,b) => a+b; conc('al', 'pha')`)).toEqual('alpha')
446
- expect(run(`let conc = (a,b,c,d,e,f) => a+b+c+d+e+f; conc('M', 'o', 'n', 'd', 'a', 'y')`)).toEqual('Monday')
447
- })
448
- test('body of an arrow function can be { return <expression>}', () => {
449
- expect(run(`let triple = a => { return 3*a }; triple(100)`)).toEqual(300)
450
- expect(run(`let triple = (a) => { return 3*a }; triple(100)`)).toEqual(300)
451
- expect(run(`let five = () => { return 5 }; five()`)).toEqual(5)
452
- expect(run(`let concat = (a,b) => { return a+b }; concat('al', 'pha')`)).toEqual('alpha')
453
- })
454
- test('body of an arrow function can include let definitions', () => {
455
- expect(run(`let triple = a => { let factor = 3; return factor*a }; triple(100)`)).toEqual(300)
456
- expect(run(`let triple = (a) => { let factor = 3; return 3*a }; triple(100)`)).toEqual(300)
457
- expect(run(`let five = () => { let two = 2; let three = 3; return three+two }; five()`)).toEqual(5)
458
- expect(run(`let concat = (a,b) => { let u = '_'; return u+a+b+u }; concat('a', 'b')`)).toEqual('_ab_')
459
- })
460
- })
461
- test('can have no args', () => {
462
- expect(run(`let pi = fun() 3.14; 2*pi()`)).toEqual(6.28)
463
- expect(run(`(fun() 3.14)()*2`)).toEqual(6.28)
464
- })
465
- test('error on arg list mismatch', () => {
466
- expect(() => run(`let quadSum = fun(a,b,c,d) a+b+c+d; quadSum(4,8,2)`)).toThrowError(
467
- 'Arg list length mismatch: expected 4 but got 3',
468
- )
469
- expect(run(`let quadSum = fun(a,b,c,d) a+b+c+d; quadSum(4,8,2,6)`)).toEqual(20)
470
- })
471
- test('can be recursive', () => {
472
- expect(run(`let factorial = fun(n) if (n > 0) n*factorial(n-1) else 1; factorial(6)`)).toEqual(720)
473
- expect(run(`let gcd = fun(a, b) if (b == 0) a else gcd(b, a % b); [gcd(24, 60), gcd(1071, 462)]`)).toEqual([
474
- 12, 21,
475
- ])
476
- })
477
- test('can access definitions from the enclosing scope', () => {
478
- expect(run(`let a = 1; (let inc = fun(n) n+a; inc(2))`)).toEqual(3)
479
- expect(run(`let by2 = fun(x) x*2; (let by10 = (let by5 = fun(x) x*5; fun(x) by2(by5(x))); by10(20))`)).toEqual(
480
- 200,
481
- )
482
- })
483
- test('expression trace on error', () => {
484
- const expected = [
485
- ' at (1:1..88) let d = fun(x1) x2; let c = fun(x) d(x); let b = fun (x) c(x); let a = fun(x) b(...',
486
- ' at (1:85..88) a(5)',
487
- ' at (1:79..82) b(x)',
488
- ' at (1:58..61) c(x)',
489
- ' at (1:36..39) d(x)',
490
- ' at (1:17..18) x2',
491
- ].join('\n')
492
-
493
- expect(() =>
494
- run(`let d = fun(x1) x2; let c = fun(x) d(x); let b = fun (x) c(x); let a = fun(x) b(x); a(5)`),
495
- ).toThrowError(expected)
496
- })
497
- test('only lexical scope is considered when looking up a definition', () => {
498
- expect(run(`let a = 1; let inc = fun(n) n+a; (let a = 100; inc(2))`)).toEqual(3)
499
- })
500
- test('can return another lambda expression (a-la currying)', () => {
501
- expect(run(`let sum = fun(a) fun(b,c) a+b+c; sum(1)(600,20)`)).toEqual(621)
502
- expect(run(`let sum = fun(a) fun(b) fun(c) a+b+c; sum(1)(600)(20)`)).toEqual(621)
503
- expect(run(`let sum = fun(a) fun(b,c) a+b+c; let plusOne = sum(1); plusOne(600,20)`)).toEqual(621)
504
- expect(run(`let sum = fun(a) fun(b) fun(c) a+b+c; let plusOne = sum(1); plusOne(600)(20)`)).toEqual(621)
505
- })
506
- })
507
-
508
- describe('sink', () => {
509
- test('specified via the "sink" literal', () => {
510
- expect(run(`sink`)).toEqual(undefined)
511
- })
512
- test('access to non-existing attribute of an object evalutes to a sink', () => {
513
- expect(run(`{a: 1}.b`)).toEqual(undefined)
514
- expect(runSink(`6\n+ 7\n+ 8\n+ 9 + 10 + 11 + {a: 9000}.b`).where).toEqual({
515
- from: { offset: 26 },
516
- to: { offset: 36 },
517
- })
518
- })
519
- test('an expression involving a sink evaluates to sink', () => {
520
- expect(run(`5+8+9+sink+20+30`)).toEqual(undefined)
521
- expect(run(`let x = sink; 5+8+9+x+20+30`)).toEqual(undefined)
522
- expect(run(`let f = fun (a) if (a > 0) a else sink; 2+f(-1)+4`)).toEqual(undefined)
523
- expect(run(`let f = fun (a) if (a > 0) a else sink; 2+f(3)+4`)).toEqual(9)
524
- })
525
- test('an array can hold a sink without becoming a sink itself', () => {
526
- expect(run(`let f = fun (a) if (a > 0) a else sink; [f(1), f(-1), f(8)]`)).toEqual([1, undefined, 8])
527
- })
528
- test('an object can hold a sink without becoming a sink itself', () => {
529
- expect(run(`{a: 5, b: sink, c: 20}`)).toEqual({ a: 5, b: undefined, c: 20 })
530
- })
531
- test('an if() expression an have a sink positive/negative branch without becoming a sink itself', () => {
532
- expect(run(`if (true) 5 else sink`)).toEqual(5)
533
- expect(run(`if (false) sink else 5`)).toEqual(5)
534
- })
535
- test('an if() expression becomes a sink itself if the branch dictated by the condition evaluates to sink', () => {
536
- expect(run(`if (false) 5 else sink`)).toEqual(undefined)
537
- expect(run(`if (true) sink else 5`)).toEqual(undefined)
538
- })
539
- test('an if() expression becomes a sink itself if the the condition expression evaluates to sink', () => {
540
- expect(run(`if (sink) 5 else 7`)).toEqual(undefined)
541
- })
542
- test('an && expression with sinks', () => {
543
- expect(run(`sink && false`)).toEqual(undefined)
544
- expect(run(`sink && true`)).toEqual(undefined)
545
- expect(run(`false && sink`)).toEqual(false)
546
- expect(run(`true && sink`)).toEqual(undefined)
547
- })
548
- test('an || expression with sinks', () => {
549
- expect(run(`sink || false`)).toEqual(undefined)
550
- expect(run(`sink || true`)).toEqual(undefined)
551
- expect(run(`false || sink`)).toEqual(undefined)
552
- expect(run(`true || sink`)).toEqual(true)
553
- })
554
- test('access to an attribute of a sink evaluates to sink', () => {
555
- expect(run(`sink.x`)).toEqual(undefined)
556
- })
557
- test('calling a sink evaluates to sink', () => {
558
- expect(run(`sink()`)).toEqual(undefined)
559
- })
560
- test('a sink compared with itself evaluates to true', () => {
561
- expect(run(`sink == sink`)).toEqual(true)
562
- expect(run(`sink != sink`)).toEqual(false)
563
- })
564
- test('a sink compared with other types evaluates to false', () => {
565
- expect(run(`sink == []`)).toEqual(false)
566
- expect(run(`sink == false`)).toEqual(false)
567
- expect(run(`sink == true`)).toEqual(false)
568
- expect(run(`sink == (fun () sink)`)).toEqual(false)
569
- expect(run(`sink == 0`)).toEqual(false)
570
- expect(run(`sink == 5`)).toEqual(false)
571
- expect(run(`sink == {}`)).toEqual(false)
572
- expect(run(`sink == ''`)).toEqual(false)
573
- expect(run(`sink == 'x'`)).toEqual(false)
574
- })
575
- test('errors when a sink is ordered with other types', () => {
576
- expect(() => run(`sink < []`)).toThrowError('Cannot compare a sink value with a value of another type')
577
- expect(() => run(`sink < false`)).toThrowError('Cannot compare a sink value with a value of another type')
578
- expect(() => run(`sink < true`)).toThrowError('Cannot compare a sink value with a value of another type')
579
- expect(() => run(`sink < (fun () sink)`)).toThrowError('Cannot compare a sink value with a value of another type')
580
- expect(() => run(`sink < 0`)).toThrowError('Cannot compare a sink value with a value of another type')
581
- expect(() => run(`sink < 5`)).toThrowError('Cannot compare a sink value with a value of another type')
582
- expect(() => run(`sink < {}`)).toThrowError('Cannot compare a sink value with a value of another type')
583
- expect(() => run(`sink < ''`)).toThrowError('Cannot compare a sink value with a value of another type')
584
- expect(() => run(`sink < 'x'`)).toThrowError('Cannot compare a sink value with a value of another type')
585
- })
586
- test(`the ?? operator evaluates to its right-hand-side if its left-hand-side is a sink`, () => {
587
- expect(run(`sink ?? 1`)).toEqual(1)
588
- })
589
- test(`the ?? operator evaluates to its left-hand-side if it is a non-sink`, () => {
590
- expect(run(`0 ?? 1`)).toEqual(0)
591
- })
592
- test(`the .where attribure of the result holds the source code of the sink`, () => {
593
- expect(runSink(`1000 + 2000 + 3000 + sink + 5000 + sink`).where).toEqual({
594
- from: { offset: 21 },
595
- to: { offset: 24 },
596
- })
597
- expect(runSink(`1000 + 2000 + 3000 + 4000 + 5000 + sink`).where).toEqual({
598
- from: { offset: 35 },
599
- to: { offset: 38 },
600
- })
601
- expect(runSink(`1000\n + 2000\n + sink\n + 4000\n + 5000\n + sink`).where).toEqual({
602
- from: { offset: 16 },
603
- to: { offset: 19 },
604
- })
605
- })
606
- test(`the .message attribure of the result provides a human readable summary`, () => {
607
- expect(runSink(`1000 + 2000\n+ 3000 + sink + 5000 + 6000`).message).toEqual(
608
- 'Evaluated to sink: at (2:10..13) sink',
609
- )
610
- })
611
- })
612
- describe('sink!', () => {
613
- test(`captures the expression trace at runtime`, () => {
614
- expect(runSink(`1000 + 2000 + 3000 + sink!`).trace).toEqual(
615
- [
616
- ` at (1:1..26) 1000 + 2000 + 3000 + sink!`,
617
- ` at (1:1..26) 1000 + 2000 + 3000 + sink!`,
618
- ` at (1:8..26) 2000 + 3000 + sink!`,
619
- ` at (1:15..26) 3000 + sink!`,
620
- ` at (1:22..26) sink!`,
621
- ].join('\n'),
622
- )
623
- })
624
- })
625
- describe('sink!!', () => {
626
- test(`captures the expression trace and the symbol-table at runtime`, () => {
627
- const actual = runSink(`let a = 2; let f = fun(x, y) x * y * sink!! * a; f(30, 40)`)
628
- expect(actual.symbols).toMatchObject({
629
- f: 'fun (x, y) (x * (y * (sink!! * a)))',
630
- a: 2,
631
- x: 30,
632
- y: 40,
633
- })
634
- expect(Object.keys(actual.symbols ?? {})).toEqual(['Object', 'a', 'f', 'x', 'y'])
635
- expect(actual.trace).toEqual(
636
- [
637
- ` at (1:1..58) let a = 2; let f = fun(x, y) x * y * sink!! * a; f(30, 40)`,
638
- ` at (1:1..58) let a = 2; let f = fun(x, y) x * y * sink!! * a; f(30, 40)`,
639
- ` at (1:50..58) f(30, 40)`,
640
- ` at (1:30..47) x * y * sink!! * a`,
641
- ` at (1:34..47) y * sink!! * a`,
642
- ` at (1:38..47) sink!! * a`,
643
- ` at (1:38..43) sink!!`,
644
- ].join('\n'),
645
- )
646
- })
647
- test('can be used to recover values of definitions from a crash site', () => {
648
- expect(runSink(`let f = fun (n) if (n >= 0) f(n-7) else (sink!! && [n].goo()); f(18)`).symbols).toMatchObject({
649
- n: -3,
650
- })
651
- })
652
- })
653
-
654
- describe('array methods', () => {
655
- test('concat', () => {
656
- expect(run(`['foo', 'bar', 'goo'].concat(['zoo', 'poo'])`)).toEqual(['foo', 'bar', 'goo', 'zoo', 'poo'])
657
- })
658
- test('every', () => {
659
- expect(run(`["", 'x', 'xx'].every(fun (item, i) item.length == i)`)).toEqual(true)
660
- expect(run(`["", 'yy', 'zz'].every(fun (item, i) item.length == i)`)).toEqual(false)
661
- expect(
662
- run(`let cb = fun (item, i, a) item == a[(a.length - i) - 1]; [[2, 7, 2].every(cb), [2, 7, 7].every(cb)]`),
663
- ).toEqual([true, false])
664
- })
665
- test('filter', () => {
666
- expect(run(`['foo', 'bar', 'goo'].filter(fun (item) item.endsWith('oo'))`)).toEqual(['foo', 'goo'])
667
- expect(run(`['a', 'b', 'c', 'd'].filter(fun (item, i) i % 2 == 1)`)).toEqual(['b', 'd'])
668
- expect(run(`[8, 8, 2, 2, 2, 7].filter(fun (x, i, a) x == a[(i + 1) % a.length])`)).toEqual([8, 2, 2])
669
- })
670
- test('find', () => {
671
- expect(run(`[10, 20, 30, 40].find(fun (item, i) item + i == 21)`)).toEqual(20)
672
- expect(run(`[8, 3, 7, 7, 6, 9].find(fun (x, i, a) x == a[a.length - (i+1)])`)).toEqual(7)
673
- })
674
- test('find returns sink if no matching element exists', () => {
675
- expect(run(`[3, 5, 7, 9].find(fun (x) x % 2 == 0)`)).toEqual(undefined)
676
- expect(run(`[].find(fun () true)`)).toEqual(undefined)
677
- })
678
- test('findIndex', () => {
679
- expect(run(`[10, 20, 30, 40].findIndex(fun (item, i) item + i == 32)`)).toEqual(2)
680
- expect(run(`[8, 3, 7, 7, 6, 9].findIndex(fun (x, i, a) x == a[a.length - (i+1)])`)).toEqual(2)
681
- })
682
- test('findIndex returns -1 if no matching element exists', () => {
683
- expect(run(`[3, 5, 7, 9].findIndex(fun (x) x % 2 == 0)`)).toEqual(-1)
684
- expect(run(`[].findIndex(fun () true)`)).toEqual(-1)
685
- })
686
- test('flatMap', () => {
687
- expect(run(`['Columbia', 'Eagle'].flatMap(fun (x) [x, x.length])`)).toEqual(['Columbia', 8, 'Eagle', 5])
688
- expect(run(`[6,7,9].flatMap(fun (x,i) if (i % 2 == 0) [x, x/3] else [])`)).toEqual([6, 2, 9, 3])
689
- expect(run(`[2,1,6,5,9,8].flatMap(fun (x,i,a) if (i % 2 == 1) [x, a[i-1]] else [])`)).toEqual([1, 2, 5, 6, 8, 9])
690
- })
691
- test('map', () => {
692
- expect(run(`['foo', 'bar', 'goo'].map(fun (s) s.charAt(0))`)).toEqual(['f', 'b', 'g'])
693
- expect(run(`['a', 'b'].map(fun (item, i) item + ':' + i)`)).toEqual(['a:0', 'b:1'])
694
- expect(run(`['a', 'b', 'p', 'q'].map(fun (x, i, a) x + a[a.length - (i+1)])`)).toEqual(['aq', 'bp', 'pb', 'qa'])
695
- })
696
- test('reduce', () => {
697
- expect(run(`['a','b','c','d'].reduce(fun (w, x) w+x, '')`)).toEqual('abcd')
698
- expect(run(`['a','b','c','d','e'].reduce(fun (w, x, i) if (i % 2 == 0) w+x else w, '')`)).toEqual('ace')
699
- expect(run(`[['w',2], ['x',0], ['y',1]].reduce(fun (w, x, i, a) w+a[x[1]][0], '')`)).toEqual('ywx')
700
- })
701
- test('reduceRight', () => {
702
- expect(run(`['a','b','c','d'].reduceRight(fun (w, x) w+x, '')`)).toEqual('dcba')
703
- expect(run(`['a','b','c','d','e'].reduceRight(fun (w, x, i) if (i % 2 == 0) w+x else w, '')`)).toEqual('eca')
704
- expect(run(`[['w',2], ['x',0], ['y',1]].reduceRight(fun (w, x, i, a) w+a[x[1]][0], '')`)).toEqual('xwy')
705
- })
706
- test('some', () => {
707
- expect(run(`['foo', 'bar', 'goo'].some(fun (item) item.endsWith('oo'))`)).toEqual(true)
708
- expect(run(`['foo', 'bar', 'goo'].some(fun (item) item.endsWith('pp'))`)).toEqual(false)
709
- expect(run(`['a', 'xyz', 'bc'].some(fun (item, i) i == item.length)`)).toEqual(true)
710
- expect(run(`[8, 3, 7, 7, 6, 9].some(fun (x, i, a) x == a[a.length - (i+1)])`)).toEqual(true)
711
- })
712
- })
713
- describe('Object.keys()', () => {
714
- test('returns names of all attributes of the given object', () => {
715
- expect(run(`Object.keys({a: 1, b: 2, w: 30})`)).toEqual(['a', 'b', 'w'])
716
- // expect(run(`Object.entries({a: 1, b: 2, w: 30})`)).toEqual([['a', 1], ['b', 2], ['w', 30]])
717
- })
718
- test('fails if applied to a non-object value', () => {
719
- expect(() => run(`Object.keys('a')`)).toThrowError('value type error: expected obj but found "a"')
720
- expect(() => run(`Object.keys(5)`)).toThrowError('value type error: expected obj but found 5')
721
- expect(() => run(`Object.keys(false)`)).toThrowError('value type error: expected obj but found false')
722
- expect(() => run(`Object.keys(['a'])`)).toThrowError('value type error: expected obj but found ["a"]')
723
- expect(() => run(`Object.keys(fun () 5)`)).toThrowError('value type error: expected obj but found "fun () 5"')
724
- })
725
- })
726
- describe('Object.entries()', () => {
727
- test('returns a [key, value] pair for each attribute of the given object', () => {
728
- expect(run(`Object.entries({a: 1, b: 2, w: 30})`)).toEqual([
729
- ['a', 1],
730
- ['b', 2],
731
- ['w', 30],
732
- ])
733
- })
734
- test('fails if applied to a non-object value', () => {
735
- expect(() => run(`Object.entries('a')`)).toThrowError('type error: expected obj but found "a"')
736
- expect(() => run(`Object.entries(5)`)).toThrowError('type error: expected obj but found 5')
737
- expect(() => run(`Object.entries(false)`)).toThrowError('type error: expected obj but found false')
738
- expect(() => run(`Object.entries(['a'])`)).toThrowError('type error: expected obj but found ["a"]')
739
- expect(() => run(`Object.entries(fun () 5)`)).toThrowError('type error: expected obj but found "fun () 5"')
740
- })
741
- })
742
- describe('Object.fromEntries()', () => {
743
- test('constructs an object from a list of [key, value] pairs describing its attributes', () => {
744
- expect(run(`Object.fromEntries([['a', 1], ['b', 2], ['w', 30], ['y', 'yoo'], ['z', true]])`)).toEqual({
745
- a: 1,
746
- b: 2,
747
- w: 30,
748
- y: 'yoo',
749
- z: true,
750
- })
751
- })
752
- test('fails if applied to a non-array value', () => {
753
- expect(() => run(`Object.fromEntries('a')`)).toThrowError('type error: expected arr but found "a"')
754
- expect(() => run(`Object.fromEntries(5)`)).toThrowError('type error: expected arr but found 5')
755
- expect(() => run(`Object.fromEntries(false)`)).toThrowError('type error: expected arr but found false')
756
- expect(() => run(`Object.fromEntries({x: 1})`)).toThrowError('type error: expected arr but found {"x":1}')
757
- expect(() => run(`Object.fromEntries(fun () 5)`)).toThrowError('type error: expected arr but found "fun () 5"')
758
- })
759
- test('the input array must be an array of pairs', () => {
760
- expect(() => run(`Object.fromEntries([['a', 1], ['b']])`)).toThrowError('each entry must be a [key, value] pair')
761
- })
762
- test('the first element in each pair must be a string', () => {
763
- expect(() => run(`Object.fromEntries([[1, 'a']])`)).toThrowError('value type error: expected str but found 1')
764
- })
765
- })
766
- describe('comments', () => {
767
- test(`anything from '//' up to the end-of-line is ignored`, () => {
768
- expect(
769
- run(`
770
- 1 + 20 + // 300
771
- 4000`),
772
- ).toEqual(4021)
773
- })
774
- test(`allow consecutive lines which are all commented out`, () => {
775
- expect(
776
- run(`
777
- 1 +
778
- // 20 +
779
- // 300 +
780
- // 4000 +
781
- 50000`),
782
- ).toEqual(50001)
783
- })
784
- test(`a comment inside a comment has no effect`, () => {
785
- expect(
786
- run(`
787
- 1 +
788
- // 20 + // 300 +
789
- 4000`),
790
- ).toEqual(4001)
791
- })
792
- })
793
- describe('evaluation stack', () => {
794
- test('max recursion depth', () => {
795
- expect(run(`let count = fun (n) if (n <= 0) 0 else 1 + count(n-1); count(330)`)).toEqual(330)
796
- })
797
- })
798
- describe('preimport', () => {
799
- test('definitions from a preimported file can be used', () => {
800
- const septima = new Septima()
801
-
802
- const input = `libA.plus10(4) + libA.plus20(2)`
803
- const preimports = {
804
- libA: `{ plus10: fun (n) n+10, plus20: fun (n) n+20}`,
805
- }
806
- expect(septima.compute(input, preimports)).toMatchObject({ value: 36 })
807
- })
808
- test('supports multiple preimports', () => {
809
- const septima = new Septima()
810
-
811
- const input = `a.calc(4) + b.calc(1)`
812
- const preimports = {
813
- a: `{ calc: fun (n) n+10 }`,
814
- b: `{ calc: fun (n) n+20 }`,
815
- }
816
- expect(septima.compute(input, preimports)).toMatchObject({ value: 35 })
817
- })
818
- })
819
- test.todo('support file names in locations')
820
- test.todo('string interpolation via `foo` strings')
821
- test.todo('imports')
822
- test.todo('arrow functions')
823
- test.todo('optional parameters')
824
- test.todo('optional type annotations?')
825
- test.todo('allow redundant commas')
826
- test.todo('left associativity of +/-')
827
- test.todo('comparison of arrays')
828
- test.todo('comparison of lambdas?')
829
- test.todo('deep equality of objects')
830
- test.todo('"abcdef"[1] == "b"')
831
- test.todo('an object literal cannot have a repeated attribute name that')
832
- test.todo('quoting of a ticks inside a string')
833
- test.todo('number in scientific notation')
834
- test.todo('number methods')
835
- test.todo('drop the fun () notation and use just arrow functions')
836
- test.todo('proper internal representation of arrow function, in particular: show(), span()')
837
- test.todo('sink sinkifies arrays and objects it is stored at')
838
- test.todo('{foo}')
839
- })