fez-lisp 1.3.1 → 1.3.3
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/lib/baked/macros.js +29 -4
- package/lib/baked/std.js +1 -1
- package/package.json +2 -3
- package/src/compiler.js +32 -10
- package/src/interpreter.js +314 -329
- package/src/keywords.js +0 -13
- package/src/macros.js +406 -0
- package/src/utils.js +15 -374
package/src/utils.js
CHANGED
@@ -1,42 +1,16 @@
|
|
1
1
|
import std from '../lib/baked/std.js'
|
2
|
-
import { comp } from './compiler.js'
|
3
|
-
import {
|
4
|
-
APPLY,
|
5
|
-
ATOM,
|
6
|
-
FALSE,
|
7
|
-
KEYWORDS,
|
8
|
-
SUGGAR,
|
9
|
-
TRUE,
|
10
|
-
TYPE,
|
11
|
-
VALUE,
|
12
|
-
WORD
|
13
|
-
} from './keywords.js'
|
2
|
+
import { comp, OPTIMIZATIONS } from './compiler.js'
|
3
|
+
import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
|
14
4
|
import { evaluate, run } from './evaluator.js'
|
15
5
|
import { AST, isLeaf, LISP } from './parser.js'
|
16
|
-
import {
|
6
|
+
import {
|
7
|
+
deSuggarAst,
|
8
|
+
deSuggarSource,
|
9
|
+
handleUnbalancedQuotes
|
10
|
+
} from './macros.js'
|
17
11
|
export const logError = (error) =>
|
18
12
|
console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
|
19
13
|
export const logSuccess = (output) => console.log(output, '\x1b[0m')
|
20
|
-
export const replaceStrings = (source) => {
|
21
|
-
// const quotes = source.match(/"(.*?)"/g)
|
22
|
-
const quotes = source.match(/"(?:.*?(\n|\r))*?.*?"/g)
|
23
|
-
// TODO handle escaping
|
24
|
-
if (quotes)
|
25
|
-
for (const q of quotes)
|
26
|
-
source = source.replaceAll(
|
27
|
-
q,
|
28
|
-
`(array ${[...q.replaceAll('\r', '')]
|
29
|
-
.slice(1, -1)
|
30
|
-
.map((x) => x.charCodeAt(0))
|
31
|
-
.join(' ')})`
|
32
|
-
)
|
33
|
-
return source
|
34
|
-
}
|
35
|
-
export const replaceQuotes = (source) =>
|
36
|
-
source
|
37
|
-
.replaceAll(/\'\(/g, '(array ')
|
38
|
-
.replaceAll(/\`\(/g, '(list ')
|
39
|
-
.replaceAll(/\(\)/g, '(array)')
|
40
14
|
// export const replaceEmptyArrays = (source) =>
|
41
15
|
// source
|
42
16
|
export const removeNoCode = (source) =>
|
@@ -113,8 +87,8 @@ export const isForbiddenVariableName = (name) => {
|
|
113
87
|
switch (name) {
|
114
88
|
case '_':
|
115
89
|
case KEYWORDS.DEFINE_VARIABLE:
|
116
|
-
case
|
117
|
-
case
|
90
|
+
case OPTIMIZATIONS.RECURSION:
|
91
|
+
case OPTIMIZATIONS.CACHE:
|
118
92
|
return true
|
119
93
|
default:
|
120
94
|
return !isNaN(name[0])
|
@@ -168,11 +142,6 @@ export const handleUnbalancedParens = (source) => {
|
|
168
142
|
)
|
169
143
|
return source
|
170
144
|
}
|
171
|
-
export const handleUnbalancedQuotes = (source) => {
|
172
|
-
const diff = (source.match(/\"/g) ?? []).length % 2
|
173
|
-
if (diff !== 0) throw new SyntaxError(`Quotes are unbalanced "`)
|
174
|
-
return source
|
175
|
-
}
|
176
145
|
export const removeMutation = (source) => source.replace(new RegExp(/!/g), 'ǃ')
|
177
146
|
const isDefinition = (x) =>
|
178
147
|
x[TYPE] === APPLY && x[VALUE] === KEYWORDS.DEFINE_VARIABLE
|
@@ -246,13 +215,13 @@ export const fez = (source, options = {}) => {
|
|
246
215
|
const env = Object.create(null)
|
247
216
|
try {
|
248
217
|
if (typeof source === 'string') {
|
249
|
-
source =
|
218
|
+
source = deSuggarSource(source)
|
250
219
|
const valid = handleUnbalancedQuotes(
|
251
220
|
handleUnbalancedParens(removeNoCode(source))
|
252
221
|
)
|
253
222
|
const code = !options.mutation ? removeMutation(valid) : valid
|
254
223
|
if (!code.length && options.throw) throw new Error('Nothing to parse!')
|
255
|
-
const parsed =
|
224
|
+
const parsed = deSuggarAst(LISP.parse(code))
|
256
225
|
const ast = [...treeShake(parsed, std), ...parsed]
|
257
226
|
// if (options.check) typeCheck(ast)
|
258
227
|
if (options.compile) return comp(ast)
|
@@ -310,17 +279,12 @@ export const decompress = (raw) => {
|
|
310
279
|
export const shake = (parsed, std) => [...treeShake(parsed, std), ...parsed]
|
311
280
|
export const tree = (source, std) =>
|
312
281
|
std
|
313
|
-
? shake(
|
314
|
-
|
315
|
-
std
|
316
|
-
)
|
317
|
-
: LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source))))
|
282
|
+
? shake(LISP.parse(deSuggarSource(removeNoCode(source))), std)
|
283
|
+
: LISP.parse(deSuggarSource(removeNoCode(source)))
|
318
284
|
export const minify = (source) =>
|
319
|
-
LISP.source(
|
320
|
-
deSuggar(LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source)))))
|
321
|
-
)
|
285
|
+
LISP.source(deSuggarAst(LISP.parse(deSuggarSource(removeNoCode(source)))))
|
322
286
|
export const prep = (source) =>
|
323
|
-
|
287
|
+
deSuggarAst(LISP.parse(removeNoCode(deSuggarSource(source))))
|
324
288
|
export const src = (source, deps) => {
|
325
289
|
source = prep(source)
|
326
290
|
return LISP.source([
|
@@ -363,326 +327,3 @@ export const js = (source, deps) => {
|
|
363
327
|
])
|
364
328
|
return `${top}${program}`
|
365
329
|
}
|
366
|
-
|
367
|
-
export const deSuggar = (ast) => {
|
368
|
-
if (ast.length === 0) throw new SyntaxError(`No expressions to evaluate`)
|
369
|
-
// for (const node of ast)
|
370
|
-
// if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
|
371
|
-
// throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
|
372
|
-
let prev = undefined
|
373
|
-
const evaluate = (exp) => {
|
374
|
-
const [first, ...rest] = isLeaf(exp) ? [exp] : exp
|
375
|
-
if (first != undefined) {
|
376
|
-
switch (first[TYPE]) {
|
377
|
-
case WORD:
|
378
|
-
{
|
379
|
-
switch (first[VALUE]) {
|
380
|
-
case SUGGAR.POWER:
|
381
|
-
exp.length = 0
|
382
|
-
exp.push(...EXPONENTIATION)
|
383
|
-
break
|
384
|
-
case SUGGAR.INTEGER_DEVISION:
|
385
|
-
exp.length = 0
|
386
|
-
exp.push(...FLOOR)
|
387
|
-
break
|
388
|
-
}
|
389
|
-
}
|
390
|
-
break
|
391
|
-
case ATOM:
|
392
|
-
break
|
393
|
-
case APPLY:
|
394
|
-
{
|
395
|
-
switch (first[VALUE]) {
|
396
|
-
case KEYWORDS.BLOCK:
|
397
|
-
{
|
398
|
-
if (
|
399
|
-
prev == undefined ||
|
400
|
-
(prev &&
|
401
|
-
prev[TYPE] === APPLY &&
|
402
|
-
prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
|
403
|
-
) {
|
404
|
-
exp[0][VALUE] = KEYWORDS.CALL_FUNCTION
|
405
|
-
exp[0][TYPE] = APPLY
|
406
|
-
exp.length = 1
|
407
|
-
exp[1] = [
|
408
|
-
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
409
|
-
[[APPLY, KEYWORDS.BLOCK], ...rest]
|
410
|
-
]
|
411
|
-
deSuggar(exp)
|
412
|
-
}
|
413
|
-
}
|
414
|
-
break
|
415
|
-
case SUGGAR.PIPE:
|
416
|
-
{
|
417
|
-
if (rest.length < 1)
|
418
|
-
throw new RangeError(
|
419
|
-
`Invalid number of arguments to (${
|
420
|
-
SUGGAR.PIPE
|
421
|
-
}) (>= 1 required). (${SUGGAR.PIPE} ${stringifyArgs(
|
422
|
-
rest
|
423
|
-
)})`
|
424
|
-
)
|
425
|
-
let inp = rest[0]
|
426
|
-
exp.length = 0
|
427
|
-
for (let i = 1; i < rest.length; ++i) {
|
428
|
-
if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
|
429
|
-
throw new TypeError(
|
430
|
-
`Argument at position (${i}) of (${
|
431
|
-
SUGGAR.PIPE
|
432
|
-
}) is not an invoked (${
|
433
|
-
KEYWORDS.ANONYMOUS_FUNCTION
|
434
|
-
}). (${SUGGAR.PIPE} ${stringifyArgs(rest)})`
|
435
|
-
)
|
436
|
-
inp = [rest[i].shift(), inp, ...rest[i]]
|
437
|
-
}
|
438
|
-
for (let i = 0; i < inp.length; ++i) exp[i] = inp[i]
|
439
|
-
deSuggar(exp)
|
440
|
-
}
|
441
|
-
break
|
442
|
-
case SUGGAR.CONDITION:
|
443
|
-
{
|
444
|
-
if (rest.length < 2)
|
445
|
-
throw new RangeError(
|
446
|
-
`Invalid number of arguments for (${
|
447
|
-
SUGGAR.CONDITION
|
448
|
-
}), expected (> 2 required) but got ${rest.length} (${
|
449
|
-
SUGGAR.CONDITION
|
450
|
-
} ${stringifyArgs(rest)})`
|
451
|
-
)
|
452
|
-
if (rest.length % 2 !== 0)
|
453
|
-
throw new RangeError(
|
454
|
-
`Invalid number of arguments for (${
|
455
|
-
SUGGAR.CONDITION
|
456
|
-
}), expected even number of arguments but got ${
|
457
|
-
rest.length
|
458
|
-
} (${SUGGAR.CONDITION} ${stringifyArgs(rest)})`
|
459
|
-
)
|
460
|
-
exp.length = 0
|
461
|
-
let temp = exp
|
462
|
-
for (let i = 0; i < rest.length; i += 2) {
|
463
|
-
if (i === rest.length - 2) {
|
464
|
-
temp.push([APPLY, KEYWORDS.IF], rest[i], rest.at(-1))
|
465
|
-
} else {
|
466
|
-
temp.push([APPLY, KEYWORDS.IF], rest[i], rest[i + 1], [])
|
467
|
-
temp = temp.at(-1)
|
468
|
-
}
|
469
|
-
}
|
470
|
-
deSuggar(exp)
|
471
|
-
}
|
472
|
-
break
|
473
|
-
case SUGGAR.LIST_TYPE:
|
474
|
-
{
|
475
|
-
exp.length = 0
|
476
|
-
let temp = exp
|
477
|
-
for (const item of rest) {
|
478
|
-
temp.push([APPLY, KEYWORDS.ARRAY_TYPE], item, [])
|
479
|
-
temp = temp.at(-1)
|
480
|
-
}
|
481
|
-
temp.push([APPLY, KEYWORDS.ARRAY_TYPE])
|
482
|
-
}
|
483
|
-
deSuggar(exp)
|
484
|
-
break
|
485
|
-
case SUGGAR.INTEGER_DEVISION:
|
486
|
-
{
|
487
|
-
if (rest.length !== 2)
|
488
|
-
throw new RangeError(
|
489
|
-
`Invalid number of arguments for (${
|
490
|
-
SUGGAR.INTEGER_DEVISION
|
491
|
-
}), expected (= 2) but got ${rest.length} (${
|
492
|
-
SUGGAR.INTEGER_DEVISION
|
493
|
-
} ${stringifyArgs(rest)})`
|
494
|
-
)
|
495
|
-
else if (rest.some((x) => x[TYPE] === APPLY)) {
|
496
|
-
exp.length = 0
|
497
|
-
exp.push([0, KEYWORDS.CALL_FUNCTION], FLOOR, ...rest)
|
498
|
-
} else {
|
499
|
-
exp.length = 1
|
500
|
-
exp[0] = [APPLY, KEYWORDS.BITWISE_OR]
|
501
|
-
exp.push([[APPLY, KEYWORDS.DIVISION], ...rest])
|
502
|
-
exp.push([ATOM, 0])
|
503
|
-
}
|
504
|
-
}
|
505
|
-
break
|
506
|
-
case SUGGAR.POWER:
|
507
|
-
{
|
508
|
-
if (rest.length !== 2)
|
509
|
-
throw new RangeError(
|
510
|
-
`Invalid number of arguments for (${
|
511
|
-
SUGGAR.POWER
|
512
|
-
}), expected (= 2) but got ${rest.length} (${
|
513
|
-
SUGGAR.POWER
|
514
|
-
} ${stringifyArgs(rest)})`
|
515
|
-
)
|
516
|
-
const isExponentAtom = exp[1][TYPE] === ATOM
|
517
|
-
const isPowerAtom = exp[2][TYPE] === ATOM
|
518
|
-
const isExponentWord = exp[1][TYPE] === WORD
|
519
|
-
if ((isExponentWord || isExponentAtom) && isPowerAtom) {
|
520
|
-
if (isExponentAtom) {
|
521
|
-
exp[0][VALUE] = KEYWORDS.MULTIPLICATION
|
522
|
-
const exponent = exp[1]
|
523
|
-
const power = exp[2][VALUE]
|
524
|
-
exp.length = 1
|
525
|
-
exp.push(exponent, [ATOM, exponent[VALUE] ** (power - 1)])
|
526
|
-
} else if (isExponentWord) {
|
527
|
-
const exponent = exp[1]
|
528
|
-
const power = exp[2]
|
529
|
-
exp.length = 0
|
530
|
-
exp.push(
|
531
|
-
[0, KEYWORDS.CALL_FUNCTION],
|
532
|
-
EXPONENTIATION,
|
533
|
-
exponent,
|
534
|
-
power
|
535
|
-
)
|
536
|
-
}
|
537
|
-
} else {
|
538
|
-
const exponent = exp[1]
|
539
|
-
const power = exp[2]
|
540
|
-
exp.length = 0
|
541
|
-
exp.push(
|
542
|
-
[0, KEYWORDS.CALL_FUNCTION],
|
543
|
-
EXPONENTIATION,
|
544
|
-
exponent,
|
545
|
-
power
|
546
|
-
)
|
547
|
-
}
|
548
|
-
deSuggar(exp)
|
549
|
-
}
|
550
|
-
break
|
551
|
-
case KEYWORDS.MULTIPLICATION:
|
552
|
-
if (!rest.length) {
|
553
|
-
exp[0][TYPE] = ATOM
|
554
|
-
exp[0][VALUE] = TRUE
|
555
|
-
} else if (rest.length > 2) {
|
556
|
-
exp.length = 0
|
557
|
-
let temp = exp
|
558
|
-
for (let i = 0; i < rest.length; i += 1) {
|
559
|
-
if (i < rest.length - 1) {
|
560
|
-
temp.push([APPLY, KEYWORDS.MULTIPLICATION], rest[i], [])
|
561
|
-
temp = temp.at(-1)
|
562
|
-
} else {
|
563
|
-
temp.push(...rest[i])
|
564
|
-
}
|
565
|
-
}
|
566
|
-
deSuggar(exp)
|
567
|
-
}
|
568
|
-
break
|
569
|
-
case KEYWORDS.ADDITION:
|
570
|
-
if (!rest.length) {
|
571
|
-
exp[0][TYPE] = ATOM
|
572
|
-
exp[0][VALUE] = FALSE
|
573
|
-
} else if (rest.length > 2) {
|
574
|
-
exp.length = 0
|
575
|
-
let temp = exp
|
576
|
-
for (let i = 0; i < rest.length; i += 1) {
|
577
|
-
if (i < rest.length - 1) {
|
578
|
-
temp.push([APPLY, KEYWORDS.ADDITION], rest[i], [])
|
579
|
-
temp = temp.at(-1)
|
580
|
-
} else {
|
581
|
-
temp.push(...rest[i])
|
582
|
-
}
|
583
|
-
}
|
584
|
-
deSuggar(exp)
|
585
|
-
}
|
586
|
-
break
|
587
|
-
case KEYWORDS.DIVISION:
|
588
|
-
if (!rest.length) {
|
589
|
-
exp[0][TYPE] = ATOM
|
590
|
-
exp[0][VALUE] = FALSE
|
591
|
-
} else if (rest.length > 2) {
|
592
|
-
exp.length = 0
|
593
|
-
let temp = exp
|
594
|
-
for (let i = 0; i < rest.length; i += 1) {
|
595
|
-
if (i < rest.length - 1) {
|
596
|
-
temp.push([APPLY, KEYWORDS.DIVISION], rest[i], [])
|
597
|
-
temp = temp.at(-1)
|
598
|
-
} else {
|
599
|
-
temp.push(...rest[i])
|
600
|
-
}
|
601
|
-
}
|
602
|
-
deSuggar(exp)
|
603
|
-
}
|
604
|
-
break
|
605
|
-
case KEYWORDS.AND:
|
606
|
-
if (!rest.length) {
|
607
|
-
exp[0][TYPE] = ATOM
|
608
|
-
exp[0][VALUE] = FALSE
|
609
|
-
} else if (rest.length > 2) {
|
610
|
-
exp.length = 0
|
611
|
-
let temp = exp
|
612
|
-
for (let i = 0; i < rest.length; i += 1) {
|
613
|
-
if (i < rest.length - 1) {
|
614
|
-
temp.push([APPLY, KEYWORDS.AND], rest[i], [])
|
615
|
-
temp = temp.at(-1)
|
616
|
-
} else {
|
617
|
-
temp.push(...rest[i])
|
618
|
-
}
|
619
|
-
}
|
620
|
-
deSuggar(exp)
|
621
|
-
}
|
622
|
-
break
|
623
|
-
case KEYWORDS.OR:
|
624
|
-
if (!rest.length) {
|
625
|
-
exp[0][TYPE] = ATOM
|
626
|
-
exp[0][VALUE] = FALSE
|
627
|
-
} else if (rest.length > 2) {
|
628
|
-
exp.length = 0
|
629
|
-
let temp = exp
|
630
|
-
for (let i = 0; i < rest.length; i += 1) {
|
631
|
-
if (i < rest.length - 1) {
|
632
|
-
temp.push([APPLY, KEYWORDS.OR], rest[i], [])
|
633
|
-
temp = temp.at(-1)
|
634
|
-
} else {
|
635
|
-
temp.push(...rest[i])
|
636
|
-
}
|
637
|
-
}
|
638
|
-
deSuggar(exp)
|
639
|
-
}
|
640
|
-
break
|
641
|
-
case SUGGAR.UNLESS:
|
642
|
-
{
|
643
|
-
if (rest.length > 3 || rest.length < 2)
|
644
|
-
throw new RangeError(
|
645
|
-
`Invalid number of arguments for (${
|
646
|
-
SUGGAR.UNLESS
|
647
|
-
}), expected (or (= 3) (= 2)) but got ${rest.length} (${
|
648
|
-
SUGGAR.UNLESS
|
649
|
-
} ${stringifyArgs(rest)})`
|
650
|
-
)
|
651
|
-
exp[0][VALUE] = KEYWORDS.IF
|
652
|
-
const temp = exp[2]
|
653
|
-
exp[2] = exp[3] ?? [ATOM, FALSE]
|
654
|
-
exp[3] = temp
|
655
|
-
}
|
656
|
-
deSuggar(exp)
|
657
|
-
break
|
658
|
-
case SUGGAR.NOT_EQUAL_1:
|
659
|
-
case SUGGAR.NOT_EQUAL_2:
|
660
|
-
{
|
661
|
-
if (rest.length > 3 || rest.length < 2)
|
662
|
-
throw new RangeError(
|
663
|
-
`Invalid number of arguments for (${
|
664
|
-
exp[0][1]
|
665
|
-
}), expected (or (= 3) (= 2)) but got ${rest.length} (${
|
666
|
-
exp[0][1]
|
667
|
-
} ${stringifyArgs(rest)})`
|
668
|
-
)
|
669
|
-
exp[0][VALUE] = KEYWORDS.NOT
|
670
|
-
exp[1] = [[APPLY, KEYWORDS.EQUAL], exp[1], exp[2]]
|
671
|
-
exp.length = 2
|
672
|
-
deSuggar(exp)
|
673
|
-
}
|
674
|
-
break
|
675
|
-
}
|
676
|
-
prev = first
|
677
|
-
}
|
678
|
-
break
|
679
|
-
default:
|
680
|
-
for (const e of exp) evaluate(e)
|
681
|
-
break
|
682
|
-
}
|
683
|
-
for (const r of rest) evaluate(r)
|
684
|
-
}
|
685
|
-
}
|
686
|
-
evaluate(ast)
|
687
|
-
return ast
|
688
|
-
}
|