fez-lisp 1.5.93 → 1.5.95

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 +398 -515
  3. package/src/types.js +36 -4
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.95",
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,10 @@ 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,
36
+ ANONYMOUS_FUNCTION_TYPE_PREFIX
37
37
  } from './types.js'
38
38
  import {
39
39
  getSuffix,
@@ -65,88 +65,79 @@ const deepLambdaReturn = (rest, condition) => {
65
65
  const rem = hasBlock(body) ? body.at(-1) : body
66
66
  return condition(rem) ? rem : deepLambdaReturn(rem, condition)
67
67
  }
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))
68
+ export const isTypeAbstraction = (stats) => stats[TYPE_PROP] === APPLY
69
+ export const setPropToAtom = (stats, prop) =>
70
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
71
+ (stats[prop][0] = ATOM)
72
+ export const setProp = (stats, prop, value) =>
73
+ stats[prop][0] === UNKNOWN &&
74
+ value[prop][0] !== UNKNOWN &&
75
+ (stats[prop][0] = value[prop][0])
76
+ export const setPropToReturn = (stats, prop, value) =>
77
+ stats[prop][0] === UNKNOWN &&
78
+ value[RETURNS][0] !== UNKNOWN &&
79
+ (stats[prop][0] = value[RETURNS][0])
80
+ export const setPropToReturnRef = (stats, prop, value) =>
81
+ stats[prop][0] === UNKNOWN &&
82
+ value[RETURNS][0] !== UNKNOWN &&
83
+ (stats[prop] = value[RETURNS])
84
+ export const setPropToType = (stats, prop, value) =>
85
+ stats[prop][0] === UNKNOWN &&
86
+ value[UNKNOWN][0] !== UNKNOWN &&
87
+ (stats[prop][0] = value[UNKNOWN][0])
88
+ export const setPropToTypeRef = (stats, prop, value) =>
89
+ stats[prop][0] === UNKNOWN &&
90
+ value[TYPE_PROP][0] !== UNKNOWN &&
91
+ (stats[prop] = value[TYPE_PROP])
92
+ export const setReturnToAtom = (stats) =>
93
+ isUnknownReturn(stats) && (stats[RETURNS][0] = ATOM)
94
+ export const setTypeToAtom = (stats) =>
95
+ isUnknownType(stats) && (stats[TYPE_PROP][0] = ATOM)
96
+ export const setReturnToAbbstraction = (stats) =>
97
+ isUnknownReturn(stats) && (stats[RETURNS][0] = APPLY)
98
+ export const setTypeRef = (stats, value) =>
99
+ isUnknownType(stats) && (stats[TYPE_PROP] = value[TYPE_PROP])
100
+ export const setReturnRef = (stats, value) =>
101
+ isUnknownReturn(stats) && (stats[RETURNS] = value[RETURNS])
102
+ export const setReturnToTypeRef = (stats, value) =>
103
+ isUnknownReturn(stats) && (stats[RETURNS] = value[TYPE_PROP])
104
+ export const setTypeToReturnRef = (stats, value) =>
105
+ isUnknownType(stats) && (stats[TYPE_PROP] = value[RETURNS])
106
+ export const setPropRef = (stats, prop, value) =>
107
+ stats[prop][0] === UNKNOWN && (stats[prop] = value[prop])
108
+ export const setReturn = (stats, value) =>
109
+ isUnknownReturn(stats) &&
110
+ !isUnknownReturn(value) &&
111
+ (stats[RETURNS][0] = value[RETURNS][0])
112
+ export const setType = (stats, value) =>
113
+ isUnknownType(stats) &&
114
+ !isUnknownType(value) &&
115
+ (stats[TYPE_PROP][0] = value[TYPE_PROP][0])
116
+ export const setTypeToReturn = (stats, value) =>
117
+ isUnknownType(stats) &&
118
+ !isUnknownReturn(value) &&
119
+ (stats[TYPE_PROP][0] = value[RETURNS][0])
120
+ export const setReturnToType = (stats, value) =>
121
+ isUnknownReturn(stats) &&
122
+ !isUnknownType(value) &&
123
+ (stats[RETURNS][0] = value[TYPE_PROP][0])
124
+ export const isAnyReturn = (stats) => stats && stats[RETURNS][0] === ANY
125
+ export const isAnyType = (stats) => stats && stats[TYPE_PROP][0] === ANY
126
+ export const isUnknownType = (stats) => stats && stats[TYPE_PROP][0] === UNKNOWN
127
+ export const isUnknownReturn = (stats) => stats[RETURNS][0] === UNKNOWN
128
+ export const getType = (stats) => stats && stats[TYPE_PROP][0]
129
+ export const getReturn = (stats) => stats && stats[RETURNS][0]
130
+ export const isAtomType = (stats) =>
131
+ isAnyType(stats) || stats[TYPE_PROP][0] === ATOM
132
+ export const isAtomReturn = (stats) =>
133
+ isAnyType(stats) || stats[RETURNS][0] === ATOM
134
+ export const compareTypes = (a, b) =>
135
+ isAnyType(a) || isAnyType(b) || a[TYPE_PROP][0] === b[TYPE_PROP][0]
136
+ export const compareReturns = (a, b) =>
137
+ isAnyReturn(a) || isAnyReturn(b) || a[RETURNS][0] === b[RETURNS][0]
138
+ export const compareTypeWithReturn = (a, b) =>
139
+ isAnyType(a) || isAnyReturn(b) || a[TYPE_PROP][0] === b[RETURNS][0]
98
140
 
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
141
  const checkPredicateName = (exp, rest, warningStack) => {
151
142
  if (getSuffix(rest[0][VALUE]) === PREDICATE_SUFFIX) {
152
143
  const last = rest.at(-1)
@@ -227,38 +218,6 @@ const fillUknownArgs = (n) =>
227
218
  [ARG_COUNT]: 0
228
219
  }
229
220
  }))
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
221
  const getScopeNames = (scope) => {
263
222
  const scopeNames = []
264
223
  let current = scope
@@ -272,177 +231,148 @@ const getScopeNames = (scope) => {
272
231
  }
273
232
  const withScope = (name, scope) => {
274
233
  const chain = getScopeNames(scope)
275
- return `${chain.length === 1 ? '; ' : ''}${chain
276
- .map((x) => (Number.isInteger(+x) ? '::' : x))
277
- .join(' ')} ${name}`
234
+ return `${chain.length === 1 ? '; ' : ''}${chain.join(' ')} ${name}`
278
235
  }
279
236
  export const typeCheck = (ast, error = true) => {
237
+ let scopeIndex = 0
280
238
  const root = structuredClone(SPECIAL_FORM_TYPES)
281
- // root[ORDER] = 0
282
239
  const errorStack = new Set()
283
240
  const warningStack = new Set()
284
241
  // TODO delete this
285
- const tempStack = new Set()
242
+ // const tempStack = new Set()
286
243
  const Types = new Map()
287
244
  const stack = []
288
245
  const check = (exp, env, scope) => {
289
246
  const [first, ...rest] = isLeaf(exp) ? [exp] : exp
290
- if (first === undefined) {
247
+ if (first === undefined)
291
248
  throw new TypeError(
292
249
  `(lambda) invocation with missing (Abstraction) name () Provide an (Abstraction) name as the (1) argument.`
293
250
  )
294
- }
295
251
  const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
296
252
  switch (first[TYPE]) {
297
253
  case WORD:
298
- {
299
- if (!isSpecial)
300
- stack.push(() => {
254
+ if (!isSpecial)
255
+ stack.push(
256
+ () =>
301
257
  // 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
- }
258
+ env[first[VALUE]] === undefined &&
259
+ errorStack.add(
260
+ `Trying to access undefined variable ${first[VALUE]} (check #11)`
261
+ )
262
+ )
309
263
  break
310
264
  case ATOM:
311
265
  break
312
266
  case APPLY: {
313
267
  switch (first[VALUE]) {
314
268
  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,
269
+ if (rest.length !== 2)
270
+ throw new TypeError(
271
+ `Incorrect number of arguments for (${
272
+ first[VALUE]
273
+ }). Expected (= 2) but got ${rest.length} (${stringifyArgs(
274
+ exp
275
+ )})`
276
+ )
277
+ else {
278
+ const name = rest[0][VALUE]
279
+ // Predicate name consistency
280
+ const resolveRetunType = (returns, rem, prop) => {
281
+ if (returns[TYPE] === ATOM) {
282
+ // ATOM ASSIGMENT
283
+ setPropToAtom(env[name][STATS], prop)
284
+ checkPredicateName(exp, [[WORD, name], returns], warningStack)
285
+ } else {
286
+ switch (returns[VALUE]) {
287
+ case KEYWORDS.IF:
288
+ {
289
+ const re = rem.slice(2)
290
+ checkPredicateName(
433
291
  exp,
434
- rest,
435
- returns,
292
+ [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
436
293
  warningStack
437
294
  )
438
- if (!env[returns[VALUE]]) {
439
- return false
440
- // env[name][STATS][RETURNS] = [ANY]
441
- }
442
- // env[name][STATS][RETURNS] = APPLY
295
+ checkPredicateName(
296
+ exp,
297
+ [[WORD, name], isLeaf(re[1]) ? re[1] : re[1][0]],
298
+ warningStack
299
+ )
300
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM)
301
+ // ATOM ASSIGMENT
302
+ setPropToAtom(env[name][STATS], prop)
443
303
  else if (
444
- getType(env[returns[VALUE]][STATS]) === APPLY
304
+ !isLeaf(re[0]) &&
305
+ env[re[0][0][VALUE]] &&
306
+ !isUnknownReturn(env[re[0][0][VALUE]][STATS])
307
+ ) {
308
+ env[name][STATS][prop] =
309
+ env[re[0][0][VALUE]][STATS][RETURNS]
310
+ if (re[0][0][TYPE] === APPLY) {
311
+ switch (re[0][0][VALUE]) {
312
+ case KEYWORDS.ANONYMOUS_FUNCTION:
313
+ // FN UKNONW ASSIGMENT
314
+ env[name][STATS][TYPE_PROP] = [APPLY]
315
+ env[name][STATS][RETURNS] = [UNKNOWN]
316
+ env[name][STATS][ARG_COUNT] = re[0].length - 2
317
+ env[name][STATS][ARGUMENTS] = fillUknownArgs(
318
+ re[0].length - 2
319
+ )
320
+ break
321
+ }
322
+ }
323
+ // env[name][STATS] = env[re[0][0][VALUE]][STATS]
324
+ } else if (
325
+ !isLeaf(re[1]) &&
326
+ env[re[1][0][VALUE]] &&
327
+ !isUnknownReturn(env[re[1][0][VALUE]][STATS])
445
328
  ) {
329
+ setProp(
330
+ env[name][STATS],
331
+ prop,
332
+ env[re[1][0][VALUE]][STATS]
333
+ )
334
+ if (re[1][0][TYPE] === APPLY) {
335
+ switch (re[1][0][VALUE]) {
336
+ case KEYWORDS.ANONYMOUS_FUNCTION:
337
+ // FN ASSIGMENT
338
+ env[name][STATS][TYPE_PROP] = [APPLY]
339
+ env[name][STATS][RETURNS] = [UNKNOWN]
340
+ env[name][STATS][ARG_COUNT] = re[1].length - 2
341
+ env[name][STATS][ARGUMENTS] = fillUknownArgs(
342
+ re[1].length - 2
343
+ )
344
+ break
345
+ }
346
+ }
347
+ } else if (env[re[0][VALUE]])
348
+ // ASSIGMENT
349
+ setPropRef(
350
+ env[name][STATS],
351
+ prop,
352
+ env[re[0][VALUE]][STATS]
353
+ )
354
+ else if (env[re[1][VALUE]])
355
+ // ASSIGMENT
356
+ setPropRef(
357
+ env[name][STATS],
358
+ prop,
359
+ env[re[1][VALUE]][STATS]
360
+ )
361
+ }
362
+ break
363
+ default:
364
+ checkPredicateNameDeep(
365
+ name,
366
+ exp,
367
+ rest,
368
+ returns,
369
+ warningStack
370
+ )
371
+ if (!env[returns[VALUE]]) return false
372
+ else if (getType(env[returns[VALUE]][STATS]) === APPLY) {
373
+ if (returns[TYPE] === WORD)
374
+ setReturnToAbbstraction(env[name][STATS])
375
+ else {
446
376
  // ALWAYS APPLY
447
377
  // rest.at(-1)[0][TYPE] === APPLY
448
378
  // Here is upon application to store the result in the variable
@@ -458,241 +388,221 @@ export const typeCheck = (ast, error = true) => {
458
388
  // env[name][STATS][TYPE_PROP][1] =
459
389
  // env[returns[VALUE]][STATS][RETURNS][1]
460
390
  })
461
- setReturnRef(
462
- env[name][STATS],
463
- env[returns[VALUE]][STATS]
464
- )
391
+ else
392
+ setReturnRef(
393
+ env[name][STATS],
394
+ env[returns[VALUE]][STATS]
395
+ )
465
396
  }
466
- break
467
- }
397
+ }
398
+ break
468
399
  }
469
- return true
470
400
  }
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)
401
+ return true
402
+ }
403
+ const checkReturnType = () => {
404
+ const last = rest.at(-1).at(-1)
405
+ const body = hasApplyLambdaBlock(last)
406
+ ? last.at(-1).at(-1)
407
+ : last
408
+ const rem = hasBlock(body) ? body.at(-1) : body
409
+ const returns = isLeaf(rem) ? rem : rem[0]
410
+ return resolveRetunType(returns, rem, RETURNS)
411
+ }
412
+ const rightHand = rest.at(-1)
413
+ if (
414
+ rightHand &&
415
+ rightHand[0] &&
416
+ rightHand[0][TYPE] === APPLY &&
417
+ rightHand[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
418
+ ) {
419
+ const n = rightHand.length
420
+ env[name] = {
421
+ [STATS]: {
422
+ [TYPE_PROP]: [APPLY],
423
+ [SIGNATURE]: name,
424
+ retried: 0,
425
+ counter: 0,
426
+ [ARG_COUNT]: n - 2,
427
+ [ARGUMENTS]: fillUknownArgs(n - 2),
428
+ [RETURNS]: [UNKNOWN]
429
+ }
479
430
  }
480
- const rightHand = rest.at(-1)
481
431
  if (
482
- rightHand &&
483
- rightHand[0] &&
484
- rightHand[0][TYPE] === APPLY &&
485
- rightHand[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
432
+ !checkReturnType() ||
433
+ (isUnknownReturn(env[name][STATS]) &&
434
+ env[name][STATS].retried < MAX_RETRY_DEFINITION)
486
435
  ) {
487
- const n = rightHand.length
436
+ env[name][STATS].retried += 1
437
+ stack.unshift(() => {
438
+ checkReturnType()
439
+ check(rightHand, env, exp)
440
+ })
441
+ check(rightHand, env, exp)
442
+ } else check(rightHand, env, exp)
443
+ } else {
444
+ checkPredicateName(exp, rest, warningStack)
445
+ const isLeafNode = isLeaf(rightHand)
446
+ if (isLeafNode && rightHand[TYPE] === WORD) {
447
+ // TODO make sure this prevents the assigment all together
448
+ if (env[rest[1][VALUE]] === undefined)
449
+ errorStack.add(
450
+ `Trying to access undefined variable ${rest[1][VALUE]} (check #22)`
451
+ )
452
+
453
+ // Used to be checkin if it's an assigment to a special form
454
+ // but this should not cause problems
455
+ // env[name] = SPECIAL_FORMS_SET.has(rest[1][VALUE])
456
+ // ? structuredClone(env[rest[1][VALUE]])
457
+ // : env[rest[1][VALUE]]
458
+ // FULL REFF ASSIGMENT
459
+ env[name] = env[rest[1][VALUE]]
460
+ } else if (isLeafNode && rightHand[TYPE] === ATOM) {
461
+ // DECLARATION of ATOM
488
462
  env[name] = {
489
463
  [STATS]: {
490
- [TYPE_PROP]: [APPLY],
491
464
  [SIGNATURE]: name,
492
465
  retried: 0,
493
466
  counter: 0,
494
- // [VARIABLE_ORDER_INDEX]: env[ORDER],
495
- [ARG_COUNT]: n - 2,
496
- [ARGUMENTS]: fillUknownArgs(n - 2),
497
- [RETURNS]: [UNKNOWN]
467
+ [TYPE_PROP]: [ATOM],
468
+ [RETURNS]: [ATOM]
498
469
  }
499
470
  }
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)
471
+ } else if (rightHand[0]) {
472
+ const right = rightHand[0]
473
+ //DECLARATION
474
+ env[name] = {
475
+ [STATS]: {
476
+ retried: 0,
477
+ counter: 0,
478
+ [SIGNATURE]: name,
479
+ [TYPE_PROP]: [
480
+ isLeafNode
481
+ ? right[TYPE]
482
+ : env[right[VALUE]] == undefined
483
+ ? UNKNOWN
484
+ : env[right[VALUE]][STATS][RETURNS][0]
485
+ ],
486
+ [RETURNS]: [UNKNOWN]
571
487
  }
572
488
  }
573
- check(rightHand, env, scope)
489
+ const body = rightHand
490
+ const rem = hasBlock(body) ? body.at(-1) : body
491
+ const returns = isLeaf(rem) ? rem : rem[0]
492
+ resolveRetunType(returns, rem, TYPE_PROP)
574
493
  }
575
- Types.set(withScope(name, env), () => formatType(name, env))
494
+ check(rightHand, env, scope)
576
495
  }
577
- // root[ORDER]++
496
+ Types.set(withScope(name, env), () => formatType(name, env))
578
497
  }
579
498
  break
580
499
  case KEYWORDS.ANONYMOUS_FUNCTION:
581
- {
582
- if (exp.length === 1) {
583
- throw new TypeError(
584
- `Incorrect number of arguments for (${
500
+ if (exp.length === 1)
501
+ throw new TypeError(
502
+ `Incorrect number of arguments for (${
503
+ first[VALUE]
504
+ }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
505
+ exp
506
+ )})`
507
+ )
508
+ const params = exp.slice(1, -1)
509
+ const copy = Object.create(env)
510
+ if (Array.isArray(scope[1]) && scope[1][TYPE] === WORD)
511
+ copy[SCOPE_NAME] = scope[1][VALUE]
512
+ else copy[SCOPE_NAME] = ++scopeIndex
513
+ for (let i = 0; i < params.length; ++i) {
514
+ const param = params[i]
515
+ // TODO move this somewhere else
516
+ if (!isLeaf(param))
517
+ warningStack.add(
518
+ `Invalid body for (${
585
519
  first[VALUE]
586
- }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
587
- exp
588
- )})`
520
+ }) if it takes more than one expression it must be wrapped in a (${
521
+ KEYWORDS.BLOCK
522
+ }) (${stringifyArgs(exp)}) (check #666)`
589
523
  )
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
- )
609
- }
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
- }
524
+ copy[param[VALUE]] = {
525
+ [STATS]: {
526
+ [SIGNATURE]: param[VALUE],
527
+ [TYPE_PROP]: [UNKNOWN],
528
+ [RETURNS]: [UNKNOWN],
529
+ [ARGUMENTS]: [],
530
+ retried: 0,
531
+ counter: 0
619
532
  }
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]]
533
+ }
534
+ const ref = env[copy[SCOPE_NAME]]
535
+ if (!ref) continue
536
+ ref[STATS][ARGUMENTS][i] = copy[param[VALUE]]
537
+ const returns = deepLambdaReturn(
538
+ hasBlock(exp) ? exp.at(-1) : exp,
539
+ (result) => result[VALUE] !== KEYWORDS.IF
540
+ )
541
+ if (isLeaf(returns))
542
+ // TODO figure out what we do here
543
+ // this here is a variable WORD
544
+ // so return type of that function is that varible type
545
+ stack.push(
546
+ () =>
547
+ copy[returns[VALUE]] &&
548
+ setReturnToType(ref[STATS], copy[returns[VALUE]][STATS])
549
+ )
550
+ else {
551
+ const ret = returns[0]
552
+ switch (ret[VALUE]) {
553
+ case KEYWORDS.IF:
554
+ const re = returns.slice(2)
555
+ // If either is an ATOM then IF returns an ATOM
556
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM)
557
+ setReturnToAtom(ref[STATS])
558
+ // TODO check that both brancehs are predicates if one is
559
+ else {
560
+ const concequent = isLeaf(re[0])
561
+ ? copy[re[0][VALUE]]
562
+ : copy[re[0][0][VALUE]]
563
+ const alternative = isLeaf(re[1])
564
+ ? copy[re[1][VALUE]]
565
+ : copy[re[1][0][VALUE]]
651
566
 
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:
567
+ // todo check if condition matches alternative
568
+ // TODO make this more simple - it's so many different things just because types are functions or not
569
+ // WHY not consiter making return types for everything
570
+ if (
571
+ concequent &&
572
+ getType(concequent[STATS]) !== UNKNOWN
573
+ ) {
574
+ if (getType(concequent[STATS]) === APPLY)
575
+ setReturnRef(ref[STATS], concequent[STATS])
576
+ else ref[STATS][RETURNS] = concequent[STATS][TYPE_PROP]
577
+ } else if (
578
+ alternative &&
579
+ isUnknownType(alternative[STATS])
580
+ ) {
581
+ if (getType(alternative[STATS]) === APPLY)
582
+ setReturnRef(ref[STATS], alternative[STATS])
583
+ else setReturnToTypeRef(ref[STATS], alternative[STATS])
584
+ } else if (concequent) {
585
+ if (getType(concequent[STATS]) === APPLY)
586
+ setReturnRef(ref[STATS], concequent[STATS])
587
+ else setReturnToTypeRef(ref[STATS], concequent[STATS])
588
+ }
589
+ }
590
+ break
591
+ default:
592
+ if (copy[ret[VALUE]])
593
+ setReturnRef(ref[STATS], copy[ret[VALUE]][STATS])
594
+ else
595
+ stack.push(() => {
680
596
  if (copy[ret[VALUE]])
681
597
  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
- })
598
+ })
687
599
 
688
- break
689
- }
690
- }
691
- // TODO overwrite return type check here
600
+ break
692
601
  }
693
602
  }
694
- check(rest.at(-1), copy, copy)
603
+ // TODO overwrite return type check here
695
604
  }
605
+ check(rest.at(-1), copy, copy)
696
606
  break
697
607
  default:
698
608
  if (!STATIC_TYPES_SET.has(first[VALUE]))
@@ -705,7 +615,7 @@ export const typeCheck = (ast, error = true) => {
705
615
  env[first[VALUE]][STATS][TYPE_PROP][0] === APPLY &&
706
616
  env[first[VALUE]][STATS][ARG_COUNT] !== VARIADIC &&
707
617
  env[first[VALUE]][STATS][ARG_COUNT] !== rest.length
708
- ) {
618
+ )
709
619
  errorStack.add(
710
620
  `Incorrect number of arguments for (${
711
621
  first[VALUE]
@@ -715,21 +625,17 @@ export const typeCheck = (ast, error = true) => {
715
625
  exp
716
626
  )}) (check #15)`
717
627
  )
718
- } else {
628
+ else {
719
629
  if (first[TYPE] === APPLY && !isSpecial) {
720
- if (getType(env[first[VALUE]][STATS]) === ATOM) {
630
+ if (getType(env[first[VALUE]][STATS]) === ATOM)
721
631
  errorStack.add(
722
632
  `(${first[VALUE]}) is not a (lambda) (${stringifyArgs(
723
633
  exp
724
634
  )}) (check #12)`
725
635
  )
726
- } else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
636
+ else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
727
637
  // 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
638
  // FN ASSIGMENT
732
-
733
639
  // ASSIGMENT of paramaters of lambda that are a lambda
734
640
  // minus one to remove the body
735
641
  env[first[VALUE]][STATS][TYPE_PROP] = [APPLY]
@@ -751,7 +657,6 @@ export const typeCheck = (ast, error = true) => {
751
657
  }
752
658
  const ARG = isLeaf(rest[i]) ? rest[i] : rest[i][0]
753
659
  if (!env[ARG[VALUE]]) continue
754
- // console.log(stringifyArgs(exp), ARG)
755
660
  switch (ARG[TYPE]) {
756
661
  // THERE ARE NO ATOM ARGUMENTS
757
662
  // case ATOM:
@@ -793,7 +698,7 @@ export const typeCheck = (ast, error = true) => {
793
698
  if (isLeaf(rest[i].at(-1))) {
794
699
  const fnName = rest[i].at(-1)[VALUE]
795
700
  const fn = env[fnName]
796
- if (fn && getReturn(fn[STATS]) !== ATOM) {
701
+ if (fn && getReturn(fn[STATS]) !== ATOM)
797
702
  errorStack.add(
798
703
  `Incorrect type of argument (${i}) for (${
799
704
  first[VALUE]
@@ -803,13 +708,12 @@ export const typeCheck = (ast, error = true) => {
803
708
  getReturn(fn[STATS])
804
709
  )}) (${stringifyArgs(exp)}) (check #26)`
805
710
  )
806
- }
807
711
  } else {
808
712
  const body = rest[i].at(-1).at(-1)
809
713
  const rem = hasBlock(body) ? body.at(-1) : body
810
714
  const returns = isLeaf(rem) ? rem : rem[0]
811
715
  if (returns[TYPE] === ATOM) {
812
- if (MAIN_TYPE !== ATOM) {
716
+ if (MAIN_TYPE !== ATOM)
813
717
  errorStack.add(
814
718
  `Incorrect type of argument ${i} for (${
815
719
  first[VALUE]
@@ -819,12 +723,11 @@ export const typeCheck = (ast, error = true) => {
819
723
  ATOM
820
724
  )}) (${stringifyArgs(exp)}) (check #27)`
821
725
  )
822
- }
823
726
  } else if (
824
727
  env[returns[VALUE]] &&
825
728
  !isUnknownReturn(env[returns[VALUE]][STATS]) &&
826
729
  getReturn(env[returns[VALUE]][STATS]) !== ATOM
827
- ) {
730
+ )
828
731
  errorStack.add(
829
732
  `Incorrect type of argument ${i} for (${
830
733
  first[VALUE]
@@ -834,15 +737,11 @@ export const typeCheck = (ast, error = true) => {
834
737
  getReturn(env[returns[VALUE]][STATS])
835
738
  )}) (${stringifyArgs(exp)}) (check #29)`
836
739
  )
837
- }
838
740
  }
839
741
  }
840
742
  }
841
743
  const isCast = STATIC_TYPES_SET.has(first[VALUE])
842
744
  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
745
  if (!isRestILeaf) {
847
746
  const CAR = rest[i][0][VALUE]
848
747
  if (!env[CAR]) continue
@@ -853,7 +752,7 @@ export const typeCheck = (ast, error = true) => {
853
752
  expectedArgs[i][STATS],
854
753
  env[CAR][STATS]
855
754
  )
856
- ) {
755
+ )
857
756
  errorStack.add(
858
757
  `Incorrect type of argument (${i}) for special form (${
859
758
  first[VALUE]
@@ -863,22 +762,12 @@ export const typeCheck = (ast, error = true) => {
863
762
  getReturn(env[CAR][STATS])
864
763
  )}) (${stringifyArgs(exp)}) (check #1)`
865
764
  )
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
765
  } else if (!isKnown && !isCast) {
874
- if (env[CAR] && getType(env[CAR][STATS]) === APPLY) {
766
+ if (env[CAR] && getType(env[CAR][STATS]) === APPLY)
875
767
  switch (first[VALUE]) {
876
768
  case KEYWORDS.IF:
877
769
  break
878
- case KEYWORDS.CALL_FUNCTION:
879
- break
880
770
  default:
881
- // console.log(stringifyArgs(exp))
882
771
  // TODO fix this assigment
883
772
  // It turns out it's not possible to determine return type of function here
884
773
  // what if it's a global function used elsewhere where the return type mwould be different
@@ -889,8 +778,6 @@ export const typeCheck = (ast, error = true) => {
889
778
  )
890
779
  break
891
780
  }
892
- }
893
-
894
781
  // TODO also handle casting
895
782
  }
896
783
  } else {
@@ -906,7 +793,7 @@ export const typeCheck = (ast, error = true) => {
906
793
  expectedArgs[i][STATS],
907
794
  env[CAR][STATS]
908
795
  )
909
- ) {
796
+ )
910
797
  errorStack.add(
911
798
  `Incorrect type of argument (${i}) for special form (${
912
799
  first[VALUE]
@@ -916,7 +803,6 @@ export const typeCheck = (ast, error = true) => {
916
803
  getType(env[CAR][STATS])
917
804
  )}) (${stringifyArgs(exp)}) (check #3)`
918
805
  )
919
- }
920
806
  } else if (env[CAR]) {
921
807
  if (isCast) {
922
808
  // CAST assigment
@@ -942,7 +828,7 @@ export const typeCheck = (ast, error = true) => {
942
828
  if (
943
829
  rest[i][TYPE] !==
944
830
  expectedArgs[i][STATS][TYPE_PROP][0]
945
- ) {
831
+ )
946
832
  errorStack.add(
947
833
  `Incorrect type of argument (${i}) for special form (${
948
834
  first[VALUE]
@@ -952,7 +838,6 @@ export const typeCheck = (ast, error = true) => {
952
838
  rest[i][TYPE]
953
839
  )}) (${stringifyArgs(exp)}) (check #2)`
954
840
  )
955
- }
956
841
  break
957
842
  }
958
843
  }
@@ -1120,8 +1005,8 @@ export const typeCheck = (ast, error = true) => {
1120
1005
  if (
1121
1006
  !isUnknownType(expected) &&
1122
1007
  !isUnknownReturn(actual)
1123
- ) {
1124
- if (!compareTypeWithReturn(expected, actual)) {
1008
+ )
1009
+ if (!compareTypeWithReturn(expected, actual))
1125
1010
  errorStack.add(
1126
1011
  `Incorrect type of arguments ${i} for (${
1127
1012
  first[VALUE]
@@ -1131,7 +1016,7 @@ export const typeCheck = (ast, error = true) => {
1131
1016
  getReturn(actual)
1132
1017
  )}) (${stringifyArgs(exp)}) (check #16)`
1133
1018
  )
1134
- } else {
1019
+ else {
1135
1020
  switch (getType(expected)) {
1136
1021
  // almost exclusively for anonymous lambdas
1137
1022
  case APPLY:
@@ -1141,7 +1026,7 @@ export const typeCheck = (ast, error = true) => {
1141
1026
  env[rest[i][0][VALUE]][STATS][SIGNATURE] ===
1142
1027
  KEYWORDS.ANONYMOUS_FUNCTION
1143
1028
  ) {
1144
- if (argsN !== args[i][STATS][ARG_COUNT]) {
1029
+ if (argsN !== args[i][STATS][ARG_COUNT])
1145
1030
  errorStack.add(
1146
1031
  `Incorrect number of arguments for (${
1147
1032
  args[i][STATS][SIGNATURE]
@@ -1153,10 +1038,10 @@ export const typeCheck = (ast, error = true) => {
1153
1038
  exp
1154
1039
  )}) (check #777)`
1155
1040
  )
1156
- } else {
1041
+ else {
1157
1042
  // ANONYMOUS LAMBDAS TYPE CHECKING
1158
1043
  const local = Object.create(env)
1159
- const lambdaName = `lambda::annonymous::${i}`
1044
+ const lambdaName = `${ANONYMOUS_FUNCTION_TYPE_PREFIX}${i}::${++scopeIndex}`
1160
1045
  check(
1161
1046
  [
1162
1047
  [APPLY, KEYWORDS.DEFINE_VARIABLE],
@@ -1179,7 +1064,7 @@ export const typeCheck = (ast, error = true) => {
1179
1064
  expected[STATS],
1180
1065
  actual[STATS]
1181
1066
  )
1182
- ) {
1067
+ )
1183
1068
  errorStack.add(
1184
1069
  `Incorrect return type for (${
1185
1070
  expected[STATS][SIGNATURE]
@@ -1193,7 +1078,7 @@ export const typeCheck = (ast, error = true) => {
1193
1078
  exp
1194
1079
  )}) (check #779)`
1195
1080
  )
1196
- } else if (
1081
+ else if (
1197
1082
  actual[STATS].retried <
1198
1083
  MAX_RETRY_DEFINITION
1199
1084
  ) {
@@ -1221,7 +1106,7 @@ export const typeCheck = (ast, error = true) => {
1221
1106
  actual[STATS],
1222
1107
  expected[STATS]
1223
1108
  )
1224
- ) {
1109
+ )
1225
1110
  errorStack.add(
1226
1111
  `Incorrect type for (lambda) (${
1227
1112
  args[i][STATS][SIGNATURE]
@@ -1237,7 +1122,7 @@ export const typeCheck = (ast, error = true) => {
1237
1122
  exp
1238
1123
  )}) (check #780)`
1239
1124
  )
1240
- } else if (
1125
+ else if (
1241
1126
  actual[STATS].retried <
1242
1127
  MAX_RETRY_DEFINITION
1243
1128
  ) {
@@ -1258,7 +1143,7 @@ export const typeCheck = (ast, error = true) => {
1258
1143
  // break
1259
1144
  }
1260
1145
  }
1261
- } else if (
1146
+ else if (
1262
1147
  isUnknownType(expected) &&
1263
1148
  args[i][STATS].retried < MAX_RETRY_DEFINITION
1264
1149
  ) {
@@ -1273,8 +1158,8 @@ export const typeCheck = (ast, error = true) => {
1273
1158
  })
1274
1159
  for (let i = 0; i < rest.length; ++i) {
1275
1160
  const r = rest[i]
1276
- if (isLeaf(r) && r[TYPE] !== ATOM) {
1277
- if (env[r[VALUE]] == undefined) {
1161
+ if (isLeaf(r) && r[TYPE] !== ATOM)
1162
+ if (env[r[VALUE]] == undefined)
1278
1163
  errorStack.add(
1279
1164
  `(${
1280
1165
  first[VALUE]
@@ -1282,8 +1167,6 @@ export const typeCheck = (ast, error = true) => {
1282
1167
  r[VALUE]
1283
1168
  }) at argument (${i}) (${stringifyArgs(exp)}) (check #20)`
1284
1169
  )
1285
- }
1286
- }
1287
1170
  check(r, env, scope)
1288
1171
  }
1289
1172
  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,13 +15,11 @@ 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
15
21
  export const ANY = 5
16
-
22
+ export const ANONYMOUS_FUNCTION_TYPE_PREFIX = 'lambda::annonymous::'
17
23
  export const MAX_ARGUMENT_RETRY = 1
18
24
  export const MAX_RETRY_DEFINITION = 10
19
25
  export const toTypeNames = (type) => {
@@ -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]?.length
1171
+ ? stats[ARGUMENTS].map(
1172
+ (x, i) =>
1173
+ `${
1174
+ getType(x[STATS]) === APPLY
1175
+ ? `${formatType(i, stats[ARGUMENTS])}`
1176
+ : `${toTypeNames(getType(x[STATS]))}`
1177
+ }`
1178
+ ).join(' ') + ' '
1179
+ : ''
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
+ }