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