fez-lisp 1.3.0 → 1.3.2

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/utils.js CHANGED
@@ -1,41 +1,17 @@
1
1
  import std from '../lib/baked/std.js'
2
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'
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'
6
+ import {
7
+ deSuggarAst,
8
+ deSuggarSource,
9
+ handleUnbalancedQuotes,
10
+ SUGGAR
11
+ } from './macros.js'
16
12
  export const logError = (error) =>
17
13
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
18
14
  export const logSuccess = (output) => console.log(output, '\x1b[0m')
19
- export const replaceStrings = (source) => {
20
- // const quotes = source.match(/"(.*?)"/g)
21
- const quotes = source.match(/"(?:.*?(\n|\r))*?.*?"/g)
22
- // TODO handle escaping
23
- if (quotes)
24
- for (const q of quotes)
25
- source = source.replaceAll(
26
- q,
27
- `(array ${[...q.replaceAll('\r', '')]
28
- .slice(1, -1)
29
- .map((x) => x.charCodeAt(0))
30
- .join(' ')})`
31
- )
32
- return source
33
- }
34
- export const replaceQuotes = (source) =>
35
- source
36
- .replaceAll(/\'\(/g, '(array ')
37
- .replaceAll(/\`\(/g, '(list ')
38
- .replaceAll(/\(\)/g, '(array)')
39
15
  // export const replaceEmptyArrays = (source) =>
40
16
  // source
41
17
  export const removeNoCode = (source) =>
@@ -167,11 +143,6 @@ export const handleUnbalancedParens = (source) => {
167
143
  )
168
144
  return source
169
145
  }
170
- export const handleUnbalancedQuotes = (source) => {
171
- const diff = (source.match(/\"/g) ?? []).length % 2
172
- if (diff !== 0) throw new SyntaxError(`Quotes are unbalanced "`)
173
- return source
174
- }
175
146
  export const removeMutation = (source) => source.replace(new RegExp(/!/g), 'ǃ')
176
147
  const isDefinition = (x) =>
177
148
  x[TYPE] === APPLY && x[VALUE] === KEYWORDS.DEFINE_VARIABLE
@@ -245,13 +216,13 @@ export const fez = (source, options = {}) => {
245
216
  const env = Object.create(null)
246
217
  try {
247
218
  if (typeof source === 'string') {
248
- source = replaceQuotes(replaceStrings(source))
219
+ source = deSuggarSource(source)
249
220
  const valid = handleUnbalancedQuotes(
250
221
  handleUnbalancedParens(removeNoCode(source))
251
222
  )
252
223
  const code = !options.mutation ? removeMutation(valid) : valid
253
224
  if (!code.length && options.throw) throw new Error('Nothing to parse!')
254
- const parsed = deSuggar(LISP.parse(code))
225
+ const parsed = deSuggarAst(LISP.parse(code))
255
226
  const ast = [...treeShake(parsed, std), ...parsed]
256
227
  // if (options.check) typeCheck(ast)
257
228
  if (options.compile) return comp(ast)
@@ -309,17 +280,12 @@ export const decompress = (raw) => {
309
280
  export const shake = (parsed, std) => [...treeShake(parsed, std), ...parsed]
310
281
  export const tree = (source, std) =>
311
282
  std
312
- ? shake(
313
- LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source)))),
314
- std
315
- )
316
- : LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source))))
283
+ ? shake(LISP.parse(deSuggarSource(removeNoCode(source))), std)
284
+ : LISP.parse(deSuggarSource(removeNoCode(source)))
317
285
  export const minify = (source) =>
318
- LISP.source(
319
- deSuggar(LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source)))))
320
- )
286
+ LISP.source(deSuggarAst(LISP.parse(deSuggarSource(removeNoCode(source)))))
321
287
  export const prep = (source) =>
322
- deSuggar(LISP.parse(removeNoCode(replaceQuotes(replaceStrings(source)))))
288
+ deSuggarAst(LISP.parse(removeNoCode(deSuggarSource(source))))
323
289
  export const src = (source, deps) => {
324
290
  source = prep(source)
325
291
  return LISP.source([
@@ -362,471 +328,3 @@ export const js = (source, deps) => {
362
328
  ])
363
329
  return `${top}${program}`
364
330
  }
365
- const EXPONENTIATION = [
366
- [0, 'lambda'],
367
- [1, 'base'],
368
- [1, 'exp'],
369
- [
370
- [0, 'do'],
371
- [
372
- [0, 'let'],
373
- [1, 'power'],
374
- [
375
- [0, 'lambda'],
376
- [1, 'base'],
377
- [1, 'exp'],
378
- [
379
- [0, 'if'],
380
- [
381
- [0, '<'],
382
- [1, 'exp'],
383
- [2, 0]
384
- ],
385
- [
386
- [0, 'if'],
387
- [
388
- [0, '='],
389
- [1, 'base'],
390
- [2, 0]
391
- ],
392
- [
393
- [0, 'throw'],
394
- [
395
- [0, 'array'],
396
- [2, 66],
397
- [2, 97],
398
- [2, 115],
399
- [2, 101],
400
- [2, 32],
401
- [2, 99],
402
- [2, 97],
403
- [2, 110],
404
- [2, 39],
405
- [2, 116],
406
- [2, 32],
407
- [2, 98],
408
- [2, 101],
409
- [2, 32],
410
- [2, 48],
411
- [2, 32],
412
- [2, 105],
413
- [2, 102],
414
- [2, 32],
415
- [2, 101],
416
- [2, 120],
417
- [2, 112],
418
- [2, 111],
419
- [2, 110],
420
- [2, 101],
421
- [2, 110],
422
- [2, 116],
423
- [2, 32],
424
- [2, 105],
425
- [2, 115],
426
- [2, 32],
427
- [2, 60],
428
- [2, 32],
429
- [2, 48]
430
- ]
431
- ],
432
- [
433
- [0, '/'],
434
- [
435
- [0, '*'],
436
- [1, 'base'],
437
- [
438
- [0, 'power'],
439
- [1, 'base'],
440
- [
441
- [0, '-'],
442
- [
443
- [0, '*'],
444
- [1, 'exp'],
445
- [2, -1]
446
- ],
447
- [2, 1]
448
- ]
449
- ]
450
- ]
451
- ]
452
- ],
453
- [
454
- [0, 'if'],
455
- [
456
- [0, '='],
457
- [1, 'exp'],
458
- [2, 0]
459
- ],
460
- [2, 1],
461
- [
462
- [0, 'if'],
463
- [
464
- [0, '='],
465
- [1, 'exp'],
466
- [2, 1]
467
- ],
468
- [1, 'base'],
469
- [
470
- [0, 'if'],
471
- [[2, 1]],
472
- [
473
- [0, '*'],
474
- [1, 'base'],
475
- [
476
- [0, 'power'],
477
- [1, 'base'],
478
- [
479
- [0, '-'],
480
- [1, 'exp'],
481
- [2, 1]
482
- ]
483
- ]
484
- ]
485
- ]
486
- ]
487
- ]
488
- ]
489
- ]
490
- ],
491
- [
492
- [0, 'power'],
493
- [1, 'base'],
494
- [1, 'exp']
495
- ]
496
- ]
497
- ]
498
- export const deSuggar = (ast) => {
499
- if (ast.length === 0) throw new SyntaxError(`No expressions to evaluate`)
500
- // for (const node of ast)
501
- // if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
502
- // throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
503
- let prev = undefined
504
- const evaluate = (exp) => {
505
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
506
- if (first != undefined) {
507
- switch (first[TYPE]) {
508
- case WORD:
509
- {
510
- switch (first[VALUE]) {
511
- case SUGGAR.POWER:
512
- exp.length = 0
513
- exp.push(...EXPONENTIATION)
514
- break
515
- case SUGGAR.INTEGER_DEVISION:
516
- exp.length = 0
517
- exp.push(
518
- ...[
519
- [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
520
- [WORD, 'a'],
521
- [WORD, 'b'],
522
- [
523
- [APPLY, KEYWORDS.BITWISE_OR],
524
- [
525
- [APPLY, KEYWORDS.DIVISION],
526
- [WORD, 'a'],
527
- [WORD, 'b']
528
- ],
529
- [ATOM, 0]
530
- ]
531
- ]
532
- )
533
- break
534
- }
535
- }
536
- break
537
- case ATOM:
538
- break
539
- case APPLY:
540
- {
541
- switch (first[VALUE]) {
542
- case KEYWORDS.BLOCK:
543
- {
544
- if (
545
- prev == undefined ||
546
- (prev &&
547
- prev[TYPE] === APPLY &&
548
- prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
549
- ) {
550
- exp[0][VALUE] = KEYWORDS.CALL_FUNCTION
551
- exp[0][TYPE] = APPLY
552
- exp.length = 1
553
- exp[1] = [
554
- [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
555
- [[APPLY, KEYWORDS.BLOCK], ...rest]
556
- ]
557
- deSuggar(exp)
558
- }
559
- }
560
- break
561
- case SUGGAR.PIPE:
562
- {
563
- if (rest.length < 1)
564
- throw new RangeError(
565
- `Invalid number of arguments to (${
566
- SUGGAR.PIPE
567
- }) (>= 1 required). (${SUGGAR.PIPE} ${stringifyArgs(
568
- rest
569
- )})`
570
- )
571
- let inp = rest[0]
572
- exp.length = 0
573
- for (let i = 1; i < rest.length; ++i) {
574
- if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
575
- throw new TypeError(
576
- `Argument at position (${i}) of (${
577
- SUGGAR.PIPE
578
- }) is not an invoked (${
579
- KEYWORDS.ANONYMOUS_FUNCTION
580
- }). (${SUGGAR.PIPE} ${stringifyArgs(rest)})`
581
- )
582
- inp = [rest[i].shift(), inp, ...rest[i]]
583
- }
584
- for (let i = 0; i < inp.length; ++i) exp[i] = inp[i]
585
- deSuggar(exp)
586
- }
587
- break
588
- case SUGGAR.CONDITION:
589
- {
590
- if (rest.length < 2)
591
- throw new RangeError(
592
- `Invalid number of arguments for (${
593
- SUGGAR.CONDITION
594
- }), expected (> 2 required) but got ${rest.length} (${
595
- SUGGAR.CONDITION
596
- } ${stringifyArgs(rest)})`
597
- )
598
- if (rest.length % 2 !== 0)
599
- throw new RangeError(
600
- `Invalid number of arguments for (${
601
- SUGGAR.CONDITION
602
- }), expected even number of arguments but got ${
603
- rest.length
604
- } (${SUGGAR.CONDITION} ${stringifyArgs(rest)})`
605
- )
606
- exp.length = 0
607
- let temp = exp
608
- for (let i = 0; i < rest.length; i += 2) {
609
- if (i === rest.length - 2) {
610
- temp.push([APPLY, KEYWORDS.IF], rest[i], rest.at(-1))
611
- } else {
612
- temp.push([APPLY, KEYWORDS.IF], rest[i], rest[i + 1], [])
613
- temp = temp.at(-1)
614
- }
615
- }
616
- deSuggar(exp)
617
- }
618
- break
619
- case SUGGAR.LIST_TYPE:
620
- {
621
- exp.length = 0
622
- let temp = exp
623
- for (const item of rest) {
624
- temp.push([APPLY, KEYWORDS.ARRAY_TYPE], item, [])
625
- temp = temp.at(-1)
626
- }
627
- temp.push([APPLY, KEYWORDS.ARRAY_TYPE])
628
- }
629
- deSuggar(exp)
630
- break
631
- case SUGGAR.INTEGER_DEVISION:
632
- {
633
- if (rest.length !== 2)
634
- throw new RangeError(
635
- `Invalid number of arguments for (${
636
- SUGGAR.INTEGER_DEVISION
637
- }), expected (= 2) but got ${rest.length} (${
638
- SUGGAR.INTEGER_DEVISION
639
- } ${stringifyArgs(rest)})`
640
- )
641
- else if (rest.some((x) => x[TYPE] === APPLY))
642
- throw new TypeError(
643
- `Arguments of (${
644
- SUGGAR.INTEGER_DEVISION
645
- }), must be (or atom word) (hint use (math:floor (${
646
- KEYWORDS.DIVISION
647
- } a b)) instead) (${
648
- SUGGAR.INTEGER_DEVISION
649
- } ${stringifyArgs(rest)})`
650
- )
651
- else {
652
- exp.length = 1
653
- exp[0] = [APPLY, KEYWORDS.BITWISE_OR]
654
- exp.push([[APPLY, KEYWORDS.DIVISION], ...rest])
655
- exp.push([ATOM, 0])
656
- }
657
- }
658
- break
659
- case SUGGAR.POWER:
660
- {
661
- if (rest.length !== 2)
662
- throw new RangeError(
663
- `Invalid number of arguments for (${
664
- SUGGAR.POWER
665
- }), expected (= 2) but got ${rest.length} (${
666
- SUGGAR.POWER
667
- } ${stringifyArgs(rest)})`
668
- )
669
- const isExponentAtom = exp[1][TYPE] === ATOM
670
- const isPowerAtom = exp[2][TYPE] === ATOM
671
- const isExponentWord = exp[1][TYPE] === WORD
672
- if ((isExponentWord || isExponentAtom) && isPowerAtom) {
673
- if (isExponentAtom) {
674
- exp[0][VALUE] = KEYWORDS.MULTIPLICATION
675
- const exponent = exp[1]
676
- const power = exp[2][VALUE]
677
- exp.length = 1
678
- exp.push(exponent, [ATOM, exponent[VALUE] ** (power - 1)])
679
- } else if (isExponentWord) {
680
- const exponent = exp[1]
681
- const power = exp[2]
682
- exp.length = 0
683
- exp.push([0, 'apply'], EXPONENTIATION, exponent, power)
684
- }
685
- } else {
686
- const exponent = exp[1]
687
- const power = exp[2]
688
- exp.length = 0
689
- exp.push([0, 'apply'], EXPONENTIATION, exponent, power)
690
- }
691
- deSuggar(exp)
692
- }
693
- break
694
- case KEYWORDS.MULTIPLICATION:
695
- if (!rest.length) {
696
- exp[0][TYPE] = ATOM
697
- exp[0][VALUE] = TRUE
698
- } else if (rest.length > 2) {
699
- exp.length = 0
700
- let temp = exp
701
- for (let i = 0; i < rest.length; i += 1) {
702
- if (i < rest.length - 1) {
703
- temp.push([APPLY, KEYWORDS.MULTIPLICATION], rest[i], [])
704
- temp = temp.at(-1)
705
- } else {
706
- temp.push(...rest[i])
707
- }
708
- }
709
- deSuggar(exp)
710
- }
711
- break
712
- case KEYWORDS.ADDITION:
713
- if (!rest.length) {
714
- exp[0][TYPE] = ATOM
715
- exp[0][VALUE] = FALSE
716
- } else if (rest.length > 2) {
717
- exp.length = 0
718
- let temp = exp
719
- for (let i = 0; i < rest.length; i += 1) {
720
- if (i < rest.length - 1) {
721
- temp.push([APPLY, KEYWORDS.ADDITION], rest[i], [])
722
- temp = temp.at(-1)
723
- } else {
724
- temp.push(...rest[i])
725
- }
726
- }
727
- deSuggar(exp)
728
- }
729
- break
730
- case KEYWORDS.DIVISION:
731
- if (!rest.length) {
732
- exp[0][TYPE] = ATOM
733
- exp[0][VALUE] = FALSE
734
- } else if (rest.length > 2) {
735
- exp.length = 0
736
- let temp = exp
737
- for (let i = 0; i < rest.length; i += 1) {
738
- if (i < rest.length - 1) {
739
- temp.push([APPLY, KEYWORDS.DIVISION], rest[i], [])
740
- temp = temp.at(-1)
741
- } else {
742
- temp.push(...rest[i])
743
- }
744
- }
745
- deSuggar(exp)
746
- }
747
- break
748
- case KEYWORDS.AND:
749
- if (!rest.length) {
750
- exp[0][TYPE] = ATOM
751
- exp[0][VALUE] = FALSE
752
- } else if (rest.length > 2) {
753
- exp.length = 0
754
- let temp = exp
755
- for (let i = 0; i < rest.length; i += 1) {
756
- if (i < rest.length - 1) {
757
- temp.push([APPLY, KEYWORDS.AND], rest[i], [])
758
- temp = temp.at(-1)
759
- } else {
760
- temp.push(...rest[i])
761
- }
762
- }
763
- deSuggar(exp)
764
- }
765
- break
766
- case KEYWORDS.OR:
767
- if (!rest.length) {
768
- exp[0][TYPE] = ATOM
769
- exp[0][VALUE] = FALSE
770
- } else if (rest.length > 2) {
771
- exp.length = 0
772
- let temp = exp
773
- for (let i = 0; i < rest.length; i += 1) {
774
- if (i < rest.length - 1) {
775
- temp.push([APPLY, KEYWORDS.OR], rest[i], [])
776
- temp = temp.at(-1)
777
- } else {
778
- temp.push(...rest[i])
779
- }
780
- }
781
- deSuggar(exp)
782
- }
783
- break
784
- case SUGGAR.UNLESS:
785
- {
786
- if (rest.length > 3 || rest.length < 2)
787
- throw new RangeError(
788
- `Invalid number of arguments for (${
789
- SUGGAR.UNLESS
790
- }), expected (or (= 3) (= 2)) but got ${rest.length} (${
791
- SUGGAR.UNLESS
792
- } ${stringifyArgs(rest)})`
793
- )
794
- exp[0][VALUE] = KEYWORDS.IF
795
- const temp = exp[2]
796
- exp[2] = exp[3] ?? [ATOM, FALSE]
797
- exp[3] = temp
798
- }
799
- deSuggar(exp)
800
- break
801
-
802
- case SUGGAR.NOT_EQUAL_1:
803
- case SUGGAR.NOT_EQUAL_2:
804
- {
805
- if (rest.length > 3 || rest.length < 2)
806
- throw new RangeError(
807
- `Invalid number of arguments for (${
808
- exp[0][1]
809
- }), expected (or (= 3) (= 2)) but got ${rest.length} (${
810
- exp[0][1]
811
- } ${stringifyArgs(rest)})`
812
- )
813
- exp[0][VALUE] = KEYWORDS.NOT
814
- exp[1] = [[APPLY, KEYWORDS.EQUAL], exp[1], exp[2]]
815
- exp.length = 2
816
- deSuggar(exp)
817
- }
818
- break
819
- }
820
- prev = first
821
- }
822
- break
823
- default:
824
- for (const e of exp) evaluate(e)
825
- break
826
- }
827
- for (const r of rest) evaluate(r)
828
- }
829
- }
830
- evaluate(ast)
831
- return ast
832
- }