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/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.0",
5
+ "version": "1.4.1",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
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=(fm)=>+(typeof fn==='function')`,
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) evaluate.stack.pop()
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]
@@ -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) evaluate.stack.push(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(${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
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
- if (
471
- !error.message.includes('Maximum call stack size exceeded') &&
472
- !error.message.includes('too much recursion') &&
473
- error.message !== 'Maximum function invocation limit exceeded'
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(