fez-lisp 1.1.9 → 1.1.10
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 +1 -1
- package/src/compiler.js +1 -3
- package/src/ocaml.js +373 -0
- package/src/utils.js +23 -5
package/package.json
CHANGED
package/src/compiler.js
CHANGED
@@ -239,7 +239,7 @@ const compile = (tree, Drill) => {
|
|
239
239
|
Drill.Variables.add(name)
|
240
240
|
Drill.Variables.add(newName)
|
241
241
|
Drill.Helpers.add('__tco')
|
242
|
-
const functionArgs =
|
242
|
+
const functionArgs = val.slice(1)
|
243
243
|
const body = functionArgs.pop()
|
244
244
|
const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
|
245
245
|
deepRename(arg[VALUE], newName, body)
|
@@ -263,8 +263,6 @@ const compile = (tree, Drill) => {
|
|
263
263
|
return `(${parseArgs(Arguments, Drill, '&&')});`
|
264
264
|
case KEYWORDS.OR:
|
265
265
|
return `((${parseArgs(Arguments, Drill, '||')}) || 0);`
|
266
|
-
case KEYWORDS.CONCATENATION:
|
267
|
-
return '(' + parseArgs(Arguments, Drill, '+') + ');'
|
268
266
|
case KEYWORDS.EQUAL:
|
269
267
|
return `+(${parseArgs(Arguments, Drill, '===')});`
|
270
268
|
case KEYWORDS.GREATHER_THAN_OR_EQUAL:
|
package/src/ocaml.js
ADDED
@@ -0,0 +1,373 @@
|
|
1
|
+
import {
|
2
|
+
APPLY,
|
3
|
+
ATOM,
|
4
|
+
PLACEHOLDER,
|
5
|
+
KEYWORDS,
|
6
|
+
TYPE,
|
7
|
+
VALUE,
|
8
|
+
WORD
|
9
|
+
} from './keywords.js'
|
10
|
+
import { leaf, isLeaf } from './parser.js'
|
11
|
+
import { deepRename } from './utils.js'
|
12
|
+
const earMuffsToLodashes = (name) => name.replace(new RegExp(/\*/g), '_')
|
13
|
+
const dotNamesToEmpty = (name) => name.replace(new RegExp(/\./g), '')
|
14
|
+
const commaToLodash = (name) => name.replace(new RegExp(/\,/g), '_')
|
15
|
+
const arrowFromTo = (name) => name.replace(new RegExp(/->/g), '-to-')
|
16
|
+
const moduleNameToLodashes = (name) => name.replace(new RegExp(/:/g), '_')
|
17
|
+
const questionMarkToPredicate = (name) =>
|
18
|
+
name.replace(new RegExp(/\?/g), 'Predicate')
|
19
|
+
const exclamationMarkMarkToEffect = (name) =>
|
20
|
+
name.replace(new RegExp(/\!/g), 'Effect')
|
21
|
+
const toCamelCase = (name) => {
|
22
|
+
let out = name[0]
|
23
|
+
for (let i = 1; i < name.length; ++i) {
|
24
|
+
const current = name[i],
|
25
|
+
prev = name[i - 1]
|
26
|
+
if (current === '-') continue
|
27
|
+
else if (prev === '-') out += current.toUpperCase()
|
28
|
+
else out += current
|
29
|
+
}
|
30
|
+
return out
|
31
|
+
}
|
32
|
+
const keywordToHelper = (name) => {
|
33
|
+
switch (name) {
|
34
|
+
case KEYWORDS.ADDITION:
|
35
|
+
return '__add'
|
36
|
+
case KEYWORDS.MULTIPLICATION:
|
37
|
+
return '__mult'
|
38
|
+
case KEYWORDS.SUBTRACTION:
|
39
|
+
return '__sub'
|
40
|
+
case KEYWORDS.GREATHER_THAN:
|
41
|
+
return '__gt'
|
42
|
+
case KEYWORDS.EQUAL:
|
43
|
+
return '__eq'
|
44
|
+
case KEYWORDS.GREATHER_THAN_OR_EQUAL:
|
45
|
+
return '__gteq'
|
46
|
+
case KEYWORDS.LESS_THAN:
|
47
|
+
return '__lt'
|
48
|
+
case KEYWORDS.LESS_THAN_OR_EQUAL:
|
49
|
+
return '__lteq'
|
50
|
+
default:
|
51
|
+
return name
|
52
|
+
}
|
53
|
+
}
|
54
|
+
const lispToJavaScriptVariableName = (name) =>
|
55
|
+
toCamelCase(
|
56
|
+
arrowFromTo(
|
57
|
+
dotNamesToEmpty(
|
58
|
+
exclamationMarkMarkToEffect(
|
59
|
+
questionMarkToPredicate(
|
60
|
+
commaToLodash(
|
61
|
+
moduleNameToLodashes(earMuffsToLodashes(keywordToHelper(name)))
|
62
|
+
)
|
63
|
+
)
|
64
|
+
)
|
65
|
+
)
|
66
|
+
)
|
67
|
+
)
|
68
|
+
const Helpers = {
|
69
|
+
// __string: `__string=(...args)=>{const str=args.flat();str.isString=true;return str}`,
|
70
|
+
// __add: `__add=(...numbers)=>{return numbers.reduce((a,b)=>a+b,0)}`,
|
71
|
+
// __sub: `__sub=(...numbers)=>{return numbers.reduce((a,b)=>a-b,0)}`,
|
72
|
+
// __mult: `__mult=(...numbers)=>{return numbers.reduce((a,b)=>a*b,1)}`,
|
73
|
+
// __gteq: '__gteq=(a,b)=>+(a>=b)',
|
74
|
+
// __gt: '__gt=(a,b)=>+(a>b)',
|
75
|
+
// __eq: '__eq=(a,b)=>+(a===b)',
|
76
|
+
// __lteq: '__lteq=(a,b)=>+(a<=b)',
|
77
|
+
// __lt: '__lt=(a,b)=>+(a<b)',
|
78
|
+
// not: 'not=(a)=>+!a',
|
79
|
+
// and: `and=(...args)=>{
|
80
|
+
// let circuit;
|
81
|
+
// for(let i=0; i<args.length-1;++i){
|
82
|
+
// circuit=args[i]
|
83
|
+
// if(circuit) continue
|
84
|
+
// else return circuit
|
85
|
+
// }
|
86
|
+
// return args.at(-1)
|
87
|
+
// }`,
|
88
|
+
// or: `or=(...args)=>{
|
89
|
+
// let circuit;
|
90
|
+
// for(let i=0;i<args.length-1;++i) {
|
91
|
+
// circuit = args[i]
|
92
|
+
// if(circuit)return circuit
|
93
|
+
// else continue
|
94
|
+
// }
|
95
|
+
// return args.at(-1)
|
96
|
+
// }`,
|
97
|
+
// logEffect: `logEffect=(msg)=>{console.log(msg);return msg}`,
|
98
|
+
// clearEffect: `clearEffect=()=>{console.clear();return 0}`,
|
99
|
+
array_cons: `rec array_cons lists =
|
100
|
+
match lists with
|
101
|
+
| [] -> []
|
102
|
+
| hd::tl -> hd @ array_cons tl`,
|
103
|
+
car: 'car = fun (arr::_) -> arr',
|
104
|
+
cdr: 'cdr = fun (_::arr) -> arr',
|
105
|
+
array_get: `rec array_get = function
|
106
|
+
| [], _ -> raise (Failure "array_get")
|
107
|
+
| list, n when n < 0 -> array_get(list, List.length(list) - n)
|
108
|
+
| x::_, 0 -> x
|
109
|
+
| x::xs, n -> array_get(xs, n - 1)`,
|
110
|
+
length: 'length(arr)=float_of_int(List.length(arr))'
|
111
|
+
// numberPredicate: `numberPredicate=(number)=>+(typeof number==='number')`,
|
112
|
+
// lambdaPredicate: `lambdaPredicate=(lambda)=>+(typeof lambda==='function')`,
|
113
|
+
// arrayPredicate: `arrayPredicate=(array)=>+Array.isArray(array)`,
|
114
|
+
// error: `error=(error)=>{throw new Error(error)}`,
|
115
|
+
// array_setEffect: `array_setEffect=(array,index,value)=>{if(index<0){const target=array.length+index;while(array.length!==target)array.pop()}else array[index] = value;return array}`
|
116
|
+
// array_setEffect: `array_setEffect=(array,index,value)=>{if(index<0){const target=array.length+index;while(array.length!==target)array.pop()}else array[index] = value;return array}`
|
117
|
+
}
|
118
|
+
const semiColumnEdgeCases = new Set([
|
119
|
+
';)',
|
120
|
+
';-',
|
121
|
+
';+',
|
122
|
+
';*',
|
123
|
+
';%',
|
124
|
+
';&',
|
125
|
+
';/',
|
126
|
+
';:',
|
127
|
+
';.',
|
128
|
+
';=',
|
129
|
+
';<',
|
130
|
+
';>',
|
131
|
+
';|',
|
132
|
+
';,',
|
133
|
+
';?',
|
134
|
+
',,',
|
135
|
+
// ';;',
|
136
|
+
';]'
|
137
|
+
])
|
138
|
+
const parse = (Arguments, Drill) => Arguments.map((x) => compile(x, Drill))
|
139
|
+
const parseArgs = (Arguments, Drill, separator = ',') =>
|
140
|
+
parse(Arguments, Drill).join(separator)
|
141
|
+
const compile = (tree, Drill) => {
|
142
|
+
if (!tree) return ''
|
143
|
+
const [first, ...Arguments] = !isLeaf(tree) ? tree : [tree]
|
144
|
+
if (first == undefined) return '[];'
|
145
|
+
const token = first[VALUE]
|
146
|
+
if (first[TYPE] === APPLY) {
|
147
|
+
switch (token) {
|
148
|
+
case KEYWORDS.BLOCK: {
|
149
|
+
if (Arguments.length > 1) {
|
150
|
+
return `(${Arguments.map((x) =>
|
151
|
+
(compile(x, Drill) ?? '').toString().trimStart().replace(';;', '')
|
152
|
+
)
|
153
|
+
.filter(Boolean)
|
154
|
+
.join(' in\n')})`
|
155
|
+
} else {
|
156
|
+
const res = compile(Arguments[0], Drill)
|
157
|
+
return res !== undefined ? res.toString().trim() : ''
|
158
|
+
}
|
159
|
+
}
|
160
|
+
case KEYWORDS.CALL_FUNCTION: {
|
161
|
+
const [first, ...rest] = Arguments
|
162
|
+
const apply = compile(first, Drill)
|
163
|
+
return `${
|
164
|
+
apply[apply.length - 1] === ';'
|
165
|
+
? apply.substring(0, apply.length - 1)
|
166
|
+
: apply
|
167
|
+
}(${parseArgs(rest, Drill)})`
|
168
|
+
}
|
169
|
+
case KEYWORDS.DEFINE_VARIABLE: {
|
170
|
+
let name,
|
171
|
+
out = 'let '
|
172
|
+
if (Arguments[0][TYPE] === WORD) {
|
173
|
+
name = lispToJavaScriptVariableName(Arguments[0][VALUE])
|
174
|
+
Drill.Variables.add(name)
|
175
|
+
}
|
176
|
+
out += `${name} = ${compile(Arguments[1], Drill)}`
|
177
|
+
out += `;;`
|
178
|
+
return out
|
179
|
+
}
|
180
|
+
case KEYWORDS.IS_NUMBER:
|
181
|
+
Drill.Helpers.add('numberPredicate')
|
182
|
+
return `numberPredicate(${compile(Arguments[0], Drill)});`
|
183
|
+
case KEYWORDS.IS_FUNCTION:
|
184
|
+
Drill.Helpers.add('lambdaPredicate')
|
185
|
+
return `lambdaPredicate(${compile(Arguments[0], Drill)});`
|
186
|
+
case KEYWORDS.IS_ARRAY:
|
187
|
+
Drill.Helpers.add('arrayPredicate')
|
188
|
+
return `arrayPredicate(${compile(Arguments[0], Drill)});`
|
189
|
+
case KEYWORDS.NUMBER_TYPE:
|
190
|
+
return '0'
|
191
|
+
case KEYWORDS.BOOLEAN_TYPE:
|
192
|
+
return '1'
|
193
|
+
case KEYWORDS.STRING_TYPE:
|
194
|
+
Drill.Helpers.add('__string')
|
195
|
+
return `__string(${parseArgs(Arguments, Drill)});`
|
196
|
+
case KEYWORDS.ARRAY_TYPE:
|
197
|
+
return Arguments.length === 2 &&
|
198
|
+
Arguments[1][TYPE] === WORD &&
|
199
|
+
Arguments[1][VALUE] === 'length'
|
200
|
+
? `(List.make ${compile(Arguments[0], Drill)} 0)`
|
201
|
+
: `[${parseArgs(Arguments, Drill, ';')}]`
|
202
|
+
case KEYWORDS.ARRAY_LENGTH:
|
203
|
+
Drill.Helpers.add('length')
|
204
|
+
return `length(${compile(Arguments[0], Drill)})`
|
205
|
+
case KEYWORDS.FIRST_ARRAY:
|
206
|
+
Drill.Helpers.add('car')
|
207
|
+
return `car(${compile(Arguments[0], Drill)})`
|
208
|
+
case KEYWORDS.REST_ARRAY:
|
209
|
+
Drill.Helpers.add('cdr')
|
210
|
+
return `cdr(${compile(Arguments[0], Drill)})`
|
211
|
+
case KEYWORDS.GET_ARRAY:
|
212
|
+
Drill.Helpers.add('array_get')
|
213
|
+
return `array_get(${compile(
|
214
|
+
Arguments[0],
|
215
|
+
Drill
|
216
|
+
)}, int_of_float(${compile(Arguments[1], Drill)}))`
|
217
|
+
case KEYWORDS.CONS:
|
218
|
+
Drill.Helpers.add('array_cons')
|
219
|
+
return `array_cons[${parseArgs(Arguments, Drill, ';')}]`
|
220
|
+
case KEYWORDS.ANONYMOUS_FUNCTION: {
|
221
|
+
const functionArgs = Arguments
|
222
|
+
const body = Arguments.pop()
|
223
|
+
const InnerDrills = { Variables: new Set(), Helpers: Drill.Helpers }
|
224
|
+
const evaluatedBody = compile(body, InnerDrills)
|
225
|
+
// const vars = InnerDrills.Variables.size
|
226
|
+
// ? `let ${[...InnerDrills.Variables].join(',')};`
|
227
|
+
// : ''
|
228
|
+
return `(fun (${parseArgs(
|
229
|
+
functionArgs.map((node, index) =>
|
230
|
+
node[VALUE] === PLACEHOLDER
|
231
|
+
? leaf(node[TYPE], `_${index}`)
|
232
|
+
: leaf(node[TYPE], node[VALUE])
|
233
|
+
),
|
234
|
+
InnerDrills
|
235
|
+
)}) -> ${evaluatedBody.toString().trimStart()})`
|
236
|
+
}
|
237
|
+
case KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION: {
|
238
|
+
const arg = Arguments[0]
|
239
|
+
const val = Arguments[1]
|
240
|
+
if (val[0][0] === APPLY && val[0][1] === KEYWORDS.ANONYMOUS_FUNCTION) {
|
241
|
+
const name = lispToJavaScriptVariableName(arg[VALUE])
|
242
|
+
const functionArgs = val.slice(1)
|
243
|
+
const body = functionArgs.pop()
|
244
|
+
const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
|
245
|
+
const evaluatedBody = compile(body, FunctionDrill)
|
246
|
+
return `let rec ${name} (${parseArgs(
|
247
|
+
functionArgs.map((node, index) =>
|
248
|
+
node[VALUE] === PLACEHOLDER
|
249
|
+
? leaf(node[TYPE], `_${index}`)
|
250
|
+
: leaf(node[TYPE], node[VALUE])
|
251
|
+
)
|
252
|
+
)}) = ${evaluatedBody.toString().trimStart()};;`
|
253
|
+
}
|
254
|
+
}
|
255
|
+
case KEYWORDS.AND:
|
256
|
+
return `(${parseArgs(Arguments, Drill, '&&')})`
|
257
|
+
case KEYWORDS.OR:
|
258
|
+
return `((${parseArgs(Arguments, Drill, '||')}) || 0.0)`
|
259
|
+
case KEYWORDS.EQUAL:
|
260
|
+
return `(if ${parseArgs(Arguments, Drill, '==')} then 1.0 else 0.0)`
|
261
|
+
case KEYWORDS.GREATHER_THAN_OR_EQUAL:
|
262
|
+
case KEYWORDS.LESS_THAN_OR_EQUAL:
|
263
|
+
case KEYWORDS.GREATHER_THAN:
|
264
|
+
case KEYWORDS.LESS_THAN:
|
265
|
+
return `(if ${parseArgs(Arguments, Drill, token)} then 1.0 else 0.0)`
|
266
|
+
case KEYWORDS.SUBTRACTION:
|
267
|
+
return Arguments.length === 1
|
268
|
+
? `(-.${compile(Arguments[0], Drill)})`
|
269
|
+
: `(${parse(Arguments, Drill)
|
270
|
+
// Add space so it doesn't consider it 2--1 but 2- -1
|
271
|
+
.map((x) => (typeof x === 'number' && x < 0 ? ` ${x}` : x))
|
272
|
+
.join(`${token}.`)})`
|
273
|
+
case KEYWORDS.MULTIPLICATION:
|
274
|
+
return Arguments.length
|
275
|
+
? `(${parseArgs(Arguments, Drill, `${token}.`)})`
|
276
|
+
: `(1.0)`
|
277
|
+
case KEYWORDS.DIVISION:
|
278
|
+
return Arguments.length
|
279
|
+
? Arguments.length === 1
|
280
|
+
? `(1.0/.${compile(Arguments[0], Drill)})`
|
281
|
+
: `(${parseArgs(Arguments, Drill, `${token}.`)})`
|
282
|
+
: `(0.0)`
|
283
|
+
case KEYWORDS.ADDITION:
|
284
|
+
return Arguments.length
|
285
|
+
? `(${parseArgs(Arguments, Drill, `${token}.`)})`
|
286
|
+
: `(0.0)`
|
287
|
+
case KEYWORDS.BITWISE_AND:
|
288
|
+
case KEYWORDS.BITWISE_OR:
|
289
|
+
case KEYWORDS.BITWISE_XOR:
|
290
|
+
case KEYWORDS.BITWISE_LEFT_SHIFT:
|
291
|
+
case KEYWORDS.BITWISE_RIGHT_SHIFT:
|
292
|
+
case KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT:
|
293
|
+
return `(${parseArgs(Arguments, Drill, token)})`
|
294
|
+
case KEYWORDS.REMAINDER_OF_DIVISION:
|
295
|
+
return `(mod_float ${compile(Arguments[0], Drill)} ${compile(
|
296
|
+
Arguments[1],
|
297
|
+
Drill
|
298
|
+
)})`
|
299
|
+
case KEYWORDS.BIT_TYPE:
|
300
|
+
return `(${compile(Arguments[0], Drill)}>>>0).toString(2)`
|
301
|
+
case KEYWORDS.BITWISE_NOT:
|
302
|
+
return `~(${compile(Arguments[0], Drill)})`
|
303
|
+
case KEYWORDS.NOT:
|
304
|
+
return `(if ${compile(Arguments[0], Drill)} == 0.0 then 1.0 else 0.0)`
|
305
|
+
case KEYWORDS.IF: {
|
306
|
+
return `(if ${compile(Arguments[0], Drill)} != 0.0 then ${compile(
|
307
|
+
Arguments[1],
|
308
|
+
Drill
|
309
|
+
)} else ${Arguments.length === 3 ? compile(Arguments[2], Drill) : 0})`
|
310
|
+
}
|
311
|
+
case KEYWORDS.CONDITION: {
|
312
|
+
let out = ''
|
313
|
+
for (let i = 0; i < Arguments.length; i += 2)
|
314
|
+
out += `(if ${compile(Arguments[i], Drill)} != 0.0 then ${compile(
|
315
|
+
Arguments[i + 1],
|
316
|
+
Drill
|
317
|
+
)} else `
|
318
|
+
out += '0.0)'
|
319
|
+
return out
|
320
|
+
}
|
321
|
+
// case KEYWORDS.PIPE: {
|
322
|
+
// let inp = Arguments[0]
|
323
|
+
// for (let i = 1; i < Arguments.length; ++i)
|
324
|
+
// inp = [Arguments[i].shift(), inp, ...Arguments[i]]
|
325
|
+
// return compile(inp, Drill)
|
326
|
+
// }
|
327
|
+
case KEYWORDS.IMMUTABLE_FUNCTION: {
|
328
|
+
const [first, ...rest] = Arguments
|
329
|
+
return compile([leaf(APPLY, first[VALUE]), ...rest], Drill)
|
330
|
+
}
|
331
|
+
case KEYWORDS.NOT_COMPILED_BLOCK:
|
332
|
+
case KEYWORDS.TEST_CASE:
|
333
|
+
case KEYWORDS.TEST_BED:
|
334
|
+
case KEYWORDS.DOC:
|
335
|
+
return ''
|
336
|
+
default: {
|
337
|
+
const camelCased = lispToJavaScriptVariableName(token)
|
338
|
+
if (camelCased in Helpers) Drill.Helpers.add(camelCased)
|
339
|
+
return `${camelCased}(${parseArgs(Arguments, Drill)})`
|
340
|
+
}
|
341
|
+
}
|
342
|
+
} else if (first[TYPE] === ATOM)
|
343
|
+
return Number.isInteger(first[TYPE])
|
344
|
+
? `${first[VALUE]}.0`
|
345
|
+
: first[VALUE].toString()
|
346
|
+
else if (first[TYPE] === WORD) {
|
347
|
+
const camelCased = lispToJavaScriptVariableName(token)
|
348
|
+
if (camelCased in Helpers) Drill.Helpers.add(camelCased)
|
349
|
+
return camelCased
|
350
|
+
}
|
351
|
+
}
|
352
|
+
const HelpersEntries = new Map(Object.entries(Helpers))
|
353
|
+
export const comp = (ast) => {
|
354
|
+
const Drill = { Variables: new Set(), Helpers: new Set() }
|
355
|
+
const raw = ast
|
356
|
+
.map((tree) => compile(tree, Drill))
|
357
|
+
.filter(Boolean)
|
358
|
+
.join('\n')
|
359
|
+
let program = ''
|
360
|
+
for (let i = 0; i < raw.length; ++i) {
|
361
|
+
const current = raw[i]
|
362
|
+
const next = raw[i + 1]
|
363
|
+
if (!semiColumnEdgeCases.has(current + next)) program += current
|
364
|
+
}
|
365
|
+
const help = Drill.Helpers.size
|
366
|
+
? `${[...Drill.Helpers.keys()]
|
367
|
+
.map((x) => `let ${HelpersEntries.get(x)};;`)
|
368
|
+
.join('\n')}\n`
|
369
|
+
: ''
|
370
|
+
|
371
|
+
const top = `${help}`
|
372
|
+
return { top, program }
|
373
|
+
}
|
package/src/utils.js
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import std from '../lib/baked/std.js'
|
2
|
-
import { comp } from './compiler.js'
|
2
|
+
import { comp as JavaScript } from './compiler.js'
|
3
|
+
import { comp as OCaml } from './ocaml.js'
|
4
|
+
|
3
5
|
import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
|
4
6
|
import { run } from './evaluator.js'
|
5
7
|
import { AST, isLeaf, LISP } from './parser.js'
|
@@ -178,8 +180,16 @@ export const fez = (source, options = {}) => {
|
|
178
180
|
)
|
179
181
|
const ast = [...treeShake(parsed, std), ...parsed]
|
180
182
|
if (options.compile) {
|
181
|
-
|
182
|
-
|
183
|
+
switch (options.compile) {
|
184
|
+
case 1: {
|
185
|
+
const js = Object.values(JavaScript(deepClone(ast))).join('')
|
186
|
+
return options.eval ? eval(js) : js
|
187
|
+
}
|
188
|
+
case 2: {
|
189
|
+
const oCaml = Object.values(OCaml(deepClone(ast))).join('')
|
190
|
+
return oCaml
|
191
|
+
}
|
192
|
+
}
|
183
193
|
}
|
184
194
|
return run(ast, env)
|
185
195
|
} else if (Array.isArray(source)) {
|
@@ -187,8 +197,16 @@ export const fez = (source, options = {}) => {
|
|
187
197
|
? AST.parse(AST.stringify(source).replace(new RegExp(/!/g), 'ǃ'))
|
188
198
|
: source
|
189
199
|
if (options.compile) {
|
190
|
-
|
191
|
-
|
200
|
+
switch (options.compile) {
|
201
|
+
case 1: {
|
202
|
+
const js = Object.values(JavaScript(deepClone(ast))).join('')
|
203
|
+
return options.eval ? eval(js) : js
|
204
|
+
}
|
205
|
+
case 2: {
|
206
|
+
const OCaml = Object.values(OCaml(deepClone(ast))).join('')
|
207
|
+
return OCaml
|
208
|
+
}
|
209
|
+
}
|
192
210
|
}
|
193
211
|
return run(ast, env)
|
194
212
|
} else {
|