fez-lisp 1.3.1 → 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,42 +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'
16
- import { EXPONENTIATION, FLOOR } from '../lib/baked/macros.js'
6
+ import {
7
+ deSuggarAst,
8
+ deSuggarSource,
9
+ handleUnbalancedQuotes,
10
+ SUGGAR
11
+ } from './macros.js'
17
12
  export const logError = (error) =>
18
13
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
19
14
  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
15
  // export const replaceEmptyArrays = (source) =>
41
16
  // source
42
17
  export const removeNoCode = (source) =>
@@ -168,11 +143,6 @@ export const handleUnbalancedParens = (source) => {
168
143
  )
169
144
  return source
170
145
  }
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
146
  export const removeMutation = (source) => source.replace(new RegExp(/!/g), 'ǃ')
177
147
  const isDefinition = (x) =>
178
148
  x[TYPE] === APPLY && x[VALUE] === KEYWORDS.DEFINE_VARIABLE
@@ -246,13 +216,13 @@ export const fez = (source, options = {}) => {
246
216
  const env = Object.create(null)
247
217
  try {
248
218
  if (typeof source === 'string') {
249
- source = replaceQuotes(replaceStrings(source))
219
+ source = deSuggarSource(source)
250
220
  const valid = handleUnbalancedQuotes(
251
221
  handleUnbalancedParens(removeNoCode(source))
252
222
  )
253
223
  const code = !options.mutation ? removeMutation(valid) : valid
254
224
  if (!code.length && options.throw) throw new Error('Nothing to parse!')
255
- const parsed = deSuggar(LISP.parse(code))
225
+ const parsed = deSuggarAst(LISP.parse(code))
256
226
  const ast = [...treeShake(parsed, std), ...parsed]
257
227
  // if (options.check) typeCheck(ast)
258
228
  if (options.compile) return comp(ast)
@@ -310,17 +280,12 @@ export const decompress = (raw) => {
310
280
  export const shake = (parsed, std) => [...treeShake(parsed, std), ...parsed]
311
281
  export const tree = (source, std) =>
312
282
  std
313
- ? shake(
314
- LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source)))),
315
- std
316
- )
317
- : LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source))))
283
+ ? shake(LISP.parse(deSuggarSource(removeNoCode(source))), std)
284
+ : LISP.parse(deSuggarSource(removeNoCode(source)))
318
285
  export const minify = (source) =>
319
- LISP.source(
320
- deSuggar(LISP.parse(replaceQuotes(replaceStrings(removeNoCode(source)))))
321
- )
286
+ LISP.source(deSuggarAst(LISP.parse(deSuggarSource(removeNoCode(source)))))
322
287
  export const prep = (source) =>
323
- deSuggar(LISP.parse(removeNoCode(replaceQuotes(replaceStrings(source)))))
288
+ deSuggarAst(LISP.parse(removeNoCode(deSuggarSource(source))))
324
289
  export const src = (source, deps) => {
325
290
  source = prep(source)
326
291
  return LISP.source([
@@ -363,326 +328,3 @@ export const js = (source, deps) => {
363
328
  ])
364
329
  return `${top}${program}`
365
330
  }
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
- }