fez-lisp 1.5.109 → 1.5.111

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.109",
5
+ "version": "1.5.111",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/check.js CHANGED
@@ -38,7 +38,12 @@ import {
38
38
  formatType,
39
39
  ANONYMOUS_FUNCTION_TYPE_PREFIX,
40
40
  validateLambda,
41
- NIL
41
+ NIL,
42
+ TRUE_WORD,
43
+ FALSE_WORD,
44
+ BOOLEAN_SUBTYPE,
45
+ formatSubType,
46
+ PREDICATE
42
47
  } from './types.js'
43
48
  import {
44
49
  Brr,
@@ -48,7 +53,35 @@ import {
48
53
  logExp,
49
54
  stringifyArgs
50
55
  } from './utils.js'
56
+ Set.prototype.union = function (B) {
57
+ const A = this
58
+ const out = new Set()
59
+ A.forEach((element) => out.add(element))
60
+ B.forEach((element) => out.add(element))
61
+ return out
62
+ }
63
+
64
+ Set.prototype.xor = function (B) {
65
+ const A = this
66
+ const out = new Set()
67
+ B.forEach((element) => !A.has(element) && out.add(element))
68
+ A.forEach((element) => !B.has(element) && out.add(element))
69
+ return out
70
+ }
71
+
72
+ Set.prototype.intersection = function (B) {
73
+ const A = this
74
+ const out = new Set()
75
+ B.forEach((element) => A.has(element) && out.add(element))
76
+ return out
77
+ }
51
78
 
79
+ Set.prototype.difference = function (B) {
80
+ const A = this
81
+ const out = new Set()
82
+ A.forEach((element) => !B.has(element) && out.add(element))
83
+ return out
84
+ }
52
85
  export const identity = (name) => [
53
86
  [0, 'let'],
54
87
  [1, name],
@@ -93,6 +126,15 @@ export const setPropToAtom = (stats, prop) => {
93
126
  (stats[prop][0] = ATOM)
94
127
  )
95
128
  }
129
+ export const setPropToPredicate = (stats, prop) => {
130
+ return (stats[prop][1] = BOOLEAN_SUBTYPE())
131
+ }
132
+ export const setReturnToPredicate = (stats) => {
133
+ return (stats[RETURNS][1] = BOOLEAN_SUBTYPE())
134
+ }
135
+ export const setTypeToPredicate = (stats) => {
136
+ return (stats[RETURNS][1] = BOOLEAN_SUBTYPE())
137
+ }
96
138
  export const setPropToAbstraction = (stats, prop) => {
97
139
  return (
98
140
  (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
@@ -202,6 +244,10 @@ export const getType = (stats) => stats && stats[TYPE_PROP][0]
202
244
  export const getTypes = (stats) => stats && stats[TYPE_PROP]
203
245
  export const getReturn = (stats) => stats && stats[RETURNS][0]
204
246
  export const getReturns = (stats) => stats && stats[RETURNS]
247
+ export const getSubType = (stats) => stats && stats[TYPE_PROP][1]
248
+ export const hasSubType = (stats) => stats && stats[TYPE_PROP][1] instanceof Set
249
+ export const getSubReturn = (stats) => stats && stats[RETURNS][1]
250
+ export const hasSubReturn = (stats) => stats && stats[RETURNS][1] instanceof Set
205
251
  export const isAtomType = (stats) =>
206
252
  isAnyType(stats) || stats[TYPE_PROP][0] === ATOM
207
253
  export const isAtomReturn = (stats) =>
@@ -212,59 +258,70 @@ export const compareReturns = (a, b) =>
212
258
  isAnyReturn(a) || isAnyReturn(b) || a[RETURNS][0] === b[RETURNS][0]
213
259
  export const compareTypeWithReturn = (a, b) =>
214
260
  isAnyType(a) || isAnyReturn(b) || a[TYPE_PROP][0] === b[RETURNS][0]
261
+ const IsPredicate = (leaf) =>
262
+ (leaf[TYPE] === ATOM && (leaf[VALUE] === TRUE || leaf[VALUE] === FALSE)) ||
263
+ (leaf[TYPE] === WORD &&
264
+ (leaf[VALUE] === TRUE_WORD ||
265
+ leaf[VALUE] === FALSE_WORD ||
266
+ leaf[VALUE] === NIL ||
267
+ getSuffix(leaf[VALUE]) === PREDICATE_SUFFIX)) ||
268
+ (leaf[TYPE] === APPLY &&
269
+ (PREDICATES_OUTPUT_SET.has(leaf[VALUE]) ||
270
+ getSuffix(leaf[VALUE]) === PREDICATE_SUFFIX))
271
+
272
+ const notABooleanType = (a, b) =>
273
+ hasSubType(a) &&
274
+ getSubType(a).has(PREDICATE) &&
275
+ !isUnknownType(b) &&
276
+ !isAnyType(b) &&
277
+ (!hasSubType(b) || getSubType(a).difference(getSubType(b)).size !== 0)
278
+ const notABooleanReturn = (a, b) =>
279
+ hasSubType(a) &&
280
+ getSubType(a).has(PREDICATE) &&
281
+ !isUnknownReturn(b) &&
282
+ !isAnyReturn(b) &&
283
+ (!hasSubReturn(b) || getSubType(a).difference(getSubReturn(b)).size !== 0)
284
+ const isAtomABoolean = (atom) => atom === TRUE || atom === FALSE
215
285
  const checkPredicateName = (exp, rest) => {
216
286
  if (getSuffix(rest[0][VALUE]) === PREDICATE_SUFFIX) {
217
287
  const last = rest.at(-1)
218
- if (isLeaf(last)) {
219
- if (last[TYPE] === ATOM && last[VALUE] !== TRUE && last[VALUE] !== FALSE)
288
+ if (last[TYPE] !== APPLY && isLeaf(last) && !IsPredicate(last)) {
289
+ if (!IsPredicate(last))
220
290
  throw new TypeError(
221
- `Assigning predicate (ending in ?) variable (${
291
+ `Assigning predicate (ending in ?) variable (${
222
292
  rest[0][VALUE]
223
293
  }) to an (${
224
294
  STATIC_TYPES.ATOM
225
- }) that is not (or ${TRUE} ${FALSE}) (${stringifyArgs(exp)})`
226
- )
227
- else if (
228
- last[TYPE] === WORD &&
229
- getSuffix(last[VALUE]) !== PREDICATE_SUFFIX &&
230
- !PREDICATES_OUTPUT_SET.has(last[VALUE])
231
- )
232
- throw new TypeError(
233
- `Assigning predicate (ending in ?) variable (${
234
- rest[0][VALUE]
235
- }) to another variable which is not a predicate (also ending in ?) (${stringifyArgs(
295
+ }) that is not (or ${TRUE} ${FALSE}) or to another variable which is not a predicate (also ending in ?) or to a variable that is not (or true false nil) (${stringifyArgs(
236
296
  exp
237
- )})`
297
+ )}) (check #100)`
238
298
  )
239
299
  } else if (last[0][0] === APPLY) {
240
300
  const application = last[0]
241
- if (
242
- application[VALUE] !== KEYWORDS.IF &&
243
- getSuffix(application[VALUE]) !== PREDICATE_SUFFIX &&
244
- !PREDICATES_OUTPUT_SET.has(application[VALUE])
245
- )
301
+ if (application[VALUE] !== KEYWORDS.IF && !IsPredicate(application))
246
302
  throw new TypeError(
247
303
  `Assigning predicate (ending in ?) variable (${
248
304
  application[VALUE]
249
- }) to another variable which is not a predicate (also ending in ?) (${stringifyArgs(
305
+ }) to another variable which is not a predicate (also ending in ?) or to a variable that is not (or true false nil) (${stringifyArgs(
250
306
  exp
251
- )})`
307
+ )}) (check #101)`
252
308
  )
253
309
  }
310
+ return true
254
311
  }
312
+ return false
255
313
  }
256
314
  const checkPredicateNameDeep = (name, exp, rest, returns) => {
257
315
  if (returns[VALUE] === KEYWORDS.CALL_FUNCTION) {
258
316
  const fn = rest.at(-1).at(-1).at(-1)
259
- checkPredicateName(exp, [
317
+ return checkPredicateName(exp, [
260
318
  [WORD, name],
261
319
  isLeaf(fn)
262
320
  ? fn // when apply is a word (let x? (lambda (apply [] array:empty!)))
263
321
  : drillReturnType(fn, (r) => r[VALUE] === KEYWORDS.CALL_FUNCTION) // when apply is an annonymous lambda // (let fn? (lambda x (apply x (lambda x (array:empty! [])))))
264
322
  ])
265
- } else {
266
- checkPredicateName(exp, [[WORD, name], returns])
267
323
  }
324
+ return checkPredicateName(exp, [[WORD, name], returns])
268
325
  }
269
326
  const fillUknownArgs = (n) =>
270
327
  Array.from({ length: n })
@@ -420,31 +477,33 @@ const resolveRetunType = ({ returns, rem, stack, prop, exp, name, env }) => {
420
477
  if (returns[TYPE] === ATOM) {
421
478
  // ATOM ASSIGMENT
422
479
  setPropToAtom(env[name][STATS], prop)
423
- checkPredicateName(exp, [[WORD, name], returns])
424
480
  } else {
425
481
  switch (returns[VALUE]) {
426
482
  case KEYWORDS.IF:
427
483
  resolveCondition({ rem, name, env, exp, prop })
428
484
  break
429
485
  default:
430
- checkPredicateNameDeep(name, exp, exp.slice(1), returns)
431
- if (!env[returns[VALUE]]) return false
432
- else if (getType(env[returns[VALUE]][STATS]) === APPLY) {
433
- if (returns[TYPE] === WORD) setReturnToAbbstraction(env[name][STATS])
434
- else {
435
- // ALWAYS APPLY
436
- // rest.at(-1)[0][TYPE] === APPLY
437
- // Here is upon application to store the result in the variable
438
- if (isUnknownType(env[name][STATS]))
439
- stack.prepend(() => {
440
- setTypeToReturn(env[name][STATS], env[returns[VALUE]][STATS])
441
- // env[name][STATS][TYPE_PROP][0] =
442
- // env[returns[VALUE]][STATS][RETURNS][0]
443
- // this seems to be able to be deleted
444
- // env[name][STATS][TYPE_PROP][1] =
445
- // env[returns[VALUE]][STATS][RETURNS][1]
446
- })
447
- else setReturnRef(env[name][STATS], env[returns[VALUE]][STATS])
486
+ {
487
+ checkPredicateNameDeep(name, exp, exp.slice(1), returns)
488
+ if (!env[returns[VALUE]]) return false
489
+ else if (getType(env[returns[VALUE]][STATS]) === APPLY) {
490
+ if (returns[TYPE] === WORD)
491
+ setReturnToAbbstraction(env[name][STATS])
492
+ else {
493
+ // ALWAYS APPLY
494
+ // rest.at(-1)[0][TYPE] === APPLY
495
+ // Here is upon application to store the result in the variable
496
+ if (isUnknownType(env[name][STATS]))
497
+ stack.prepend(() => {
498
+ setTypeToReturn(env[name][STATS], env[returns[VALUE]][STATS])
499
+ // env[name][STATS][TYPE_PROP][0] =
500
+ // env[returns[VALUE]][STATS][RETURNS][0]
501
+ // this seems to be able to be deleted
502
+ // env[name][STATS][TYPE_PROP][1] =
503
+ // env[returns[VALUE]][STATS][RETURNS][1]
504
+ })
505
+ else setReturnRef(env[name][STATS], env[returns[VALUE]][STATS])
506
+ }
448
507
  }
449
508
  }
450
509
  break
@@ -582,16 +641,18 @@ export const typeCheck = (ast, error = true) => {
582
641
  retried: 0,
583
642
  counter: 0,
584
643
  [SIGNATURE]: name,
585
- [TYPE_PROP]: [
586
- isLeafNode
587
- ? right[TYPE]
588
- : env[right[VALUE]] == undefined
589
- ? UNKNOWN
590
- : env[right[VALUE]][STATS][RETURNS][0]
591
- ],
644
+ [TYPE_PROP]: [UNKNOWN],
592
645
  [RETURNS]: [UNKNOWN]
593
646
  }
594
647
  }
648
+ const type = isLeafNode
649
+ ? right[TYPE]
650
+ : env[right[VALUE]] == undefined
651
+ ? UNKNOWN
652
+ : env[right[VALUE]][STATS][RETURNS][0]
653
+ if (type !== UNKNOWN)
654
+ setTypeToReturn(env[name][STATS], env[right[VALUE]][STATS])
655
+
595
656
  const body = rightHand
596
657
  const rem = hasBlock(body) ? body.at(-1) : body
597
658
  const returns = isLeaf(rem) ? rem : rem[0]
@@ -776,88 +837,42 @@ export const typeCheck = (ast, error = true) => {
776
837
  // also type of arg
777
838
  const args = env[first[VALUE]][STATS][ARGUMENTS] ?? []
778
839
  for (let i = 0; i < args.length; ++i) {
779
- const isRestILeaf = isLeaf(rest[i])
840
+ const isResLeaf = isLeaf(rest[i])
780
841
  // type check
781
842
  // TODO get rof pred type
782
843
  // const PRED_TYPE = args[i][STATS][TYPE_PROP][1]
783
844
  const MAIN_TYPE = getType(args[i][STATS])
784
845
  if (MAIN_TYPE === ANY) continue
785
846
  if (first[TYPE] === APPLY && isSpecial) {
786
- if (
787
- MAIN_TYPE === ATOM &&
788
- PREDICATES_INPUT_SET.has(first[VALUE])
789
- ) {
790
- if (
791
- !isRestILeaf &&
792
- rest[i][0][TYPE] === APPLY &&
793
- rest[i][0][VALUE] === KEYWORDS.CALL_FUNCTION
794
- ) {
795
- if (isLeaf(rest[i].at(-1))) {
796
- const fnName = rest[i].at(-1)[VALUE]
797
- const fn = env[fnName]
798
- if (fn && getReturn(fn[STATS]) !== ATOM)
799
- throw new TypeError(
800
- `Incorrect type of argument (${i}) for (${
801
- first[VALUE]
802
- }). Expected (${toTypeNames(
803
- ATOM
804
- )}) but got an (${toTypeNames(
805
- getReturn(fn[STATS])
806
- )}) (${stringifyArgs(exp)}) (check #26)`
807
- )
808
- } else {
809
- const body = rest[i].at(-1).at(-1)
810
- const rem = hasBlock(body) ? body.at(-1) : body
811
- const returns = isLeaf(rem) ? rem : rem[0]
812
- if (returns[TYPE] === ATOM) {
813
- if (MAIN_TYPE !== ATOM)
814
- throw new TypeError(
815
- `Incorrect type of argument ${i} for (${
816
- first[VALUE]
817
- }). Expected (${toTypeNames(
818
- MAIN_TYPE
819
- )}) but got an (${toTypeNames(
820
- ATOM
821
- )}) (${stringifyArgs(exp)}) (check #27)`
822
- )
823
- } else if (
824
- env[returns[VALUE]] &&
825
- !isUnknownReturn(env[returns[VALUE]][STATS]) &&
826
- getReturn(env[returns[VALUE]][STATS]) !== ATOM
827
- )
828
- throw new TypeError(
829
- `Incorrect type of argument ${i} for (${
830
- first[VALUE]
831
- }). Expected (${toTypeNames(
832
- ATOM
833
- )}) but got (${toTypeNames(
834
- getReturn(env[returns[VALUE]][STATS])
835
- )}) (${stringifyArgs(exp)}) (check #29)`
836
- )
837
- }
838
- }
839
- }
840
- const expectedArgs = env[first[VALUE]][STATS][ARGUMENTS]
841
- if (!isRestILeaf) {
847
+ if (!isResLeaf) {
842
848
  const name = rest[i][0][VALUE]
843
849
  if (!env[name]) continue
844
850
  if (
845
851
  !isUnknownReturn(env[name][STATS]) &&
846
- !compareTypeWithReturn(
847
- expectedArgs[i][STATS],
848
- env[name][STATS]
849
- )
852
+ !compareTypeWithReturn(args[i][STATS], env[name][STATS])
850
853
  )
851
854
  throw new TypeError(
852
855
  `Incorrect type of argument (${i}) for special form (${
853
856
  first[VALUE]
854
857
  }). Expected (${toTypeNames(
855
- getType(expectedArgs[i][STATS])
858
+ getType(args[i][STATS])
856
859
  )}) but got (${toTypeNames(
857
860
  getReturn(env[name][STATS])
858
861
  )}) (${stringifyArgs(exp)}) (check #1)`
859
862
  )
860
- else {
863
+ else if (
864
+ notABooleanReturn(args[i][STATS], env[name][STATS])
865
+ ) {
866
+ throw new TypeError(
867
+ `Incorrect type of argument (${i}) for special form (${
868
+ first[VALUE]
869
+ }). Expected (${formatSubType(
870
+ getTypes(args[i][STATS])
871
+ )}) but got (${formatSubType(
872
+ getReturns(env[name][STATS])
873
+ )}) (${stringifyArgs(exp)}) (check #201)`
874
+ )
875
+ } else {
861
876
  if (env[name] && getType(env[name][STATS]) === APPLY)
862
877
  switch (first[VALUE]) {
863
878
  case KEYWORDS.IF:
@@ -868,10 +883,7 @@ export const typeCheck = (ast, error = true) => {
868
883
  // what if it's a global function used elsewhere where the return type mwould be different
869
884
  // THIS willgive lambda return types but refactor is needed still
870
885
  if (!SPECIAL_FORMS_SET.has(name))
871
- setReturn(
872
- env[name][STATS],
873
- expectedArgs[i][STATS]
874
- )
886
+ setReturn(env[name][STATS], args[i][STATS])
875
887
  break
876
888
  }
877
889
  // TODO also handle casting
@@ -884,45 +896,64 @@ export const typeCheck = (ast, error = true) => {
884
896
  if (!env[name]) continue
885
897
  if (
886
898
  !isUnknownType(env[name][STATS]) &&
887
- !compareTypes(
888
- expectedArgs[i][STATS],
889
- env[name][STATS]
890
- )
899
+ !compareTypes(args[i][STATS], env[name][STATS])
891
900
  )
892
901
  throw new TypeError(
893
902
  `Incorrect type of argument (${i}) for special form (${
894
903
  first[VALUE]
895
904
  }). Expected (${toTypeNames(
896
- getType(expectedArgs[i][STATS])
905
+ getType(args[i][STATS])
897
906
  )}) but got (${toTypeNames(
898
907
  getType(env[name][STATS])
899
908
  )}) (${stringifyArgs(exp)}) (check #3)`
900
909
  )
901
- else
902
- setType(env[name][STATS], expectedArgs[i][STATS])
910
+ else if (
911
+ notABooleanType(args[i][STATS], env[name][STATS])
912
+ )
913
+ throw new TypeError(
914
+ `Incorrect type of argument (${i}) for special form (${
915
+ first[VALUE]
916
+ }). Expected (${formatSubType(
917
+ getTypes(args[i][STATS])
918
+ )}) but got (${formatSubType(
919
+ getTypes(env[name][STATS])
920
+ )}) (${stringifyArgs(exp)}) (check #202)`
921
+ )
922
+ else setType(env[name][STATS], args[i][STATS])
903
923
  }
904
924
  break
905
925
  case ATOM: {
906
- if (
907
- rest[i][TYPE] !==
908
- expectedArgs[i][STATS][TYPE_PROP][0]
909
- )
926
+ if (rest[i][TYPE] !== args[i][STATS][TYPE_PROP][0])
910
927
  throw new TypeError(
911
928
  `Incorrect type of argument (${i}) for special form (${
912
929
  first[VALUE]
913
930
  }). Expected (${toTypeNames(
914
- expectedArgs[i][STATS][TYPE_PROP][0]
931
+ args[i][STATS][TYPE_PROP][0]
915
932
  )}) but got (${toTypeNames(
916
933
  rest[i][TYPE]
917
934
  )}) (${stringifyArgs(exp)}) (check #2)`
918
935
  )
936
+ else if (
937
+ hasSubType(args[i][STATS]) &&
938
+ getSubType(args[i][STATS]).has(PREDICATE) &&
939
+ !isAtomABoolean(rest[i][VALUE])
940
+ )
941
+ throw new TypeError(
942
+ `Incorrect type of argument (${i}) for special form (${
943
+ first[VALUE]
944
+ }). Expected (${formatSubType(
945
+ getTypes(args[i][STATS])
946
+ )}) but got (${rest[i][VALUE]}) (${stringifyArgs(
947
+ exp
948
+ )}) (check #203)`
949
+ )
919
950
  break
920
951
  }
921
952
  }
922
953
  }
923
954
  }
924
955
  // type checking
925
- else if (isRestILeaf) {
956
+ else if (isResLeaf) {
926
957
  const T =
927
958
  rest[i][TYPE] === WORD
928
959
  ? env[rest[i][VALUE]]
package/src/compiler.js CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  STATIC_TYPES
10
10
  } from './keywords.js'
11
11
  import { leaf, isLeaf, AST } from './parser.js'
12
+ import { FALSE_WORD, TRUE_WORD } from './types.js'
12
13
  const deepRename = (name, newName, tree) => {
13
14
  if (!isLeaf(tree))
14
15
  for (const leaf of tree) {
@@ -40,6 +41,10 @@ const toCamelCase = (name) => {
40
41
  const dashToLodashes = (name) => name.replace(new RegExp(/-/g), '_')
41
42
  const keywordToHelper = (name) => {
42
43
  switch (name) {
44
+ case TRUE_WORD:
45
+ return '__true'
46
+ case FALSE_WORD:
47
+ return '__false'
43
48
  case KEYWORDS.ADDITION:
44
49
  return '__add'
45
50
  case KEYWORDS.MULTIPLICATION:
package/src/macros.js CHANGED
@@ -246,8 +246,9 @@ export const deSuggarAst = (ast, scope) => {
246
246
  break
247
247
  case KEYWORDS.MULTIPLICATION:
248
248
  if (!rest.length) {
249
- exp[0][TYPE] = ATOM
250
- exp[0][VALUE] = TRUE
249
+ // exp[0][TYPE] = ATOM
250
+ exp[0][VALUE] = KEYWORDS.NOT
251
+ exp[1] = [ATOM, FALSE]
251
252
  } else if (rest.length > 2) {
252
253
  exp.length = 0
253
254
  let temp = exp