fez-lisp 1.2.43 → 1.2.45
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/README.md +39 -29
- package/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/compiler.js +38 -10
- package/src/interpreter.js +13 -38
- package/src/keywords.js +3 -1
- package/src/utils.js +4 -3
package/package.json
CHANGED
package/src/compiler.js
CHANGED
@@ -8,13 +8,22 @@ import {
|
|
8
8
|
WORD
|
9
9
|
} from './keywords.js'
|
10
10
|
import { leaf, isLeaf } from './parser.js'
|
11
|
-
const
|
11
|
+
const deepRenameTco = (name, newName, tree) => {
|
12
12
|
if (!isLeaf(tree))
|
13
13
|
for (const leaf of tree) {
|
14
14
|
// Figure out a non mutable solution so
|
15
15
|
// I can get rid of deep copy
|
16
16
|
if (leaf[VALUE] === name) leaf[VALUE] = `()=>${newName}`
|
17
|
-
|
17
|
+
deepRenameTco(name, newName, leaf)
|
18
|
+
}
|
19
|
+
}
|
20
|
+
const deepRenameCache = (name, newName, tree) => {
|
21
|
+
if (!isLeaf(tree))
|
22
|
+
for (const leaf of tree) {
|
23
|
+
// Figure out a non mutable solution so
|
24
|
+
// I can get rid of deep copy
|
25
|
+
if (leaf[VALUE] === name) leaf[VALUE] = newName
|
26
|
+
deepRenameCache(name, newName, leaf)
|
18
27
|
}
|
19
28
|
}
|
20
29
|
const earMuffsToLodashes = (name) => name.replace(new RegExp(/\*/g), '_')
|
@@ -109,7 +118,7 @@ const Helpers = {
|
|
109
118
|
__tco: `__tco=fn=>(...args)=>{let result=fn(...args);while(typeof result==='function')result=result();return result}`,
|
110
119
|
atom_predicate: `atom_predicate=(number)=>+(typeof number==='number')`,
|
111
120
|
lambda_predicate: `lambda_predicate=(fm)=>+(typeof fn==='function')`,
|
112
|
-
set_effect: `set_effect=(array,index,value)
|
121
|
+
set_effect: `set_effect=function(array,index,value){if(arguments.length===1){array.pop()}else{array[index] = value};return array}`,
|
113
122
|
__error: `__error=(error)=>{throw new Error(error.map((x)=>String.fromCharCode(x)).join(''))}`
|
114
123
|
}
|
115
124
|
const semiColumnEdgeCases = new Set([
|
@@ -166,16 +175,20 @@ const compile = (tree, Drill) => {
|
|
166
175
|
}
|
167
176
|
case KEYWORDS.DEFINE_VARIABLE: {
|
168
177
|
const n = Arguments[0][VALUE]
|
169
|
-
|
178
|
+
const prefix = n.split(':')[0]
|
179
|
+
if (prefix === KEYWORDS.RECURSION) {
|
170
180
|
const name = lispToJavaScriptVariableName(n)
|
171
|
-
const newName = `
|
181
|
+
const newName = `recursive_${performance
|
182
|
+
.now()
|
183
|
+
.toString()
|
184
|
+
.replace('.', 7)}`
|
172
185
|
Drill.Variables.add(name)
|
173
186
|
Drill.Variables.add(newName)
|
174
187
|
Drill.Helpers.add('__tco')
|
175
188
|
const functionArgs = Arguments.at(-1).slice(1)
|
176
189
|
const body = functionArgs.pop()
|
177
190
|
const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
|
178
|
-
|
191
|
+
deepRenameTco(n, newName, body)
|
179
192
|
const evaluatedBody = compile(body, FunctionDrill)
|
180
193
|
const vars = FunctionDrill.Variables.size
|
181
194
|
? `var ${[...FunctionDrill.Variables].join(',')};`
|
@@ -186,6 +199,25 @@ const compile = (tree, Drill) => {
|
|
186
199
|
)})=>{${vars}return ${evaluatedBody
|
187
200
|
.toString()
|
188
201
|
.trim()}}, ${newName})));`
|
202
|
+
} else if (prefix === KEYWORDS.CACHE) {
|
203
|
+
// memoization here
|
204
|
+
const name = lispToJavaScriptVariableName(n)
|
205
|
+
const newName = name.substring(KEYWORDS.CACHE.length + 1)
|
206
|
+
Drill.Variables.add(name)
|
207
|
+
const functionArgs = Arguments.at(-1).slice(1)
|
208
|
+
const body = functionArgs.pop()
|
209
|
+
deepRenameCache(n, newName, body)
|
210
|
+
const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
|
211
|
+
const evaluatedBody = compile(body, FunctionDrill)
|
212
|
+
const vars = FunctionDrill.Variables.size
|
213
|
+
? `var ${[...FunctionDrill.Variables].join(',')};`
|
214
|
+
: ''
|
215
|
+
return `(${name}=function(){var __${newName}_map = new Map();var ${newName}=(function(${parseArgs(
|
216
|
+
functionArgs,
|
217
|
+
Drill
|
218
|
+
)}){${vars};var __key=[...arguments].join(',');if(__${newName}_map.has(__key)){return __${newName}_map.get(__key)}else{var __res = ${evaluatedBody
|
219
|
+
.toString()
|
220
|
+
.trim()};__${newName}_map.set(__key, __res);return __res}});return ${newName}(...arguments)});`
|
189
221
|
} else {
|
190
222
|
const name = lispToJavaScriptVariableName(n)
|
191
223
|
Drill.Variables.add(name)
|
@@ -198,10 +230,6 @@ const compile = (tree, Drill) => {
|
|
198
230
|
case KEYWORDS.IS_LAMBDA:
|
199
231
|
Drill.Helpers.add('lambda_predicate')
|
200
232
|
return `lambda_predicate(${compile(Arguments[0], Drill)});`
|
201
|
-
case KEYWORDS.NUMBER_TYPE:
|
202
|
-
return '0'
|
203
|
-
case KEYWORDS.BOOLEAN_TYPE:
|
204
|
-
return '1'
|
205
233
|
case KEYWORDS.ARRAY_TYPE:
|
206
234
|
return `[${parseArgs(Arguments, Drill)}];`
|
207
235
|
case KEYWORDS.ARRAY_LENGTH:
|
package/src/interpreter.js
CHANGED
@@ -675,11 +675,11 @@ export const keywords = {
|
|
675
675
|
// return evaluate(inp, env)
|
676
676
|
// },
|
677
677
|
[KEYWORDS.SET_ARRAY]: (args, env) => {
|
678
|
-
if (args.length !==
|
678
|
+
if (args.length !== 1 && args.length !== 3)
|
679
679
|
throw new RangeError(
|
680
680
|
`Invalid number of arguments for (${
|
681
681
|
KEYWORDS.SET_ARRAY
|
682
|
-
}) (or
|
682
|
+
}) (or 1 3) required (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
|
683
683
|
)
|
684
684
|
const array = evaluate(args[0], env)
|
685
685
|
if (!Array.isArray(array))
|
@@ -688,31 +688,17 @@ export const keywords = {
|
|
688
688
|
KEYWORDS.ARRAY_TYPE
|
689
689
|
}) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
|
690
690
|
)
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
`Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
|
701
|
-
KEYWORDS.ARRAY_TYPE
|
702
|
-
}) bounds (index ${index} bounds ${array.length}) (${
|
703
|
-
KEYWORDS.SET_ARRAY
|
704
|
-
} ${stringifyArgs(args)})`
|
705
|
-
)
|
706
|
-
if (index < 0) {
|
707
|
-
if (args.length !== 2)
|
708
|
-
throw new RangeError(
|
709
|
-
`Invalid number of arguments for (${
|
710
|
-
KEYWORDS.SET_ARRAY
|
711
|
-
}) (if (< index 0) then 2 required) (${
|
712
|
-
KEYWORDS.SET_ARRAY
|
713
|
-
} ${stringifyArgs(args)})`
|
691
|
+
if (args.length === 1) {
|
692
|
+
array.pop()
|
693
|
+
} else {
|
694
|
+
const index = evaluate(args[1], env)
|
695
|
+
if (!Number.isInteger(index) || index < 0)
|
696
|
+
throw new TypeError(
|
697
|
+
`Second argument of (${KEYWORDS.SET_ARRAY}) must be a positive (${
|
698
|
+
KEYWORDS.NUMBER_TYPE
|
699
|
+
} integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
|
714
700
|
)
|
715
|
-
if (index
|
701
|
+
if (index > array.length)
|
716
702
|
throw new RangeError(
|
717
703
|
`Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
|
718
704
|
KEYWORDS.ARRAY_TYPE
|
@@ -720,17 +706,6 @@ export const keywords = {
|
|
720
706
|
KEYWORDS.SET_ARRAY
|
721
707
|
} ${stringifyArgs(args)})`
|
722
708
|
)
|
723
|
-
const target = array.length + index
|
724
|
-
while (array.length !== target) array.pop()
|
725
|
-
} else {
|
726
|
-
if (args.length !== 3)
|
727
|
-
throw new RangeError(
|
728
|
-
`Invalid number of arguments for (${
|
729
|
-
KEYWORDS.SET_ARRAY
|
730
|
-
}) (if (>= index 0) then 3 required) (${
|
731
|
-
KEYWORDS.SET_ARRAY
|
732
|
-
} ${stringifyArgs(args)})`
|
733
|
-
)
|
734
709
|
const value = evaluate(args[2], env)
|
735
710
|
if (value == undefined)
|
736
711
|
throw new RangeError(
|
@@ -819,4 +794,4 @@ export const keywords = {
|
|
819
794
|
)
|
820
795
|
throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
|
821
796
|
}
|
822
|
-
}
|
797
|
+
}
|
package/src/keywords.js
CHANGED
package/src/utils.js
CHANGED
@@ -102,6 +102,8 @@ export const isForbiddenVariableName = (name) => {
|
|
102
102
|
switch (name) {
|
103
103
|
case '_':
|
104
104
|
case KEYWORDS.DEFINE_VARIABLE:
|
105
|
+
case KEYWORDS.RECURSION:
|
106
|
+
case KEYWORDS.CACHE:
|
105
107
|
return true
|
106
108
|
default:
|
107
109
|
return !isNaN(name[0])
|
@@ -262,9 +264,8 @@ export const fez = (source, options = {}) => {
|
|
262
264
|
}
|
263
265
|
} catch (error) {
|
264
266
|
// console.log(error)
|
265
|
-
const err = error.message
|
266
|
-
|
267
|
-
.replace('object', '(array)')
|
267
|
+
const err = error.message.replace("'[object Array]'", '(array)')
|
268
|
+
// .replace('object', '(array)')
|
268
269
|
logError(err)
|
269
270
|
if (options.throw) throw err
|
270
271
|
return err
|