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