fez-lisp 1.4.4 → 1.4.6

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.4",
5
+ "version": "1.4.6",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/evaluator.js CHANGED
@@ -2,6 +2,7 @@ import { keywords } from './interpreter.js'
2
2
  import {
3
3
  APPLY,
4
4
  ATOM,
5
+ DEBUG,
5
6
  KEYWORDS,
6
7
  SPECIAL_FORMS_SET,
7
8
  TYPE,
@@ -9,7 +10,7 @@ import {
9
10
  WORD
10
11
  } from './keywords.js'
11
12
  import { isLeaf } from './parser.js'
12
- import { callStack, stringifyArgs } from './utils.js'
13
+ import { stringifyArgs } from './utils.js'
13
14
  export const evaluate = (exp, env = keywords) => {
14
15
  const [first, ...rest] = isLeaf(exp) ? [exp] : exp
15
16
  if (first == undefined) return []
@@ -33,7 +34,8 @@ export const evaluate = (exp, env = keywords) => {
33
34
  )
34
35
  const isSpecial = SPECIAL_FORMS_SET.has(value)
35
36
  const result = apply(rest, env, value)
36
- if (!isSpecial) callStack.pop()
37
+ if (!isSpecial && Array.isArray(env[DEBUG.CALLSTACK]))
38
+ env[DEBUG.CALLSTACK].pop()
37
39
  return result
38
40
  }
39
41
  case ATOM:
@@ -6,10 +6,11 @@ import {
6
6
  FALSE,
7
7
  TRUE,
8
8
  TYPES,
9
- RUNTIME_TYPES
9
+ RUNTIME_TYPES,
10
+ DEBUG
10
11
  } from './keywords.js'
11
12
  import { evaluate } from './evaluator.js'
12
- import { callStack, isForbiddenVariableName, stringifyArgs } from './utils.js'
13
+ import { isForbiddenVariableName, stringifyArgs } from './utils.js'
13
14
  import { LISP } from './parser.js'
14
15
  export const keywords = {
15
16
  [KEYWORDS.ADDITION]: (args, env) => {
@@ -773,7 +774,12 @@ export const keywords = {
773
774
  writable: true
774
775
  })
775
776
  }
776
- if (name) callStack.push(name)
777
+ if (
778
+ name &&
779
+ Array.isArray(env[DEBUG.CALLSTACK]) &&
780
+ name !== env[DEBUG.CALLSTACK].at(-1)
781
+ )
782
+ env[DEBUG.CALLSTACK].push(name)
777
783
  return evaluate(body, localEnv)
778
784
  }
779
785
  },
package/src/keywords.js CHANGED
@@ -40,7 +40,7 @@ export const KEYWORDS = {
40
40
  DEFINE_VARIABLE: 'let',
41
41
 
42
42
  SET_ARRAY: 'set!',
43
- ERROR: 'throw'
43
+ ERROR: 'throw',
44
44
  }
45
45
 
46
46
  export const TYPES = {
@@ -54,7 +54,9 @@ export const RUNTIME_TYPES = {
54
54
  }
55
55
  export const DEBUG = {
56
56
  LOG: 'log',
57
- ASSERT: 'assert'
57
+ ASSERT: 'assert',
58
+ CALLSTACK: '(CALLSTACK)' // so that you can't use it in the code
59
+
58
60
  }
59
61
 
60
62
  export const SPECIAL_FORMS_SET = new Set(Object.values(KEYWORDS))
package/src/utils.js CHANGED
@@ -232,39 +232,6 @@ export const wrapInBlock = (ast) => [
232
232
  ]
233
233
  export const interpret = (ast, keywords) =>
234
234
  ast.reduce((_, x) => evaluate(x, keywords), 0)
235
- export const fez = (source, options = {}) => {
236
- const env = { ...keywords }
237
- try {
238
- if (typeof source === 'string') {
239
- source = deSuggarSource(source)
240
- const valid = handleUnbalancedQuotes(
241
- handleUnbalancedParens(removeNoCode(source))
242
- )
243
- const code = !options.mutation ? removeMutation(valid) : valid
244
- if (!code.length && options.throw) throw new Error('Nothing to parse!')
245
- const parsed = LISP.parse(code)
246
- const scope = deSuggarAst(parsed)
247
- const ast = wrapInBlock(shake(scope, std))
248
- // if (options.check) typeCheck(ast)
249
- if (options.compile) return compile(ast)
250
- return evaluate(ast, env)
251
- } else if (Array.isArray(source)) {
252
- const ast = !options.mutation
253
- ? AST.parse(AST.stringify(source).replace(new RegExp(/!/g), 'ǃ'))
254
- : source
255
- if (options.compile) return compile(ast)
256
- return evaluate(ast, env)
257
- } else {
258
- throw new Error('Source has to be either a lisp source code or an AST')
259
- }
260
- } catch (error) {
261
- const err = error.message.replace("'[object Array]'", '(array)')
262
- // .replace('object', '(array)')
263
- logError(err)
264
- if (options.throw) throw err
265
- return err
266
- }
267
- }
268
235
  export const shake = (parsed, std) => treeShake(parsed, std).concat(parsed)
269
236
  export const tree = (source, std) =>
270
237
  std
@@ -317,133 +284,162 @@ const identity = (name) => [
317
284
  [1, 'x']
318
285
  ]
319
286
  ]
320
- export const callStack = [KEYWORDS.BLOCK]
287
+ // export const result = (ast) => {
288
+ // try {
289
+ // return { output: evaluate(ast, keywords), error: null }
290
+ // } catch (error) {
291
+ // const isMaxCallStack =
292
+ // error.message.includes('Maximum call stack size exceeded') ||
293
+ // error.message.includes('too much recursion')
294
+ // return {
295
+ // output: null,
296
+ // error: {
297
+ // stack: [...callStack],
298
+ // message: isMaxCallStack
299
+ // ? error
300
+ // : `${error}\n${callStack
301
+ // .reverse()
302
+ // .map((x, i) => `${Array(i + 2).join(' ')}(${x} ...)`)
303
+ // .join('\n')}`
304
+ // }
305
+ // }
306
+ // }
307
+ // }
321
308
  export const debug = (ast) => {
322
- callStack.length = 0
323
- callStack.push(KEYWORDS.BLOCK)
324
- try {
325
- const debugEnv = {
326
- ...keywords,
327
- [DEBUG.LOG]: (args, env) => {
328
- if (args.length !== 1 && args.length !== 2)
329
- throw new RangeError(
330
- `Invalid number of arguments to (${DEBUG.LOG}) (or (= 1) (= 2)) (${
331
- DEBUG.LOG
332
- } ${stringifyArgs(args)})`
309
+ const debugEnv = {
310
+ ...keywords,
311
+ [DEBUG.CALLSTACK]: [KEYWORDS.BLOCK],
312
+ [DEBUG.LOG]: (args, env) => {
313
+ if (args.length !== 1 && args.length !== 2)
314
+ throw new RangeError(
315
+ `Invalid number of arguments to (${DEBUG.LOG}) (or (= 1) (= 2)) (${
316
+ DEBUG.LOG
317
+ } ${stringifyArgs(args)})`
318
+ )
319
+ const expression = evaluate(args[0], env)
320
+ if (args.length === 2) {
321
+ const option = evaluate(args[1], env)
322
+ if (!Array.isArray(option)) {
323
+ throw new TypeError(
324
+ `Second argument of (${DEBUG.LOG}) must be an (${
325
+ RUNTIME_TYPES.ARRAY
326
+ }) but got (${expression}) (${DEBUG.LOG} ${stringifyArgs(args)})`
333
327
  )
334
- const expression = evaluate(args[0], env)
335
- if (args.length === 2) {
336
- const option = evaluate(args[1], env)
337
- if (!Array.isArray(option)) {
338
- throw new TypeError(
339
- `Second argument of (${DEBUG.LOG}) must be an (${
340
- RUNTIME_TYPES.ARRAY
341
- }) but got (${expression}) (${DEBUG.LOG} ${stringifyArgs(args)})`
342
- )
343
- }
344
- const type = option.map((x) => String.fromCharCode(x)).join('')
345
- switch (type) {
346
- case 'string':
347
- case 'str':
348
- {
349
- if (!Array.isArray(expression))
350
- throw new TypeError(
351
- `Argument of (${DEBUG.LOG}) must be an (${
352
- RUNTIME_TYPES.ARRAY
353
- }) in the case ${type} but got (${expression}) (${
354
- DEBUG.LOG
355
- } ${stringifyArgs(args)})`
356
- )
357
- console.log(
358
- expression.map((x) => String.fromCharCode(x)).join('')
328
+ }
329
+ const type = option.map((x) => String.fromCharCode(x)).join('')
330
+ switch (type) {
331
+ case 'string':
332
+ case 'str':
333
+ {
334
+ if (!Array.isArray(expression))
335
+ throw new TypeError(
336
+ `Argument of (${DEBUG.LOG}) must be an (${
337
+ RUNTIME_TYPES.ARRAY
338
+ }) in the case ${type} but got (${expression}) (${
339
+ DEBUG.LOG
340
+ } ${stringifyArgs(args)})`
359
341
  )
360
- }
361
- break
362
- case 'char':
363
- case 'ch':
364
- {
365
- if (typeof expression !== 'number')
366
- throw new TypeError(
367
- `Argument argument of (${DEBUG.LOG}) must be a (${
368
- RUNTIME_TYPES.NUMBER
369
- }) in the case ${type} but got (${expression}) (${
370
- DEBUG.LOG
371
- } ${stringifyArgs(args)})`
372
- )
373
- console.log(String.fromCharCode(expression))
374
- }
375
-
376
- break
377
- case '*':
378
- console.log(expression)
379
- break
380
- default:
381
- throw new TypeError(
382
- `Invalid number of option to (${
383
- DEBUG.LOG
384
- }) got ${option} ${stringifyArgs(args)})`
342
+ console.log(
343
+ expression.map((x) => String.fromCharCode(x)).join('')
385
344
  )
386
- }
387
- } else console.log(expression)
388
- return expression
389
- },
390
- [DEBUG.ASSERT]: (args, env) => {
391
- if (args.length < 2)
392
- throw new RangeError(
393
- `Invalid number of arguments for (${
394
- DEBUG.ASSERT
395
- }), expected (> 2 required) but got ${args.length} (${
396
- DEBUG.ASSERT
397
- } ${stringifyArgs(args)})`
398
- )
399
- if (args.length % 2 !== 0)
400
- throw new RangeError(
401
- `Invalid number of arguments for (${
345
+ }
346
+ break
347
+ case 'char':
348
+ case 'ch':
349
+ {
350
+ if (typeof expression !== 'number')
351
+ throw new TypeError(
352
+ `Argument argument of (${DEBUG.LOG}) must be a (${
353
+ RUNTIME_TYPES.NUMBER
354
+ }) in the case ${type} but got (${expression}) (${
355
+ DEBUG.LOG
356
+ } ${stringifyArgs(args)})`
357
+ )
358
+ console.log(String.fromCharCode(expression))
359
+ }
360
+
361
+ break
362
+ case '*':
363
+ console.log(expression)
364
+ break
365
+ default:
366
+ throw new TypeError(
367
+ `Invalid number of option to (${
368
+ DEBUG.LOG
369
+ }) got ${option} ${stringifyArgs(args)})`
370
+ )
371
+ }
372
+ } else console.log(expression)
373
+ return expression
374
+ },
375
+ [DEBUG.ASSERT]: (args, env) => {
376
+ if (args.length < 2)
377
+ throw new RangeError(
378
+ `Invalid number of arguments for (${
379
+ DEBUG.ASSERT
380
+ }), expected (> 2 required) but got ${args.length} (${
381
+ DEBUG.ASSERT
382
+ } ${stringifyArgs(args)})`
383
+ )
384
+ if (args.length % 2 !== 0)
385
+ throw new RangeError(
386
+ `Invalid number of arguments for (${
387
+ DEBUG.ASSERT
388
+ }), expected even number of arguments but got ${args.length} (${
389
+ DEBUG.ASSERT
390
+ } ${stringifyArgs(args)})`
391
+ )
392
+ for (let i = 0; i < args.length; i += 2) {
393
+ const condition = evaluate(args[i], env)
394
+ if (condition !== FALSE && condition !== TRUE)
395
+ throw new TypeError(
396
+ `Condition of (${
402
397
  DEBUG.ASSERT
403
- }), expected even number of arguments but got ${args.length} (${
398
+ }) must be ${TRUE} or ${FALSE} but got (${
404
399
  DEBUG.ASSERT
405
400
  } ${stringifyArgs(args)})`
406
401
  )
407
- for (let i = 0; i < args.length; i += 2) {
408
- const condition = evaluate(args[i], env)
409
- if (condition !== FALSE && condition !== TRUE)
402
+ if (condition) {
403
+ const error = args[i + 1]
404
+ if (error[0][TYPE] === APPLY && error[0][VALUE] === KEYWORDS.ERROR)
405
+ return evaluate(error, env)
406
+ else
410
407
  throw new TypeError(
411
- `Condition of (${
412
- DEBUG.ASSERT
413
- }) must be ${TRUE} or ${FALSE} but got (${
414
- DEBUG.ASSERT
415
- } ${stringifyArgs(args)})`
408
+ `Concequence of (${DEBUG.ASSERT}) must be (${
409
+ KEYWORDS.ERROR
410
+ }) but got (${DEBUG.ASSERT} ${stringifyArgs(args)})`
416
411
  )
417
- if (condition) {
418
- const error = args[i + 1]
419
- if (error[0][TYPE] === APPLY && error[0][VALUE] === KEYWORDS.ERROR)
420
- return evaluate(error, env)
421
- else
422
- throw new TypeError(
423
- `Concequence of (${DEBUG.ASSERT}) must be (${
424
- KEYWORDS.ERROR
425
- }) but got (${DEBUG.ASSERT} ${stringifyArgs(args)})`
426
- )
427
- }
428
412
  }
429
- return 0
430
413
  }
414
+ return 0
415
+ }
416
+ }
417
+ try {
418
+ const evaluated = evaluate(ast, debugEnv)
419
+ const block = ast[1][1]
420
+ const temp = block.shift()
421
+ block.unshift(temp, identity(DEBUG.LOG), identity(DEBUG.ASSERT))
422
+ return {
423
+ evaluated,
424
+ compiled: compile(ast),
425
+ error: null
431
426
  }
432
- evaluate(ast, debugEnv)
433
427
  } catch (error) {
434
428
  const isMaxCallStack =
435
429
  error.message.includes('Maximum call stack size exceeded') ||
436
430
  error.message.includes('too much recursion')
437
- if (!isMaxCallStack) {
438
- error.message += `\n${callStack
439
- .reverse()
440
- .map((x, i) => `\x1b[33m${Array(i + 2).join('.')}\x1b[31m(${x} \x1b[39m...\x1b[31m)`)
441
- .join('\n')}`
442
- throw error
443
- } else logError(error.message)
431
+ return {
432
+ compiled: null,
433
+ evaluated: null,
434
+ error: {
435
+ message: isMaxCallStack
436
+ ? error.message
437
+ : `${error.message}\n${debugEnv[DEBUG.CALLSTACK]
438
+ .reverse()
439
+ .map((x, i) => `${Array(i + 2).join(' ')}(${x} ...)`)
440
+ .join('\n')}`,
441
+ stack: debugEnv[DEBUG.CALLSTACK]
442
+ }
443
+ }
444
444
  }
445
- const block = ast[1][1]
446
- const temp = block.shift()
447
- block.unshift(temp, identity(DEBUG.LOG), identity(DEBUG.ASSERT))
448
- return compile(ast)
449
445
  }