fez-lisp 1.5.94 → 1.5.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/check.js CHANGED
@@ -32,7 +32,9 @@ import {
32
32
  MAX_ARGUMENT_RETRY,
33
33
  COLLECTION,
34
34
  ANY,
35
- formatType
35
+ formatType,
36
+ ANONYMOUS_FUNCTION_TYPE_PREFIX,
37
+ validateLambda
36
38
  } from './types.js'
37
39
  import {
38
40
  getSuffix,
@@ -64,34 +66,40 @@ const deepLambdaReturn = (rest, condition) => {
64
66
  const rem = hasBlock(body) ? body.at(-1) : body
65
67
  return condition(rem) ? rem : deepLambdaReturn(rem, condition)
66
68
  }
69
+ export const castType = (stats, type) =>
70
+ (stats[TYPE_PROP][0] = type[RETURNS][0])
71
+ export const castReturn = (stats, type) =>
72
+ (stats[RETURNS][0] = type[RETURNS][0])
67
73
  export const isTypeAbstraction = (stats) => stats[TYPE_PROP] === APPLY
68
74
  export const setPropToAtom = (stats, prop) =>
69
75
  (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
70
76
  (stats[prop][0] = ATOM)
71
77
  export const setProp = (stats, prop, value) =>
72
- stats[prop][0] === UNKNOWN &&
78
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
73
79
  value[prop][0] !== UNKNOWN &&
74
80
  (stats[prop][0] = value[prop][0])
75
81
  export const setPropToReturn = (stats, prop, value) =>
76
- stats[prop][0] === UNKNOWN &&
82
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
77
83
  value[RETURNS][0] !== UNKNOWN &&
78
84
  (stats[prop][0] = value[RETURNS][0])
79
85
  export const setPropToReturnRef = (stats, prop, value) =>
80
- stats[prop][0] === UNKNOWN &&
86
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
81
87
  value[RETURNS][0] !== UNKNOWN &&
82
88
  (stats[prop] = value[RETURNS])
83
89
  export const setPropToType = (stats, prop, value) =>
84
- stats[prop][0] === UNKNOWN &&
90
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
85
91
  value[UNKNOWN][0] !== UNKNOWN &&
86
92
  (stats[prop][0] = value[UNKNOWN][0])
87
93
  export const setPropToTypeRef = (stats, prop, value) =>
88
- stats[prop][0] === UNKNOWN &&
94
+ (stats[prop][0] === UNKNOWN || stats[prop][0] === ANY) &&
89
95
  value[TYPE_PROP][0] !== UNKNOWN &&
90
96
  (stats[prop] = value[TYPE_PROP])
91
97
  export const setReturnToAtom = (stats) =>
92
- isUnknownReturn(stats) && (stats[RETURNS] = ATOM)
98
+ isUnknownReturn(stats) && (stats[RETURNS][0] = ATOM)
93
99
  export const setTypeToAtom = (stats) =>
94
- isUnknownType(stats) && (stats[TYPE_PROP] = ATOM)
100
+ isUnknownType(stats) && (stats[TYPE_PROP][0] = ATOM)
101
+ export const setReturnToAbbstraction = (stats) =>
102
+ isUnknownReturn(stats) && (stats[RETURNS][0] = APPLY)
95
103
  export const setTypeRef = (stats, value) =>
96
104
  isUnknownType(stats) && (stats[TYPE_PROP] = value[TYPE_PROP])
97
105
  export const setReturnRef = (stats, value) =>
@@ -134,13 +142,12 @@ export const compareReturns = (a, b) =>
134
142
  isAnyReturn(a) || isAnyReturn(b) || a[RETURNS][0] === b[RETURNS][0]
135
143
  export const compareTypeWithReturn = (a, b) =>
136
144
  isAnyType(a) || isAnyReturn(b) || a[TYPE_PROP][0] === b[RETURNS][0]
137
-
138
- const checkPredicateName = (exp, rest, warningStack) => {
145
+ const checkPredicateName = (exp, rest, errors) => {
139
146
  if (getSuffix(rest[0][VALUE]) === PREDICATE_SUFFIX) {
140
147
  const last = rest.at(-1)
141
148
  if (isLeaf(last)) {
142
149
  if (last[TYPE] === ATOM && last[VALUE] !== TRUE && last[VALUE] !== FALSE)
143
- warningStack.add(
150
+ errors.add(
144
151
  `Assigning predicate (ending in ?) variable (${
145
152
  rest[0][VALUE]
146
153
  }) to an (${
@@ -152,7 +159,7 @@ const checkPredicateName = (exp, rest, warningStack) => {
152
159
  getSuffix(last[VALUE]) !== PREDICATE_SUFFIX &&
153
160
  !PREDICATES_OUTPUT_SET.has(last[VALUE])
154
161
  )
155
- warningStack.add(
162
+ errors.add(
156
163
  `Assigning predicate (ending in ?) variable (${
157
164
  rest[0][VALUE]
158
165
  }) to another variable which is not a predicate (also ending in ?) (${stringifyArgs(
@@ -170,7 +177,7 @@ const checkPredicateName = (exp, rest, warningStack) => {
170
177
  getSuffix(application[VALUE]) !== PREDICATE_SUFFIX &&
171
178
  !PREDICATES_OUTPUT_SET.has(application[VALUE])
172
179
  )
173
- warningStack.add(
180
+ errors.add(
174
181
  `Assigning predicate (ending in ?) variable (${
175
182
  application[VALUE]
176
183
  }) to another variable which is not a predicate (also ending in ?) (${stringifyArgs(
@@ -182,7 +189,7 @@ const checkPredicateName = (exp, rest, warningStack) => {
182
189
  }
183
190
  }
184
191
  }
185
- const checkPredicateNameDeep = (name, exp, rest, returns, warningStack) => {
192
+ const checkPredicateNameDeep = (name, exp, rest, returns, errors) => {
186
193
  if (returns[VALUE] === KEYWORDS.CALL_FUNCTION) {
187
194
  const fn = rest.at(-1).at(-1).at(-1)
188
195
  checkPredicateName(
@@ -193,15 +200,12 @@ const checkPredicateNameDeep = (name, exp, rest, returns, warningStack) => {
193
200
  ? fn // when apply is a word (let x? (lambda (apply [] array:empty!)))
194
201
  : drillReturnType(fn, (r) => r[VALUE] === KEYWORDS.CALL_FUNCTION) // when apply is an annonymous lambda // (let fn? (lambda x (apply x (lambda x (array:empty! [])))))
195
202
  ],
196
- warningStack
203
+ errors
197
204
  )
198
205
  } else {
199
- checkPredicateName(exp, [[WORD, name], returns], warningStack)
206
+ checkPredicateName(exp, [[WORD, name], returns], errors)
200
207
  }
201
208
  }
202
- // const assign = (a, b, i) => {
203
- // a[i] = b[i]
204
- // }
205
209
  const fillUknownArgs = (n) =>
206
210
  Array.from({ length: n })
207
211
  .fill(null)
@@ -228,17 +232,182 @@ const getScopeNames = (scope) => {
228
232
  }
229
233
  const withScope = (name, scope) => {
230
234
  const chain = getScopeNames(scope)
231
- return `${chain.length === 1 ? '; ' : ''}${chain
232
- .map((x) => (Number.isInteger(+x) ? '::' : x))
233
- .join(' ')} ${name}`
235
+ return `${chain.length === 1 ? '; ' : ''}${chain.join(' ')} ${name}`
236
+ }
237
+
238
+ const ifExpression = ({ re, env, ref }) => {
239
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) setReturnToAtom(ref[STATS])
240
+ // TODO check that both brancehs are predicates if one is
241
+ else {
242
+ const concequent = isLeaf(re[0]) ? env[re[0][VALUE]] : env[re[0][0][VALUE]]
243
+ const alternative = isLeaf(re[1]) ? env[re[1][VALUE]] : env[re[1][0][VALUE]]
244
+ // todo check if condition matches alternative
245
+ // TODO make this more simple - it's so many different things just because types are functions or not
246
+ // WHY not consiter making return types for everything
247
+ if (concequent && getType(concequent[STATS]) !== UNKNOWN) {
248
+ if (getType(concequent[STATS]) === APPLY)
249
+ setReturnRef(ref[STATS], concequent[STATS])
250
+ else ref[STATS][RETURNS] = concequent[STATS][TYPE_PROP]
251
+ } else if (alternative && isUnknownType(alternative[STATS])) {
252
+ if (getType(alternative[STATS]) === APPLY)
253
+ setReturnRef(ref[STATS], alternative[STATS])
254
+ else setReturnToTypeRef(ref[STATS], alternative[STATS])
255
+ } else if (concequent) {
256
+ if (getType(concequent[STATS]) === APPLY)
257
+ setReturnRef(ref[STATS], concequent[STATS])
258
+ else setReturnToTypeRef(ref[STATS], concequent[STATS])
259
+ }
260
+ }
261
+ }
262
+ const resolveIfAssigment = ({ rem, name, env, exp, errors, prop }) => {
263
+ const re = rem.slice(2)
264
+ checkPredicateName(
265
+ exp,
266
+ [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
267
+ errors
268
+ )
269
+ checkPredicateName(
270
+ exp,
271
+ [[WORD, name], isLeaf(re[1]) ? re[1] : re[1][0]],
272
+ errors
273
+ )
274
+ if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM)
275
+ // ATOM ASSIGMENT
276
+ setPropToAtom(env[name][STATS], prop)
277
+ else if (
278
+ !isLeaf(re[0]) &&
279
+ env[re[0][0][VALUE]] &&
280
+ !isUnknownReturn(env[re[0][0][VALUE]][STATS])
281
+ ) {
282
+ setPropToReturnRef(env[name][STATS], prop, env[re[0][0][VALUE]][STATS])
283
+ if (re[0][0][TYPE] === APPLY) {
284
+ switch (re[0][0][VALUE]) {
285
+ case KEYWORDS.ANONYMOUS_FUNCTION:
286
+ // FN UKNONW ASSIGMENT
287
+ env[name][STATS][TYPE_PROP] = [APPLY]
288
+ env[name][STATS][RETURNS] = [UNKNOWN]
289
+ env[name][STATS][ARG_COUNT] = re[0].length - 2
290
+ env[name][STATS][ARGUMENTS] = fillUknownArgs(re[0].length - 2)
291
+ break
292
+ }
293
+ }
294
+ // env[name][STATS] = env[re[0][0][VALUE]][STATS]
295
+ } else if (
296
+ !isLeaf(re[1]) &&
297
+ env[re[1][0][VALUE]] &&
298
+ !isUnknownReturn(env[re[1][0][VALUE]][STATS])
299
+ ) {
300
+ setPropToReturnRef(env[name][STATS], prop, env[re[1][0][VALUE]][STATS])
301
+ if (re[1][0][TYPE] === APPLY) {
302
+ switch (re[1][0][VALUE]) {
303
+ case KEYWORDS.ANONYMOUS_FUNCTION:
304
+ // FN ASSIGMENT
305
+ env[name][STATS][TYPE_PROP] = [APPLY]
306
+ env[name][STATS][RETURNS] = [UNKNOWN]
307
+ env[name][STATS][ARG_COUNT] = re[1].length - 2
308
+ env[name][STATS][ARGUMENTS] = fillUknownArgs(re[1].length - 2)
309
+ break
310
+ }
311
+ }
312
+ } else if (env[re[0][VALUE]])
313
+ // ASSIGMENT
314
+ setPropRef(env[name][STATS], prop, env[re[0][VALUE]][STATS])
315
+ else if (env[re[1][VALUE]])
316
+ // ASSIGMENT
317
+ setPropRef(env[name][STATS], prop, env[re[1][VALUE]][STATS])
318
+ }
319
+ const resolveCondition = ({ rem, name, env, exp, errors }) => {
320
+ const ret = rem[0]
321
+ const re = rem.slice(2)
322
+ const ref = env[name]
323
+ checkPredicateName(
324
+ exp,
325
+ [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
326
+ errors
327
+ )
328
+ checkPredicateName(
329
+ exp,
330
+ [[WORD, name], isLeaf(re[1]) ? re[1] : re[1][0]],
331
+ errors
332
+ )
333
+ switch (ret[VALUE]) {
334
+ case KEYWORDS.IF:
335
+ ifExpression({ re, env, ref })
336
+ break
337
+ default:
338
+ if (env[ret[VALUE]]) setReturnRef(ref[STATS], env[ret[VALUE]][STATS])
339
+ else
340
+ stack.push(() => {
341
+ if (env[ret[VALUE]]) setReturnRef(ref[STATS], env[ret[VALUE]][STATS])
342
+ })
343
+ break
344
+ }
345
+ }
346
+ const resolveRetunType = ({
347
+ returns,
348
+ rem,
349
+ stack,
350
+ prop,
351
+ exp,
352
+ name,
353
+ errors,
354
+ env
355
+ }) => {
356
+ if (returns[TYPE] === ATOM) {
357
+ // ATOM ASSIGMENT
358
+ setPropToAtom(env[name][STATS], prop)
359
+ checkPredicateName(exp, [[WORD, name], returns], errors)
360
+ } else {
361
+ switch (returns[VALUE]) {
362
+ case KEYWORDS.IF:
363
+ resolveIfAssigment({ rem, name, env, exp, errors, prop })
364
+ break
365
+ default:
366
+ checkPredicateNameDeep(name, exp, exp.slice(1), returns, errors)
367
+ if (!env[returns[VALUE]]) return false
368
+ else if (getType(env[returns[VALUE]][STATS]) === APPLY) {
369
+ if (returns[TYPE] === WORD) setReturnToAbbstraction(env[name][STATS])
370
+ else {
371
+ // ALWAYS APPLY
372
+ // rest.at(-1)[0][TYPE] === APPLY
373
+ // Here is upon application to store the result in the variable
374
+ if (isUnknownType(env[name][STATS]))
375
+ stack.unshift(() => {
376
+ setTypeToReturn(env[name][STATS], env[returns[VALUE]][STATS])
377
+ // env[name][STATS][TYPE_PROP][0] =
378
+ // env[returns[VALUE]][STATS][RETURNS][0]
379
+ // this seems to be able to be deleted
380
+ // env[name][STATS][TYPE_PROP][1] =
381
+ // env[returns[VALUE]][STATS][RETURNS][1]
382
+ })
383
+ else setReturnRef(env[name][STATS], env[returns[VALUE]][STATS])
384
+ }
385
+ }
386
+ break
387
+ }
388
+ }
389
+ return true
390
+ }
391
+ const checkReturnType = ({ exp, stack, name, errors, env }) => {
392
+ const last = exp.at(-1).at(-1)
393
+ const body = hasApplyLambdaBlock(last) ? last.at(-1).at(-1) : last
394
+ const rem = hasBlock(body) ? body.at(-1) : body
395
+ const returns = isLeaf(rem) ? rem : rem[0]
396
+ return resolveRetunType({
397
+ returns,
398
+ rem,
399
+ prop: RETURNS,
400
+ exp,
401
+ name,
402
+ errors,
403
+ env,
404
+ stack
405
+ })
234
406
  }
235
407
  export const typeCheck = (ast, error = true) => {
236
408
  let scopeIndex = 0
237
409
  const root = structuredClone(SPECIAL_FORM_TYPES)
238
- const errorStack = new Set()
239
- const warningStack = new Set()
240
- // TODO delete this
241
- // const tempStack = new Set()
410
+ const errors = new Set()
242
411
  const Types = new Map()
243
412
  const stack = []
244
413
  const check = (exp, env, scope) => {
@@ -247,7 +416,8 @@ export const typeCheck = (ast, error = true) => {
247
416
  throw new TypeError(
248
417
  `(lambda) invocation with missing (Abstraction) name () Provide an (Abstraction) name as the (1) argument.`
249
418
  )
250
- const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
419
+ const isSpecial =
420
+ SPECIAL_FORMS_SET.has(first[VALUE]) || STATIC_TYPES_SET.has(first[VALUE])
251
421
  switch (first[TYPE]) {
252
422
  case WORD:
253
423
  if (!isSpecial)
@@ -255,7 +425,7 @@ export const typeCheck = (ast, error = true) => {
255
425
  () =>
256
426
  // Figure out how to determine if varible is define after it's used
257
427
  env[first[VALUE]] === undefined &&
258
- errorStack.add(
428
+ errors.add(
259
429
  `Trying to access undefined variable ${first[VALUE]} (check #11)`
260
430
  )
261
431
  )
@@ -276,133 +446,6 @@ export const typeCheck = (ast, error = true) => {
276
446
  else {
277
447
  const name = rest[0][VALUE]
278
448
  // 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(
290
- exp,
291
- [[WORD, name], isLeaf(re[0]) ? re[0] : re[0][0]],
292
- warningStack
293
- )
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)
302
- else if (
303
- !isLeaf(re[0]) &&
304
- env[re[0][0][VALUE]] &&
305
- !isUnknownReturn(env[re[0][0][VALUE]][STATS])
306
- ) {
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(
329
- env[name][STATS],
330
- prop,
331
- env[re[1][0][VALUE]][STATS]
332
- )
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
393
- }
394
- }
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
449
  const rightHand = rest.at(-1)
407
450
  if (
408
451
  rightHand &&
@@ -410,6 +453,7 @@ export const typeCheck = (ast, error = true) => {
410
453
  rightHand[0][TYPE] === APPLY &&
411
454
  rightHand[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
412
455
  ) {
456
+ validateLambda(rightHand, name)
413
457
  const n = rightHand.length
414
458
  env[name] = {
415
459
  [STATS]: {
@@ -423,24 +467,36 @@ export const typeCheck = (ast, error = true) => {
423
467
  }
424
468
  }
425
469
  if (
426
- !checkReturnType() ||
470
+ !checkReturnType({
471
+ stack,
472
+ exp,
473
+ env,
474
+ name,
475
+ errors
476
+ }) ||
427
477
  (isUnknownReturn(env[name][STATS]) &&
428
478
  env[name][STATS].retried < MAX_RETRY_DEFINITION)
429
479
  ) {
430
480
  env[name][STATS].retried += 1
431
481
  stack.unshift(() => {
432
- checkReturnType()
482
+ checkReturnType({
483
+ stack,
484
+ exp,
485
+ env,
486
+ name,
487
+ errors
488
+ })
433
489
  check(rightHand, env, exp)
434
490
  })
435
491
  check(rightHand, env, exp)
436
492
  } else check(rightHand, env, exp)
437
493
  } else {
438
- checkPredicateName(exp, rest, warningStack)
494
+ checkPredicateName(exp, rest, errors)
439
495
  const isLeafNode = isLeaf(rightHand)
440
496
  if (isLeafNode && rightHand[TYPE] === WORD) {
441
497
  // TODO make sure this prevents the assigment all together
442
498
  if (env[rest[1][VALUE]] === undefined)
443
- errorStack.add(
499
+ errors.add(
444
500
  `Trying to access undefined variable ${rest[1][VALUE]} (check #22)`
445
501
  )
446
502
 
@@ -483,7 +539,16 @@ export const typeCheck = (ast, error = true) => {
483
539
  const body = rightHand
484
540
  const rem = hasBlock(body) ? body.at(-1) : body
485
541
  const returns = isLeaf(rem) ? rem : rem[0]
486
- resolveRetunType(returns, rem, TYPE_PROP)
542
+ resolveRetunType({
543
+ stack,
544
+ returns,
545
+ rem,
546
+ prop: TYPE_PROP,
547
+ exp,
548
+ env,
549
+ name,
550
+ errors
551
+ })
487
552
  }
488
553
  check(rightHand, env, scope)
489
554
  }
@@ -491,14 +556,7 @@ export const typeCheck = (ast, error = true) => {
491
556
  }
492
557
  break
493
558
  case KEYWORDS.ANONYMOUS_FUNCTION:
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
- )
559
+ validateLambda(exp)
502
560
  const params = exp.slice(1, -1)
503
561
  const copy = Object.create(env)
504
562
  if (Array.isArray(scope[1]) && scope[1][TYPE] === WORD)
@@ -508,7 +566,7 @@ export const typeCheck = (ast, error = true) => {
508
566
  const param = params[i]
509
567
  // TODO move this somewhere else
510
568
  if (!isLeaf(param))
511
- warningStack.add(
569
+ errors.add(
512
570
  `Invalid body for (${
513
571
  first[VALUE]
514
572
  }) if it takes more than one expression it must be wrapped in a (${
@@ -543,44 +601,17 @@ export const typeCheck = (ast, error = true) => {
543
601
  )
544
602
  else {
545
603
  const ret = returns[0]
604
+
546
605
  switch (ret[VALUE]) {
547
606
  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
- }
607
+ resolveCondition({
608
+ rem: returns,
609
+ name: ref[STATS][SIGNATURE],
610
+ env: copy,
611
+ exp,
612
+ errors,
613
+ stack
614
+ })
584
615
  break
585
616
  default:
586
617
  if (copy[ret[VALUE]])
@@ -598,563 +629,550 @@ export const typeCheck = (ast, error = true) => {
598
629
  }
599
630
  check(rest.at(-1), copy, copy)
600
631
  break
632
+ case STATIC_TYPES.ABSTRACTION:
633
+ case STATIC_TYPES.COLLECTION:
634
+ case STATIC_TYPES.UNKNOWN:
635
+ case STATIC_TYPES.ATOM:
636
+ case STATIC_TYPES.PREDICATE:
637
+ case STATIC_TYPES.ANY:
638
+ {
639
+ const ret = isLeaf(rest[0]) ? rest[0] : rest[0][0]
640
+ const ref = env[ret[VALUE]]
641
+ if (!ref) break
642
+ const caster = root[first[VALUE]]
643
+ if (ret[TYPE] === APPLY && isUnknownReturn(ref[STATS]))
644
+ castReturn(ref[STATS], caster[STATS])
645
+ else if (isUnknownType(ref[STATS]))
646
+ castType(ref[STATS], caster[STATS])
647
+ check(rest[0], env, env)
648
+ }
649
+ break
601
650
  default:
602
- if (!STATIC_TYPES_SET.has(first[VALUE]))
603
- stack.push(() => {
604
- if (env[first[VALUE]] === undefined)
605
- errorStack.add(
606
- `Trying to call undefined (lambda) ${first[VALUE]} (check #9)`
607
- )
608
- else if (
609
- env[first[VALUE]][STATS][TYPE_PROP][0] === APPLY &&
610
- env[first[VALUE]][STATS][ARG_COUNT] !== VARIADIC &&
611
- env[first[VALUE]][STATS][ARG_COUNT] !== rest.length
651
+ stack.push(() => {
652
+ if (!isSpecial && env[first[VALUE]] === undefined)
653
+ errors.add(
654
+ `Trying to call undefined (lambda) ${first[VALUE]} (check #9)`
612
655
  )
613
- errorStack.add(
614
- `Incorrect number of arguments for (${
615
- first[VALUE]
616
- }). Expected (= ${
617
- env[first[VALUE]][STATS][ARG_COUNT]
618
- }) but got ${rest.length} (${stringifyArgs(
619
- exp
620
- )}) (check #15)`
621
- )
622
- else {
623
- if (first[TYPE] === APPLY && !isSpecial) {
624
- if (getType(env[first[VALUE]][STATS]) === ATOM)
625
- errorStack.add(
626
- `(${first[VALUE]}) is not a (lambda) (${stringifyArgs(
627
- exp
628
- )}) (check #12)`
629
- )
630
- else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
631
- // TODO recursively take return type of applicaion
632
- // FN ASSIGMENT
633
- // ASSIGMENT of paramaters of lambda that are a lambda
634
- // minus one to remove the body
635
- env[first[VALUE]][STATS][TYPE_PROP] = [APPLY]
636
- env[first[VALUE]][STATS][ARG_COUNT] = rest.length
637
- env[first[VALUE]][STATS][ARGUMENTS] = fillUknownArgs(
638
- rest.length
639
- )
640
- for (let i = 0; i < rest.length; ++i) {
641
- const arg = env[first[VALUE]][STATS][ARGUMENTS]
642
- arg[i] = {
643
- [STATS]: {
644
- retried: 0,
645
- [SIGNATURE]: PLACEHOLDER,
646
- [TYPE_PROP]: [UNKNOWN],
647
- [RETURNS]: [UNKNOWN],
648
- [ARGUMENTS]: [],
649
- [ARG_COUNT]: 0
650
- }
651
- }
652
- const ARG = isLeaf(rest[i]) ? rest[i] : rest[i][0]
653
- if (!env[ARG[VALUE]]) continue
654
- switch (ARG[TYPE]) {
655
- // THERE ARE NO ATOM ARGUMENTS
656
- // case ATOM:
657
- // break
658
- case APPLY:
659
- // passing arg asA APPLICATION
660
- if (isUnknownType(arg[i][STATS]))
661
- arg[i][STATS][TYPE_PROP] =
662
- env[ARG[VALUE]][STATS][RETURNS]
663
- break
664
- case WORD:
665
- // if param is a word we assosiate them by referanc
666
- if (isUnknownType(arg[i][STATS]))
667
- arg[i][STATS] = env[ARG[VALUE]][STATS]
668
- break
656
+ else if (
657
+ env[first[VALUE]][STATS][TYPE_PROP][0] === APPLY &&
658
+ env[first[VALUE]][STATS][ARG_COUNT] !== VARIADIC &&
659
+ env[first[VALUE]][STATS][ARG_COUNT] !== rest.length
660
+ )
661
+ errors.add(
662
+ `Incorrect number of arguments for (${
663
+ first[VALUE]
664
+ }). Expected (= ${
665
+ env[first[VALUE]][STATS][ARG_COUNT]
666
+ }) but got ${rest.length} (${stringifyArgs(exp)}) (check #15)`
667
+ )
668
+ else {
669
+ if (first[TYPE] === APPLY && !isSpecial) {
670
+ if (getType(env[first[VALUE]][STATS]) === ATOM)
671
+ errors.add(
672
+ `(${first[VALUE]}) is not a (lambda) (${stringifyArgs(
673
+ exp
674
+ )}) (check #12)`
675
+ )
676
+ else if (!env[first[VALUE]][STATS][ARG_COUNT]) {
677
+ // TODO recursively take return type of applicaion
678
+ // FN ASSIGMENT
679
+ // ASSIGMENT of paramaters of lambda that are a lambda
680
+ // minus one to remove the body
681
+ env[first[VALUE]][STATS][TYPE_PROP] = [APPLY]
682
+ env[first[VALUE]][STATS][ARG_COUNT] = rest.length
683
+ env[first[VALUE]][STATS][ARGUMENTS] = fillUknownArgs(
684
+ rest.length
685
+ )
686
+ for (let i = 0; i < rest.length; ++i) {
687
+ const arg = env[first[VALUE]][STATS][ARGUMENTS]
688
+ arg[i] = {
689
+ [STATS]: {
690
+ retried: 0,
691
+ [SIGNATURE]: PLACEHOLDER,
692
+ [TYPE_PROP]: [UNKNOWN],
693
+ [RETURNS]: [UNKNOWN],
694
+ [ARGUMENTS]: [],
695
+ [ARG_COUNT]: 0
669
696
  }
670
697
  }
698
+ const ARG = isLeaf(rest[i]) ? rest[i] : rest[i][0]
699
+ if (!env[ARG[VALUE]]) continue
700
+ switch (ARG[TYPE]) {
701
+ // THERE ARE NO ATOM ARGUMENTS
702
+ // case ATOM:
703
+ // break
704
+ case APPLY:
705
+ // passing arg asA APPLICATION
706
+ if (isUnknownType(arg[i][STATS]))
707
+ arg[i][STATS][TYPE_PROP] =
708
+ env[ARG[VALUE]][STATS][RETURNS]
709
+ break
710
+ case WORD:
711
+ // if param is a word we assosiate them by referanc
712
+ if (isUnknownType(arg[i][STATS]))
713
+ arg[i][STATS] = env[ARG[VALUE]][STATS]
714
+ break
715
+ }
671
716
  }
672
717
  }
673
- // also type of arg
674
- const args = env[first[VALUE]][STATS][ARGUMENTS] ?? []
675
- for (let i = 0; i < args.length; ++i) {
676
- const isRestILeaf = isLeaf(rest[i])
677
- // type check
678
- // TODO get rof pred type
679
- // const PRED_TYPE = args[i][STATS][TYPE_PROP][1]
680
- const MAIN_TYPE = getType(args[i][STATS])
681
- if (MAIN_TYPE === ANY) continue
682
- if (first[TYPE] === APPLY && isSpecial) {
718
+ }
719
+ // also type of arg
720
+ const args = env[first[VALUE]][STATS][ARGUMENTS] ?? []
721
+ for (let i = 0; i < args.length; ++i) {
722
+ const isRestILeaf = isLeaf(rest[i])
723
+ // type check
724
+ // TODO get rof pred type
725
+ // const PRED_TYPE = args[i][STATS][TYPE_PROP][1]
726
+ const MAIN_TYPE = getType(args[i][STATS])
727
+ if (MAIN_TYPE === ANY) continue
728
+ if (first[TYPE] === APPLY && isSpecial) {
729
+ if (
730
+ MAIN_TYPE === ATOM &&
731
+ PREDICATES_INPUT_SET.has(first[VALUE])
732
+ ) {
683
733
  if (
684
- MAIN_TYPE === ATOM &&
685
- PREDICATES_INPUT_SET.has(first[VALUE])
734
+ !isRestILeaf &&
735
+ rest[i][0][TYPE] === APPLY &&
736
+ rest[i][0][VALUE] === KEYWORDS.CALL_FUNCTION
686
737
  ) {
687
- if (
688
- !isRestILeaf &&
689
- rest[i][0][TYPE] === APPLY &&
690
- rest[i][0][VALUE] === KEYWORDS.CALL_FUNCTION
691
- ) {
692
- if (isLeaf(rest[i].at(-1))) {
693
- const fnName = rest[i].at(-1)[VALUE]
694
- const fn = env[fnName]
695
- if (fn && getReturn(fn[STATS]) !== ATOM)
696
- errorStack.add(
697
- `Incorrect type of argument (${i}) for (${
698
- first[VALUE]
699
- }). Expected (${toTypeNames(
700
- ATOM
701
- )}) but got an (${toTypeNames(
702
- getReturn(fn[STATS])
703
- )}) (${stringifyArgs(exp)}) (check #26)`
704
- )
705
- } else {
706
- const body = rest[i].at(-1).at(-1)
707
- const rem = hasBlock(body) ? body.at(-1) : body
708
- const returns = isLeaf(rem) ? rem : rem[0]
709
- if (returns[TYPE] === ATOM) {
710
- if (MAIN_TYPE !== ATOM)
711
- errorStack.add(
712
- `Incorrect type of argument ${i} for (${
713
- first[VALUE]
714
- }). Expected (${toTypeNames(
715
- MAIN_TYPE
716
- )}) but got an (${toTypeNames(
717
- ATOM
718
- )}) (${stringifyArgs(exp)}) (check #27)`
719
- )
720
- } else if (
721
- env[returns[VALUE]] &&
722
- !isUnknownReturn(env[returns[VALUE]][STATS]) &&
723
- getReturn(env[returns[VALUE]][STATS]) !== ATOM
738
+ if (isLeaf(rest[i].at(-1))) {
739
+ const fnName = rest[i].at(-1)[VALUE]
740
+ const fn = env[fnName]
741
+ if (fn && getReturn(fn[STATS]) !== ATOM)
742
+ errors.add(
743
+ `Incorrect type of argument (${i}) for (${
744
+ first[VALUE]
745
+ }). Expected (${toTypeNames(
746
+ ATOM
747
+ )}) but got an (${toTypeNames(
748
+ getReturn(fn[STATS])
749
+ )}) (${stringifyArgs(exp)}) (check #26)`
724
750
  )
725
- errorStack.add(
751
+ } else {
752
+ const body = rest[i].at(-1).at(-1)
753
+ const rem = hasBlock(body) ? body.at(-1) : body
754
+ const returns = isLeaf(rem) ? rem : rem[0]
755
+ if (returns[TYPE] === ATOM) {
756
+ if (MAIN_TYPE !== ATOM)
757
+ errors.add(
726
758
  `Incorrect type of argument ${i} for (${
727
759
  first[VALUE]
728
760
  }). Expected (${toTypeNames(
761
+ MAIN_TYPE
762
+ )}) but got an (${toTypeNames(
729
763
  ATOM
730
- )}) but got (${toTypeNames(
731
- getReturn(env[returns[VALUE]][STATS])
732
- )}) (${stringifyArgs(exp)}) (check #29)`
764
+ )}) (${stringifyArgs(exp)}) (check #27)`
733
765
  )
734
- }
735
- }
736
- }
737
- const isCast = STATIC_TYPES_SET.has(first[VALUE])
738
- const expectedArgs = env[first[VALUE]][STATS][ARGUMENTS]
739
- if (!isRestILeaf) {
740
- const CAR = rest[i][0][VALUE]
741
- if (!env[CAR]) continue
742
- const isKnown = !isUnknownReturn(env[CAR][STATS])
743
- if (isKnown && !isCast) {
744
- if (
745
- !compareTypeWithReturn(
746
- expectedArgs[i][STATS],
747
- env[CAR][STATS]
748
- )
766
+ } else if (
767
+ env[returns[VALUE]] &&
768
+ !isUnknownReturn(env[returns[VALUE]][STATS]) &&
769
+ getReturn(env[returns[VALUE]][STATS]) !== ATOM
749
770
  )
750
- errorStack.add(
751
- `Incorrect type of argument (${i}) for special form (${
771
+ errors.add(
772
+ `Incorrect type of argument ${i} for (${
752
773
  first[VALUE]
753
774
  }). Expected (${toTypeNames(
754
- getType(expectedArgs[i][STATS])
775
+ ATOM
755
776
  )}) but got (${toTypeNames(
756
- getReturn(env[CAR][STATS])
757
- )}) (${stringifyArgs(exp)}) (check #1)`
777
+ getReturn(env[returns[VALUE]][STATS])
778
+ )}) (${stringifyArgs(exp)}) (check #29)`
758
779
  )
759
- } else if (!isKnown && !isCast) {
760
- if (env[CAR] && getType(env[CAR][STATS]) === APPLY)
761
- switch (first[VALUE]) {
762
- case KEYWORDS.IF:
763
- break
764
- default:
765
- // TODO fix this assigment
766
- // It turns out it's not possible to determine return type of function here
767
- // what if it's a global function used elsewhere where the return type mwould be different
768
- // THIS willgive lambda return types but refactor is needed still
769
- setReturn(
770
- env[CAR][STATS],
771
- expectedArgs[i][STATS]
772
- )
773
- break
774
- }
775
- // TODO also handle casting
776
780
  }
777
- } else {
778
- switch (rest[i][TYPE]) {
779
- case WORD:
780
- {
781
- const CAR = rest[i][VALUE]
782
- if (!env[CAR]) continue
783
- const isKnown = !isUnknownType(env[CAR][STATS])
784
- if (isKnown && !isCast) {
785
- if (
786
- !compareTypes(
787
- expectedArgs[i][STATS],
788
- env[CAR][STATS]
789
- )
790
- )
791
- errorStack.add(
792
- `Incorrect type of argument (${i}) for special form (${
793
- first[VALUE]
794
- }). Expected (${toTypeNames(
795
- getType(expectedArgs[i][STATS])
796
- )}) but got (${toTypeNames(
797
- getType(env[CAR][STATS])
798
- )}) (${stringifyArgs(exp)}) (check #3)`
799
- )
800
- } else if (env[CAR]) {
801
- if (isCast) {
802
- // CAST assigment
803
- setTypeToReturn(
804
- env[rest[i][VALUE]][STATS],
805
- root[first[VALUE]][STATS]
806
- )
807
- // root[first[VALUE]][STATS][RETURNS] =
808
- // root[first[VALUE]][STATS][RETURNS]
809
- } else {
810
- // VALUE assigment
811
- setType(
812
- env[CAR][STATS],
813
- expectedArgs[i][STATS]
814
- )
815
- // env[CAR][STATS][TYPE_PROP][0] =
816
- // expectedArgs[i][STATS][TYPE_PROP][0]
817
- }
818
- }
819
- }
820
- break
821
- case ATOM: {
781
+ }
782
+ }
783
+ const expectedArgs = env[first[VALUE]][STATS][ARGUMENTS]
784
+ if (!isRestILeaf) {
785
+ const name = rest[i][0][VALUE]
786
+ if (!env[name]) continue
787
+ if (
788
+ !isUnknownReturn(env[name][STATS]) &&
789
+ !compareTypeWithReturn(
790
+ expectedArgs[i][STATS],
791
+ env[name][STATS]
792
+ )
793
+ )
794
+ errors.add(
795
+ `Incorrect type of argument (${i}) for special form (${
796
+ first[VALUE]
797
+ }). Expected (${toTypeNames(
798
+ getType(expectedArgs[i][STATS])
799
+ )}) but got (${toTypeNames(
800
+ getReturn(env[name][STATS])
801
+ )}) (${stringifyArgs(exp)}) (check #1)`
802
+ )
803
+ else {
804
+ if (env[name] && getType(env[name][STATS]) === APPLY)
805
+ switch (first[VALUE]) {
806
+ case KEYWORDS.IF:
807
+ break
808
+ default:
809
+ // TODO fix this assigment
810
+ // It turns out it's not possible to determine return type of function here
811
+ // what if it's a global function used elsewhere where the return type mwould be different
812
+ // THIS willgive lambda return types but refactor is needed still
813
+ setReturn(
814
+ env[name][STATS],
815
+ expectedArgs[i][STATS]
816
+ )
817
+ break
818
+ }
819
+ // TODO also handle casting
820
+ }
821
+ } else {
822
+ switch (rest[i][TYPE]) {
823
+ case WORD:
824
+ {
825
+ const name = rest[i][VALUE]
826
+ if (!env[name]) continue
822
827
  if (
823
- rest[i][TYPE] !==
824
- expectedArgs[i][STATS][TYPE_PROP][0]
828
+ !isUnknownType(env[name][STATS]) &&
829
+ !compareTypes(
830
+ expectedArgs[i][STATS],
831
+ env[name][STATS]
832
+ )
825
833
  )
826
- errorStack.add(
834
+ errors.add(
827
835
  `Incorrect type of argument (${i}) for special form (${
828
836
  first[VALUE]
829
837
  }). Expected (${toTypeNames(
830
- expectedArgs[i][STATS][TYPE_PROP][0]
838
+ getType(expectedArgs[i][STATS])
831
839
  )}) but got (${toTypeNames(
832
- rest[i][TYPE]
833
- )}) (${stringifyArgs(exp)}) (check #2)`
840
+ getType(env[name][STATS])
841
+ )}) (${stringifyArgs(exp)}) (check #3)`
834
842
  )
835
- break
843
+ else
844
+ setType(env[name][STATS], expectedArgs[i][STATS])
836
845
  }
846
+ break
847
+ case ATOM: {
848
+ if (
849
+ rest[i][TYPE] !==
850
+ expectedArgs[i][STATS][TYPE_PROP][0]
851
+ )
852
+ errors.add(
853
+ `Incorrect type of argument (${i}) for special form (${
854
+ first[VALUE]
855
+ }). Expected (${toTypeNames(
856
+ expectedArgs[i][STATS][TYPE_PROP][0]
857
+ )}) but got (${toTypeNames(
858
+ rest[i][TYPE]
859
+ )}) (${stringifyArgs(exp)}) (check #2)`
860
+ )
861
+ break
837
862
  }
838
863
  }
839
864
  }
840
- // type checking
841
- else if (isRestILeaf) {
842
- const T =
843
- rest[i][TYPE] === WORD
844
- ? env[rest[i][VALUE]]
845
- ? getType(env[rest[i][VALUE]][STATS])
846
- : UNKNOWN
847
- : rest[i][TYPE]
865
+ }
866
+ // type checking
867
+ else if (isRestILeaf) {
868
+ const T =
869
+ rest[i][TYPE] === WORD
870
+ ? env[rest[i][VALUE]]
871
+ ? getType(env[rest[i][VALUE]][STATS])
872
+ : UNKNOWN
873
+ : rest[i][TYPE]
874
+ if (
875
+ T === ATOM &&
876
+ !isUnknownType(args[i][STATS]) &&
877
+ getType(args[i][STATS]) !== ATOM
878
+ ) {
879
+ errors.add(
880
+ `Incorrect type of arguments ${i} for (${
881
+ first[VALUE]
882
+ }). Expected (${toTypeNames(
883
+ getType(args[i][STATS])
884
+ )}) but got (${toTypeNames(T)}) (${stringifyArgs(
885
+ exp
886
+ )}) (check #10)`
887
+ )
888
+ } else if (
889
+ T === APPLY &&
890
+ !isUnknownType(args[i][STATS]) &&
891
+ !isUnknownType(env[rest[i][VALUE]][STATS]) &&
892
+ env[rest[i][VALUE]][STATS][ARG_COUNT] !== VARIADIC
893
+ ) {
894
+ // Handles words that are Lambdas
848
895
  if (
849
- T === ATOM &&
850
- !isUnknownType(args[i][STATS]) &&
851
- getType(args[i][STATS]) !== ATOM
896
+ env[rest[i][VALUE]][STATS][ARG_COUNT] !==
897
+ args[i][STATS][ARG_COUNT]
852
898
  ) {
853
- errorStack.add(
854
- `Incorrect type of arguments ${i} for (${
899
+ errors.add(
900
+ `Incorrect number of arguments for (${
901
+ args[i][STATS][SIGNATURE]
902
+ }) the (lambda) argument of (${
855
903
  first[VALUE]
856
- }). Expected (${toTypeNames(
857
- getType(args[i][STATS])
858
- )}) but got (${toTypeNames(T)}) (${stringifyArgs(
859
- exp
860
- )}) (check #10)`
904
+ }) at position (${i}). Expected (= ${
905
+ args[i][STATS][ARG_COUNT]
906
+ }) but got ${
907
+ env[rest[i][VALUE]][STATS][ARG_COUNT]
908
+ } (${stringifyArgs(exp)}) (check #778)`
861
909
  )
862
- } else if (
863
- T === APPLY &&
864
- !isUnknownType(args[i][STATS]) &&
865
- !isUnknownType(env[rest[i][VALUE]][STATS]) &&
866
- env[rest[i][VALUE]][STATS][ARG_COUNT] !== VARIADIC
867
- ) {
868
- // Handles words that are Lambdas
869
- if (
870
- env[rest[i][VALUE]][STATS][ARG_COUNT] !==
871
- args[i][STATS][ARG_COUNT]
910
+ } else {
911
+ // DEFINED LAMBDAS TYPE CHECKING
912
+ // #C1
913
+ // TODO delete this maybe
914
+ // It will not be possilbe to know return type
915
+ const match1 = () => {
916
+ const actual = env[rest[i][VALUE]]
917
+ const expected = args[i]
918
+ if (
919
+ !isUnknownReturn(expected[STATS]) &&
920
+ !isUnknownReturn(actual[STATS]) &&
921
+ !compareReturns(expected[STATS], actual[STATS])
922
+ ) {
923
+ errors.add(
924
+ `Incorrect return type for (${
925
+ expected[STATS][SIGNATURE]
926
+ }) the (lambda) argument of (${
927
+ first[VALUE]
928
+ }) at position (${i}). Expected (${toTypeNames(
929
+ getReturn(expected[STATS])
930
+ )}) but got (${toTypeNames(
931
+ getReturn(actual[STATS])
932
+ )}) (${stringifyArgs(exp)}) (check #782)`
933
+ )
934
+ } else if (
935
+ actual[STATS].retried < MAX_RETRY_DEFINITION
936
+ ) {
937
+ actual[STATS].retried += 1
938
+ stack.unshift(() => match1())
939
+ }
940
+ }
941
+ match1()
942
+ for (
943
+ let j = 0;
944
+ j < args[i][STATS][ARGUMENTS].length;
945
+ ++j
872
946
  ) {
873
- errorStack.add(
874
- `Incorrect number of arguments for (${
875
- args[i][STATS][SIGNATURE]
876
- }) the (lambda) argument of (${
877
- first[VALUE]
878
- }) at position (${i}). Expected (= ${
879
- args[i][STATS][ARG_COUNT]
880
- }) but got ${
881
- env[rest[i][VALUE]][STATS][ARG_COUNT]
882
- } (${stringifyArgs(exp)}) (check #778)`
883
- )
884
- } else {
885
- // DEFINED LAMBDAS TYPE CHECKING
886
- // #C1
887
- // TODO delete this maybe
888
- // It will not be possilbe to know return type
889
- const match1 = () => {
890
- const actual = env[rest[i][VALUE]]
891
- const expected = args[i]
947
+ const match2 = () => {
948
+ const actual =
949
+ env[rest[i][VALUE]][STATS][ARGUMENTS][j]
950
+ const expected = args[i][STATS][ARGUMENTS][j]
892
951
  if (
893
- !isUnknownReturn(expected[STATS]) &&
894
- !isUnknownReturn(actual[STATS]) &&
895
- !compareReturns(expected[STATS], actual[STATS])
896
- ) {
897
- errorStack.add(
898
- `Incorrect return type for (${
899
- expected[STATS][SIGNATURE]
900
- }) the (lambda) argument of (${
901
- first[VALUE]
902
- }) at position (${i}). Expected (${toTypeNames(
903
- getReturn(expected[STATS])
952
+ !isUnknownType(actual[STATS]) &&
953
+ !isUnknownType(expected[STATS]) &&
954
+ !compareTypes(actual[STATS], expected[STATS])
955
+ )
956
+ errors.add(
957
+ `Incorrect type for (lambda) (${
958
+ args[i][STATS][SIGNATURE]
959
+ }) argument at position (${j}) named as (${
960
+ actual[STATS][SIGNATURE]
961
+ }). Expected (${toTypeNames(
962
+ getType(expected[STATS])
904
963
  )}) but got (${toTypeNames(
905
- getReturn(actual[STATS])
906
- )}) (${stringifyArgs(exp)}) (check #782)`
964
+ getType(actual[STATS])
965
+ )}) (${stringifyArgs(exp)}) (check #781)`
907
966
  )
908
- } else if (
967
+ else if (
909
968
  actual[STATS].retried < MAX_RETRY_DEFINITION
910
969
  ) {
911
970
  actual[STATS].retried += 1
912
- stack.unshift(() => match1())
971
+ stack.unshift(() => match2())
913
972
  }
914
973
  }
915
- match1()
916
- for (
917
- let j = 0;
918
- j < args[i][STATS][ARGUMENTS].length;
919
- ++j
920
- ) {
921
- const match2 = () => {
922
- const actual =
923
- env[rest[i][VALUE]][STATS][ARGUMENTS][j]
924
- const expected = args[i][STATS][ARGUMENTS][j]
925
- if (
926
- !isUnknownType(actual[STATS]) &&
927
- !isUnknownType(expected[STATS]) &&
928
- !compareTypes(actual[STATS], expected[STATS])
929
- )
930
- errorStack.add(
931
- `Incorrect type for (lambda) (${
932
- args[i][STATS][SIGNATURE]
933
- }) argument at position (${j}) named as (${
934
- actual[STATS][SIGNATURE]
935
- }). Expected (${toTypeNames(
936
- getType(expected[STATS])
937
- )}) but got (${toTypeNames(
938
- getType(actual[STATS])
939
- )}) (${stringifyArgs(exp)}) (check #781)`
940
- )
941
- else if (
942
- actual[STATS].retried < MAX_RETRY_DEFINITION
943
- ) {
944
- actual[STATS].retried += 1
945
- stack.unshift(() => match2())
946
- }
947
- }
948
- match2()
949
- }
974
+ match2()
950
975
  }
951
976
  }
977
+ }
978
+ if (
979
+ T === COLLECTION &&
980
+ env[rest[i][VALUE]] &&
981
+ !isUnknownType(env[rest[i][VALUE]][STATS]) &&
982
+ !isUnknownType(args[i][STATS]) &&
983
+ !compareTypes(env[rest[i][VALUE]][STATS], args[i][STATS])
984
+ ) {
985
+ errors.add(
986
+ `Incorrect type of arguments ${i} for (${
987
+ first[VALUE]
988
+ }). Expected (${toTypeNames(
989
+ getType(args[i][STATS])
990
+ )}) but got (${toTypeNames(T)}) (${stringifyArgs(
991
+ exp
992
+ )}) (check #30)`
993
+ )
994
+ } else if (
995
+ isUnknownType(args[i][STATS]) &&
996
+ args[i][STATS].retried < MAX_RETRY_DEFINITION
997
+ ) {
998
+ args[i][STATS].retried += 1
999
+ stack.unshift(() => check(exp, env, scope))
1000
+ } else {
952
1001
  if (
953
- T === COLLECTION &&
954
1002
  env[rest[i][VALUE]] &&
955
- !isUnknownType(env[rest[i][VALUE]][STATS]) &&
956
1003
  !isUnknownType(args[i][STATS]) &&
957
- !compareTypes(
958
- env[rest[i][VALUE]][STATS],
959
- args[i][STATS]
960
- )
1004
+ isUnknownType(env[rest[i][VALUE]][STATS]) &&
1005
+ getType(args[i][STATS]) !== APPLY
961
1006
  ) {
962
- errorStack.add(
963
- `Incorrect type of arguments ${i} for (${
964
- first[VALUE]
965
- }). Expected (${toTypeNames(
966
- getType(args[i][STATS])
967
- )}) but got (${toTypeNames(T)}) (${stringifyArgs(
968
- exp
969
- )}) (check #30)`
970
- )
971
- } else if (
972
- isUnknownType(args[i][STATS]) &&
973
- args[i][STATS].retried < MAX_RETRY_DEFINITION
974
- ) {
975
- args[i][STATS].retried += 1
976
- stack.unshift(() => check(exp, env, scope))
977
- } else {
978
- if (
979
- env[rest[i][VALUE]] &&
980
- !isUnknownType(args[i][STATS]) &&
981
- isUnknownType(env[rest[i][VALUE]][STATS]) &&
982
- getType(args[i][STATS]) !== APPLY
983
- ) {
984
- // REFF ASSIGMENT
985
- env[rest[i][VALUE]][STATS][TYPE_PROP] =
986
- args[i][STATS][TYPE_PROP]
987
- env[rest[i][VALUE]][STATS][RETURNS] =
988
- args[i][STATS][RETURNS]
989
- }
1007
+ // REFF ASSIGMENT
1008
+ env[rest[i][VALUE]][STATS][TYPE_PROP] =
1009
+ args[i][STATS][TYPE_PROP]
1010
+ env[rest[i][VALUE]][STATS][RETURNS] =
1011
+ args[i][STATS][RETURNS]
990
1012
  }
991
- } else if (env[rest[i][0][VALUE]]) {
992
- const match = () => {
993
- const actual = env[rest[i][0][VALUE]][STATS]
994
- const expected = args[i][STATS]
995
- if (args[i][STATS].counter < MAX_ARGUMENT_RETRY) {
996
- args[i][STATS].counter++
997
- stack.unshift(() => match())
998
- }
999
- if (
1000
- !isUnknownType(expected) &&
1001
- !isUnknownReturn(actual)
1002
- )
1003
- if (!compareTypeWithReturn(expected, actual))
1004
- errorStack.add(
1005
- `Incorrect type of arguments ${i} for (${
1006
- first[VALUE]
1007
- }). Expected (${toTypeNames(
1008
- getType(expected)
1009
- )}) but got (${toTypeNames(
1010
- getReturn(actual)
1011
- )}) (${stringifyArgs(exp)}) (check #16)`
1012
- )
1013
- else {
1014
- switch (getType(expected)) {
1015
- // almost exclusively for anonymous lambdas
1016
- case APPLY:
1017
- {
1018
- const argsN = rest[i].length - 2
1019
- if (
1020
- env[rest[i][0][VALUE]][STATS][SIGNATURE] ===
1021
- KEYWORDS.ANONYMOUS_FUNCTION
1022
- ) {
1023
- if (argsN !== args[i][STATS][ARG_COUNT])
1024
- errorStack.add(
1025
- `Incorrect number of arguments for (${
1026
- args[i][STATS][SIGNATURE]
1027
- }) the (lambda) argument of (${
1028
- first[VALUE]
1029
- }) at position (${i}). Expected (= ${
1030
- args[i][STATS][ARG_COUNT]
1031
- }) but got ${argsN} (${stringifyArgs(
1032
- exp
1033
- )}) (check #777)`
1034
- )
1035
- else {
1036
- // ANONYMOUS LAMBDAS TYPE CHECKING
1037
- const local = Object.create(env)
1038
- const lambdaName = `lambda::annonymous::${i}`
1039
- check(
1040
- [
1041
- [APPLY, KEYWORDS.DEFINE_VARIABLE],
1042
- [WORD, lambdaName],
1043
- rest[i]
1044
- ],
1045
- local,
1046
- scope
1013
+ }
1014
+ } else if (env[rest[i][0][VALUE]]) {
1015
+ const match = () => {
1016
+ const actual = env[rest[i][0][VALUE]][STATS]
1017
+ const expected = args[i][STATS]
1018
+ if (args[i][STATS].counter < MAX_ARGUMENT_RETRY) {
1019
+ args[i][STATS].counter++
1020
+ stack.unshift(() => match())
1021
+ }
1022
+ if (!isUnknownType(expected) && !isUnknownReturn(actual))
1023
+ if (!compareTypeWithReturn(expected, actual))
1024
+ errors.add(
1025
+ `Incorrect type of arguments ${i} for (${
1026
+ first[VALUE]
1027
+ }). Expected (${toTypeNames(
1028
+ getType(expected)
1029
+ )}) but got (${toTypeNames(
1030
+ getReturn(actual)
1031
+ )}) (${stringifyArgs(exp)}) (check #16)`
1032
+ )
1033
+ else {
1034
+ switch (getType(expected)) {
1035
+ // almost exclusively for anonymous lambdas
1036
+ case APPLY:
1037
+ {
1038
+ const argsN = rest[i].length - 2
1039
+ if (
1040
+ env[rest[i][0][VALUE]][STATS][SIGNATURE] ===
1041
+ KEYWORDS.ANONYMOUS_FUNCTION
1042
+ ) {
1043
+ if (argsN !== args[i][STATS][ARG_COUNT])
1044
+ errors.add(
1045
+ `Incorrect number of arguments for (${
1046
+ args[i][STATS][SIGNATURE]
1047
+ }) the (lambda) argument of (${
1048
+ first[VALUE]
1049
+ }) at position (${i}). Expected (= ${
1050
+ args[i][STATS][ARG_COUNT]
1051
+ }) but got ${argsN} (${stringifyArgs(
1052
+ exp
1053
+ )}) (check #777)`
1054
+ )
1055
+ else {
1056
+ // ANONYMOUS LAMBDAS TYPE CHECKING
1057
+ const local = Object.create(env)
1058
+ const lambdaName = `${ANONYMOUS_FUNCTION_TYPE_PREFIX}${i}::${++scopeIndex}`
1059
+ check(
1060
+ [
1061
+ [APPLY, KEYWORDS.DEFINE_VARIABLE],
1062
+ [WORD, lambdaName],
1063
+ rest[i]
1064
+ ],
1065
+ local,
1066
+ scope
1067
+ )
1068
+ // TODO delete this maybe
1069
+ // #C2
1070
+ // It will not be possilbe to know return type
1071
+ const match1 = () => {
1072
+ const actual = local[lambdaName]
1073
+ const expected = args[i]
1074
+ if (
1075
+ !isUnknownReturn(expected[STATS]) &&
1076
+ !isUnknownReturn(actual[STATS]) &&
1077
+ !compareReturns(
1078
+ expected[STATS],
1079
+ actual[STATS]
1080
+ )
1047
1081
  )
1048
- // TODO delete this maybe
1049
- // #C2
1050
- // It will not be possilbe to know return type
1051
- const match1 = () => {
1052
- const actual = local[lambdaName]
1053
- const expected = args[i]
1082
+ errors.add(
1083
+ `Incorrect return type for (${
1084
+ expected[STATS][SIGNATURE]
1085
+ }) the (lambda) argument of (${
1086
+ first[VALUE]
1087
+ }) at position (${i}). Expected (${toTypeNames(
1088
+ getReturn(expected[STATS])
1089
+ )}) but got (${toTypeNames(
1090
+ getReturn(actual[STATS])
1091
+ )}) (${stringifyArgs(
1092
+ exp
1093
+ )}) (check #779)`
1094
+ )
1095
+ else if (
1096
+ actual[STATS].retried <
1097
+ MAX_RETRY_DEFINITION
1098
+ ) {
1099
+ actual[STATS].retried += 1
1100
+ stack.unshift(() => match1())
1101
+ }
1102
+ }
1103
+ match1()
1104
+ for (
1105
+ let j = 0;
1106
+ j < args[i][STATS][ARGUMENTS].length;
1107
+ ++j
1108
+ ) {
1109
+ const match2 = () => {
1110
+ const actual =
1111
+ local[lambdaName][STATS][ARGUMENTS][j]
1112
+ const expected =
1113
+ args[i][STATS][ARGUMENTS][j]
1054
1114
  if (
1055
- !isUnknownReturn(expected[STATS]) &&
1056
- !isUnknownReturn(actual[STATS]) &&
1057
- !compareReturns(
1058
- expected[STATS],
1059
- actual[STATS]
1115
+ !isUnknownType(actual[STATS]) &&
1116
+ !isUnknownType(expected[STATS]) &&
1117
+ !compareTypes(
1118
+ actual[STATS],
1119
+ expected[STATS]
1060
1120
  )
1061
1121
  )
1062
- errorStack.add(
1063
- `Incorrect return type for (${
1064
- expected[STATS][SIGNATURE]
1065
- }) the (lambda) argument of (${
1066
- first[VALUE]
1067
- }) at position (${i}). Expected (${toTypeNames(
1068
- getReturn(expected[STATS])
1122
+ errors.add(
1123
+ `Incorrect type for (lambda) (${
1124
+ args[i][STATS][SIGNATURE]
1125
+ }) argument at position (${j}) named as (${
1126
+ local[lambdaName][STATS][
1127
+ ARGUMENTS
1128
+ ][j][STATS][SIGNATURE]
1129
+ }). Expected (${toTypeNames(
1130
+ getType(expected[STATS])
1069
1131
  )}) but got (${toTypeNames(
1070
- getReturn(actual[STATS])
1132
+ getType(actual[STATS])
1071
1133
  )}) (${stringifyArgs(
1072
1134
  exp
1073
- )}) (check #779)`
1135
+ )}) (check #780)`
1074
1136
  )
1075
1137
  else if (
1076
1138
  actual[STATS].retried <
1077
1139
  MAX_RETRY_DEFINITION
1078
1140
  ) {
1079
1141
  actual[STATS].retried += 1
1080
- stack.unshift(() => match1())
1081
- }
1082
- }
1083
- match1()
1084
- for (
1085
- let j = 0;
1086
- j < args[i][STATS][ARGUMENTS].length;
1087
- ++j
1088
- ) {
1089
- const match2 = () => {
1090
- const actual =
1091
- local[lambdaName][STATS][ARGUMENTS][
1092
- j
1093
- ]
1094
- const expected =
1095
- args[i][STATS][ARGUMENTS][j]
1096
- if (
1097
- !isUnknownType(actual[STATS]) &&
1098
- !isUnknownType(expected[STATS]) &&
1099
- !compareTypes(
1100
- actual[STATS],
1101
- expected[STATS]
1102
- )
1103
- )
1104
- errorStack.add(
1105
- `Incorrect type for (lambda) (${
1106
- args[i][STATS][SIGNATURE]
1107
- }) argument at position (${j}) named as (${
1108
- local[lambdaName][STATS][
1109
- ARGUMENTS
1110
- ][j][STATS][SIGNATURE]
1111
- }). Expected (${toTypeNames(
1112
- getType(expected[STATS])
1113
- )}) but got (${toTypeNames(
1114
- getType(actual[STATS])
1115
- )}) (${stringifyArgs(
1116
- exp
1117
- )}) (check #780)`
1118
- )
1119
- else if (
1120
- actual[STATS].retried <
1121
- MAX_RETRY_DEFINITION
1122
- ) {
1123
- actual[STATS].retried += 1
1124
- stack.unshift(() => match2())
1125
- }
1142
+ stack.unshift(() => match2())
1126
1143
  }
1127
- match2()
1128
1144
  }
1145
+ match2()
1129
1146
  }
1130
- } else {
1131
- // TODO fix curry: lambdas enter here as undefined
1132
1147
  }
1148
+ } else {
1149
+ // TODO fix curry: lambdas enter here as undefined
1133
1150
  }
1134
- break
1135
- // case ATOM:
1136
- // case COLLECTION:
1137
- // break
1138
- }
1151
+ }
1152
+ break
1153
+ // case ATOM:
1154
+ // case COLLECTION:
1155
+ // break
1139
1156
  }
1140
- else if (
1141
- isUnknownType(expected) &&
1142
- args[i][STATS].retried < MAX_RETRY_DEFINITION
1143
- ) {
1144
- args[i][STATS].retried += 1
1145
- stack.unshift(() => match())
1146
1157
  }
1158
+ else if (
1159
+ isUnknownType(expected) &&
1160
+ args[i][STATS].retried < MAX_RETRY_DEFINITION
1161
+ ) {
1162
+ args[i][STATS].retried += 1
1163
+ stack.unshift(() => match())
1147
1164
  }
1148
- match()
1149
1165
  }
1166
+ match()
1150
1167
  }
1151
1168
  }
1152
- })
1169
+ }
1170
+ })
1153
1171
  for (let i = 0; i < rest.length; ++i) {
1154
1172
  const r = rest[i]
1155
1173
  if (isLeaf(r) && r[TYPE] !== ATOM)
1156
1174
  if (env[r[VALUE]] == undefined)
1157
- errorStack.add(
1175
+ errors.add(
1158
1176
  `(${
1159
1177
  first[VALUE]
1160
1178
  }) is trying to access undefined variable (${
@@ -1171,10 +1189,7 @@ export const typeCheck = (ast, error = true) => {
1171
1189
  const copy = JSON.parse(JSON.stringify(ast))
1172
1190
  check(copy, root, copy)
1173
1191
  while (stack.length) stack.pop()()
1174
- if (error) {
1175
- const issues = [...errorStack, ...warningStack]
1176
- if (issues.length) throw new TypeError(issues.join('\n'))
1177
- }
1192
+ if (error && errors.size) throw new TypeError([...errors.values()].join('\n'))
1178
1193
  return [ast, Types]
1179
1194
  }
1180
1195
  export const type = (ast) => typeCheck(ast)[0]