fez-lisp 1.5.36 → 1.5.38

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.5.36",
5
+ "version": "1.5.38",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/check.js CHANGED
@@ -2,16 +2,18 @@ import {
2
2
  APPLY,
3
3
  ATOM,
4
4
  DEBUG,
5
+ FALSE,
5
6
  KEYWORDS,
6
7
  PLACEHOLDER,
7
8
  PREDICATE_SUFFIX,
8
9
  SPECIAL_FORMS_SET,
10
+ TRUE,
9
11
  TYPE,
10
12
  VALUE,
11
13
  WORD
12
14
  } from './keywords.js'
13
15
  import { isLeaf } from './parser.js'
14
- import { hasBlock, stringifyArgs } from './utils.js'
16
+ import { hasApplyLambdaBlock, hasBlock, stringifyArgs } from './utils.js'
15
17
  const ARGS_COUNT = 'n'
16
18
  const VARIADIC = '...'
17
19
  const STATS = '__stats__'
@@ -19,10 +21,11 @@ const ARGS = 'args'
19
21
  const UNKNOWN = -1
20
22
  const RETURNS = 'returns'
21
23
  const SCOPE_NAME = '__scope__'
22
- const SUBTYPE = 'subtype'
24
+ const SUB_RETURN_TYPE = 'sub_return_type'
23
25
  const PREDICATE = 3
24
26
  const RETRY_COUNT = 1
25
27
  const DEFINITON_RETRY_COUNT = 1
28
+ const SUB = 2
26
29
  const toTypeNames = (type) => {
27
30
  switch (type) {
28
31
  case APPLY:
@@ -130,8 +133,7 @@ export const typeCheck = (ast) => {
130
133
  [ATOM, PLACEHOLDER, PREDICATE],
131
134
  [UNKNOWN, PLACEHOLDER]
132
135
  ],
133
- [RETURNS]: ATOM,
134
- [SUBTYPE]: PREDICATE
136
+ [RETURNS]: ATOM
135
137
  }
136
138
  },
137
139
  [KEYWORDS.ADDITION]: {
@@ -326,7 +328,7 @@ export const typeCheck = (ast) => {
326
328
  [ARGS_COUNT]: 1,
327
329
  [ARGS]: [[ATOM, PLACEHOLDER, PREDICATE]],
328
330
  [RETURNS]: ATOM,
329
- [SUBTYPE]: PREDICATE
331
+ [SUB_RETURN_TYPE]: PREDICATE
330
332
  }
331
333
  },
332
334
  [KEYWORDS.EQUAL]: {
@@ -339,7 +341,7 @@ export const typeCheck = (ast) => {
339
341
  [ATOM, PLACEHOLDER]
340
342
  ],
341
343
  [RETURNS]: ATOM,
342
- [SUBTYPE]: PREDICATE
344
+ [SUB_RETURN_TYPE]: PREDICATE
343
345
  }
344
346
  },
345
347
  [KEYWORDS.LESS_THAN]: {
@@ -352,7 +354,7 @@ export const typeCheck = (ast) => {
352
354
  [ATOM, PLACEHOLDER]
353
355
  ],
354
356
  [RETURNS]: ATOM,
355
- [SUBTYPE]: PREDICATE
357
+ [SUB_RETURN_TYPE]: PREDICATE
356
358
  }
357
359
  },
358
360
  [KEYWORDS.GREATHER_THAN]: {
@@ -365,7 +367,7 @@ export const typeCheck = (ast) => {
365
367
  [ATOM, PLACEHOLDER]
366
368
  ],
367
369
  [RETURNS]: ATOM,
368
- [SUBTYPE]: PREDICATE
370
+ [SUB_RETURN_TYPE]: PREDICATE
369
371
  }
370
372
  },
371
373
  [KEYWORDS.GREATHER_THAN_OR_EQUAL]: {
@@ -378,7 +380,7 @@ export const typeCheck = (ast) => {
378
380
  [ATOM, PLACEHOLDER]
379
381
  ],
380
382
  [RETURNS]: ATOM,
381
- [SUBTYPE]: PREDICATE
383
+ [SUB_RETURN_TYPE]: PREDICATE
382
384
  }
383
385
  },
384
386
  [KEYWORDS.LESS_THAN_OR_EQUAL]: {
@@ -391,7 +393,7 @@ export const typeCheck = (ast) => {
391
393
  [ATOM, PLACEHOLDER]
392
394
  ],
393
395
  [RETURNS]: ATOM,
394
- [SUBTYPE]: PREDICATE
396
+ [SUB_RETURN_TYPE]: PREDICATE
395
397
  }
396
398
  },
397
399
  [KEYWORDS.AND]: {
@@ -404,7 +406,7 @@ export const typeCheck = (ast) => {
404
406
  [ATOM, PLACEHOLDER, PREDICATE]
405
407
  ],
406
408
  [RETURNS]: ATOM,
407
- [SUBTYPE]: PREDICATE
409
+ [SUB_RETURN_TYPE]: PREDICATE
408
410
  }
409
411
  },
410
412
  [KEYWORDS.OR]: {
@@ -417,7 +419,7 @@ export const typeCheck = (ast) => {
417
419
  [ATOM, PLACEHOLDER, PREDICATE]
418
420
  ],
419
421
  [RETURNS]: ATOM,
420
- [SUBTYPE]: PREDICATE
422
+ [SUB_RETURN_TYPE]: PREDICATE
421
423
  }
422
424
  },
423
425
  [KEYWORDS.IS_ATOM]: {
@@ -427,7 +429,7 @@ export const typeCheck = (ast) => {
427
429
  [ARGS_COUNT]: 1,
428
430
  [ARGS]: [[UNKNOWN, PLACEHOLDER]],
429
431
  [RETURNS]: ATOM,
430
- [SUBTYPE]: PREDICATE
432
+ [SUB_RETURN_TYPE]: PREDICATE
431
433
  }
432
434
  },
433
435
  [KEYWORDS.IS_LAMBDA]: {
@@ -437,7 +439,7 @@ export const typeCheck = (ast) => {
437
439
  [ARGS_COUNT]: 1,
438
440
  [ARGS]: [[UNKNOWN, PLACEHOLDER]],
439
441
  [RETURNS]: ATOM,
440
- [SUBTYPE]: PREDICATE
442
+ [SUB_RETURN_TYPE]: PREDICATE
441
443
  }
442
444
  },
443
445
  [KEYWORDS.ERROR]: {
@@ -451,6 +453,8 @@ export const typeCheck = (ast) => {
451
453
  }
452
454
  }
453
455
  const errorStack = new Map()
456
+ const warningStack = new Set()
457
+
454
458
  // const isDefinitionOfAFunction = (head, tail) =>
455
459
  // head[TYPE] === APPLY &&
456
460
  // head[VALUE] === KEYWORDS.DEFINE_VARIABLE &&
@@ -487,6 +491,12 @@ export const typeCheck = (ast) => {
487
491
  errorStack.set(
488
492
  key.str,
489
493
  `Trying to access undefined variable ${first[VALUE]} (check #11)`
494
+
495
+ // `Trying to access undefined variable ${
496
+ // first[VALUE]
497
+ // }\n${formatCallstack(
498
+ // key.chain.filter((x) => isNaN(Number(x[0])))
499
+ // )}\n(check #11)`
490
500
  )
491
501
  }
492
502
  })
@@ -522,49 +532,84 @@ export const typeCheck = (ast) => {
522
532
  }
523
533
  }
524
534
  const checkReturnType = () => {
525
- if (name[name.length - 1] === PREDICATE_SUFFIX) {
535
+ // if (name[name.length - 1] === PREDICATE_SUFFIX) {
536
+ // env[name][STATS][RETURNS] = ATOM
537
+ // env[name][STATS][SUB_RETURN_TYPE] = PREDICATE
538
+ // } else {
539
+ const isPredicate =
540
+ name[name.length - 1] === PREDICATE_SUFFIX
541
+ const last = rest.at(-1).at(-1)
542
+ const body = hasApplyLambdaBlock(last)
543
+ ? last.at(-1).at(-1)
544
+ : last
545
+ const rem = hasBlock(body) ? body.at(-1) : body
546
+ const returns = isLeaf(rem) ? rem : rem[0]
547
+ if (returns[TYPE] === ATOM) {
526
548
  env[name][STATS][RETURNS] = ATOM
527
- env[name][STATS][SUBTYPE] = PREDICATE
528
549
  } else {
529
- const body = rest.at(-1).at(-1)
530
- const rem = hasBlock(body) ? body.at(-1) : body
531
- const returns = isLeaf(rem) ? rem : rem[0]
532
- if (returns[TYPE] === ATOM) {
533
- env[name][STATS][RETURNS] = ATOM
534
- } else {
535
- switch (returns[VALUE]) {
536
- case KEYWORDS.IF:
537
- const re = rem.slice(2)
538
- if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM)
539
- env[name][STATS][RETURNS] = ATOM
540
- else if (!isLeaf(re[0]) && env[re[0][0][VALUE]]) {
550
+ switch (returns[VALUE]) {
551
+ case KEYWORDS.IF:
552
+ const re = rem.slice(2)
553
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
554
+ env[name][STATS][RETURNS] = ATOM
555
+ // if (
556
+ // re[0][VALUE] === FALSE ||
557
+ // re[0][VALUE] === TRUE ||
558
+ // re[1][VALUE] === FALSE ||
559
+ // re[1][VALUE] === TRUE
560
+ // ) {
561
+ // env[name][STATS][SUB_RETURN_TYPE] = PREDICATE
562
+ // }
563
+ } else if (!isLeaf(re[0]) && env[re[0][0][VALUE]]) {
564
+ env[name][STATS][RETURNS] =
565
+ env[re[0][0][VALUE]][STATS][RETURNS]
566
+ env[name][STATS][SUB_RETURN_TYPE] =
567
+ env[re[0][0][VALUE]][STATS][SUB_RETURN_TYPE]
568
+ } else {
569
+ if (env[re[0][VALUE]]) {
541
570
  env[name][STATS][RETURNS] =
542
- env[re[0][0][VALUE]][STATS][RETURNS]
543
- } else {
544
- if (env[re[0][VALUE]])
545
- env[name][STATS][RETURNS] =
546
- env[re[0][VALUE]][STATS].type
547
- else env[name][STATS][RETURNS] = UNKNOWN
548
- }
549
- break
550
- default:
551
- if (env[returns[VALUE]]) {
552
- if (env[returns[VALUE]][STATS].type === APPLY) {
553
- env[name][STATS][RETURNS] =
554
- env[returns[VALUE]][STATS][RETURNS]
555
- // env[name][STATS][SUBTYPE] =
556
- // env[returns[VALUE]][STATS][SUBTYPE]
557
- } else {
558
- env[name][STATS][RETURNS] =
559
- env[returns[VALUE]].type
560
- }
571
+ env[re[0][VALUE]][STATS].type
572
+ env[name][STATS][SUB_RETURN_TYPE] =
573
+ env[re[0][VALUE]][STATS][SUB_RETURN_TYPE]
574
+ } else env[name][STATS][RETURNS] = UNKNOWN
575
+ }
576
+ break
577
+ default:
578
+ if (env[returns[VALUE]]) {
579
+ if (env[returns[VALUE]][STATS].type === APPLY) {
580
+ env[name][STATS][RETURNS] =
581
+ env[returns[VALUE]][STATS][RETURNS]
582
+ env[name][STATS][SUB_RETURN_TYPE] =
583
+ env[returns[VALUE]][STATS][SUB_RETURN_TYPE]
561
584
  } else {
562
- env[name][STATS][RETURNS] = UNKNOWN
585
+ env[name][STATS][RETURNS] =
586
+ env[returns[VALUE]][STATS].type
587
+ env[name][STATS][SUB_RETURN_TYPE] =
588
+ env[returns[VALUE]][SUB_RETURN_TYPE]
563
589
  }
564
- break
565
- }
590
+ } else {
591
+ env[name][STATS][RETURNS] = UNKNOWN
592
+ }
593
+ break
566
594
  }
567
595
  }
596
+ if (
597
+ isPredicate &&
598
+ env[name][STATS][RETURNS] !== UNKNOWN &&
599
+ env[name][STATS][SUB_RETURN_TYPE] !== PREDICATE
600
+ ) {
601
+ warningStack.add(
602
+ `${name} ends in (${PREDICATE_SUFFIX}) and is expected to return (Predicate) but it doesn't (check #7)`
603
+ )
604
+ } else if (
605
+ !isPredicate &&
606
+ env[name][STATS][SUB_RETURN_TYPE] === PREDICATE
607
+ ) {
608
+ warningStack.add(
609
+ `${name} should end in (${PREDICATE_SUFFIX}) because it return (Predicate) (check #8)`
610
+ )
611
+ }
612
+ // }
568
613
  // if (
569
614
  // env[name][STATS][RETURNS] === UNKNOWN &&
570
615
  // env[name][STATS].retried < RETRY_COUNT
@@ -696,10 +741,12 @@ export const typeCheck = (ast) => {
696
741
  if (expectedArgs[i][TYPE] === UNKNOWN) continue
697
742
  if (!isLeaf(rest[i])) {
698
743
  const CAR = rest[i][0][VALUE]
699
- if (
744
+ const isKnown =
700
745
  env[CAR] &&
701
746
  env[CAR][STATS][RETURNS] != undefined &&
702
- env[CAR][STATS][RETURNS] !== UNKNOWN &&
747
+ env[CAR][STATS][RETURNS] !== UNKNOWN
748
+ if (
749
+ isKnown &&
703
750
  env[CAR][STATS][RETURNS] !==
704
751
  expectedArgs[i][TYPE]
705
752
  ) {
@@ -714,10 +761,24 @@ export const typeCheck = (ast) => {
714
761
  env[CAR][STATS][RETURNS]
715
762
  )}) (${stringifyArgs(exp)}) (check #1)`
716
763
  )
764
+ } else if (
765
+ isKnown &&
766
+ expectedArgs[i][SUB] &&
767
+ env[CAR][STATS][SUB_RETURN_TYPE] !==
768
+ expectedArgs[i][SUB]
769
+ ) {
770
+ errorStack.set(
771
+ key.str,
772
+ `Incorrect type of arguments for special form (${
773
+ first[VALUE]
774
+ }). Expected (${toTypeNames(
775
+ expectedArgs[i][SUB]
776
+ )}) but got (${toTypeNames(
777
+ env[CAR][STATS][SUB_RETURN_TYPE] ??
778
+ env[CAR][STATS][RETURNS]
779
+ )}) (${stringifyArgs(exp)}) (check #13)`
780
+ )
717
781
  }
718
- // else {
719
- // console.log(env[CAR])
720
- // }
721
782
  }
722
783
  if (
723
784
  env[rest[i][VALUE]] &&
@@ -886,6 +947,8 @@ export const typeCheck = (ast) => {
886
947
  check(copy, root, copy)
887
948
  while (stack.length) stack.pop()()
888
949
  if (errorStack.size)
889
- throw new TypeError([...new Set(errorStack.values())].join('\n'))
950
+ throw new TypeError(
951
+ [...new Set(errorStack.values()), ...warningStack].join('\n')
952
+ )
890
953
  return ast
891
954
  }
package/src/compiler.js CHANGED
@@ -258,7 +258,7 @@ const comp = (tree, Drill) => {
258
258
  return `(()=>{while(${comp(tail[0], Drill)}){${comp(
259
259
  tail[1],
260
260
  Drill
261
- )}}return 0})();`
261
+ )}}return -1})();`
262
262
  }
263
263
  case KEYWORDS.ERROR: {
264
264
  Drill.Helpers.add('__error')
@@ -17,7 +17,7 @@ export const keywords = {
17
17
  if (args.length != 2)
18
18
  throw new RangeError(`Wrong number of args to ${KEYWORDS.LOOP}`)
19
19
  while (evaluate(args[0], env) === TRUE) evaluate(args[1], env)
20
- return FALSE
20
+ return -1
21
21
  },
22
22
  [KEYWORDS.ADDITION]: (args, env) => {
23
23
  if (args.length !== 2)
package/src/utils.js CHANGED
@@ -11,11 +11,13 @@ import {
11
11
  export const logError = (error) =>
12
12
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
13
13
  export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
14
- export const formatErrorWithCallstack = (error, callstack) => {
15
- return `${error.message}\n${callstack
14
+ export const formatCallstack = (callstack) =>
15
+ callstack
16
16
  .reverse()
17
17
  .map((x, i) => `${Array(i + 2).join(' ')}(${x} ...)`)
18
- .join('\n')}`
18
+ .join('\n')
19
+ export const formatErrorWithCallstack = (error, callstack) => {
20
+ return `${error.message}\n${formatCallstack(callstack)}`
19
21
  }
20
22
  export const removeNoCode = (source) =>
21
23
  source
@@ -193,7 +195,12 @@ const deepShake = (tree, deps, visited = new Set(), ignored = new Set()) => {
193
195
 
194
196
  export const hasBlock = (body) =>
195
197
  body[0] && body[0][TYPE] === APPLY && body[0][VALUE] === KEYWORDS.BLOCK
196
-
198
+ export const hasApplyLambdaBlock = (body) =>
199
+ body[0] &&
200
+ body[0][TYPE] === APPLY &&
201
+ body[0][VALUE] === KEYWORDS.CALL_FUNCTION &&
202
+ body[1][0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION &&
203
+ body[1][1][0][VALUE] === KEYWORDS.BLOCK
197
204
  const extractDeps = (visited, deps) =>
198
205
  [...visited]
199
206
  .map((x) => deps.get(x))