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