fez-lisp 1.5.93 → 1.5.94

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.
Files changed (3) hide show
  1. package/package.json +3 -2
  2. package/src/check.js +402 -525
  3. package/src/types.js +35 -3
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.93",
5
+ "version": "1.5.94",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
@@ -24,7 +24,8 @@
24
24
  "scripts": {
25
25
  "build": "node ./lib/builder.js",
26
26
  "fez": "node main.js",
27
- "test": "mocha"
27
+ "test": "mocha",
28
+ "examples": "node ./examples/2015/test.spec.js && node ./examples/2019/test.spec.js && node ./examples/2020/test.spec.js && node ./examples/2023/test.spec.js && node ./examples/2024/test.spec.js"
28
29
  },
29
30
  "license": "MIT",
30
31
  "devDependencies": {
package/src/check.js CHANGED
@@ -30,10 +30,9 @@ import {
30
30
  SIGNATURE,
31
31
  MAX_RETRY_DEFINITION,
32
32
  MAX_ARGUMENT_RETRY,
33
- ORDER,
34
- VARIABLE_ORDER_INDEX,
35
33
  COLLECTION,
36
- ANY
34
+ ANY,
35
+ formatType
37
36
  } from './types.js'
38
37
  import {
39
38
  getSuffix,
@@ -65,88 +64,77 @@ const deepLambdaReturn = (rest, condition) => {
65
64
  const rem = hasBlock(body) ? body.at(-1) : body
66
65
  return condition(rem) ? rem : deepLambdaReturn(rem, condition)
67
66
  }
68
- export const isTypeAbstraction = (stats) => {
69
- return stats[TYPE_PROP] === APPLY
70
- }
71
- export const setTypeRef = (stats, value) => {
72
- // if (!isAnyReturn(stats) && !isAnyReturn(value))
73
- if (isUnknownType(stats)) stats[TYPE_PROP] = value[TYPE_PROP]
74
- }
75
- export const setReturnRef = (stats, value) => {
76
- // if (!isAnyReturn(stats) && !isAnyReturn(value))
77
- if (isUnknownReturn(stats)) stats[RETURNS] = value[RETURNS]
78
- }
79
- export const setReturnToTypeRef = (stats, value) => {
80
- // if (!isAnyReturn(stats) && !isAnyReturn(value))
81
- if (isUnknownReturn(stats)) stats[RETURNS] = value[TYPE_PROP]
82
- }
83
- export const setTypeToReturnRef = (stats, value) => {
84
- // if (!isAnyReturn(stats) && !isAnyReturn(value))
85
- if (isUnknownType(stats)) stats[TYPE_PROP] = value[RETURNS]
86
- }
87
- export const setPropRef = (stats, prop, value) => {
88
- // if (stats[prop][0] !== ANY && value[prop][0] !== ANY)
89
- if (stats[prop][0] === UNKNOWN) stats[prop] = value[prop]
90
- }
91
- export const setReturn = (stats, value) => {
92
- // if (!isAnyReturn(stats) && !isAnyReturn(value))
93
- if (isUnknownReturn(stats) && !isUnknownReturn(value))
94
- stats[RETURNS][0] = value[RETURNS][0]
95
- }
96
- export const setType = (stats, value) => {
97
- // if (!isAnyType(stats) && !isAnyType(value))
67
+ export const isTypeAbstraction = (stats) => stats[TYPE_PROP] === APPLY
68
+ export const setPropToAtom = (stats, prop) =>
69
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
70
+ (stats[prop][0] = ATOM)
71
+ export const setProp = (stats, prop, value) =>
72
+ stats[prop][0] === UNKNOWN &&
73
+ value[prop][0] !== UNKNOWN &&
74
+ (stats[prop][0] = value[prop][0])
75
+ export const setPropToReturn = (stats, prop, value) =>
76
+ stats[prop][0] === UNKNOWN &&
77
+ value[RETURNS][0] !== UNKNOWN &&
78
+ (stats[prop][0] = value[RETURNS][0])
79
+ export const setPropToReturnRef = (stats, prop, value) =>
80
+ stats[prop][0] === UNKNOWN &&
81
+ value[RETURNS][0] !== UNKNOWN &&
82
+ (stats[prop] = value[RETURNS])
83
+ export const setPropToType = (stats, prop, value) =>
84
+ stats[prop][0] === UNKNOWN &&
85
+ value[UNKNOWN][0] !== UNKNOWN &&
86
+ (stats[prop][0] = value[UNKNOWN][0])
87
+ export const setPropToTypeRef = (stats, prop, value) =>
88
+ stats[prop][0] === UNKNOWN &&
89
+ value[TYPE_PROP][0] !== UNKNOWN &&
90
+ (stats[prop] = value[TYPE_PROP])
91
+ export const setReturnToAtom = (stats) =>
92
+ isUnknownReturn(stats) && (stats[RETURNS] = ATOM)
93
+ export const setTypeToAtom = (stats) =>
94
+ isUnknownType(stats) && (stats[TYPE_PROP] = ATOM)
95
+ export const setTypeRef = (stats, value) =>
96
+ isUnknownType(stats) && (stats[TYPE_PROP] = value[TYPE_PROP])
97
+ export const setReturnRef = (stats, value) =>
98
+ isUnknownReturn(stats) && (stats[RETURNS] = value[RETURNS])
99
+ export const setReturnToTypeRef = (stats, value) =>
100
+ isUnknownReturn(stats) && (stats[RETURNS] = value[TYPE_PROP])
101
+ export const setTypeToReturnRef = (stats, value) =>
102
+ isUnknownType(stats) && (stats[TYPE_PROP] = value[RETURNS])
103
+ export const setPropRef = (stats, prop, value) =>
104
+ stats[prop][0] === UNKNOWN && (stats[prop] = value[prop])
105
+ export const setReturn = (stats, value) =>
106
+ isUnknownReturn(stats) &&
107
+ !isUnknownReturn(value) &&
108
+ (stats[RETURNS][0] = value[RETURNS][0])
109
+ export const setType = (stats, value) =>
110
+ isUnknownType(stats) &&
111
+ !isUnknownType(value) &&
112
+ (stats[TYPE_PROP][0] = value[TYPE_PROP][0])
113
+ export const setTypeToReturn = (stats, value) =>
114
+ isUnknownType(stats) &&
115
+ !isUnknownReturn(value) &&
116
+ (stats[TYPE_PROP][0] = value[RETURNS][0])
117
+ export const setReturnToType = (stats, value) =>
118
+ isUnknownReturn(stats) &&
119
+ !isUnknownType(value) &&
120
+ (stats[RETURNS][0] = value[TYPE_PROP][0])
121
+ export const isAnyReturn = (stats) => stats && stats[RETURNS][0] === ANY
122
+ export const isAnyType = (stats) => stats && stats[TYPE_PROP][0] === ANY
123
+ export const isUnknownType = (stats) => stats && stats[TYPE_PROP][0] === UNKNOWN
124
+ export const isUnknownReturn = (stats) => stats[RETURNS][0] === UNKNOWN
125
+ export const getType = (stats) => stats && stats[TYPE_PROP][0]
126
+ export const getReturn = (stats) => stats && stats[RETURNS][0]
127
+ export const isAtomType = (stats) =>
128
+ isAnyType(stats) || stats[TYPE_PROP][0] === ATOM
129
+ export const isAtomReturn = (stats) =>
130
+ isAnyType(stats) || stats[RETURNS][0] === ATOM
131
+ export const compareTypes = (a, b) =>
132
+ isAnyType(a) || isAnyType(b) || a[TYPE_PROP][0] === b[TYPE_PROP][0]
133
+ export const compareReturns = (a, b) =>
134
+ isAnyReturn(a) || isAnyReturn(b) || a[RETURNS][0] === b[RETURNS][0]
135
+ export const compareTypeWithReturn = (a, b) =>
136
+ isAnyType(a) || isAnyReturn(b) || a[TYPE_PROP][0] === b[RETURNS][0]
98
137
 
99
- if (isUnknownType(stats) && !isUnknownType(value))
100
- stats[TYPE_PROP][0] = value[TYPE_PROP][0]
101
- }
102
- export const setTypeToReturn = (stats, value) => {
103
- // if (!isAnyType(stats) && !isAnyReturn(value))
104
- if (isUnknownType(stats) && !isUnknownReturn(value))
105
- stats[TYPE_PROP][0] = value[RETURNS][0]
106
- }
107
- export const setReturnToType = (stats, value) => {
108
- // if (!isAnyType(stats) && !isAnyReturn(value))
109
- if (isUnknownReturn(stats) && !isUnknownType(value))
110
- stats[RETURNS][0] = value[TYPE_PROP][0]
111
- }
112
- export const setProp = (stats, prop, value) => {
113
- // if (stats[prop][0] !== ANY && value[prop][0] !== ANY)
114
- if (stats[prop][0] === UNKNOWN && value[prop][0] !== UNKNOWN)
115
- stats[prop][0] = value[prop][0]
116
- }
117
- export const isAnyReturn = (stats) => {
118
- return stats && stats[RETURNS][0] === ANY
119
- }
120
- export const isAnyType = (stats) => {
121
- return stats && stats[TYPE_PROP][0] === ANY
122
- }
123
- export const isUnknownType = (stats) => {
124
- return stats && stats[TYPE_PROP][0] === UNKNOWN
125
- }
126
- export const isUnknownReturn = (stats) => {
127
- return stats[RETURNS][0] === UNKNOWN
128
- }
129
- export const getType = (stats) => {
130
- return stats && stats[TYPE_PROP][0]
131
- }
132
- export const getReturn = (stats) => {
133
- return stats && stats[RETURNS][0]
134
- }
135
- export const isAtomType = (stats) => {
136
- return isAnyType(stats) || stats[TYPE_PROP][0] === ATOM
137
- }
138
- export const isAtomReturn = (stats) => {
139
- return isAnyType(stats) || stats[RETURNS][0] === ATOM
140
- }
141
- export const compareTypes = (a, b) => {
142
- return isAnyType(a) || isAnyType(b) || a[TYPE_PROP][0] === b[TYPE_PROP][0]
143
- }
144
- export const compareReturns = (a, b) => {
145
- return isAnyReturn(a) || isAnyReturn(b) || a[RETURNS][0] === b[RETURNS][0]
146
- }
147
- export const compareTypeWithReturn = (a, b) => {
148
- return isAnyType(a) || isAnyReturn(b) || a[TYPE_PROP][0] === b[RETURNS][0]
149
- }
150
138
  const checkPredicateName = (exp, rest, warningStack) => {
151
139
  if (getSuffix(rest[0][VALUE]) === PREDICATE_SUFFIX) {
152
140
  const last = rest.at(-1)
@@ -227,38 +215,6 @@ const fillUknownArgs = (n) =>
227
215
  [ARG_COUNT]: 0
228
216
  }
229
217
  }))
230
- export const formatType = (name, env) => {
231
- const stats = env[name][STATS]
232
- const isAnonymous = typeof name === 'number'
233
- return stats
234
- ? getType(stats) === APPLY
235
- ? `${isAnonymous ? '' : `(let ${name} `}(lambda ${
236
- stats[ARG_COUNT] === VARIADIC
237
- ? '... ' + STATIC_TYPES.UNKNOWN
238
- : (stats[ARGUMENTS] ?? [])
239
- .map(
240
- (x, i) =>
241
- `${
242
- getType(x[STATS]) === APPLY
243
- ? `${formatType(i, stats[ARGUMENTS])}`
244
- : `${toTypeNames(getType(x[STATS]))}`
245
- }`
246
- )
247
- .join(' ')
248
- // TODO format returned functions when type support is added
249
- } (${KEYWORDS.BLOCK} ${toTypeNames(getReturn(stats))})${
250
- isAnonymous ? '' : ')'
251
- })`
252
- : `(let ${name} ${toTypeNames(getType(stats))})`
253
- : name
254
- }
255
- const formatTypes = (env) => {
256
- const out = []
257
- for (let x in env) {
258
- if (x !== SCOPE_NAME) out.push(formatType(x, env))
259
- }
260
- return out
261
- }
262
218
  const getScopeNames = (scope) => {
263
219
  const scopeNames = []
264
220
  let current = scope
@@ -277,422 +233,370 @@ const withScope = (name, scope) => {
277
233
  .join(' ')} ${name}`
278
234
  }
279
235
  export const typeCheck = (ast, error = true) => {
236
+ let scopeIndex = 0
280
237
  const root = structuredClone(SPECIAL_FORM_TYPES)
281
- // root[ORDER] = 0
282
238
  const errorStack = new Set()
283
239
  const warningStack = new Set()
284
240
  // TODO delete this
285
- const tempStack = new Set()
241
+ // const tempStack = new Set()
286
242
  const Types = new Map()
287
243
  const stack = []
288
244
  const check = (exp, env, scope) => {
289
245
  const [first, ...rest] = isLeaf(exp) ? [exp] : exp
290
- if (first === undefined) {
246
+ if (first === undefined)
291
247
  throw new TypeError(
292
248
  `(lambda) invocation with missing (Abstraction) name () Provide an (Abstraction) name as the (1) argument.`
293
249
  )
294
- }
295
250
  const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
296
251
  switch (first[TYPE]) {
297
252
  case WORD:
298
- {
299
- if (!isSpecial)
300
- stack.push(() => {
253
+ if (!isSpecial)
254
+ stack.push(
255
+ () =>
301
256
  // Figure out how to determine if varible is define after it's used
302
- if (env[first[VALUE]] === undefined) {
303
- errorStack.add(
304
- `Trying to access undefined variable ${first[VALUE]} (check #11)`
305
- )
306
- }
307
- })
308
- }
257
+ env[first[VALUE]] === undefined &&
258
+ errorStack.add(
259
+ `Trying to access undefined variable ${first[VALUE]} (check #11)`
260
+ )
261
+ )
309
262
  break
310
263
  case ATOM:
311
264
  break
312
265
  case APPLY: {
313
266
  switch (first[VALUE]) {
314
267
  case KEYWORDS.DEFINE_VARIABLE:
315
- {
316
- if (rest.length !== 2) {
317
- throw new TypeError(
318
- `Incorrect number of arguments for (${
319
- first[VALUE]
320
- }). Expected (= 2) but got ${rest.length} (${stringifyArgs(
321
- exp
322
- )})`
323
- )
324
- } else {
325
- const name = rest[0][VALUE]
326
- // Predicate name consistency
327
- const resolveRetunType = (returns, rem, prop) => {
328
- if (returns[TYPE] === ATOM) {
329
- // ATOM ASSIGMENT
330
- env[name][STATS][prop][0] = ATOM
331
- env[name][STATS][RETURNS][0] = ATOM
332
- checkPredicateName(
333
- exp,
334
- [[WORD, name], returns],
335
- warningStack
336
- )
337
- } else {
338
- switch (returns[VALUE]) {
339
- case KEYWORDS.IF:
340
- {
341
- const re = rem.slice(2)
342
- checkPredicateName(
343
- exp,
344
- [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
345
- warningStack
346
- )
347
- checkPredicateName(
348
- exp,
349
- [[WORD, name], isLeaf(re[1]) ? re[1] : re[1][0]],
350
- warningStack
351
- )
352
- if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
353
- // ATOM ASSIGMENT
354
- env[name][STATS][prop][0] = ATOM
355
- // TODO maybe delete this
356
- env[name][STATS][RETURNS][0] = ATOM
357
- } else if (
358
- !isLeaf(re[0]) &&
359
- env[re[0][0][VALUE]] &&
360
- !isUnknownReturn(env[re[0][0][VALUE]][STATS])
361
- ) {
362
- env[name][STATS][prop] =
363
- env[re[0][0][VALUE]][STATS][RETURNS]
364
- if (re[0][0][TYPE] === APPLY) {
365
- switch (re[0][0][VALUE]) {
366
- case KEYWORDS.ANONYMOUS_FUNCTION:
367
- // FN UKNONW ASSIGMENT
368
- env[name][STATS][RETURNS] = [UNKNOWN]
369
- env[name][STATS][ARG_COUNT] = re[0].length - 2
370
- env[name][STATS][ARGUMENTS] = fillUknownArgs(
371
- re[0].length - 2
372
- )
373
- break
374
- }
375
- }
376
- // env[name][STATS] = env[re[0][0][VALUE]][STATS]
377
- } else if (
378
- !isLeaf(re[1]) &&
379
- env[re[1][0][VALUE]] &&
380
- !isUnknownReturn(env[re[1][0][VALUE]][STATS])
381
- ) {
382
- setProp(
383
- env[name][STATS],
384
- prop,
385
- env[re[1][0][VALUE]][STATS]
386
- )
387
- env[name][STATS][prop] =
388
- env[re[1][0][VALUE]][STATS][RETURNS]
389
- if (re[1][0][TYPE] === APPLY) {
390
- switch (re[1][0][VALUE]) {
391
- case KEYWORDS.ANONYMOUS_FUNCTION:
392
- // FN ASSIGMENT
393
- env[name][STATS][TYPE_PROP] = [APPLY]
394
- env[name][STATS][RETURNS] = [UNKNOWN]
395
- env[name][STATS][ARG_COUNT] = re[1].length - 2
396
- env[name][STATS][ARGUMENTS] = fillUknownArgs(
397
- re[1].length - 2
398
- )
399
- break
400
- }
401
- }
402
- } else if (env[re[0][VALUE]]) {
403
- // ASSIGMENT
404
- env[name][STATS][prop] =
405
- env[re[0][VALUE]][STATS][prop]
406
- env[name][STATS][RETURNS] =
407
- env[re[0][VALUE]][STATS][RETURNS]
408
- } else if (env[re[1][VALUE]]) {
409
- // ASSIGMENT
410
- setProp(
411
- env[name][STATS],
412
- prop,
413
- env[re[1][VALUE]][STATS]
414
- )
415
- // env[name][STATS][prop] =
416
- // env[re[1][VALUE]][STATS][prop]
417
- setReturnRef(
418
- env[name][STATS],
419
- env[re[1][VALUE]][STATS]
420
- )
421
- }
422
- // else {
423
- // // setProp(env[name][STATS], prop, {
424
- // // [prop]: [UNKNOWN]
425
- // // })
426
- // // env[name][STATS][prop] = [UNKNOWN]
427
- // }
428
- }
429
- break
430
- default:
431
- checkPredicateNameDeep(
432
- name,
268
+ if (rest.length !== 2)
269
+ throw new TypeError(
270
+ `Incorrect number of arguments for (${
271
+ first[VALUE]
272
+ }). Expected (= 2) but got ${rest.length} (${stringifyArgs(
273
+ exp
274
+ )})`
275
+ )
276
+ else {
277
+ const name = rest[0][VALUE]
278
+ // Predicate name consistency
279
+ const resolveRetunType = (returns, rem, prop) => {
280
+ if (returns[TYPE] === ATOM) {
281
+ // ATOM ASSIGMENT
282
+ setPropToAtom(env[name][STATS], prop)
283
+ checkPredicateName(exp, [[WORD, name], returns], warningStack)
284
+ } else {
285
+ switch (returns[VALUE]) {
286
+ case KEYWORDS.IF:
287
+ {
288
+ const re = rem.slice(2)
289
+ checkPredicateName(
433
290
  exp,
434
- rest,
435
- returns,
291
+ [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
436
292
  warningStack
437
293
  )
438
- if (!env[returns[VALUE]]) {
439
- return false
440
- // env[name][STATS][RETURNS] = [ANY]
441
- }
442
- // env[name][STATS][RETURNS] = APPLY
294
+ checkPredicateName(
295
+ exp,
296
+ [[WORD, name], isLeaf(re[1]) ? re[1] : re[1][0]],
297
+ warningStack
298
+ )
299
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM)
300
+ // ATOM ASSIGMENT
301
+ setPropToAtom(env[name][STATS], prop)
443
302
  else if (
444
- getType(env[returns[VALUE]][STATS]) === APPLY
303
+ !isLeaf(re[0]) &&
304
+ env[re[0][0][VALUE]] &&
305
+ !isUnknownReturn(env[re[0][0][VALUE]][STATS])
445
306
  ) {
446
- // ALWAYS APPLY
447
- // rest.at(-1)[0][TYPE] === APPLY
448
- // Here is upon application to store the result in the variable
449
- if (isUnknownType(env[name][STATS]))
450
- stack.unshift(() => {
451
- setTypeToReturn(
452
- env[name][STATS],
453
- env[returns[VALUE]][STATS]
454
- )
455
- // env[name][STATS][TYPE_PROP][0] =
456
- // env[returns[VALUE]][STATS][RETURNS][0]
457
- // this seems to be able to be deleted
458
- // env[name][STATS][TYPE_PROP][1] =
459
- // env[returns[VALUE]][STATS][RETURNS][1]
460
- })
461
- setReturnRef(
307
+ env[name][STATS][prop] =
308
+ env[re[0][0][VALUE]][STATS][RETURNS]
309
+ if (re[0][0][TYPE] === APPLY) {
310
+ switch (re[0][0][VALUE]) {
311
+ case KEYWORDS.ANONYMOUS_FUNCTION:
312
+ // FN UKNONW ASSIGMENT
313
+ env[name][STATS][TYPE_PROP] = [APPLY]
314
+ env[name][STATS][RETURNS] = [UNKNOWN]
315
+ env[name][STATS][ARG_COUNT] = re[0].length - 2
316
+ env[name][STATS][ARGUMENTS] = fillUknownArgs(
317
+ re[0].length - 2
318
+ )
319
+ break
320
+ }
321
+ }
322
+ // env[name][STATS] = env[re[0][0][VALUE]][STATS]
323
+ } else if (
324
+ !isLeaf(re[1]) &&
325
+ env[re[1][0][VALUE]] &&
326
+ !isUnknownReturn(env[re[1][0][VALUE]][STATS])
327
+ ) {
328
+ setProp(
462
329
  env[name][STATS],
463
- env[returns[VALUE]][STATS]
330
+ prop,
331
+ env[re[1][0][VALUE]][STATS]
464
332
  )
465
- }
466
- break
467
- }
333
+ if (re[1][0][TYPE] === APPLY) {
334
+ switch (re[1][0][VALUE]) {
335
+ case KEYWORDS.ANONYMOUS_FUNCTION:
336
+ // FN ASSIGMENT
337
+ env[name][STATS][TYPE_PROP] = [APPLY]
338
+ env[name][STATS][RETURNS] = [UNKNOWN]
339
+ env[name][STATS][ARG_COUNT] = re[1].length - 2
340
+ env[name][STATS][ARGUMENTS] = fillUknownArgs(
341
+ re[1].length - 2
342
+ )
343
+ break
344
+ }
345
+ }
346
+ } else if (env[re[0][VALUE]])
347
+ // ASSIGMENT
348
+ setPropRef(
349
+ env[name][STATS],
350
+ prop,
351
+ env[re[0][VALUE]][STATS]
352
+ )
353
+ else if (env[re[1][VALUE]])
354
+ // ASSIGMENT
355
+ setPropRef(
356
+ env[name][STATS],
357
+ prop,
358
+ env[re[1][VALUE]][STATS]
359
+ )
360
+ }
361
+ break
362
+ default:
363
+ checkPredicateNameDeep(
364
+ name,
365
+ exp,
366
+ rest,
367
+ returns,
368
+ warningStack
369
+ )
370
+ if (!env[returns[VALUE]]) return false
371
+ else if (getType(env[returns[VALUE]][STATS]) === APPLY) {
372
+ // ALWAYS APPLY
373
+ // rest.at(-1)[0][TYPE] === APPLY
374
+ // Here is upon application to store the result in the variable
375
+ if (isUnknownType(env[name][STATS]))
376
+ stack.unshift(() => {
377
+ setTypeToReturn(
378
+ env[name][STATS],
379
+ env[returns[VALUE]][STATS]
380
+ )
381
+ // env[name][STATS][TYPE_PROP][0] =
382
+ // env[returns[VALUE]][STATS][RETURNS][0]
383
+ // this seems to be able to be deleted
384
+ // env[name][STATS][TYPE_PROP][1] =
385
+ // env[returns[VALUE]][STATS][RETURNS][1]
386
+ })
387
+ setReturnRef(
388
+ env[name][STATS],
389
+ env[returns[VALUE]][STATS]
390
+ )
391
+ }
392
+ break
468
393
  }
469
- return true
470
394
  }
471
- const checkReturnType = () => {
472
- const last = rest.at(-1).at(-1)
473
- const body = hasApplyLambdaBlock(last)
474
- ? last.at(-1).at(-1)
475
- : last
476
- const rem = hasBlock(body) ? body.at(-1) : body
477
- const returns = isLeaf(rem) ? rem : rem[0]
478
- return resolveRetunType(returns, rem, RETURNS)
395
+ return true
396
+ }
397
+ const checkReturnType = () => {
398
+ const last = rest.at(-1).at(-1)
399
+ const body = hasApplyLambdaBlock(last)
400
+ ? last.at(-1).at(-1)
401
+ : last
402
+ const rem = hasBlock(body) ? body.at(-1) : body
403
+ const returns = isLeaf(rem) ? rem : rem[0]
404
+ return resolveRetunType(returns, rem, RETURNS)
405
+ }
406
+ const rightHand = rest.at(-1)
407
+ if (
408
+ rightHand &&
409
+ rightHand[0] &&
410
+ rightHand[0][TYPE] === APPLY &&
411
+ rightHand[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
412
+ ) {
413
+ const n = rightHand.length
414
+ env[name] = {
415
+ [STATS]: {
416
+ [TYPE_PROP]: [APPLY],
417
+ [SIGNATURE]: name,
418
+ retried: 0,
419
+ counter: 0,
420
+ [ARG_COUNT]: n - 2,
421
+ [ARGUMENTS]: fillUknownArgs(n - 2),
422
+ [RETURNS]: [UNKNOWN]
423
+ }
479
424
  }
480
- const rightHand = rest.at(-1)
481
425
  if (
482
- rightHand &&
483
- rightHand[0] &&
484
- rightHand[0][TYPE] === APPLY &&
485
- rightHand[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
426
+ !checkReturnType() ||
427
+ (isUnknownReturn(env[name][STATS]) &&
428
+ env[name][STATS].retried < MAX_RETRY_DEFINITION)
486
429
  ) {
487
- const n = rightHand.length
430
+ env[name][STATS].retried += 1
431
+ stack.unshift(() => {
432
+ checkReturnType()
433
+ check(rightHand, env, exp)
434
+ })
435
+ check(rightHand, env, exp)
436
+ } else check(rightHand, env, exp)
437
+ } else {
438
+ checkPredicateName(exp, rest, warningStack)
439
+ const isLeafNode = isLeaf(rightHand)
440
+ if (isLeafNode && rightHand[TYPE] === WORD) {
441
+ // TODO make sure this prevents the assigment all together
442
+ if (env[rest[1][VALUE]] === undefined)
443
+ errorStack.add(
444
+ `Trying to access undefined variable ${rest[1][VALUE]} (check #22)`
445
+ )
446
+
447
+ // Used to be checkin if it's an assigment to a special form
448
+ // but this should not cause problems
449
+ // env[name] = SPECIAL_FORMS_SET.has(rest[1][VALUE])
450
+ // ? structuredClone(env[rest[1][VALUE]])
451
+ // : env[rest[1][VALUE]]
452
+ // FULL REFF ASSIGMENT
453
+ env[name] = env[rest[1][VALUE]]
454
+ } else if (isLeafNode && rightHand[TYPE] === ATOM) {
455
+ // DECLARATION of ATOM
488
456
  env[name] = {
489
457
  [STATS]: {
490
- [TYPE_PROP]: [APPLY],
491
458
  [SIGNATURE]: name,
492
459
  retried: 0,
493
460
  counter: 0,
494
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
495
- [ARG_COUNT]: n - 2,
496
- [ARGUMENTS]: fillUknownArgs(n - 2),
497
- [RETURNS]: [UNKNOWN]
461
+ [TYPE_PROP]: [ATOM],
462
+ [RETURNS]: [ATOM]
498
463
  }
499
464
  }
500
- if (
501
- !checkReturnType() ||
502
- (isUnknownReturn(env[name][STATS]) &&
503
- env[name][STATS].retried < MAX_RETRY_DEFINITION)
504
- ) {
505
- env[name][STATS].retried += 1
506
- stack.unshift(() => {
507
- checkReturnType()
508
- check(rightHand, env, exp)
509
- })
510
- check(rightHand, env, exp)
511
- } else {
512
- check(rightHand, env, exp)
513
- }
514
- } else {
515
- checkPredicateName(exp, rest, warningStack)
516
- const isL = isLeaf(rightHand)
517
- if (isL && rightHand[TYPE] === WORD) {
518
- // TODO make sure this prevents the assigment all together
519
- if (env[rest[1][VALUE]] === undefined) {
520
- errorStack.add(
521
- `Trying to access undefined variable ${rest[1][VALUE]} (check #22)`
522
- )
523
- }
524
- // FULL REFF ASSIGMENT
525
- env[name] = SPECIAL_FORMS_SET.has(rest[1][VALUE])
526
- ? structuredClone(env[rest[1][VALUE]])
527
- : env[rest[1][VALUE]]
528
- } else if (isL && rightHand[TYPE] === ATOM) {
529
- // DECLARATION of ATOM
530
- env[name] = {
531
- [STATS]: {
532
- [SIGNATURE]: name,
533
- retried: 0,
534
- counter: 0,
535
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
536
- [TYPE_PROP]: [ATOM],
537
- [RETURNS]: [ATOM]
538
- }
539
- }
540
- } else if (rightHand[0]) {
541
- const right = rightHand[0]
542
- //DECLARATION
543
- env[name] = {
544
- [STATS]: {
545
- retried: 0,
546
- counter: 0,
547
- [SIGNATURE]: name,
548
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
549
- [TYPE_PROP]: [
550
- isL
551
- ? right[TYPE]
552
- : env[right[VALUE]] == undefined
553
- ? UNKNOWN
554
- : env[right[VALUE]][STATS][RETURNS][0]
555
- ],
556
- [RETURNS]: [UNKNOWN]
557
- }
558
- }
559
- if (right[VALUE] === KEYWORDS.CALL_FUNCTION) {
560
- if (!isLeaf(rightHand.at(-1))) {
561
- const body = rightHand.at(-1).at(-1)
562
- const rem = hasBlock(body) ? body.at(-1) : body
563
- const returns = isLeaf(rem) ? rem : rem[0]
564
- resolveRetunType(returns, rem, TYPE_PROP)
565
- }
566
- } else {
567
- const body = rightHand
568
- const rem = hasBlock(body) ? body.at(-1) : body
569
- const returns = isLeaf(rem) ? rem : rem[0]
570
- resolveRetunType(returns, rem, TYPE_PROP)
465
+ } else if (rightHand[0]) {
466
+ const right = rightHand[0]
467
+ //DECLARATION
468
+ env[name] = {
469
+ [STATS]: {
470
+ retried: 0,
471
+ counter: 0,
472
+ [SIGNATURE]: name,
473
+ [TYPE_PROP]: [
474
+ isLeafNode
475
+ ? right[TYPE]
476
+ : env[right[VALUE]] == undefined
477
+ ? UNKNOWN
478
+ : env[right[VALUE]][STATS][RETURNS][0]
479
+ ],
480
+ [RETURNS]: [UNKNOWN]
571
481
  }
572
482
  }
573
- check(rightHand, env, scope)
483
+ const body = rightHand
484
+ const rem = hasBlock(body) ? body.at(-1) : body
485
+ const returns = isLeaf(rem) ? rem : rem[0]
486
+ resolveRetunType(returns, rem, TYPE_PROP)
574
487
  }
575
- Types.set(withScope(name, env), () => formatType(name, env))
488
+ check(rightHand, env, scope)
576
489
  }
577
- // root[ORDER]++
490
+ Types.set(withScope(name, env), () => formatType(name, env))
578
491
  }
579
492
  break
580
493
  case KEYWORDS.ANONYMOUS_FUNCTION:
581
- {
582
- if (exp.length === 1) {
583
- throw new TypeError(
584
- `Incorrect number of arguments for (${
494
+ if (exp.length === 1)
495
+ throw new TypeError(
496
+ `Incorrect number of arguments for (${
497
+ first[VALUE]
498
+ }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
499
+ exp
500
+ )})`
501
+ )
502
+ const params = exp.slice(1, -1)
503
+ const copy = Object.create(env)
504
+ if (Array.isArray(scope[1]) && scope[1][TYPE] === WORD)
505
+ copy[SCOPE_NAME] = scope[1][VALUE]
506
+ else copy[SCOPE_NAME] = ++scopeIndex
507
+ for (let i = 0; i < params.length; ++i) {
508
+ const param = params[i]
509
+ // TODO move this somewhere else
510
+ if (!isLeaf(param))
511
+ warningStack.add(
512
+ `Invalid body for (${
585
513
  first[VALUE]
586
- }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
587
- exp
588
- )})`
514
+ }) if it takes more than one expression it must be wrapped in a (${
515
+ KEYWORDS.BLOCK
516
+ }) (${stringifyArgs(exp)}) (check #666)`
589
517
  )
590
- }
591
- const params = exp.slice(1, -1)
592
- const copy = Object.create(env)
593
- if (Array.isArray(scope[1]) && scope[1][TYPE] === WORD) {
594
- copy[SCOPE_NAME] = scope[1][VALUE]
595
- } else {
596
- copy[SCOPE_NAME] = performance.now().toString().replace('.', 0)
597
- }
598
- for (let i = 0; i < params.length; ++i) {
599
- const param = params[i]
600
- // TODO move this somewhere else
601
- if (!isLeaf(param)) {
602
- warningStack.add(
603
- `Invalid body for (${
604
- first[VALUE]
605
- }) if it takes more than one expression it must be wrapped in a (${
606
- KEYWORDS.BLOCK
607
- }) (${stringifyArgs(exp)}) (check #666)`
608
- )
518
+ copy[param[VALUE]] = {
519
+ [STATS]: {
520
+ [SIGNATURE]: param[VALUE],
521
+ [TYPE_PROP]: [UNKNOWN],
522
+ [RETURNS]: [UNKNOWN],
523
+ [ARGUMENTS]: [],
524
+ retried: 0,
525
+ counter: 0
609
526
  }
610
- copy[param[VALUE]] = {
611
- [STATS]: {
612
- [SIGNATURE]: param[VALUE],
613
- [TYPE_PROP]: [UNKNOWN],
614
- [RETURNS]: [UNKNOWN],
615
- [ARGUMENTS]: [],
616
- retried: 0,
617
- counter: 0
618
- }
619
- }
620
- const ref = env[copy[SCOPE_NAME]]
621
- if (ref) {
622
- ref[STATS][ARGUMENTS][i] = copy[param[VALUE]]
623
- const returns = deepLambdaReturn(
624
- hasBlock(exp) ? exp.at(-1) : exp,
625
- (result) => result[VALUE] !== KEYWORDS.IF
626
- )
627
- if (isLeaf(returns)) {
628
- // TODO figure out what we do here
629
- // this here is a variable WORD
630
- // so return type of that function is that varible type
631
- stack.push(() => {
632
- if (copy[returns[VALUE]])
633
- setReturnToType(ref[STATS], copy[returns[VALUE]][STATS])
634
- })
635
- } else {
636
- const ret = returns[0]
637
- switch (ret[VALUE]) {
638
- case KEYWORDS.IF:
639
- const re = returns.slice(2)
640
- // If either is an ATOM then IF returns an ATOM
641
- if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
642
- ref[STATS][RETURNS][0] = ATOM
643
- // TODO check that both brancehs are predicates if one is
644
- } else {
645
- const concequent = isLeaf(re[0])
646
- ? copy[re[0][VALUE]]
647
- : copy[re[0][0][VALUE]]
648
- const alternative = isLeaf(re[1])
649
- ? copy[re[1][VALUE]]
650
- : copy[re[1][0][VALUE]]
527
+ }
528
+ const ref = env[copy[SCOPE_NAME]]
529
+ if (!ref) continue
530
+ ref[STATS][ARGUMENTS][i] = copy[param[VALUE]]
531
+ const returns = deepLambdaReturn(
532
+ hasBlock(exp) ? exp.at(-1) : exp,
533
+ (result) => result[VALUE] !== KEYWORDS.IF
534
+ )
535
+ if (isLeaf(returns))
536
+ // TODO figure out what we do here
537
+ // this here is a variable WORD
538
+ // so return type of that function is that varible type
539
+ stack.push(
540
+ () =>
541
+ copy[returns[VALUE]] &&
542
+ setReturnToType(ref[STATS], copy[returns[VALUE]][STATS])
543
+ )
544
+ else {
545
+ const ret = returns[0]
546
+ switch (ret[VALUE]) {
547
+ case KEYWORDS.IF:
548
+ const re = returns.slice(2)
549
+ // If either is an ATOM then IF returns an ATOM
550
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM)
551
+ setReturnToAtom(ref[STATS])
552
+ // TODO check that both brancehs are predicates if one is
553
+ else {
554
+ const concequent = isLeaf(re[0])
555
+ ? copy[re[0][VALUE]]
556
+ : copy[re[0][0][VALUE]]
557
+ const alternative = isLeaf(re[1])
558
+ ? copy[re[1][VALUE]]
559
+ : copy[re[1][0][VALUE]]
651
560
 
652
- // todo check if condition matches alternative
653
- // TODO make this more simple - it's so many different things just because types are functions or not
654
- // WHY not consiter making return types for everything
655
- if (
656
- concequent &&
657
- getType(concequent[STATS]) !== UNKNOWN
658
- ) {
659
- if (getType(concequent[STATS]) === APPLY)
660
- setReturnRef(ref[STATS], concequent[STATS])
661
- else
662
- ref[STATS][RETURNS] = concequent[STATS][TYPE_PROP]
663
- } else if (
664
- alternative &&
665
- isUnknownType(alternative[STATS])
666
- ) {
667
- if (getType(alternative[STATS]) === APPLY)
668
- setReturnRef(ref[STATS], alternative[STATS])
669
- else
670
- setReturnToTypeRef(ref[STATS], alternative[STATS])
671
- } else if (concequent) {
672
- if (getType(concequent[STATS]) === APPLY)
673
- setReturnRef(ref[STATS], concequent[STATS])
674
- else
675
- setReturnToTypeRef(ref[STATS], concequent[STATS])
676
- }
677
- }
678
- break
679
- default:
561
+ // todo check if condition matches alternative
562
+ // TODO make this more simple - it's so many different things just because types are functions or not
563
+ // WHY not consiter making return types for everything
564
+ if (
565
+ concequent &&
566
+ getType(concequent[STATS]) !== UNKNOWN
567
+ ) {
568
+ if (getType(concequent[STATS]) === APPLY)
569
+ setReturnRef(ref[STATS], concequent[STATS])
570
+ else ref[STATS][RETURNS] = concequent[STATS][TYPE_PROP]
571
+ } else if (
572
+ alternative &&
573
+ isUnknownType(alternative[STATS])
574
+ ) {
575
+ if (getType(alternative[STATS]) === APPLY)
576
+ setReturnRef(ref[STATS], alternative[STATS])
577
+ else setReturnToTypeRef(ref[STATS], alternative[STATS])
578
+ } else if (concequent) {
579
+ if (getType(concequent[STATS]) === APPLY)
580
+ setReturnRef(ref[STATS], concequent[STATS])
581
+ else setReturnToTypeRef(ref[STATS], concequent[STATS])
582
+ }
583
+ }
584
+ break
585
+ default:
586
+ if (copy[ret[VALUE]])
587
+ setReturnRef(ref[STATS], copy[ret[VALUE]][STATS])
588
+ else
589
+ stack.push(() => {
680
590
  if (copy[ret[VALUE]])
681
591
  setReturnRef(ref[STATS], copy[ret[VALUE]][STATS])
682
- else
683
- stack.push(() => {
684
- if (copy[ret[VALUE]])
685
- setReturnRef(ref[STATS], copy[ret[VALUE]][STATS])
686
- })
592
+ })
687
593
 
688
- break
689
- }
690
- }
691
- // TODO overwrite return type check here
594
+ break
692
595
  }
693
596
  }
694
- check(rest.at(-1), copy, copy)
597
+ // TODO overwrite return type check here
695
598
  }
599
+ check(rest.at(-1), copy, copy)
696
600
  break
697
601
  default:
698
602
  if (!STATIC_TYPES_SET.has(first[VALUE]))
@@ -705,7 +609,7 @@ export const typeCheck = (ast, error = true) => {
705
609
  env[first[VALUE]][STATS][TYPE_PROP][0] === APPLY &&
706
610
  env[first[VALUE]][STATS][ARG_COUNT] !== VARIADIC &&
707
611
  env[first[VALUE]][STATS][ARG_COUNT] !== rest.length
708
- ) {
612
+ )
709
613
  errorStack.add(
710
614
  `Incorrect number of arguments for (${
711
615
  first[VALUE]
@@ -715,21 +619,17 @@ export const typeCheck = (ast, error = true) => {
715
619
  exp
716
620
  )}) (check #15)`
717
621
  )
718
- } else {
622
+ else {
719
623
  if (first[TYPE] === APPLY && !isSpecial) {
720
- if (getType(env[first[VALUE]][STATS]) === ATOM) {
624
+ if (getType(env[first[VALUE]][STATS]) === ATOM)
721
625
  errorStack.add(
722
626
  `(${first[VALUE]}) is not a (lambda) (${stringifyArgs(
723
627
  exp
724
628
  )}) (check #12)`
725
629
  )
726
- } else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
630
+ else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
727
631
  // TODO recursively take return type of applicaion
728
- // if (env[first[VALUE]][STATS][RETURNS][0] === APPLY) {
729
- // env[first[VALUE]][STATS][RETURNS] = [UNKNOWN]
730
- // }
731
632
  // FN ASSIGMENT
732
-
733
633
  // ASSIGMENT of paramaters of lambda that are a lambda
734
634
  // minus one to remove the body
735
635
  env[first[VALUE]][STATS][TYPE_PROP] = [APPLY]
@@ -751,7 +651,6 @@ export const typeCheck = (ast, error = true) => {
751
651
  }
752
652
  const ARG = isLeaf(rest[i]) ? rest[i] : rest[i][0]
753
653
  if (!env[ARG[VALUE]]) continue
754
- // console.log(stringifyArgs(exp), ARG)
755
654
  switch (ARG[TYPE]) {
756
655
  // THERE ARE NO ATOM ARGUMENTS
757
656
  // case ATOM:
@@ -793,7 +692,7 @@ export const typeCheck = (ast, error = true) => {
793
692
  if (isLeaf(rest[i].at(-1))) {
794
693
  const fnName = rest[i].at(-1)[VALUE]
795
694
  const fn = env[fnName]
796
- if (fn && getReturn(fn[STATS]) !== ATOM) {
695
+ if (fn && getReturn(fn[STATS]) !== ATOM)
797
696
  errorStack.add(
798
697
  `Incorrect type of argument (${i}) for (${
799
698
  first[VALUE]
@@ -803,13 +702,12 @@ export const typeCheck = (ast, error = true) => {
803
702
  getReturn(fn[STATS])
804
703
  )}) (${stringifyArgs(exp)}) (check #26)`
805
704
  )
806
- }
807
705
  } else {
808
706
  const body = rest[i].at(-1).at(-1)
809
707
  const rem = hasBlock(body) ? body.at(-1) : body
810
708
  const returns = isLeaf(rem) ? rem : rem[0]
811
709
  if (returns[TYPE] === ATOM) {
812
- if (MAIN_TYPE !== ATOM) {
710
+ if (MAIN_TYPE !== ATOM)
813
711
  errorStack.add(
814
712
  `Incorrect type of argument ${i} for (${
815
713
  first[VALUE]
@@ -819,12 +717,11 @@ export const typeCheck = (ast, error = true) => {
819
717
  ATOM
820
718
  )}) (${stringifyArgs(exp)}) (check #27)`
821
719
  )
822
- }
823
720
  } else if (
824
721
  env[returns[VALUE]] &&
825
722
  !isUnknownReturn(env[returns[VALUE]][STATS]) &&
826
723
  getReturn(env[returns[VALUE]][STATS]) !== ATOM
827
- ) {
724
+ )
828
725
  errorStack.add(
829
726
  `Incorrect type of argument ${i} for (${
830
727
  first[VALUE]
@@ -834,15 +731,11 @@ export const typeCheck = (ast, error = true) => {
834
731
  getReturn(env[returns[VALUE]][STATS])
835
732
  )}) (${stringifyArgs(exp)}) (check #29)`
836
733
  )
837
- }
838
734
  }
839
735
  }
840
736
  }
841
737
  const isCast = STATIC_TYPES_SET.has(first[VALUE])
842
738
  const expectedArgs = env[first[VALUE]][STATS][ARGUMENTS]
843
- // IF UKNOWN andnot csted -we have nothing much to do
844
- if (isUnknownType(expectedArgs[i][STATS]) && !isCast)
845
- continue
846
739
  if (!isRestILeaf) {
847
740
  const CAR = rest[i][0][VALUE]
848
741
  if (!env[CAR]) continue
@@ -853,7 +746,7 @@ export const typeCheck = (ast, error = true) => {
853
746
  expectedArgs[i][STATS],
854
747
  env[CAR][STATS]
855
748
  )
856
- ) {
749
+ )
857
750
  errorStack.add(
858
751
  `Incorrect type of argument (${i}) for special form (${
859
752
  first[VALUE]
@@ -863,22 +756,12 @@ export const typeCheck = (ast, error = true) => {
863
756
  getReturn(env[CAR][STATS])
864
757
  )}) (${stringifyArgs(exp)}) (check #1)`
865
758
  )
866
- }
867
- // never reached because there is only 1 subtype at the moment
868
- // else if (
869
- // PRED_TYPE &&
870
- // env[CAR][STATS][RETURNS][1] !== PRED_TYPE
871
- // ) {
872
- // }
873
759
  } else if (!isKnown && !isCast) {
874
- if (env[CAR] && getType(env[CAR][STATS]) === APPLY) {
760
+ if (env[CAR] && getType(env[CAR][STATS]) === APPLY)
875
761
  switch (first[VALUE]) {
876
762
  case KEYWORDS.IF:
877
763
  break
878
- case KEYWORDS.CALL_FUNCTION:
879
- break
880
764
  default:
881
- // console.log(stringifyArgs(exp))
882
765
  // TODO fix this assigment
883
766
  // It turns out it's not possible to determine return type of function here
884
767
  // what if it's a global function used elsewhere where the return type mwould be different
@@ -889,8 +772,6 @@ export const typeCheck = (ast, error = true) => {
889
772
  )
890
773
  break
891
774
  }
892
- }
893
-
894
775
  // TODO also handle casting
895
776
  }
896
777
  } else {
@@ -906,7 +787,7 @@ export const typeCheck = (ast, error = true) => {
906
787
  expectedArgs[i][STATS],
907
788
  env[CAR][STATS]
908
789
  )
909
- ) {
790
+ )
910
791
  errorStack.add(
911
792
  `Incorrect type of argument (${i}) for special form (${
912
793
  first[VALUE]
@@ -916,7 +797,6 @@ export const typeCheck = (ast, error = true) => {
916
797
  getType(env[CAR][STATS])
917
798
  )}) (${stringifyArgs(exp)}) (check #3)`
918
799
  )
919
- }
920
800
  } else if (env[CAR]) {
921
801
  if (isCast) {
922
802
  // CAST assigment
@@ -942,7 +822,7 @@ export const typeCheck = (ast, error = true) => {
942
822
  if (
943
823
  rest[i][TYPE] !==
944
824
  expectedArgs[i][STATS][TYPE_PROP][0]
945
- ) {
825
+ )
946
826
  errorStack.add(
947
827
  `Incorrect type of argument (${i}) for special form (${
948
828
  first[VALUE]
@@ -952,7 +832,6 @@ export const typeCheck = (ast, error = true) => {
952
832
  rest[i][TYPE]
953
833
  )}) (${stringifyArgs(exp)}) (check #2)`
954
834
  )
955
- }
956
835
  break
957
836
  }
958
837
  }
@@ -1120,8 +999,8 @@ export const typeCheck = (ast, error = true) => {
1120
999
  if (
1121
1000
  !isUnknownType(expected) &&
1122
1001
  !isUnknownReturn(actual)
1123
- ) {
1124
- if (!compareTypeWithReturn(expected, actual)) {
1002
+ )
1003
+ if (!compareTypeWithReturn(expected, actual))
1125
1004
  errorStack.add(
1126
1005
  `Incorrect type of arguments ${i} for (${
1127
1006
  first[VALUE]
@@ -1131,7 +1010,7 @@ export const typeCheck = (ast, error = true) => {
1131
1010
  getReturn(actual)
1132
1011
  )}) (${stringifyArgs(exp)}) (check #16)`
1133
1012
  )
1134
- } else {
1013
+ else {
1135
1014
  switch (getType(expected)) {
1136
1015
  // almost exclusively for anonymous lambdas
1137
1016
  case APPLY:
@@ -1141,7 +1020,7 @@ export const typeCheck = (ast, error = true) => {
1141
1020
  env[rest[i][0][VALUE]][STATS][SIGNATURE] ===
1142
1021
  KEYWORDS.ANONYMOUS_FUNCTION
1143
1022
  ) {
1144
- if (argsN !== args[i][STATS][ARG_COUNT]) {
1023
+ if (argsN !== args[i][STATS][ARG_COUNT])
1145
1024
  errorStack.add(
1146
1025
  `Incorrect number of arguments for (${
1147
1026
  args[i][STATS][SIGNATURE]
@@ -1153,7 +1032,7 @@ export const typeCheck = (ast, error = true) => {
1153
1032
  exp
1154
1033
  )}) (check #777)`
1155
1034
  )
1156
- } else {
1035
+ else {
1157
1036
  // ANONYMOUS LAMBDAS TYPE CHECKING
1158
1037
  const local = Object.create(env)
1159
1038
  const lambdaName = `lambda::annonymous::${i}`
@@ -1179,7 +1058,7 @@ export const typeCheck = (ast, error = true) => {
1179
1058
  expected[STATS],
1180
1059
  actual[STATS]
1181
1060
  )
1182
- ) {
1061
+ )
1183
1062
  errorStack.add(
1184
1063
  `Incorrect return type for (${
1185
1064
  expected[STATS][SIGNATURE]
@@ -1193,7 +1072,7 @@ export const typeCheck = (ast, error = true) => {
1193
1072
  exp
1194
1073
  )}) (check #779)`
1195
1074
  )
1196
- } else if (
1075
+ else if (
1197
1076
  actual[STATS].retried <
1198
1077
  MAX_RETRY_DEFINITION
1199
1078
  ) {
@@ -1221,7 +1100,7 @@ export const typeCheck = (ast, error = true) => {
1221
1100
  actual[STATS],
1222
1101
  expected[STATS]
1223
1102
  )
1224
- ) {
1103
+ )
1225
1104
  errorStack.add(
1226
1105
  `Incorrect type for (lambda) (${
1227
1106
  args[i][STATS][SIGNATURE]
@@ -1237,7 +1116,7 @@ export const typeCheck = (ast, error = true) => {
1237
1116
  exp
1238
1117
  )}) (check #780)`
1239
1118
  )
1240
- } else if (
1119
+ else if (
1241
1120
  actual[STATS].retried <
1242
1121
  MAX_RETRY_DEFINITION
1243
1122
  ) {
@@ -1258,7 +1137,7 @@ export const typeCheck = (ast, error = true) => {
1258
1137
  // break
1259
1138
  }
1260
1139
  }
1261
- } else if (
1140
+ else if (
1262
1141
  isUnknownType(expected) &&
1263
1142
  args[i][STATS].retried < MAX_RETRY_DEFINITION
1264
1143
  ) {
@@ -1273,8 +1152,8 @@ export const typeCheck = (ast, error = true) => {
1273
1152
  })
1274
1153
  for (let i = 0; i < rest.length; ++i) {
1275
1154
  const r = rest[i]
1276
- if (isLeaf(r) && r[TYPE] !== ATOM) {
1277
- if (env[r[VALUE]] == undefined) {
1155
+ if (isLeaf(r) && r[TYPE] !== ATOM)
1156
+ if (env[r[VALUE]] == undefined)
1278
1157
  errorStack.add(
1279
1158
  `(${
1280
1159
  first[VALUE]
@@ -1282,8 +1161,6 @@ export const typeCheck = (ast, error = true) => {
1282
1161
  r[VALUE]
1283
1162
  }) at argument (${i}) (${stringifyArgs(exp)}) (check #20)`
1284
1163
  )
1285
- }
1286
- }
1287
1164
  check(r, env, scope)
1288
1165
  }
1289
1166
  break
package/src/types.js CHANGED
@@ -1,4 +1,12 @@
1
- import { APPLY, ATOM, DEBUG, KEYWORDS, PLACEHOLDER } from './keywords.js'
1
+ import { getReturn, getType } from './check.js'
2
+ import {
3
+ APPLY,
4
+ ATOM,
5
+ DEBUG,
6
+ KEYWORDS,
7
+ PLACEHOLDER,
8
+ STATIC_TYPES
9
+ } from './keywords.js'
2
10
  export const ARG_COUNT = 'argumentsN'
3
11
  export const VARIADIC = Infinity
4
12
  export const STATS = '__stats__'
@@ -7,8 +15,6 @@ export const RETURNS = 'returns'
7
15
  export const SCOPE_NAME = '__scope__'
8
16
  export const TYPE_PROP = 'type'
9
17
  export const SIGNATURE = 'name'
10
- export const ORDER = '__order__'
11
- export const VARIABLE_ORDER_INDEX = 'index'
12
18
  export const UNKNOWN = -1
13
19
  export const COLLECTION = 3
14
20
  export const PREDICATE = 4
@@ -1152,3 +1158,29 @@ export const SPECIAL_FORM_TYPES = {
1152
1158
  }
1153
1159
  }
1154
1160
  }
1161
+
1162
+ export const formatType = (name, env) => {
1163
+ const stats = env[name][STATS]
1164
+ const isAnonymous = typeof name === 'number'
1165
+ return stats
1166
+ ? getType(stats) === APPLY
1167
+ ? `${isAnonymous ? '' : `(let ${name} `}(lambda ${
1168
+ stats[ARG_COUNT] === VARIADIC
1169
+ ? '... ' + STATIC_TYPES.UNKNOWN
1170
+ : (stats[ARGUMENTS] ?? [])
1171
+ .map(
1172
+ (x, i) =>
1173
+ `${
1174
+ getType(x[STATS]) === APPLY
1175
+ ? `${formatType(i, stats[ARGUMENTS])}`
1176
+ : `${toTypeNames(getType(x[STATS]))}`
1177
+ }`
1178
+ )
1179
+ .join(' ')
1180
+ // TODO format returned functions when type support is added
1181
+ } (${KEYWORDS.BLOCK} ${toTypeNames(getReturn(stats))})${
1182
+ isAnonymous ? '' : ')'
1183
+ })`
1184
+ : `(let ${name} ${toTypeNames(getType(stats))})`
1185
+ : name
1186
+ }