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