fez-lisp 1.2.15 → 1.2.17

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/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.17",
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
@@ -1,9 +1,8 @@
1
1
  import std from '../lib/baked/std.js'
2
2
  import { comp } from './compiler.js'
3
3
  import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
4
- import { run } from './evaluator.js'
4
+ import { evaluate, 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')
@@ -228,6 +227,8 @@ export const dfs = (tree, callback) => {
228
227
  else callback(tree)
229
228
  }
230
229
  export const deepClone = (ast) => AST.parse(AST.stringify(ast))
230
+ export const interpret = (ast, keywords) =>
231
+ ast.reduce((_, x) => evaluate(x, keywords), 0)
231
232
  export const fez = (source, options = {}) => {
232
233
  const env = Object.create(null)
233
234
  try {
@@ -355,3 +356,155 @@ export const js = (source, deps) => {
355
356
  ])
356
357
  return `${top}${program}`
357
358
  }
359
+
360
+ export const deSuggar = (ast) => {
361
+ if (ast.length === 0) throw new SyntaxError(`No expressions to evaluate`)
362
+ // for (const node of ast)
363
+ // if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
364
+ // throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
365
+ let prev = undefined
366
+ const evaluate = (exp) => {
367
+ const [first, ...rest] = isLeaf(exp) ? [exp] : exp
368
+ if (first != undefined) {
369
+ switch (first[TYPE]) {
370
+ case WORD:
371
+ break
372
+ case ATOM:
373
+ break
374
+ case APPLY:
375
+ {
376
+ switch (first[VALUE]) {
377
+ case KEYWORDS.BLOCK:
378
+ {
379
+ if (
380
+ prev == undefined ||
381
+ (prev &&
382
+ prev[TYPE] === APPLY &&
383
+ prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
384
+ ) {
385
+ exp[0][1] = KEYWORDS.CALL_FUNCTION
386
+ exp[0][0] = APPLY
387
+ exp.length = 1
388
+ exp[1] = [
389
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
390
+ [[APPLY, KEYWORDS.BLOCK], ...rest]
391
+ ]
392
+ deSuggar(exp)
393
+ }
394
+ }
395
+ break
396
+ // case KEYWORDS.DEFINE_VARIABLE:
397
+ // {
398
+ // if (
399
+ // rest[1] &&
400
+ // rest[1][0] &&
401
+ // rest[1][0][TYPE] === APPLY &&
402
+ // rest[1][0][VALUE] === KEYWORDS.BLOCK
403
+ // ) {
404
+ // throw new SyntaxError(
405
+ // `Can't use (${KEYWORDS.BLOCK}) in (${KEYWORDS.DEFINE_VARIABLE})`
406
+ // )
407
+ // }
408
+ // }
409
+ // break
410
+ case KEYWORDS.PIPE:
411
+ {
412
+ if (rest.length < 1)
413
+ throw new RangeError(
414
+ `Invalid number of arguments to (${
415
+ KEYWORDS.PIPE
416
+ }) (>= 1 required). (${KEYWORDS.PIPE} ${stringifyArgs(
417
+ rest
418
+ )})`
419
+ )
420
+ let inp = rest[0]
421
+ exp.length = 0
422
+ for (let i = 1; i < rest.length; ++i) {
423
+ if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
424
+ throw new TypeError(
425
+ `Argument at position (${i}) of (${
426
+ KEYWORDS.PIPE
427
+ }) is not an invoked (${
428
+ KEYWORDS.ANONYMOUS_FUNCTION
429
+ }). (${KEYWORDS.PIPE} ${stringifyArgs(rest)})`
430
+ )
431
+ inp = [rest[i].shift(), inp, ...rest[i]]
432
+ }
433
+ for (let i = 0; i < inp.length; ++i) exp[i] = inp[i]
434
+ deSuggar(exp)
435
+ }
436
+ break
437
+ case KEYWORDS.LIST_TYPE:
438
+ {
439
+ exp.length = 0
440
+ let temp = exp
441
+ for (const item of rest) {
442
+ temp.push([0, KEYWORDS.ARRAY_TYPE], item, [])
443
+ temp = temp.at(-1)
444
+ }
445
+ temp.push([0, 'array'])
446
+ deSuggar(exp)
447
+ }
448
+ break
449
+ case KEYWORDS.MULTIPLICATION:
450
+ if (!rest.length) {
451
+ exp[0][0] = 2
452
+ exp[0][1] = 1
453
+ }
454
+ break
455
+ case KEYWORDS.ADDITION:
456
+ case KEYWORDS.DIVISION:
457
+ if (!rest.length) {
458
+ exp[0][0] = 2
459
+ exp[0][1] = 0
460
+ }
461
+ break
462
+ case KEYWORDS.UNLESS:
463
+ {
464
+ if (rest.length > 3 || rest.length < 2)
465
+ throw new RangeError(
466
+ `Invalid number of arguments for (${
467
+ KEYWORDS.UNLESS
468
+ }), expected (or (= 3) (= 2)) but got ${rest.length} (${
469
+ KEYWORDS.UNLESS
470
+ } ${stringifyArgs(rest)})`
471
+ )
472
+ exp[0][1] = KEYWORDS.IF
473
+ const temp = exp[2]
474
+ exp[2] = exp[3] ?? [ATOM, 0]
475
+ exp[3] = temp
476
+ }
477
+ deSuggar(exp)
478
+ break
479
+
480
+ case KEYWORDS.NOT_EQUAL_1:
481
+ case KEYWORDS.NOT_EQUAL_2:
482
+ {
483
+ if (rest.length > 3 || rest.length < 2)
484
+ throw new RangeError(
485
+ `Invalid number of arguments for (${
486
+ exp[0][1]
487
+ }), expected (or (= 3) (= 2)) but got ${rest.length} (${
488
+ exp[0][1]
489
+ } ${stringifyArgs(rest)})`
490
+ )
491
+ exp[0][1] = KEYWORDS.NOT
492
+ exp[1] = [[APPLY, KEYWORDS.EQUAL], exp[1], exp[2]]
493
+ exp.length = 2
494
+ deSuggar(exp)
495
+ }
496
+ break
497
+ }
498
+ prev = first
499
+ }
500
+ break
501
+ default:
502
+ for (const e of exp) evaluate(e)
503
+ break
504
+ }
505
+ for (const r of rest) evaluate(r)
506
+ }
507
+ }
508
+ evaluate(ast)
509
+ return ast
510
+ }