fez-lisp 1.4.0 → 1.4.1
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/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/compiler.js +1 -1
- package/src/evaluator.js +2 -14
- package/src/interpreter.js +5 -3
- package/src/parser.js +2 -2
- package/src/utils.js +19 -49
package/package.json
CHANGED
package/src/compiler.js
CHANGED
@@ -116,7 +116,7 @@ const Helpers = {
|
|
116
116
|
length: 'length=(arr)=>arr.length',
|
117
117
|
__tco: `__tco=fn=>(...args)=>{let result=fn(...args);while(typeof result==='function')result=result();return result}`,
|
118
118
|
atom_predicate: `atom_predicate=(number)=>+(typeof number==='number')`,
|
119
|
-
lambda_predicate: `lambda_predicate=(
|
119
|
+
lambda_predicate: `lambda_predicate=(fn)=>+(typeof fn==='function')`,
|
120
120
|
set_effect: `set_effect=function(array,index,value){if(arguments.length===1){array.pop()}else{array[index] = value};return array}`
|
121
121
|
}
|
122
122
|
const semiColumnEdgeCases = new Set([
|
package/src/evaluator.js
CHANGED
@@ -9,11 +9,7 @@ import {
|
|
9
9
|
WORD
|
10
10
|
} from './keywords.js'
|
11
11
|
import { isLeaf } from './parser.js'
|
12
|
-
import { stringifyArgs } from './utils.js'
|
13
|
-
export const DEFAULT_MAXIMUM_FUNCTION_CALLS = 262144
|
14
|
-
export const MAXIMUM_FUNCTION_CALLS = process.env.FEZ_MAXIMUM_FUNCTION_CALLS
|
15
|
-
? +process.env.FEZ_MAXIMUM_FUNCTION_CALLS
|
16
|
-
: DEFAULT_MAXIMUM_FUNCTION_CALLS
|
12
|
+
import { callStack, stringifyArgs } from './utils.js'
|
17
13
|
export const evaluate = (exp, env = keywords) => {
|
18
14
|
const [first, ...rest] = isLeaf(exp) ? [exp] : exp
|
19
15
|
if (first == undefined) return []
|
@@ -36,15 +32,8 @@ export const evaluate = (exp, env = keywords) => {
|
|
36
32
|
`${value} is not a (${KEYWORDS.ANONYMOUS_FUNCTION})`
|
37
33
|
)
|
38
34
|
const isSpecial = SPECIAL_FORMS_SET.has(value)
|
39
|
-
if (!isSpecial) {
|
40
|
-
evaluate.count = (evaluate.count || 0) + 1
|
41
|
-
if (evaluate.count > MAXIMUM_FUNCTION_CALLS) {
|
42
|
-
evaluate.count = 0
|
43
|
-
throw new RangeError('Maximum function invocation limit exceeded')
|
44
|
-
}
|
45
|
-
}
|
46
35
|
const result = apply(rest, env, value)
|
47
|
-
if (!isSpecial)
|
36
|
+
if (!isSpecial) callStack.pop()
|
48
37
|
return result
|
49
38
|
}
|
50
39
|
case ATOM:
|
@@ -55,4 +44,3 @@ export const evaluate = (exp, env = keywords) => {
|
|
55
44
|
)
|
56
45
|
}
|
57
46
|
}
|
58
|
-
evaluate.stack = [KEYWORDS.CALL_FUNCTION]
|
package/src/interpreter.js
CHANGED
@@ -9,7 +9,7 @@ import {
|
|
9
9
|
RUNTIME_TYPES
|
10
10
|
} from './keywords.js'
|
11
11
|
import { evaluate } from './evaluator.js'
|
12
|
-
import { isForbiddenVariableName, stringifyArgs } from './utils.js'
|
12
|
+
import { callStack, isForbiddenVariableName, stringifyArgs } from './utils.js'
|
13
13
|
import { LISP } from './parser.js'
|
14
14
|
export const keywords = {
|
15
15
|
[KEYWORDS.ADDITION]: (args, env) => {
|
@@ -697,7 +697,7 @@ export const keywords = {
|
|
697
697
|
writable: true
|
698
698
|
})
|
699
699
|
}
|
700
|
-
if (name)
|
700
|
+
if (name) callStack.push(name)
|
701
701
|
return evaluate(body, localEnv)
|
702
702
|
}
|
703
703
|
},
|
@@ -724,7 +724,9 @@ export const keywords = {
|
|
724
724
|
throw new TypeError(
|
725
725
|
`Last argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
|
726
726
|
KEYWORDS.ANONYMOUS_FUNCTION
|
727
|
-
})\n\nat:\n(${
|
727
|
+
}) but got ${LISP.stringify(apply)}\n\nat:\n(${
|
728
|
+
KEYWORDS.CALL_FUNCTION
|
729
|
+
} ${stringifyArgs(args)})`
|
728
730
|
)
|
729
731
|
|
730
732
|
return apply(args.slice(0, -1), env)
|
package/src/parser.js
CHANGED
@@ -30,6 +30,8 @@ export const LISP = {
|
|
30
30
|
},
|
31
31
|
stringify: (array) => {
|
32
32
|
if (array == undefined) return '()'
|
33
|
+
else if (typeof array === 'function') return '(lambda)'
|
34
|
+
else if (typeof array === 'boolean') return +array
|
33
35
|
else if (typeof array === 'object')
|
34
36
|
if (Array.isArray(array))
|
35
37
|
return array.length
|
@@ -39,8 +41,6 @@ export const LISP = {
|
|
39
41
|
return `(array ${array
|
40
42
|
.map(([key, value]) => `("${key}" ${LISP.stringify(value)})`)
|
41
43
|
.join(' ')})`
|
42
|
-
else if (typeof array === 'function') return '()'
|
43
|
-
else if (typeof array === 'boolean') return +array
|
44
44
|
else return array
|
45
45
|
},
|
46
46
|
source: (ast) => {
|
package/src/utils.js
CHANGED
@@ -23,8 +23,6 @@ import { keywords } from './interpreter.js'
|
|
23
23
|
export const logError = (error) =>
|
24
24
|
console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
|
25
25
|
export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
|
26
|
-
// export const replaceEmptyArrays = (source) =>
|
27
|
-
// source
|
28
26
|
export const removeNoCode = (source) =>
|
29
27
|
source
|
30
28
|
.replace(/;.+/g, '')
|
@@ -160,6 +158,7 @@ export const handleUnbalancedParens = (source) => {
|
|
160
158
|
export const removeMutation = (source) => source.replace(new RegExp(/!/g), 'ǃ')
|
161
159
|
const isDefinition = (x) =>
|
162
160
|
x[TYPE] === APPLY && x[VALUE] === KEYWORDS.DEFINE_VARIABLE
|
161
|
+
// [[, [, libs]]] is because std is wrapped in (apply (lambda (do ...)))
|
163
162
|
const toDeps = ([[, [, libs]]]) =>
|
164
163
|
libs.reduce(
|
165
164
|
(a, x, i) => a.set(x.at(1)[VALUE], { value: x, index: i }),
|
@@ -266,38 +265,6 @@ export const fez = (source, options = {}) => {
|
|
266
265
|
return err
|
267
266
|
}
|
268
267
|
}
|
269
|
-
export const compress = (source) => {
|
270
|
-
let { result, occurance } = source.split('').reduce(
|
271
|
-
(acc, item) => {
|
272
|
-
if (item === ')') acc.occurance++
|
273
|
-
else {
|
274
|
-
if (acc.occurance < 3) {
|
275
|
-
acc.result += ')'.repeat(acc.occurance)
|
276
|
-
acc.occurance = 0
|
277
|
-
} else {
|
278
|
-
acc.result += '·' + acc.occurance
|
279
|
-
acc.occurance = 0
|
280
|
-
}
|
281
|
-
acc.result += item
|
282
|
-
}
|
283
|
-
return acc
|
284
|
-
},
|
285
|
-
{ result: '', occurance: 0 }
|
286
|
-
)
|
287
|
-
if (occurance > 0) result += '·' + occurance
|
288
|
-
return result
|
289
|
-
}
|
290
|
-
export const decompress = (raw) => {
|
291
|
-
const suffix = [...new Set(raw.match(/·+?\d+/g))]
|
292
|
-
const runes = suffix.reduce(
|
293
|
-
(acc, m) => acc.split(m).join(')'.repeat(parseInt(m.substring(1)))),
|
294
|
-
raw
|
295
|
-
)
|
296
|
-
let result = ''
|
297
|
-
for (const tok of runes) result += tok
|
298
|
-
return result
|
299
|
-
}
|
300
|
-
// shake(LISP.parse(removeNoCode(source)), std)
|
301
268
|
export const shake = (parsed, std) => treeShake(parsed, std).concat(parsed)
|
302
269
|
export const tree = (source, std) =>
|
303
270
|
std
|
@@ -340,7 +307,20 @@ export const parse = (source) =>
|
|
340
307
|
std
|
341
308
|
)
|
342
309
|
)
|
310
|
+
|
311
|
+
const identity = (name) => [
|
312
|
+
[0, 'let'],
|
313
|
+
[1, name],
|
314
|
+
[
|
315
|
+
[0, 'lambda'],
|
316
|
+
[1, 'x'],
|
317
|
+
[1, 'x']
|
318
|
+
]
|
319
|
+
]
|
320
|
+
export const callStack = [KEYWORDS.CALL_FUNCTION]
|
343
321
|
export const debug = (ast) => {
|
322
|
+
callStack.length = 0
|
323
|
+
callStack.push(KEYWORDS.CALL_FUNCTION)
|
344
324
|
try {
|
345
325
|
const debugEnv = {
|
346
326
|
...keywords,
|
@@ -467,24 +447,14 @@ export const debug = (ast) => {
|
|
467
447
|
}
|
468
448
|
evaluate(ast, debugEnv)
|
469
449
|
} catch (error) {
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
error.message += `\n\nscope:\n(${evaluate.stack.at(-1)})`
|
450
|
+
const isMaxCallStack =
|
451
|
+
error.message.includes('Maximum call stack size exceeded') ||
|
452
|
+
error.message.includes('too much recursion')
|
453
|
+
if (!isMaxCallStack) {
|
454
|
+
error.message += `\n\nscope:\n(${callStack.at(-1)})`
|
476
455
|
throw error
|
477
456
|
} else logError(error.message)
|
478
457
|
}
|
479
|
-
const identity = (name) => [
|
480
|
-
[0, 'let'],
|
481
|
-
[1, name],
|
482
|
-
[
|
483
|
-
[0, 'lambda'],
|
484
|
-
[1, 'x'],
|
485
|
-
[1, 'x']
|
486
|
-
]
|
487
|
-
]
|
488
458
|
const block = ast[1][1]
|
489
459
|
const temp = block.shift()
|
490
460
|
block.unshift(
|