fez-lisp 1.4.8 → 1.4.9

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 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.4.8",
5
+ "version": "1.4.9",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/compiler.js CHANGED
@@ -141,32 +141,37 @@ const semiColumnEdgeCases = new Set([
141
141
  ';]',
142
142
  ';^'
143
143
  ])
144
- const parse = (Arguments, Drill) => Arguments.map((x) => comp(x, Drill))
145
- const parseArgs = (Arguments, Drill, separator = ',') =>
146
- parse(Arguments, Drill).join(separator)
144
+ const parse = (tail, Drill) => tail.map((x) => comp(x, Drill))
145
+ const parseArgs = (tail, Drill, separator = ',') =>
146
+ parse(tail, Drill).join(separator)
147
147
  const comp = (tree, Drill) => {
148
148
  if (!tree) return ''
149
- const [first, ...Arguments] = !isLeaf(tree) ? tree : [tree]
150
- if (first == undefined) return '[];'
151
- const token = first[VALUE]
152
- if (first[TYPE] === APPLY) {
149
+ let head, tail
150
+ if (isLeaf(tree)) head = tree
151
+ else {
152
+ head = tree[0]
153
+ if (head == undefined) return '[];'
154
+
155
+ tail = tree.slice(1)
156
+ }
157
+ const token = head[VALUE]
158
+ if (head[TYPE] === APPLY) {
153
159
  switch (token) {
154
160
  case KEYWORDS.BLOCK: {
155
- if (Arguments.length > 1) {
156
- return `(${Arguments.map((x) =>
157
- (comp(x, Drill) ?? '').toString().trim()
158
- )
161
+ if (tail.length > 1) {
162
+ return `(${tail
163
+ .map((x) => (comp(x, Drill) ?? '').toString().trim())
159
164
  .filter((x) => x !== undefined)
160
165
  .join(',')});`
161
166
  } else {
162
- const res = comp(Arguments[0], Drill)
167
+ const res = comp(tail[0], Drill)
163
168
  return res !== undefined ? res.toString().trim() : ''
164
169
  }
165
170
  }
166
171
  case KEYWORDS.CALL_FUNCTION: {
167
- const first = Arguments.pop()
168
- const rest = Arguments
169
- const apply = comp(first, Drill)
172
+ const head = tail.pop()
173
+ const rest = tail
174
+ const apply = comp(head, Drill)
170
175
  return `${
171
176
  apply[apply.length - 1] === ';'
172
177
  ? apply.substring(0, apply.length - 1)
@@ -174,7 +179,7 @@ const comp = (tree, Drill) => {
174
179
  }(${parseArgs(rest, Drill)})`
175
180
  }
176
181
  case KEYWORDS.DEFINE_VARIABLE: {
177
- const n = Arguments[0][VALUE]
182
+ const n = tail[0][VALUE]
178
183
  const prefix = n.split(':')[0]
179
184
  if (prefix === OPTIMIZATIONS.RECURSION) {
180
185
  const name = lispToJavaScriptVariableName(n)
@@ -185,7 +190,7 @@ const comp = (tree, Drill) => {
185
190
  Drill.Variables.add(name)
186
191
  Drill.Variables.add(newName)
187
192
  Drill.Helpers.add('__tco')
188
- const functionArgs = Arguments.at(-1).slice(1)
193
+ const functionArgs = tail.at(-1).slice(1)
189
194
  const body = functionArgs.pop()
190
195
  const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
191
196
  deepRename(n, `()=>${newName}`, body)
@@ -204,7 +209,7 @@ const comp = (tree, Drill) => {
204
209
  const name = lispToJavaScriptVariableName(n)
205
210
  const newName = name.substring(OPTIMIZATIONS.CACHE.length + 1)
206
211
  Drill.Variables.add(name)
207
- const functionArgs = Arguments.at(-1).slice(1)
212
+ const functionArgs = tail.at(-1).slice(1)
208
213
  const body = functionArgs.pop()
209
214
  deepRename(n, newName, body)
210
215
  const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
@@ -221,29 +226,26 @@ const comp = (tree, Drill) => {
221
226
  } else {
222
227
  const name = lispToJavaScriptVariableName(n)
223
228
  Drill.Variables.add(name)
224
- return `${name}=${comp(Arguments[1], Drill)};`
229
+ return `${name}=${comp(tail[1], Drill)};`
225
230
  }
226
231
  }
227
232
  case KEYWORDS.IS_ATOM:
228
233
  Drill.Helpers.add('atom_predicate')
229
- return `atom_predicate(${comp(Arguments[0], Drill)});`
234
+ return `atom_predicate(${comp(tail[0], Drill)});`
230
235
  case KEYWORDS.IS_LAMBDA:
231
236
  Drill.Helpers.add('lambda_predicate')
232
- return `lambda_predicate(${comp(Arguments[0], Drill)});`
237
+ return `lambda_predicate(${comp(tail[0], Drill)});`
233
238
  case KEYWORDS.CREATE_ARRAY:
234
- return `[${parseArgs(Arguments, Drill)}];`
239
+ return `[${parseArgs(tail, Drill)}];`
235
240
  case KEYWORDS.ARRAY_LENGTH:
236
241
  Drill.Helpers.add('length')
237
- return `length(${comp(Arguments[0], Drill)})`
242
+ return `length(${comp(tail[0], Drill)})`
238
243
  case KEYWORDS.GET_ARRAY:
239
244
  Drill.Helpers.add('get')
240
- return `get(${comp(Arguments[0], Drill)}, ${comp(
241
- Arguments[1],
242
- Drill
243
- )});`
245
+ return `get(${comp(tail[0], Drill)}, ${comp(tail[1], Drill)});`
244
246
  case KEYWORDS.ANONYMOUS_FUNCTION: {
245
- const functionArgs = Arguments
246
- const body = Arguments.pop()
247
+ const functionArgs = tail
248
+ const body = tail.pop()
247
249
  const InnerDrills = { Variables: new Set(), Helpers: Drill.Helpers }
248
250
  const evaluatedBody = comp(body, InnerDrills)
249
251
  const vars = InnerDrills.Variables.size
@@ -263,61 +265,61 @@ const comp = (tree, Drill) => {
263
265
  .trim()}});`
264
266
  }
265
267
  case KEYWORDS.AND:
266
- return `((${parseArgs(Arguments, Drill, '&&')}) ? 1 : 0);`
268
+ return `((${parseArgs(tail, Drill, '&&')}) ? 1 : 0);`
267
269
  case KEYWORDS.OR:
268
- return `((${parseArgs(Arguments, Drill, '||')}) ? 1 : 0);`
270
+ return `((${parseArgs(tail, Drill, '||')}) ? 1 : 0);`
269
271
  case KEYWORDS.EQUAL:
270
- return `+(${parseArgs(Arguments, Drill, '===')});`
272
+ return `+(${parseArgs(tail, Drill, '===')});`
271
273
  case KEYWORDS.GREATHER_THAN_OR_EQUAL:
272
274
  case KEYWORDS.LESS_THAN_OR_EQUAL:
273
275
  case KEYWORDS.GREATHER_THAN:
274
276
  case KEYWORDS.LESS_THAN:
275
- return `+(${parseArgs(Arguments, Drill, token)});`
277
+ return `+(${parseArgs(tail, Drill, token)});`
276
278
  case KEYWORDS.SUBTRACTION:
277
- return Arguments.length === 1
278
- ? `(-${comp(Arguments[0], Drill)});`
279
- : `(${parse(Arguments, Drill)
279
+ return tail.length === 1
280
+ ? `(-${comp(tail[0], Drill)});`
281
+ : `(${parse(tail, Drill)
280
282
  // Add space so it doesn't consider it 2--1 but 2- -1
281
283
  .map((x) => (typeof x === 'number' && x < 0 ? ` ${x}` : x))
282
284
  .join(token)});`
283
285
  case KEYWORDS.MULTIPLICATION:
284
- return `(${parseArgs(Arguments, Drill, token)});`
286
+ return `(${parseArgs(tail, Drill, token)});`
285
287
  case KEYWORDS.DIVISION:
286
- return `(${parseArgs(Arguments, Drill, token)});`
288
+ return `(${parseArgs(tail, Drill, token)});`
287
289
  case KEYWORDS.ADDITION:
288
- return `(${parseArgs(Arguments, Drill, token)});`
290
+ return `(${parseArgs(tail, Drill, token)});`
289
291
  case KEYWORDS.BITWISE_AND:
290
292
  case KEYWORDS.BITWISE_OR:
291
293
  case KEYWORDS.BITWISE_XOR:
292
294
  case KEYWORDS.BITWISE_LEFT_SHIFT:
293
295
  case KEYWORDS.BITWISE_RIGHT_SHIFT:
294
296
  case KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT:
295
- return `(${parseArgs(Arguments, Drill, token)});`
297
+ return `(${parseArgs(tail, Drill, token)});`
296
298
  case KEYWORDS.REMAINDER_OF_DIVISION:
297
- return `(${comp(Arguments[0], Drill)}%${comp(Arguments[1], Drill)});`
299
+ return `(${comp(tail[0], Drill)}%${comp(tail[1], Drill)});`
298
300
  case KEYWORDS.BIT_TYPE:
299
- return `(${comp(Arguments[0], Drill)}>>>0).toString(2)`
301
+ return `(${comp(tail[0], Drill)}>>>0).toString(2)`
300
302
  case KEYWORDS.BITWISE_NOT:
301
- return `~(${comp(Arguments[0], Drill)})`
303
+ return `~(${comp(tail[0], Drill)})`
302
304
  case KEYWORDS.NOT:
303
- return `(+!${comp(Arguments[0], Drill)})`
305
+ return `(+!${comp(tail[0], Drill)})`
304
306
  case KEYWORDS.IF: {
305
- return `(${comp(Arguments[0], Drill)}?${comp(Arguments[1], Drill)}:${
306
- Arguments.length === 3 ? comp(Arguments[2], Drill) : 0
307
+ return `(${comp(tail[0], Drill)}?${comp(tail[1], Drill)}:${
308
+ tail.length === 3 ? comp(tail[2], Drill) : 0
307
309
  });`
308
310
  }
309
311
  case KEYWORDS.ERROR: {
310
312
  Drill.Helpers.add('__error')
311
- return `__error(${compile(Arguments[0], Drill)})`
313
+ return `__error(${compile(tail[0], Drill)})`
312
314
  }
313
315
  default: {
314
316
  const camelCased = lispToJavaScriptVariableName(token)
315
317
  if (camelCased in Helpers) Drill.Helpers.add(camelCased)
316
- return `${camelCased}(${parseArgs(Arguments, Drill)});`
318
+ return `${camelCased}(${parseArgs(tail, Drill)});`
317
319
  }
318
320
  }
319
- } else if (first[TYPE] === ATOM) return first[VALUE]
320
- else if (first[TYPE] === WORD) {
321
+ } else if (head[TYPE] === ATOM) return head[VALUE]
322
+ else if (head[TYPE] === WORD) {
321
323
  const camelCased = lispToJavaScriptVariableName(token)
322
324
  if (camelCased in Helpers) Drill.Helpers.add(camelCased)
323
325
  return camelCased
package/src/evaluator.js CHANGED
@@ -12,10 +12,15 @@ import {
12
12
  import { isLeaf } from './parser.js'
13
13
  import { stringifyArgs } from './utils.js'
14
14
  export const evaluate = (exp, env = keywords) => {
15
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
16
- if (first == undefined) return []
17
- const value = first[VALUE]
18
- switch (first[TYPE]) {
15
+ let head, tail
16
+ if (isLeaf(exp)) head = exp
17
+ else {
18
+ head = exp[0]
19
+ if (head == undefined) return []
20
+ tail = exp.slice(1)
21
+ }
22
+ const value = head[VALUE]
23
+ switch (head[TYPE]) {
19
24
  case WORD: {
20
25
  const word = env[value]
21
26
  if (word == undefined)
@@ -33,7 +38,7 @@ export const evaluate = (exp, env = keywords) => {
33
38
  `${value} is not a (${KEYWORDS.ANONYMOUS_FUNCTION})`
34
39
  )
35
40
  const isSpecial = SPECIAL_FORMS_SET.has(value)
36
- const result = apply(rest, env, value)
41
+ const result = apply(tail, env, value)
37
42
  if (!isSpecial && Array.isArray(env[DEBUG.CALLSTACK]))
38
43
  env[DEBUG.CALLSTACK].pop()
39
44
  return result
package/src/parser.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { APPLY, ATOM, TYPE, WORD, VALUE } from './keywords.js'
2
2
  export const leaf = (type, value) => [type, value]
3
3
  export const isLeaf = ([car]) => car === APPLY || car === ATOM || car === WORD
4
+ export const toPair = (exp) => []
4
5
  export const LISP = {
5
6
  parse: (source) => {
6
7
  const tree = []
@@ -46,17 +47,23 @@ export const LISP = {
46
47
  source: (ast) => {
47
48
  const dfs = (exp) => {
48
49
  let out = ''
49
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
50
- if (first == undefined) return (out += '()')
51
- switch (first[TYPE]) {
50
+ let head, tail
51
+ if (isLeaf(exp)) head = exp
52
+ else {
53
+ head = exp[0]
54
+ if (head == undefined) return []
55
+ tail = exp.slice(1)
56
+ }
57
+ if (head == undefined) return (out += '()')
58
+ switch (head[TYPE]) {
52
59
  case WORD:
53
- out += first[VALUE]
60
+ out += head[VALUE]
54
61
  break
55
62
  case ATOM:
56
- out += first[VALUE]
63
+ out += head[VALUE]
57
64
  break
58
65
  case APPLY:
59
- out += `(${first[VALUE]} ${rest.map(dfs).join(' ')})`
66
+ out += `(${head[VALUE]} ${tail.map(dfs).join(' ')})`
60
67
  break
61
68
  }
62
69
  return out
@@ -108,25 +115,31 @@ export const AST = {
108
115
  struct: (ast) => {
109
116
  const dfs = (exp) => {
110
117
  let out = ''
111
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
112
- if (first == undefined)
118
+ let head, tail
119
+ if (isLeaf(exp)) head = exp
120
+ else {
121
+ head = exp[0]
122
+ if (head == undefined) return []
123
+ tail = exp.slice(1)
124
+ }
125
+ if (head == undefined)
113
126
  return (out +=
114
127
  '(Expression::Apply(vec![Expression::Word("array".to_string())]))')
115
- switch (first[TYPE]) {
128
+ switch (head[TYPE]) {
116
129
  case WORD:
117
- out += `Expression::Word("${first[VALUE]}".to_string())`
130
+ out += `Expression::Word("${head[VALUE]}".to_string())`
118
131
  break
119
132
  case ATOM:
120
133
  out += `Expression::Atom(${
121
- Number.isInteger(first[VALUE])
122
- ? `${first[VALUE]}.0`
123
- : first[VALUE].toString()
134
+ Number.isInteger(head[VALUE])
135
+ ? `${head[VALUE]}.0`
136
+ : head[VALUE].toString()
124
137
  })`
125
138
  break
126
139
  case APPLY:
127
140
  out += `Expression::Apply(vec![Expression::Word("${
128
- first[VALUE]
129
- }".to_string()),${rest.map(dfs).join(',')}])`
141
+ head[VALUE]
142
+ }".to_string()),${tail.map(dfs).join(',')}])`
130
143
  break
131
144
  }
132
145
  return out