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