fez-lisp 1.2.15 → 1.2.16

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <img width="64" src="./logo.svg"/>
5
5
  </p>
6
6
 
7
- ````lisp
7
+ ```lisp
8
8
  (let fizz-buzz (lambda n
9
9
  (cond
10
10
  (= (mod n 15) 0) "Fizz Buzz"
@@ -34,7 +34,7 @@
34
34
  (math:range 1 100)
35
35
  (array:map fizz-buzz)
36
36
  (log!))
37
- ````
37
+ ```
38
38
 
39
39
  ```lisp
40
40
  ; https://adventofcode.com/2020/day/1
@@ -242,10 +242,11 @@ console.log(fez(tree(`(+ (|> 1 (+ 2) (* 3) (- 1)) (- (* (+ 1 2) 3) 1))`)))
242
242
  ```
243
243
 
244
244
  ```lisp
245
- ; all keywords
245
+ ; Build-in all keywords
246
246
  (/) (+) (*) (-) (=) (<) (>) (>=) (<=) (&) (~) (|) (^) (<<) (>>) (>>>)
247
247
  (mod) (let) (if) (not) (and) (or) (cond) (atom?) (lambda?)
248
248
  (length) (do) (array) (set!) (get) (lambda) (apply) (void)
249
249
  (log!) (log-string!) (log-char!) (clear!)
250
- (|>) (list) (unless)
250
+ ; Syntactic suggar keywords
251
+ (|>) (list) (unless) (array?) (truthy?) (falsy?) (evaluate) '() `() (!=) (<>)
251
252
  ```
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "fez-lisp",
3
3
  "description": "Lisp interpreted & compiled to JavaScript",
4
4
  "author": "AT290690",
5
- "version": "1.2.15",
5
+ "version": "1.2.16",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
@@ -799,140 +799,4 @@ const keywords = {
799
799
  }
800
800
  keywords[KEYWORDS.NOT_COMPILED_BLOCK] = keywords[KEYWORDS.BLOCK]
801
801
 
802
- export const deSuggar = (ast) => {
803
- if (ast.length === 0)
804
- throw new SyntaxError(
805
- `Top level ${KEYWORDS.NUMBER_TYPE} need to be wrapped in a (${KEYWORDS.IDENTITY})`
806
- )
807
- // for (const node of ast)
808
- // if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
809
- // throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
810
- let prev = undefined
811
- const evaluate = (exp) => {
812
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
813
- if (first != undefined) {
814
- switch (first[TYPE]) {
815
- case WORD:
816
- break
817
- case ATOM:
818
- break
819
- case APPLY:
820
- {
821
- switch (first[VALUE]) {
822
- case KEYWORDS.BLOCK:
823
- {
824
- if (
825
- prev == undefined ||
826
- (prev &&
827
- prev[TYPE] === APPLY &&
828
- prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
829
- ) {
830
- exp[0][1] = KEYWORDS.CALL_FUNCTION
831
- exp[0][0] = APPLY
832
- exp.length = 1
833
- exp[1] = [
834
- [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
835
- [[APPLY, KEYWORDS.BLOCK], ...rest]
836
- ]
837
- deSuggar(exp)
838
- }
839
- }
840
- break
841
- // case KEYWORDS.DEFINE_VARIABLE:
842
- // {
843
- // if (
844
- // rest[1] &&
845
- // rest[1][0] &&
846
- // rest[1][0][TYPE] === APPLY &&
847
- // rest[1][0][VALUE] === KEYWORDS.BLOCK
848
- // ) {
849
- // throw new SyntaxError(
850
- // `Can't use (${KEYWORDS.BLOCK}) in (${KEYWORDS.DEFINE_VARIABLE})`
851
- // )
852
- // }
853
- // }
854
- // break
855
- case KEYWORDS.PIPE:
856
- {
857
- if (rest.length < 1)
858
- throw new RangeError(
859
- `Invalid number of arguments to (${
860
- KEYWORDS.PIPE
861
- }) (>= 1 required). (${KEYWORDS.PIPE} ${stringifyArgs(
862
- rest
863
- )})`
864
- )
865
- let inp = rest[0]
866
- exp.length = 0
867
- for (let i = 1; i < rest.length; ++i) {
868
- if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
869
- throw new TypeError(
870
- `Argument at position (${i}) of (${
871
- KEYWORDS.PIPE
872
- }) is not an invoked (${
873
- KEYWORDS.ANONYMOUS_FUNCTION
874
- }). (${KEYWORDS.PIPE} ${stringifyArgs(rest)})`
875
- )
876
- inp = [rest[i].shift(), inp, ...rest[i]]
877
- }
878
- for (let i = 0; i < inp.length; ++i) exp[i] = inp[i]
879
- deSuggar(exp)
880
- }
881
- break
882
- case KEYWORDS.LIST_TYPE:
883
- {
884
- exp.length = 0
885
- let temp = exp
886
- for (const item of rest) {
887
- temp.push([0, KEYWORDS.ARRAY_TYPE], item, [])
888
- temp = temp.at(-1)
889
- }
890
- temp.push([0, 'array'])
891
- deSuggar(exp)
892
- }
893
- break
894
- case KEYWORDS.MULTIPLICATION:
895
- if (!rest.length) {
896
- exp[0][0] = 2
897
- exp[0][1] = 1
898
- }
899
- break
900
- case KEYWORDS.ADDITION:
901
- case KEYWORDS.DIVISION:
902
- if (!rest.length) {
903
- exp[0][0] = 2
904
- exp[0][1] = 0
905
- }
906
- break
907
- case KEYWORDS.UNLESS:
908
- {
909
- if (rest.length > 3 || rest.length < 2)
910
- throw new RangeError(
911
- `Invalid number of arguments for (${
912
- KEYWORDS.UNLESS
913
- }), expected (or (= 3) (= 2)) but got ${rest.length} (${
914
- KEYWORDS.UNLESS
915
- } ${stringifyArgs(rest)})`
916
- )
917
- exp[0][1] = KEYWORDS.IF
918
- const temp = exp[2]
919
- exp[2] = exp[3] ?? [ATOM, 0]
920
- exp[3] = temp
921
- }
922
- break
923
- }
924
- prev = first
925
- }
926
- break
927
- default:
928
- for (const e of exp) evaluate(e)
929
- break
930
- }
931
- for (const r of rest) evaluate(r)
932
- }
933
- }
934
- evaluate(ast)
935
- return ast
936
- }
937
-
938
802
  export { keywords }
package/src/keywords.js CHANGED
@@ -7,9 +7,7 @@ export const TRUE = 1
7
7
  export const FALSE = 0
8
8
  export const PLACEHOLDER = '.'
9
9
  export const KEYWORDS = {
10
- RECURSION: 'rec',
11
10
  NUMBER_TYPE: 'number',
12
- LIST_TYPE: 'list',
13
11
  ARRAY_TYPE: 'array',
14
12
  IDENTITY: 'identity',
15
13
  ARRAY_LENGTH: 'length',
@@ -31,7 +29,6 @@ export const KEYWORDS = {
31
29
  BLOCK: 'do',
32
30
  ANONYMOUS_FUNCTION: 'lambda',
33
31
  IF: 'if',
34
- UNLESS: 'unless',
35
32
  CONDITION: 'cond',
36
33
  NOT: 'not',
37
34
  EQUAL: '=',
@@ -41,9 +38,9 @@ export const KEYWORDS = {
41
38
  LESS_THAN_OR_EQUAL: '<=',
42
39
  AND: 'and',
43
40
  OR: 'or',
41
+
44
42
  CALL_FUNCTION: 'apply',
45
43
  DEFINE_VARIABLE: 'let',
46
- PIPE: '|>',
47
44
 
48
45
  SET_ARRAY: 'set!',
49
46
 
@@ -51,7 +48,15 @@ export const KEYWORDS = {
51
48
  LOG: 'log!',
52
49
  LOG_STRING: 'log-string!',
53
50
  LOG_CHAR: 'log-char!',
54
- CLEAR_CONSOLE: 'clear!'
51
+ CLEAR_CONSOLE: 'clear!',
52
+
53
+ // Syntactic suggars
54
+ PIPE: '|>',
55
+ NOT_EQUAL_1: '!=',
56
+ NOT_EQUAL_2: '<>',
57
+ UNLESS: 'unless',
58
+ LIST_TYPE: 'list',
59
+ RECURSION: 'rec'
55
60
  }
56
61
 
57
62
  export const TYPES = {
package/src/utils.js CHANGED
@@ -3,7 +3,6 @@ import { comp } from './compiler.js'
3
3
  import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
4
4
  import { run } from './evaluator.js'
5
5
  import { AST, isLeaf, LISP } from './parser.js'
6
- import { deSuggar } from './interpreter.js'
7
6
  export const logError = (error) =>
8
7
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
9
8
  export const logSuccess = (output) => console.log(output, '\x1b[0m')
@@ -355,3 +354,155 @@ export const js = (source, deps) => {
355
354
  ])
356
355
  return `${top}${program}`
357
356
  }
357
+
358
+ export const deSuggar = (ast) => {
359
+ if (ast.length === 0) throw new SyntaxError(`No expressions to evaluate`)
360
+ // for (const node of ast)
361
+ // if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
362
+ // throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
363
+ let prev = undefined
364
+ const evaluate = (exp) => {
365
+ const [first, ...rest] = isLeaf(exp) ? [exp] : exp
366
+ if (first != undefined) {
367
+ switch (first[TYPE]) {
368
+ case WORD:
369
+ break
370
+ case ATOM:
371
+ break
372
+ case APPLY:
373
+ {
374
+ switch (first[VALUE]) {
375
+ case KEYWORDS.BLOCK:
376
+ {
377
+ if (
378
+ prev == undefined ||
379
+ (prev &&
380
+ prev[TYPE] === APPLY &&
381
+ prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
382
+ ) {
383
+ exp[0][1] = KEYWORDS.CALL_FUNCTION
384
+ exp[0][0] = APPLY
385
+ exp.length = 1
386
+ exp[1] = [
387
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
388
+ [[APPLY, KEYWORDS.BLOCK], ...rest]
389
+ ]
390
+ deSuggar(exp)
391
+ }
392
+ }
393
+ break
394
+ // case KEYWORDS.DEFINE_VARIABLE:
395
+ // {
396
+ // if (
397
+ // rest[1] &&
398
+ // rest[1][0] &&
399
+ // rest[1][0][TYPE] === APPLY &&
400
+ // rest[1][0][VALUE] === KEYWORDS.BLOCK
401
+ // ) {
402
+ // throw new SyntaxError(
403
+ // `Can't use (${KEYWORDS.BLOCK}) in (${KEYWORDS.DEFINE_VARIABLE})`
404
+ // )
405
+ // }
406
+ // }
407
+ // break
408
+ case KEYWORDS.PIPE:
409
+ {
410
+ if (rest.length < 1)
411
+ throw new RangeError(
412
+ `Invalid number of arguments to (${
413
+ KEYWORDS.PIPE
414
+ }) (>= 1 required). (${KEYWORDS.PIPE} ${stringifyArgs(
415
+ rest
416
+ )})`
417
+ )
418
+ let inp = rest[0]
419
+ exp.length = 0
420
+ for (let i = 1; i < rest.length; ++i) {
421
+ if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
422
+ throw new TypeError(
423
+ `Argument at position (${i}) of (${
424
+ KEYWORDS.PIPE
425
+ }) is not an invoked (${
426
+ KEYWORDS.ANONYMOUS_FUNCTION
427
+ }). (${KEYWORDS.PIPE} ${stringifyArgs(rest)})`
428
+ )
429
+ inp = [rest[i].shift(), inp, ...rest[i]]
430
+ }
431
+ for (let i = 0; i < inp.length; ++i) exp[i] = inp[i]
432
+ deSuggar(exp)
433
+ }
434
+ break
435
+ case KEYWORDS.LIST_TYPE:
436
+ {
437
+ exp.length = 0
438
+ let temp = exp
439
+ for (const item of rest) {
440
+ temp.push([0, KEYWORDS.ARRAY_TYPE], item, [])
441
+ temp = temp.at(-1)
442
+ }
443
+ temp.push([0, 'array'])
444
+ deSuggar(exp)
445
+ }
446
+ break
447
+ case KEYWORDS.MULTIPLICATION:
448
+ if (!rest.length) {
449
+ exp[0][0] = 2
450
+ exp[0][1] = 1
451
+ }
452
+ break
453
+ case KEYWORDS.ADDITION:
454
+ case KEYWORDS.DIVISION:
455
+ if (!rest.length) {
456
+ exp[0][0] = 2
457
+ exp[0][1] = 0
458
+ }
459
+ break
460
+ case KEYWORDS.UNLESS:
461
+ {
462
+ if (rest.length > 3 || rest.length < 2)
463
+ throw new RangeError(
464
+ `Invalid number of arguments for (${
465
+ KEYWORDS.UNLESS
466
+ }), expected (or (= 3) (= 2)) but got ${rest.length} (${
467
+ KEYWORDS.UNLESS
468
+ } ${stringifyArgs(rest)})`
469
+ )
470
+ exp[0][1] = KEYWORDS.IF
471
+ const temp = exp[2]
472
+ exp[2] = exp[3] ?? [ATOM, 0]
473
+ exp[3] = temp
474
+ }
475
+ deSuggar(exp)
476
+ break
477
+
478
+ case KEYWORDS.NOT_EQUAL_1:
479
+ case KEYWORDS.NOT_EQUAL_2:
480
+ {
481
+ if (rest.length > 3 || rest.length < 2)
482
+ throw new RangeError(
483
+ `Invalid number of arguments for (${
484
+ exp[0][1]
485
+ }), expected (or (= 3) (= 2)) but got ${rest.length} (${
486
+ exp[0][1]
487
+ } ${stringifyArgs(rest)})`
488
+ )
489
+ exp[0][1] = KEYWORDS.NOT
490
+ exp[1] = [[APPLY, KEYWORDS.EQUAL], exp[1], exp[2]]
491
+ exp.length = 2
492
+ deSuggar(exp)
493
+ }
494
+ break
495
+ }
496
+ prev = first
497
+ }
498
+ break
499
+ default:
500
+ for (const e of exp) evaluate(e)
501
+ break
502
+ }
503
+ for (const r of rest) evaluate(r)
504
+ }
505
+ }
506
+ evaluate(ast)
507
+ return ast
508
+ }