fez-lisp 1.3.11 → 1.3.13
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.
- package/index.js +2 -19
- package/lib/baked/macros.js +62 -0
- package/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/macros.js +500 -406
- package/src/utils.js +4 -3
package/src/macros.js
CHANGED
@@ -1,406 +1,500 @@
|
|
1
|
-
import { isLeaf } from './parser.js'
|
2
|
-
import {
|
3
|
-
EXPONENTIATION,
|
4
|
-
INTEGER_DIVISION,
|
5
|
-
NOT_EQUAL
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
case SUGGAR.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
exp.
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
exp.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
exp[
|
79
|
-
|
80
|
-
|
81
|
-
]
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
temp
|
139
|
-
}
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
exp.
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
exp
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
exp
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
exp
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
exp
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
temp.push(
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
exp
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
temp.push(
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
exp
|
268
|
-
exp
|
269
|
-
} else if (rest.length
|
270
|
-
exp.length =
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
temp.push(
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
exp
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
temp.push(
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
exp
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
temp.push(
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
exp[
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
1
|
+
import { AST, isLeaf } from './parser.js'
|
2
|
+
import {
|
3
|
+
EXPONENTIATION,
|
4
|
+
INTEGER_DIVISION,
|
5
|
+
NOT_EQUAL,
|
6
|
+
SLICE
|
7
|
+
} from '../lib/baked/macros.js'
|
8
|
+
import {
|
9
|
+
APPLY,
|
10
|
+
ATOM,
|
11
|
+
FALSE,
|
12
|
+
KEYWORDS,
|
13
|
+
PLACEHOLDER,
|
14
|
+
TRUE,
|
15
|
+
TYPE,
|
16
|
+
VALUE,
|
17
|
+
WORD
|
18
|
+
} from './keywords.js'
|
19
|
+
import { stringifyArgs } from './utils.js'
|
20
|
+
export const SUGGAR = {
|
21
|
+
// Syntactic suggars
|
22
|
+
PIPE: '|>',
|
23
|
+
NOT_EQUAL_1: '!=',
|
24
|
+
NOT_EQUAL_2: '<>',
|
25
|
+
REMAINDER_OF_DIVISION_1: '%',
|
26
|
+
UNLESS: 'unless',
|
27
|
+
CREATE_LIST: 'list',
|
28
|
+
POWER: '**',
|
29
|
+
INTEGER_DEVISION: '//',
|
30
|
+
CONDITION: 'cond'
|
31
|
+
}
|
32
|
+
export const deSuggarAst = (ast, scope) => {
|
33
|
+
if (scope === undefined) scope = ast
|
34
|
+
if (ast.length === 0) throw new SyntaxError(`No expressions to evaluate`)
|
35
|
+
// for (const node of ast)
|
36
|
+
// if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
|
37
|
+
// throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
|
38
|
+
let prev = undefined
|
39
|
+
const evaluate = (exp) => {
|
40
|
+
const [first, ...rest] = isLeaf(exp) ? [exp] : exp
|
41
|
+
if (first != undefined) {
|
42
|
+
switch (first[TYPE]) {
|
43
|
+
case WORD:
|
44
|
+
{
|
45
|
+
switch (first[VALUE]) {
|
46
|
+
case SUGGAR.REMAINDER_OF_DIVISION_1:
|
47
|
+
exp[VALUE] = KEYWORDS.REMAINDER_OF_DIVISION
|
48
|
+
break
|
49
|
+
case SUGGAR.NOT_EQUAL_1:
|
50
|
+
case SUGGAR.NOT_EQUAL_2:
|
51
|
+
exp.length = 0
|
52
|
+
exp.push(...NOT_EQUAL)
|
53
|
+
break
|
54
|
+
case SUGGAR.POWER:
|
55
|
+
exp.length = 0
|
56
|
+
exp.push(...EXPONENTIATION)
|
57
|
+
break
|
58
|
+
case SUGGAR.INTEGER_DEVISION:
|
59
|
+
exp.length = 0
|
60
|
+
exp.push(...INTEGER_DIVISION)
|
61
|
+
break
|
62
|
+
}
|
63
|
+
}
|
64
|
+
break
|
65
|
+
case ATOM:
|
66
|
+
break
|
67
|
+
case APPLY:
|
68
|
+
{
|
69
|
+
switch (first[VALUE]) {
|
70
|
+
case KEYWORDS.BLOCK:
|
71
|
+
{
|
72
|
+
if (
|
73
|
+
prev == undefined ||
|
74
|
+
(prev &&
|
75
|
+
prev[TYPE] === APPLY &&
|
76
|
+
prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
|
77
|
+
) {
|
78
|
+
exp[0][VALUE] = KEYWORDS.CALL_FUNCTION
|
79
|
+
exp[0][TYPE] = APPLY
|
80
|
+
exp.length = 1
|
81
|
+
scope = [[APPLY, KEYWORDS.BLOCK], ...rest]
|
82
|
+
exp[1] = [[APPLY, KEYWORDS.ANONYMOUS_FUNCTION], scope]
|
83
|
+
deSuggarAst(exp, scope)
|
84
|
+
} else {
|
85
|
+
scope = exp
|
86
|
+
}
|
87
|
+
}
|
88
|
+
break
|
89
|
+
case SUGGAR.PIPE:
|
90
|
+
{
|
91
|
+
if (rest.length < 1)
|
92
|
+
throw new RangeError(
|
93
|
+
`Invalid number of arguments to (${
|
94
|
+
SUGGAR.PIPE
|
95
|
+
}) (>= 1 required). (${SUGGAR.PIPE} ${stringifyArgs(
|
96
|
+
rest
|
97
|
+
)})`
|
98
|
+
)
|
99
|
+
let inp = rest[0]
|
100
|
+
exp.length = 0
|
101
|
+
for (let i = 1; i < rest.length; ++i) {
|
102
|
+
if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
|
103
|
+
throw new TypeError(
|
104
|
+
`Argument at position (${i}) of (${
|
105
|
+
SUGGAR.PIPE
|
106
|
+
}) is not an invoked (${
|
107
|
+
KEYWORDS.ANONYMOUS_FUNCTION
|
108
|
+
}). (${SUGGAR.PIPE} ${stringifyArgs(rest)})`
|
109
|
+
)
|
110
|
+
inp = [rest[i].shift(), inp, ...rest[i]]
|
111
|
+
}
|
112
|
+
for (let i = 0; i < inp.length; ++i) exp[i] = inp[i]
|
113
|
+
deSuggarAst(exp, scope)
|
114
|
+
}
|
115
|
+
break
|
116
|
+
case SUGGAR.CONDITION:
|
117
|
+
{
|
118
|
+
if (rest.length < 2)
|
119
|
+
throw new RangeError(
|
120
|
+
`Invalid number of arguments for (${
|
121
|
+
SUGGAR.CONDITION
|
122
|
+
}), expected (> 2 required) but got ${rest.length} (${
|
123
|
+
SUGGAR.CONDITION
|
124
|
+
} ${stringifyArgs(rest)})`
|
125
|
+
)
|
126
|
+
if (rest.length % 2 !== 0)
|
127
|
+
throw new RangeError(
|
128
|
+
`Invalid number of arguments for (${
|
129
|
+
SUGGAR.CONDITION
|
130
|
+
}), expected even number of arguments but got ${
|
131
|
+
rest.length
|
132
|
+
} (${SUGGAR.CONDITION} ${stringifyArgs(rest)})`
|
133
|
+
)
|
134
|
+
exp.length = 0
|
135
|
+
let temp = exp
|
136
|
+
for (let i = 0; i < rest.length; i += 2) {
|
137
|
+
if (i === rest.length - 2) {
|
138
|
+
temp.push([APPLY, KEYWORDS.IF], rest[i], rest.at(-1))
|
139
|
+
} else {
|
140
|
+
temp.push([APPLY, KEYWORDS.IF], rest[i], rest[i + 1], [])
|
141
|
+
temp = temp.at(-1)
|
142
|
+
}
|
143
|
+
}
|
144
|
+
deSuggarAst(exp, scope)
|
145
|
+
}
|
146
|
+
break
|
147
|
+
case SUGGAR.CREATE_LIST:
|
148
|
+
{
|
149
|
+
exp.length = 0
|
150
|
+
let temp = exp
|
151
|
+
for (const item of rest) {
|
152
|
+
temp.push([APPLY, KEYWORDS.CREATE_ARRAY], item, [])
|
153
|
+
temp = temp.at(-1)
|
154
|
+
}
|
155
|
+
temp.push([APPLY, KEYWORDS.CREATE_ARRAY])
|
156
|
+
}
|
157
|
+
deSuggarAst(exp, scope)
|
158
|
+
break
|
159
|
+
case SUGGAR.INTEGER_DEVISION:
|
160
|
+
{
|
161
|
+
if (rest.length !== 2)
|
162
|
+
throw new RangeError(
|
163
|
+
`Invalid number of arguments for (${
|
164
|
+
SUGGAR.INTEGER_DEVISION
|
165
|
+
}), expected (= 2) but got ${rest.length} (${
|
166
|
+
SUGGAR.INTEGER_DEVISION
|
167
|
+
} ${stringifyArgs(rest)})`
|
168
|
+
)
|
169
|
+
else if (rest.some((x) => x[TYPE] === APPLY)) {
|
170
|
+
exp.length = 0
|
171
|
+
exp.push(
|
172
|
+
[0, KEYWORDS.CALL_FUNCTION],
|
173
|
+
INTEGER_DIVISION,
|
174
|
+
...rest
|
175
|
+
)
|
176
|
+
} else {
|
177
|
+
exp.length = 1
|
178
|
+
exp[0] = [APPLY, KEYWORDS.BITWISE_OR]
|
179
|
+
exp.push([[APPLY, KEYWORDS.DIVISION], ...rest])
|
180
|
+
exp.push([ATOM, 0])
|
181
|
+
}
|
182
|
+
}
|
183
|
+
break
|
184
|
+
case SUGGAR.POWER:
|
185
|
+
{
|
186
|
+
if (rest.length !== 2)
|
187
|
+
throw new RangeError(
|
188
|
+
`Invalid number of arguments for (${
|
189
|
+
SUGGAR.POWER
|
190
|
+
}), expected (= 2) but got ${rest.length} (${
|
191
|
+
SUGGAR.POWER
|
192
|
+
} ${stringifyArgs(rest)})`
|
193
|
+
)
|
194
|
+
const isExponentAtom = exp[1][TYPE] === ATOM
|
195
|
+
const isPowerAtom = exp[2][TYPE] === ATOM
|
196
|
+
const isExponentWord = exp[1][TYPE] === WORD
|
197
|
+
if ((isExponentWord || isExponentAtom) && isPowerAtom) {
|
198
|
+
if (isExponentAtom) {
|
199
|
+
exp[0][VALUE] = KEYWORDS.MULTIPLICATION
|
200
|
+
const exponent = exp[1]
|
201
|
+
const power = exp[2][VALUE]
|
202
|
+
exp.length = 1
|
203
|
+
exp.push(exponent, [ATOM, exponent[VALUE] ** (power - 1)])
|
204
|
+
} else if (isExponentWord) {
|
205
|
+
const exponent = exp[1]
|
206
|
+
const power = exp[2]
|
207
|
+
exp.length = 0
|
208
|
+
exp.push(
|
209
|
+
[0, KEYWORDS.CALL_FUNCTION],
|
210
|
+
EXPONENTIATION,
|
211
|
+
exponent,
|
212
|
+
power
|
213
|
+
)
|
214
|
+
}
|
215
|
+
} else {
|
216
|
+
const exponent = exp[1]
|
217
|
+
const power = exp[2]
|
218
|
+
exp.length = 0
|
219
|
+
exp.push(
|
220
|
+
[0, KEYWORDS.CALL_FUNCTION],
|
221
|
+
EXPONENTIATION,
|
222
|
+
exponent,
|
223
|
+
power
|
224
|
+
)
|
225
|
+
}
|
226
|
+
deSuggarAst(exp, scope)
|
227
|
+
}
|
228
|
+
break
|
229
|
+
case KEYWORDS.MULTIPLICATION:
|
230
|
+
if (!rest.length) {
|
231
|
+
exp[0][TYPE] = ATOM
|
232
|
+
exp[0][VALUE] = TRUE
|
233
|
+
} else if (rest.length > 2) {
|
234
|
+
exp.length = 0
|
235
|
+
let temp = exp
|
236
|
+
for (let i = 0; i < rest.length; i += 1) {
|
237
|
+
if (i < rest.length - 1) {
|
238
|
+
temp.push([APPLY, KEYWORDS.MULTIPLICATION], rest[i], [])
|
239
|
+
temp = temp.at(-1)
|
240
|
+
} else {
|
241
|
+
temp.push(...rest[i])
|
242
|
+
}
|
243
|
+
}
|
244
|
+
deSuggarAst(exp, scope)
|
245
|
+
}
|
246
|
+
break
|
247
|
+
case KEYWORDS.ADDITION:
|
248
|
+
if (!rest.length) {
|
249
|
+
exp[0][TYPE] = ATOM
|
250
|
+
exp[0][VALUE] = FALSE
|
251
|
+
} else if (rest.length > 2) {
|
252
|
+
exp.length = 0
|
253
|
+
let temp = exp
|
254
|
+
for (let i = 0; i < rest.length; i += 1) {
|
255
|
+
if (i < rest.length - 1) {
|
256
|
+
temp.push([APPLY, KEYWORDS.ADDITION], rest[i], [])
|
257
|
+
temp = temp.at(-1)
|
258
|
+
} else {
|
259
|
+
temp.push(...rest[i])
|
260
|
+
}
|
261
|
+
}
|
262
|
+
deSuggarAst(exp, scope)
|
263
|
+
}
|
264
|
+
break
|
265
|
+
case KEYWORDS.DIVISION:
|
266
|
+
if (!rest.length) {
|
267
|
+
exp[0][TYPE] = ATOM
|
268
|
+
exp[0][VALUE] = FALSE
|
269
|
+
} else if (rest.length === 1) {
|
270
|
+
exp.length = 1
|
271
|
+
exp.push([ATOM, 1], rest[0])
|
272
|
+
} else if (rest.length > 2) {
|
273
|
+
exp.length = 0
|
274
|
+
let temp = exp
|
275
|
+
for (let i = 0; i < rest.length; i += 1) {
|
276
|
+
if (i < rest.length - 1) {
|
277
|
+
temp.push([APPLY, KEYWORDS.DIVISION], rest[i], [])
|
278
|
+
temp = temp.at(-1)
|
279
|
+
} else {
|
280
|
+
temp.push(...rest[i])
|
281
|
+
}
|
282
|
+
}
|
283
|
+
deSuggarAst(exp, scope)
|
284
|
+
}
|
285
|
+
break
|
286
|
+
case KEYWORDS.AND:
|
287
|
+
if (!rest.length) {
|
288
|
+
exp[0][TYPE] = ATOM
|
289
|
+
exp[0][VALUE] = FALSE
|
290
|
+
} else if (rest.length > 2) {
|
291
|
+
exp.length = 0
|
292
|
+
let temp = exp
|
293
|
+
for (let i = 0; i < rest.length; i += 1) {
|
294
|
+
if (i < rest.length - 1) {
|
295
|
+
temp.push([APPLY, KEYWORDS.AND], rest[i], [])
|
296
|
+
temp = temp.at(-1)
|
297
|
+
} else {
|
298
|
+
temp.push(...rest[i])
|
299
|
+
}
|
300
|
+
}
|
301
|
+
deSuggarAst(exp, scope)
|
302
|
+
}
|
303
|
+
break
|
304
|
+
case KEYWORDS.OR:
|
305
|
+
if (!rest.length) {
|
306
|
+
exp[0][TYPE] = ATOM
|
307
|
+
exp[0][VALUE] = FALSE
|
308
|
+
} else if (rest.length > 2) {
|
309
|
+
exp.length = 0
|
310
|
+
let temp = exp
|
311
|
+
for (let i = 0; i < rest.length; i += 1) {
|
312
|
+
if (i < rest.length - 1) {
|
313
|
+
temp.push([APPLY, KEYWORDS.OR], rest[i], [])
|
314
|
+
temp = temp.at(-1)
|
315
|
+
} else {
|
316
|
+
temp.push(...rest[i])
|
317
|
+
}
|
318
|
+
}
|
319
|
+
deSuggarAst(exp, scope)
|
320
|
+
}
|
321
|
+
break
|
322
|
+
case SUGGAR.UNLESS:
|
323
|
+
{
|
324
|
+
if (rest.length > 3 || rest.length < 2)
|
325
|
+
throw new RangeError(
|
326
|
+
`Invalid number of arguments for (${
|
327
|
+
SUGGAR.UNLESS
|
328
|
+
}), expected (or (= 3) (= 2)) but got ${rest.length} (${
|
329
|
+
SUGGAR.UNLESS
|
330
|
+
} ${stringifyArgs(rest)})`
|
331
|
+
)
|
332
|
+
exp[0][VALUE] = KEYWORDS.IF
|
333
|
+
const temp = exp[2]
|
334
|
+
exp[2] = exp[3] ?? [ATOM, FALSE]
|
335
|
+
exp[3] = temp
|
336
|
+
}
|
337
|
+
deSuggarAst(exp, scope)
|
338
|
+
break
|
339
|
+
case SUGGAR.REMAINDER_OF_DIVISION_1:
|
340
|
+
{
|
341
|
+
if (rest.length !== 2)
|
342
|
+
throw new RangeError(
|
343
|
+
`Invalid number of arguments for (${
|
344
|
+
exp[0][1]
|
345
|
+
}), expected (= 2) but got ${rest.length} (${
|
346
|
+
exp[0][1]
|
347
|
+
} ${stringifyArgs(rest)})`
|
348
|
+
)
|
349
|
+
exp[0][VALUE] = KEYWORDS.REMAINDER_OF_DIVISION
|
350
|
+
deSuggarAst(exp, scope)
|
351
|
+
}
|
352
|
+
break
|
353
|
+
case SUGGAR.NOT_EQUAL_1:
|
354
|
+
case SUGGAR.NOT_EQUAL_2:
|
355
|
+
{
|
356
|
+
if (rest.length !== 2)
|
357
|
+
throw new RangeError(
|
358
|
+
`Invalid number of arguments for (${
|
359
|
+
exp[0][1]
|
360
|
+
}), expected (= 2) but got ${rest.length} (${
|
361
|
+
exp[0][1]
|
362
|
+
} ${stringifyArgs(rest)})`
|
363
|
+
)
|
364
|
+
exp[0][VALUE] = KEYWORDS.NOT
|
365
|
+
exp[1] = [[APPLY, KEYWORDS.EQUAL], exp[1], exp[2]]
|
366
|
+
exp.length = 2
|
367
|
+
deSuggarAst(exp, scope)
|
368
|
+
}
|
369
|
+
break
|
370
|
+
case KEYWORDS.DEFINE_VARIABLE:
|
371
|
+
{
|
372
|
+
if (!isLeaf(exp[VALUE])) {
|
373
|
+
const left = exp[VALUE]
|
374
|
+
const right = exp.at(-1)
|
375
|
+
// const key = AST.stringify(exp)
|
376
|
+
// const index = scope.findIndex(
|
377
|
+
// (x) => AST.stringify(x) === key
|
378
|
+
// )
|
379
|
+
const lastLeft = left.pop()
|
380
|
+
const isSlicing = lastLeft[VALUE] !== PLACEHOLDER
|
381
|
+
const vars = left.slice(1)
|
382
|
+
const indexes = vars
|
383
|
+
.map((x, i) => (x[VALUE] === PLACEHOLDER ? -1 : i))
|
384
|
+
.filter((x) => x !== -1)
|
385
|
+
let newScope
|
386
|
+
exp.length = 0
|
387
|
+
switch (left[0][VALUE]) {
|
388
|
+
case KEYWORDS.CREATE_ARRAY:
|
389
|
+
{
|
390
|
+
if (
|
391
|
+
!isLeaf(right) &&
|
392
|
+
right[0][TYPE] === APPLY &&
|
393
|
+
right[0][VALUE] === KEYWORDS.CREATE_ARRAY
|
394
|
+
) {
|
395
|
+
const values = right.slice(1)
|
396
|
+
newScope = indexes.map((i) => [
|
397
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
398
|
+
vars[i],
|
399
|
+
values[i]
|
400
|
+
])
|
401
|
+
if (isSlicing)
|
402
|
+
newScope.push([
|
403
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
404
|
+
lastLeft,
|
405
|
+
[
|
406
|
+
[APPLY, KEYWORDS.CREATE_ARRAY],
|
407
|
+
...values.slice(indexes.at(-1) + 1)
|
408
|
+
]
|
409
|
+
])
|
410
|
+
} else {
|
411
|
+
newScope = indexes.map((i) => [
|
412
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
413
|
+
vars[i],
|
414
|
+
[[APPLY, KEYWORDS.GET_ARRAY], right, [ATOM, i]]
|
415
|
+
])
|
416
|
+
if (isSlicing)
|
417
|
+
newScope.push([
|
418
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
419
|
+
lastLeft,
|
420
|
+
[
|
421
|
+
[APPLY, KEYWORDS.CALL_FUNCTION],
|
422
|
+
SLICE,
|
423
|
+
right,
|
424
|
+
[ATOM, indexes.at(-1) + 1],
|
425
|
+
[[APPLY, KEYWORDS.ARRAY_LENGTH], right]
|
426
|
+
]
|
427
|
+
])
|
428
|
+
}
|
429
|
+
exp.iron = true
|
430
|
+
exp.push(newScope)
|
431
|
+
deSuggarAst(exp)
|
432
|
+
}
|
433
|
+
break
|
434
|
+
}
|
435
|
+
}
|
436
|
+
}
|
437
|
+
break
|
438
|
+
}
|
439
|
+
prev = first
|
440
|
+
}
|
441
|
+
break
|
442
|
+
default: {
|
443
|
+
iron(scope)
|
444
|
+
for (const e of exp) evaluate(e)
|
445
|
+
}
|
446
|
+
break
|
447
|
+
}
|
448
|
+
for (const r of rest) evaluate(r)
|
449
|
+
}
|
450
|
+
}
|
451
|
+
evaluate(ast)
|
452
|
+
iron(scope)
|
453
|
+
return ast
|
454
|
+
}
|
455
|
+
export const replaceStrings = (source) => {
|
456
|
+
// const quotes = source.match(/"(.*?)"/g)
|
457
|
+
const quotes = source.match(/"(?:.*?(\n|\r))*?.*?"/g)
|
458
|
+
// TODO handle escaping
|
459
|
+
if (quotes)
|
460
|
+
for (const q of quotes)
|
461
|
+
source = source.replaceAll(
|
462
|
+
q,
|
463
|
+
`(${KEYWORDS.CREATE_ARRAY} ${[...q.replaceAll('\r', '')]
|
464
|
+
.slice(1, -1)
|
465
|
+
.map((x) => x.charCodeAt(0))
|
466
|
+
.join(' ')})`
|
467
|
+
)
|
468
|
+
return source
|
469
|
+
}
|
470
|
+
const iron = (scope) => {
|
471
|
+
const indecies = scope
|
472
|
+
.map((x, i) => {
|
473
|
+
return x.iron ? i : -1
|
474
|
+
})
|
475
|
+
.filter((x) => x !== -1)
|
476
|
+
if (indecies.length) {
|
477
|
+
const set = new Set(indecies)
|
478
|
+
const copy = []
|
479
|
+
for (let i = 0; i < scope.length; ++i) {
|
480
|
+
if (set.has(i)) {
|
481
|
+
delete scope[i].iron
|
482
|
+
copy.push(...scope[i][0])
|
483
|
+
} else {
|
484
|
+
copy.push(scope[i])
|
485
|
+
}
|
486
|
+
}
|
487
|
+
for (let i = 0; i < copy.length; ++i) scope[i] = copy[i]
|
488
|
+
}
|
489
|
+
}
|
490
|
+
export const replaceQuotes = (source) =>
|
491
|
+
source
|
492
|
+
.replaceAll(/\'\(/g, `(${KEYWORDS.CREATE_ARRAY} `)
|
493
|
+
.replaceAll(/\`\(/g, `(${SUGGAR.CREATE_LIST} `)
|
494
|
+
.replaceAll(/\(\)/g, `(${KEYWORDS.CREATE_ARRAY})`)
|
495
|
+
export const deSuggarSource = (source) => replaceQuotes(replaceStrings(source))
|
496
|
+
export const handleUnbalancedQuotes = (source) => {
|
497
|
+
const diff = (source.match(/\"/g) ?? []).length % 2
|
498
|
+
if (diff !== 0) throw new SyntaxError(`Quotes are unbalanced "`)
|
499
|
+
return source
|
500
|
+
}
|