fez-lisp 1.5.92 → 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 -533
  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.92",
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,84 +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 setPropRef = (stats, prop, value) => {
84
- // if (stats[prop][0] !== ANY && value[prop][0] !== ANY)
85
- if (stats[prop][0] === UNKNOWN) stats[prop] = value[prop]
86
- }
87
- export const setReturn = (stats, value) => {
88
- // if (!isAnyReturn(stats) && !isAnyReturn(value))
89
- if (isUnknownReturn(stats) && !isUnknownReturn(value))
90
- stats[RETURNS][0] = value[RETURNS][0]
91
- }
92
- export const setType = (stats, value) => {
93
- // 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]
94
137
 
95
- if (isUnknownType(stats) && !isUnknownType(value))
96
- stats[TYPE_PROP][0] = value[TYPE_PROP][0]
97
- }
98
- export const setTypeToReturn = (stats, value) => {
99
- // if (!isAnyType(stats) && !isAnyReturn(value))
100
- if (isUnknownType(stats) && !isUnknownReturn(value))
101
- stats[TYPE_PROP][0] = value[RETURNS][0]
102
- }
103
- export const setReturnToType = (stats, value) => {
104
- // if (!isAnyType(stats) && !isAnyReturn(value))
105
- if (isUnknownReturn(stats) && !isUnknownType(value))
106
- stats[RETURNS][0] = value[TYPE_PROP][0]
107
- }
108
- export const setProp = (stats, prop, value) => {
109
- // if (stats[prop][0] !== ANY && value[prop][0] !== ANY)
110
- if (stats[prop][0] === UNKNOWN && value[prop][0] !== UNKNOWN)
111
- stats[prop][0] = value[prop][0]
112
- }
113
- export const isAnyReturn = (stats) => {
114
- return stats && stats[RETURNS][0] === ANY
115
- }
116
- export const isAnyType = (stats) => {
117
- return stats && stats[TYPE_PROP][0] === ANY
118
- }
119
- export const isUnknownType = (stats) => {
120
- return stats && stats[TYPE_PROP][0] === UNKNOWN
121
- }
122
- export const isUnknownReturn = (stats) => {
123
- return stats[RETURNS][0] === UNKNOWN
124
- }
125
- export const getType = (stats) => {
126
- return stats && stats[TYPE_PROP][0]
127
- }
128
- export const getReturn = (stats) => {
129
- return stats && stats[RETURNS][0]
130
- }
131
- export const isAtomType = (stats) => {
132
- return isAnyType(stats) || stats[TYPE_PROP][0] === ATOM
133
- }
134
- export const isAtomReturn = (stats) => {
135
- return isAnyType(stats) || stats[RETURNS][0] === ATOM
136
- }
137
- export const compareTypes = (a, b) => {
138
- return isAnyType(a) || isAnyType(b) || a[TYPE_PROP][0] === b[TYPE_PROP][0]
139
- }
140
- export const compareReturns = (a, b) => {
141
- return isAnyReturn(a) || isAnyReturn(b) || a[RETURNS][0] === b[RETURNS][0]
142
- }
143
- export const compareTypeWithReturn = (a, b) => {
144
- return isAnyType(a) || isAnyReturn(b) || a[TYPE_PROP][0] === b[RETURNS][0]
145
- }
146
138
  const checkPredicateName = (exp, rest, warningStack) => {
147
139
  if (getSuffix(rest[0][VALUE]) === PREDICATE_SUFFIX) {
148
140
  const last = rest.at(-1)
@@ -223,38 +215,6 @@ const fillUknownArgs = (n) =>
223
215
  [ARG_COUNT]: 0
224
216
  }
225
217
  }))
226
- export const formatType = (name, env) => {
227
- const stats = env[name][STATS]
228
- const isAnonymous = typeof name === 'number'
229
- return stats
230
- ? getType(stats) === APPLY
231
- ? `${isAnonymous ? '' : `(let ${name} `}(lambda ${
232
- stats[ARG_COUNT] === VARIADIC
233
- ? '... ' + STATIC_TYPES.UNKNOWN
234
- : (stats[ARGUMENTS] ?? [])
235
- .map(
236
- (x, i) =>
237
- `${
238
- getType(x[STATS]) === APPLY
239
- ? `${formatType(i, stats[ARGUMENTS])}`
240
- : `${toTypeNames(getType(x[STATS]))}`
241
- }`
242
- )
243
- .join(' ')
244
- // TODO format returned functions when type support is added
245
- } (${KEYWORDS.BLOCK} ${toTypeNames(getReturn(stats))})${
246
- isAnonymous ? '' : ')'
247
- })`
248
- : `(let ${name} ${toTypeNames(getType(stats))})`
249
- : name
250
- }
251
- const formatTypes = (env) => {
252
- const out = []
253
- for (let x in env) {
254
- if (x !== SCOPE_NAME) out.push(formatType(x, env))
255
- }
256
- return out
257
- }
258
218
  const getScopeNames = (scope) => {
259
219
  const scopeNames = []
260
220
  let current = scope
@@ -273,431 +233,370 @@ const withScope = (name, scope) => {
273
233
  .join(' ')} ${name}`
274
234
  }
275
235
  export const typeCheck = (ast, error = true) => {
236
+ let scopeIndex = 0
276
237
  const root = structuredClone(SPECIAL_FORM_TYPES)
277
- // root[ORDER] = 0
278
238
  const errorStack = new Set()
279
239
  const warningStack = new Set()
280
240
  // TODO delete this
281
- const tempStack = new Set()
241
+ // const tempStack = new Set()
282
242
  const Types = new Map()
283
243
  const stack = []
284
244
  const check = (exp, env, scope) => {
285
245
  const [first, ...rest] = isLeaf(exp) ? [exp] : exp
286
- if (first === undefined) {
246
+ if (first === undefined)
287
247
  throw new TypeError(
288
248
  `(lambda) invocation with missing (Abstraction) name () Provide an (Abstraction) name as the (1) argument.`
289
249
  )
290
- }
291
250
  const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
292
251
  switch (first[TYPE]) {
293
252
  case WORD:
294
- {
295
- if (!isSpecial)
296
- stack.push(() => {
253
+ if (!isSpecial)
254
+ stack.push(
255
+ () =>
297
256
  // Figure out how to determine if varible is define after it's used
298
- if (env[first[VALUE]] === undefined) {
299
- errorStack.add(
300
- `Trying to access undefined variable ${first[VALUE]} (check #11)`
301
- )
302
- }
303
- })
304
- }
257
+ env[first[VALUE]] === undefined &&
258
+ errorStack.add(
259
+ `Trying to access undefined variable ${first[VALUE]} (check #11)`
260
+ )
261
+ )
305
262
  break
306
263
  case ATOM:
307
264
  break
308
265
  case APPLY: {
309
266
  switch (first[VALUE]) {
310
267
  case KEYWORDS.DEFINE_VARIABLE:
311
- {
312
- if (rest.length !== 2) {
313
- throw new TypeError(
314
- `Incorrect number of arguments for (${
315
- first[VALUE]
316
- }). Expected (= 2) but got ${rest.length} (${stringifyArgs(
317
- exp
318
- )})`
319
- )
320
- } else {
321
- const name = rest[0][VALUE]
322
- // Predicate name consistency
323
- const resolveRetunType = (returns, rem, prop) => {
324
- if (returns[TYPE] === ATOM) {
325
- // ATOM ASSIGMENT
326
- env[name][STATS][prop][0] = ATOM
327
- env[name][STATS][RETURNS][0] = ATOM
328
- checkPredicateName(
329
- exp,
330
- [[WORD, name], returns],
331
- warningStack
332
- )
333
- } else {
334
- switch (returns[VALUE]) {
335
- case KEYWORDS.IF:
336
- {
337
- const re = rem.slice(2)
338
- checkPredicateName(
339
- exp,
340
- [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
341
- warningStack
342
- )
343
- checkPredicateName(
344
- exp,
345
- [[WORD, name], isLeaf(re[1]) ? re[1] : re[1][0]],
346
- warningStack
347
- )
348
- if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
349
- // ATOM ASSIGMENT
350
- env[name][STATS][prop][0] = ATOM
351
- // TODO maybe delete this
352
- env[name][STATS][RETURNS][0] = ATOM
353
- } else if (
354
- !isLeaf(re[0]) &&
355
- env[re[0][0][VALUE]] &&
356
- !isUnknownReturn(env[re[0][0][VALUE]][STATS])
357
- ) {
358
- env[name][STATS][prop] =
359
- env[re[0][0][VALUE]][STATS][RETURNS]
360
- if (re[0][0][TYPE] === APPLY) {
361
- switch (re[0][0][VALUE]) {
362
- case KEYWORDS.ANONYMOUS_FUNCTION:
363
- // FN UKNONW ASSIGMENT
364
- env[name][STATS][RETURNS] = [UNKNOWN]
365
- env[name][STATS][ARG_COUNT] = re[0].length - 2
366
- env[name][STATS][ARGUMENTS] = fillUknownArgs(
367
- re[0].length - 2
368
- )
369
- break
370
- }
371
- }
372
- // env[name][STATS] = env[re[0][0][VALUE]][STATS]
373
- } else if (
374
- !isLeaf(re[1]) &&
375
- env[re[1][0][VALUE]] &&
376
- !isUnknownReturn(env[re[1][0][VALUE]][STATS])
377
- ) {
378
- setProp(
379
- env[name][STATS],
380
- prop,
381
- env[re[1][0][VALUE]][STATS]
382
- )
383
- env[name][STATS][prop] =
384
- env[re[1][0][VALUE]][STATS][RETURNS]
385
- if (re[1][0][TYPE] === APPLY) {
386
- switch (re[1][0][VALUE]) {
387
- case KEYWORDS.ANONYMOUS_FUNCTION:
388
- // FN ASSIGMENT
389
- env[name][STATS][TYPE_PROP] = [APPLY]
390
- env[name][STATS][RETURNS] = [UNKNOWN]
391
- env[name][STATS][ARG_COUNT] = re[1].length - 2
392
- env[name][STATS][ARGUMENTS] = fillUknownArgs(
393
- re[1].length - 2
394
- )
395
- break
396
- }
397
- }
398
- } else if (env[re[0][VALUE]]) {
399
- // ASSIGMENT
400
- env[name][STATS][prop] =
401
- env[re[0][VALUE]][STATS][prop]
402
- env[name][STATS][RETURNS] =
403
- env[re[0][VALUE]][STATS][RETURNS]
404
- } else if (env[re[1][VALUE]]) {
405
- // ASSIGMENT
406
- setProp(
407
- env[name][STATS],
408
- prop,
409
- env[re[1][VALUE]][STATS]
410
- )
411
- // env[name][STATS][prop] =
412
- // env[re[1][VALUE]][STATS][prop]
413
- setReturnRef(
414
- env[name][STATS],
415
- env[re[1][VALUE]][STATS]
416
- )
417
- }
418
- // else {
419
- // // setProp(env[name][STATS], prop, {
420
- // // [prop]: [UNKNOWN]
421
- // // })
422
- // // env[name][STATS][prop] = [UNKNOWN]
423
- // }
424
- }
425
- break
426
- default:
427
- checkPredicateNameDeep(
428
- 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(
429
290
  exp,
430
- rest,
431
- returns,
291
+ [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
432
292
  warningStack
433
293
  )
434
- if (!env[returns[VALUE]]) {
435
- return false
436
- // env[name][STATS][RETURNS] = [ANY]
437
- }
438
- // 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)
439
302
  else if (
440
- getType(env[returns[VALUE]][STATS]) === APPLY
303
+ !isLeaf(re[0]) &&
304
+ env[re[0][0][VALUE]] &&
305
+ !isUnknownReturn(env[re[0][0][VALUE]][STATS])
441
306
  ) {
442
- // ALWAYS APPLY
443
- // rest.at(-1)[0][TYPE] === APPLY
444
- // Here is upon application to store the result in the variable
445
- if (isUnknownType(env[name][STATS]))
446
- stack.unshift(() => {
447
- setTypeToReturn(
448
- env[name][STATS],
449
- env[returns[VALUE]][STATS]
450
- )
451
- // env[name][STATS][TYPE_PROP][0] =
452
- // env[returns[VALUE]][STATS][RETURNS][0]
453
- // this seems to be able to be deleted
454
- // env[name][STATS][TYPE_PROP][1] =
455
- // env[returns[VALUE]][STATS][RETURNS][1]
456
- })
457
- 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(
458
329
  env[name][STATS],
459
- env[returns[VALUE]][STATS]
330
+ prop,
331
+ env[re[1][0][VALUE]][STATS]
460
332
  )
461
- }
462
- break
463
- }
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
464
393
  }
465
- return true
466
394
  }
467
- const checkReturnType = () => {
468
- const last = rest.at(-1).at(-1)
469
- const body = hasApplyLambdaBlock(last)
470
- ? last.at(-1).at(-1)
471
- : last
472
- const rem = hasBlock(body) ? body.at(-1) : body
473
- const returns = isLeaf(rem) ? rem : rem[0]
474
- 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
+ }
475
424
  }
476
- const rightHand = rest.at(-1)
477
425
  if (
478
- rightHand &&
479
- rightHand[0] &&
480
- rightHand[0][TYPE] === APPLY &&
481
- rightHand[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
426
+ !checkReturnType() ||
427
+ (isUnknownReturn(env[name][STATS]) &&
428
+ env[name][STATS].retried < MAX_RETRY_DEFINITION)
482
429
  ) {
483
- 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
484
456
  env[name] = {
485
457
  [STATS]: {
486
- [TYPE_PROP]: [APPLY],
487
458
  [SIGNATURE]: name,
488
459
  retried: 0,
489
460
  counter: 0,
490
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
491
- [ARG_COUNT]: n - 2,
492
- [ARGUMENTS]: fillUknownArgs(n - 2),
493
- [RETURNS]: [UNKNOWN]
461
+ [TYPE_PROP]: [ATOM],
462
+ [RETURNS]: [ATOM]
494
463
  }
495
464
  }
496
- if (
497
- !checkReturnType() ||
498
- (isUnknownReturn(env[name][STATS]) &&
499
- env[name][STATS].retried < MAX_RETRY_DEFINITION)
500
- ) {
501
- env[name][STATS].retried += 1
502
- stack.unshift(() => {
503
- checkReturnType()
504
- check(rightHand, env, exp)
505
- })
506
- check(rightHand, env, exp)
507
- } else {
508
- check(rightHand, env, exp)
509
- }
510
- } else {
511
- checkPredicateName(exp, rest, warningStack)
512
- const isL = isLeaf(rightHand)
513
- if (isL && rightHand[TYPE] === WORD) {
514
- // TODO make sure this prevents the assigment all together
515
- if (env[rest[1][VALUE]] === undefined) {
516
- errorStack.add(
517
- `Trying to access undefined variable ${rest[1][VALUE]} (check #22)`
518
- )
519
- }
520
- // FULL REFF ASSIGMENT
521
- env[name] = SPECIAL_FORMS_SET.has(rest[1][VALUE])
522
- ? structuredClone(env[rest[1][VALUE]])
523
- : env[rest[1][VALUE]]
524
- } else if (isL && rightHand[TYPE] === ATOM) {
525
- // DECLARATION of ATOM
526
- env[name] = {
527
- [STATS]: {
528
- [SIGNATURE]: name,
529
- retried: 0,
530
- counter: 0,
531
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
532
- [TYPE_PROP]: [ATOM],
533
- [RETURNS]: [ATOM]
534
- }
535
- }
536
- } else if (rightHand[0]) {
537
- const right = rightHand[0]
538
- //DECLARATION
539
- env[name] = {
540
- [STATS]: {
541
- retried: 0,
542
- counter: 0,
543
- [SIGNATURE]: name,
544
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
545
- [TYPE_PROP]: [
546
- isL
547
- ? right[TYPE]
548
- : env[right[VALUE]] == undefined
549
- ? UNKNOWN
550
- : env[right[VALUE]][STATS][RETURNS][0]
551
- ],
552
- [RETURNS]: [UNKNOWN]
553
- }
554
- }
555
- if (right[VALUE] === KEYWORDS.CALL_FUNCTION) {
556
- if (!isLeaf(rightHand.at(-1))) {
557
- const body = rightHand.at(-1).at(-1)
558
- const rem = hasBlock(body) ? body.at(-1) : body
559
- const returns = isLeaf(rem) ? rem : rem[0]
560
- resolveRetunType(returns, rem, TYPE_PROP)
561
- }
562
- } else {
563
- const body = rightHand
564
- const rem = hasBlock(body) ? body.at(-1) : body
565
- const returns = isLeaf(rem) ? rem : rem[0]
566
- 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]
567
481
  }
568
482
  }
569
- 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)
570
487
  }
571
- Types.set(withScope(name, env), () => formatType(name, env))
488
+ check(rightHand, env, scope)
572
489
  }
573
- // root[ORDER]++
490
+ Types.set(withScope(name, env), () => formatType(name, env))
574
491
  }
575
492
  break
576
493
  case KEYWORDS.ANONYMOUS_FUNCTION:
577
- {
578
- if (exp.length === 1) {
579
- throw new TypeError(
580
- `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 (${
581
513
  first[VALUE]
582
- }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
583
- exp
584
- )})`
514
+ }) if it takes more than one expression it must be wrapped in a (${
515
+ KEYWORDS.BLOCK
516
+ }) (${stringifyArgs(exp)}) (check #666)`
585
517
  )
586
- }
587
- const params = exp.slice(1, -1)
588
- const copy = Object.create(env)
589
- if (Array.isArray(scope[1]) && scope[1][TYPE] === WORD) {
590
- copy[SCOPE_NAME] = scope[1][VALUE]
591
- } else {
592
- copy[SCOPE_NAME] = performance.now().toString().replace('.', 0)
593
- }
594
- for (let i = 0; i < params.length; ++i) {
595
- const param = params[i]
596
- // TODO move this somewhere else
597
- if (!isLeaf(param)) {
598
- warningStack.add(
599
- `Invalid body for (${
600
- first[VALUE]
601
- }) if it takes more than one expression it must be wrapped in a (${
602
- KEYWORDS.BLOCK
603
- }) (${stringifyArgs(exp)}) (check #666)`
604
- )
605
- }
606
- copy[param[VALUE]] = {
607
- [STATS]: {
608
- [SIGNATURE]: param[VALUE],
609
- [TYPE_PROP]: [UNKNOWN],
610
- [RETURNS]: [UNKNOWN],
611
- [ARGUMENTS]: [],
612
- retried: 0,
613
- counter: 0
614
- }
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
615
526
  }
616
- const ref = env[copy[SCOPE_NAME]]
617
- if (ref) {
618
- ref[STATS][ARGUMENTS][i] = copy[param[VALUE]]
619
- const returns = deepLambdaReturn(
620
- hasBlock(exp) ? exp.at(-1) : exp,
621
- (result) => result[VALUE] !== KEYWORDS.IF
622
- )
623
- if (isLeaf(returns)) {
624
- // TODO figure out what we do here
625
- // this here is a variable WORD
626
- // so return type of that function is that varible type
627
- if (copy[returns[VALUE]])
628
- setReturnToTypeRef(
629
- ref[STATS],
630
- copy[returns[VALUE]][STATS]
631
- )
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]]
560
+
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])
632
588
  else
633
589
  stack.push(() => {
634
- if (copy[returns[VALUE]])
635
- setReturnToTypeRef(
636
- ref[STATS],
637
- copy[returns[VALUE]][STATS]
638
- )
639
- })
640
- } else {
641
- const ret = returns[0]
642
- switch (ret[VALUE]) {
643
- case KEYWORDS.IF:
644
- const re = returns.slice(2)
645
- // If either is an ATOM then IF returns an ATOM
646
- if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
647
- ref[STATS][RETURNS][0] = ATOM
648
- // TODO check that both brancehs are predicates if one is
649
- } else {
650
- const concequent = isLeaf(re[0])
651
- ? copy[re[0][VALUE]]
652
- : copy[re[0][0][VALUE]]
653
- const alternative = isLeaf(re[1])
654
- ? copy[re[1][VALUE]]
655
- : copy[re[1][0][VALUE]]
656
-
657
- // todo check if condition matches alternative
658
- // TODO make this more simple - it's so many different things just because types are functions or not
659
- // WHY not consiter making return types for everything
660
- if (
661
- concequent &&
662
- getType(concequent[STATS]) !== UNKNOWN
663
- ) {
664
- if (getType(concequent[STATS]) === APPLY)
665
- setReturnRef(ref[STATS], concequent[STATS])
666
- else
667
- ref[STATS][RETURNS] = concequent[STATS][TYPE_PROP]
668
- } else if (
669
- alternative &&
670
- isUnknownType(alternative[STATS])
671
- ) {
672
- if (getType(alternative[STATS]) === APPLY)
673
- setReturnRef(ref[STATS], alternative[STATS])
674
- else
675
- setReturnToTypeRef(ref[STATS], alternative[STATS])
676
- } else if (concequent) {
677
- if (getType(concequent[STATS]) === APPLY)
678
- setReturnRef(ref[STATS], concequent[STATS])
679
- else
680
- setReturnToTypeRef(ref[STATS], concequent[STATS])
681
- }
682
- }
683
- break
684
- default:
685
590
  if (copy[ret[VALUE]])
686
591
  setReturnRef(ref[STATS], copy[ret[VALUE]][STATS])
687
- else
688
- stack.push(() => {
689
- if (copy[ret[VALUE]])
690
- setReturnRef(ref[STATS], copy[ret[VALUE]][STATS])
691
- })
592
+ })
692
593
 
693
- break
694
- }
695
- }
696
- // TODO overwrite return type check here
594
+ break
697
595
  }
698
596
  }
699
- check(rest.at(-1), copy, copy)
597
+ // TODO overwrite return type check here
700
598
  }
599
+ check(rest.at(-1), copy, copy)
701
600
  break
702
601
  default:
703
602
  if (!STATIC_TYPES_SET.has(first[VALUE]))
@@ -710,7 +609,7 @@ export const typeCheck = (ast, error = true) => {
710
609
  env[first[VALUE]][STATS][TYPE_PROP][0] === APPLY &&
711
610
  env[first[VALUE]][STATS][ARG_COUNT] !== VARIADIC &&
712
611
  env[first[VALUE]][STATS][ARG_COUNT] !== rest.length
713
- ) {
612
+ )
714
613
  errorStack.add(
715
614
  `Incorrect number of arguments for (${
716
615
  first[VALUE]
@@ -720,21 +619,17 @@ export const typeCheck = (ast, error = true) => {
720
619
  exp
721
620
  )}) (check #15)`
722
621
  )
723
- } else {
622
+ else {
724
623
  if (first[TYPE] === APPLY && !isSpecial) {
725
- if (getType(env[first[VALUE]][STATS]) === ATOM) {
624
+ if (getType(env[first[VALUE]][STATS]) === ATOM)
726
625
  errorStack.add(
727
626
  `(${first[VALUE]}) is not a (lambda) (${stringifyArgs(
728
627
  exp
729
628
  )}) (check #12)`
730
629
  )
731
- } else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
630
+ else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
732
631
  // TODO recursively take return type of applicaion
733
- // if (env[first[VALUE]][STATS][RETURNS][0] === APPLY) {
734
- // env[first[VALUE]][STATS][RETURNS] = [UNKNOWN]
735
- // }
736
632
  // FN ASSIGMENT
737
-
738
633
  // ASSIGMENT of paramaters of lambda that are a lambda
739
634
  // minus one to remove the body
740
635
  env[first[VALUE]][STATS][TYPE_PROP] = [APPLY]
@@ -756,7 +651,6 @@ export const typeCheck = (ast, error = true) => {
756
651
  }
757
652
  const ARG = isLeaf(rest[i]) ? rest[i] : rest[i][0]
758
653
  if (!env[ARG[VALUE]]) continue
759
- // console.log(stringifyArgs(exp), ARG)
760
654
  switch (ARG[TYPE]) {
761
655
  // THERE ARE NO ATOM ARGUMENTS
762
656
  // case ATOM:
@@ -798,7 +692,7 @@ export const typeCheck = (ast, error = true) => {
798
692
  if (isLeaf(rest[i].at(-1))) {
799
693
  const fnName = rest[i].at(-1)[VALUE]
800
694
  const fn = env[fnName]
801
- if (fn && getReturn(fn[STATS]) !== ATOM) {
695
+ if (fn && getReturn(fn[STATS]) !== ATOM)
802
696
  errorStack.add(
803
697
  `Incorrect type of argument (${i}) for (${
804
698
  first[VALUE]
@@ -808,13 +702,12 @@ export const typeCheck = (ast, error = true) => {
808
702
  getReturn(fn[STATS])
809
703
  )}) (${stringifyArgs(exp)}) (check #26)`
810
704
  )
811
- }
812
705
  } else {
813
706
  const body = rest[i].at(-1).at(-1)
814
707
  const rem = hasBlock(body) ? body.at(-1) : body
815
708
  const returns = isLeaf(rem) ? rem : rem[0]
816
709
  if (returns[TYPE] === ATOM) {
817
- if (MAIN_TYPE !== ATOM) {
710
+ if (MAIN_TYPE !== ATOM)
818
711
  errorStack.add(
819
712
  `Incorrect type of argument ${i} for (${
820
713
  first[VALUE]
@@ -824,12 +717,11 @@ export const typeCheck = (ast, error = true) => {
824
717
  ATOM
825
718
  )}) (${stringifyArgs(exp)}) (check #27)`
826
719
  )
827
- }
828
720
  } else if (
829
721
  env[returns[VALUE]] &&
830
722
  !isUnknownReturn(env[returns[VALUE]][STATS]) &&
831
723
  getReturn(env[returns[VALUE]][STATS]) !== ATOM
832
- ) {
724
+ )
833
725
  errorStack.add(
834
726
  `Incorrect type of argument ${i} for (${
835
727
  first[VALUE]
@@ -839,15 +731,11 @@ export const typeCheck = (ast, error = true) => {
839
731
  getReturn(env[returns[VALUE]][STATS])
840
732
  )}) (${stringifyArgs(exp)}) (check #29)`
841
733
  )
842
- }
843
734
  }
844
735
  }
845
736
  }
846
737
  const isCast = STATIC_TYPES_SET.has(first[VALUE])
847
738
  const expectedArgs = env[first[VALUE]][STATS][ARGUMENTS]
848
- // IF UKNOWN andnot csted -we have nothing much to do
849
- if (isUnknownType(expectedArgs[i][STATS]) && !isCast)
850
- continue
851
739
  if (!isRestILeaf) {
852
740
  const CAR = rest[i][0][VALUE]
853
741
  if (!env[CAR]) continue
@@ -858,7 +746,7 @@ export const typeCheck = (ast, error = true) => {
858
746
  expectedArgs[i][STATS],
859
747
  env[CAR][STATS]
860
748
  )
861
- ) {
749
+ )
862
750
  errorStack.add(
863
751
  `Incorrect type of argument (${i}) for special form (${
864
752
  first[VALUE]
@@ -868,22 +756,12 @@ export const typeCheck = (ast, error = true) => {
868
756
  getReturn(env[CAR][STATS])
869
757
  )}) (${stringifyArgs(exp)}) (check #1)`
870
758
  )
871
- }
872
- // never reached because there is only 1 subtype at the moment
873
- // else if (
874
- // PRED_TYPE &&
875
- // env[CAR][STATS][RETURNS][1] !== PRED_TYPE
876
- // ) {
877
- // }
878
759
  } else if (!isKnown && !isCast) {
879
- if (env[CAR] && getType(env[CAR][STATS]) === APPLY) {
760
+ if (env[CAR] && getType(env[CAR][STATS]) === APPLY)
880
761
  switch (first[VALUE]) {
881
762
  case KEYWORDS.IF:
882
763
  break
883
- case KEYWORDS.CALL_FUNCTION:
884
- break
885
764
  default:
886
- // console.log(stringifyArgs(exp))
887
765
  // TODO fix this assigment
888
766
  // It turns out it's not possible to determine return type of function here
889
767
  // what if it's a global function used elsewhere where the return type mwould be different
@@ -894,8 +772,6 @@ export const typeCheck = (ast, error = true) => {
894
772
  )
895
773
  break
896
774
  }
897
- }
898
-
899
775
  // TODO also handle casting
900
776
  }
901
777
  } else {
@@ -911,7 +787,7 @@ export const typeCheck = (ast, error = true) => {
911
787
  expectedArgs[i][STATS],
912
788
  env[CAR][STATS]
913
789
  )
914
- ) {
790
+ )
915
791
  errorStack.add(
916
792
  `Incorrect type of argument (${i}) for special form (${
917
793
  first[VALUE]
@@ -921,7 +797,6 @@ export const typeCheck = (ast, error = true) => {
921
797
  getType(env[CAR][STATS])
922
798
  )}) (${stringifyArgs(exp)}) (check #3)`
923
799
  )
924
- }
925
800
  } else if (env[CAR]) {
926
801
  if (isCast) {
927
802
  // CAST assigment
@@ -947,7 +822,7 @@ export const typeCheck = (ast, error = true) => {
947
822
  if (
948
823
  rest[i][TYPE] !==
949
824
  expectedArgs[i][STATS][TYPE_PROP][0]
950
- ) {
825
+ )
951
826
  errorStack.add(
952
827
  `Incorrect type of argument (${i}) for special form (${
953
828
  first[VALUE]
@@ -957,7 +832,6 @@ export const typeCheck = (ast, error = true) => {
957
832
  rest[i][TYPE]
958
833
  )}) (${stringifyArgs(exp)}) (check #2)`
959
834
  )
960
- }
961
835
  break
962
836
  }
963
837
  }
@@ -1125,8 +999,8 @@ export const typeCheck = (ast, error = true) => {
1125
999
  if (
1126
1000
  !isUnknownType(expected) &&
1127
1001
  !isUnknownReturn(actual)
1128
- ) {
1129
- if (!compareTypeWithReturn(expected, actual)) {
1002
+ )
1003
+ if (!compareTypeWithReturn(expected, actual))
1130
1004
  errorStack.add(
1131
1005
  `Incorrect type of arguments ${i} for (${
1132
1006
  first[VALUE]
@@ -1136,7 +1010,7 @@ export const typeCheck = (ast, error = true) => {
1136
1010
  getReturn(actual)
1137
1011
  )}) (${stringifyArgs(exp)}) (check #16)`
1138
1012
  )
1139
- } else {
1013
+ else {
1140
1014
  switch (getType(expected)) {
1141
1015
  // almost exclusively for anonymous lambdas
1142
1016
  case APPLY:
@@ -1146,7 +1020,7 @@ export const typeCheck = (ast, error = true) => {
1146
1020
  env[rest[i][0][VALUE]][STATS][SIGNATURE] ===
1147
1021
  KEYWORDS.ANONYMOUS_FUNCTION
1148
1022
  ) {
1149
- if (argsN !== args[i][STATS][ARG_COUNT]) {
1023
+ if (argsN !== args[i][STATS][ARG_COUNT])
1150
1024
  errorStack.add(
1151
1025
  `Incorrect number of arguments for (${
1152
1026
  args[i][STATS][SIGNATURE]
@@ -1158,13 +1032,10 @@ export const typeCheck = (ast, error = true) => {
1158
1032
  exp
1159
1033
  )}) (check #777)`
1160
1034
  )
1161
- } else {
1035
+ else {
1162
1036
  // ANONYMOUS LAMBDAS TYPE CHECKING
1163
1037
  const local = Object.create(env)
1164
- const lambdaName = `lambda::annonymous::${i}::${performance
1165
- .now()
1166
- .toString()
1167
- .replace('.', 0)}*`
1038
+ const lambdaName = `lambda::annonymous::${i}`
1168
1039
  check(
1169
1040
  [
1170
1041
  [APPLY, KEYWORDS.DEFINE_VARIABLE],
@@ -1187,7 +1058,7 @@ export const typeCheck = (ast, error = true) => {
1187
1058
  expected[STATS],
1188
1059
  actual[STATS]
1189
1060
  )
1190
- ) {
1061
+ )
1191
1062
  errorStack.add(
1192
1063
  `Incorrect return type for (${
1193
1064
  expected[STATS][SIGNATURE]
@@ -1201,7 +1072,7 @@ export const typeCheck = (ast, error = true) => {
1201
1072
  exp
1202
1073
  )}) (check #779)`
1203
1074
  )
1204
- } else if (
1075
+ else if (
1205
1076
  actual[STATS].retried <
1206
1077
  MAX_RETRY_DEFINITION
1207
1078
  ) {
@@ -1229,7 +1100,7 @@ export const typeCheck = (ast, error = true) => {
1229
1100
  actual[STATS],
1230
1101
  expected[STATS]
1231
1102
  )
1232
- ) {
1103
+ )
1233
1104
  errorStack.add(
1234
1105
  `Incorrect type for (lambda) (${
1235
1106
  args[i][STATS][SIGNATURE]
@@ -1245,7 +1116,7 @@ export const typeCheck = (ast, error = true) => {
1245
1116
  exp
1246
1117
  )}) (check #780)`
1247
1118
  )
1248
- } else if (
1119
+ else if (
1249
1120
  actual[STATS].retried <
1250
1121
  MAX_RETRY_DEFINITION
1251
1122
  ) {
@@ -1266,7 +1137,7 @@ export const typeCheck = (ast, error = true) => {
1266
1137
  // break
1267
1138
  }
1268
1139
  }
1269
- } else if (
1140
+ else if (
1270
1141
  isUnknownType(expected) &&
1271
1142
  args[i][STATS].retried < MAX_RETRY_DEFINITION
1272
1143
  ) {
@@ -1281,8 +1152,8 @@ export const typeCheck = (ast, error = true) => {
1281
1152
  })
1282
1153
  for (let i = 0; i < rest.length; ++i) {
1283
1154
  const r = rest[i]
1284
- if (isLeaf(r) && r[TYPE] !== ATOM) {
1285
- if (env[r[VALUE]] == undefined) {
1155
+ if (isLeaf(r) && r[TYPE] !== ATOM)
1156
+ if (env[r[VALUE]] == undefined)
1286
1157
  errorStack.add(
1287
1158
  `(${
1288
1159
  first[VALUE]
@@ -1290,8 +1161,6 @@ export const typeCheck = (ast, error = true) => {
1290
1161
  r[VALUE]
1291
1162
  }) at argument (${i}) (${stringifyArgs(exp)}) (check #20)`
1292
1163
  )
1293
- }
1294
- }
1295
1164
  check(r, env, scope)
1296
1165
  }
1297
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
+ }