fez-lisp 1.3.27 → 1.4.0

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/src/keywords.js CHANGED
@@ -39,12 +39,7 @@ export const KEYWORDS = {
39
39
  CALL_FUNCTION: 'apply',
40
40
  DEFINE_VARIABLE: 'let',
41
41
 
42
- SET_ARRAY: 'set!',
43
-
44
- LOG: 'log!',
45
- LOG_STRING: 'log-string!',
46
- LOG_CHAR: 'log-char!',
47
- CLEAR_CONSOLE: 'clear!'
42
+ SET_ARRAY: 'set!'
48
43
  }
49
44
 
50
45
  export const TYPES = {
@@ -56,3 +51,10 @@ export const RUNTIME_TYPES = {
56
51
  NUMBER: 'number',
57
52
  ARRAY: 'array'
58
53
  }
54
+ export const DEBUG = {
55
+ LOG: 'log',
56
+ ASSERT: 'assert',
57
+ ERROR: 'error'
58
+ }
59
+
60
+ export const SPECIAL_FORMS_SET = new Set(Object.values(KEYWORDS))
package/src/macros.js CHANGED
@@ -31,7 +31,7 @@ export const SUGGAR = {
31
31
  }
32
32
  export const deSuggarAst = (ast, scope) => {
33
33
  if (scope === undefined) scope = ast
34
- if (ast.length === 0) throw new SyntaxError(`No expressions to evaluate`)
34
+ if (ast.length === 0) throw new SyntaxError(`No expressions...`)
35
35
  // for (const node of ast)
36
36
  // if (node[0] && node[0][TYPE] === APPLY && node[0][VALUE] === KEYWORDS.BLOCK)
37
37
  // throw new SyntaxError(`Top level (${KEYWORDS.BLOCK}) is not allowed`)
@@ -667,11 +667,6 @@ const iron2 = (scope, exp) => {
667
667
  }
668
668
  export const replaceQuotes = (source) =>
669
669
  source
670
- .replaceAll(/\'\(/g, `(${KEYWORDS.CREATE_ARRAY} `)
671
- .replaceAll(/\`\(/g, `(${SUGGAR.CREATE_LIST} `)
672
- .replaceAll(/\(\)/g, `(${KEYWORDS.CREATE_ARRAY})`)
673
- .replaceAll(/\[\]/g, `(${KEYWORDS.CREATE_ARRAY})`)
674
- .replaceAll(/\{\}/g, `(${SUGGAR.CREATE_LIST})`)
675
670
  .replaceAll(/\[/g, `(${KEYWORDS.CREATE_ARRAY} `)
676
671
  .replaceAll(/\]/g, ')')
677
672
  .replaceAll(/\{/g, `(${SUGGAR.CREATE_LIST} `)
package/src/parser.js CHANGED
@@ -61,7 +61,7 @@ export const LISP = {
61
61
  }
62
62
  return out
63
63
  }
64
- return ast.map(dfs).join(' ')
64
+ return dfs(ast)
65
65
  }
66
66
  }
67
67
  export const AST = {
package/src/utils.js CHANGED
@@ -1,6 +1,17 @@
1
1
  import std from '../lib/baked/std.js'
2
- import { comp, OPTIMIZATIONS } from './compiler.js'
3
- import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
2
+ import { compile, OPTIMIZATIONS } from './compiler.js'
3
+ import {
4
+ APPLY,
5
+ ATOM,
6
+ DEBUG,
7
+ FALSE,
8
+ KEYWORDS,
9
+ RUNTIME_TYPES,
10
+ TRUE,
11
+ TYPE,
12
+ VALUE,
13
+ WORD
14
+ } from './keywords.js'
4
15
  import { evaluate } from './evaluator.js'
5
16
  import { AST, isLeaf, LISP } from './parser.js'
6
17
  import {
@@ -11,7 +22,7 @@ import {
11
22
  import { keywords } from './interpreter.js'
12
23
  export const logError = (error) =>
13
24
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
14
- export const logSuccess = (output) => console.log(output, '\x1b[0m')
25
+ export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
15
26
  // export const replaceEmptyArrays = (source) =>
16
27
  // source
17
28
  export const removeNoCode = (source) =>
@@ -236,19 +247,18 @@ export const fez = (source, options = {}) => {
236
247
  const scope = deSuggarAst(parsed)
237
248
  const ast = wrapInBlock(shake(scope, std))
238
249
  // if (options.check) typeCheck(ast)
239
- if (options.compile) return comp(ast)
250
+ if (options.compile) return compile(ast)
240
251
  return evaluate(ast, env)
241
252
  } else if (Array.isArray(source)) {
242
253
  const ast = !options.mutation
243
254
  ? AST.parse(AST.stringify(source).replace(new RegExp(/!/g), 'ǃ'))
244
255
  : source
245
- if (options.compile) return comp(ast)
256
+ if (options.compile) return compile(ast)
246
257
  return evaluate(ast, env)
247
258
  } else {
248
259
  throw new Error('Source has to be either a lisp source code or an AST')
249
260
  }
250
261
  } catch (error) {
251
- // console.log(error)
252
262
  const err = error.message.replace("'[object Array]'", '(array)')
253
263
  // .replace('object', '(array)')
254
264
  logError(err)
@@ -313,4 +323,175 @@ export const ast = (source, deps) =>
313
323
  deps.reduce((a, b) => a.concat(b), [])
314
324
  )
315
325
  )
326
+
316
327
  export const astWithStd = (source) => wrapInBlock(shake(prep(source), std))
328
+ export const parse = (source) =>
329
+ wrapInBlock(
330
+ shake(
331
+ deSuggarAst(
332
+ LISP.parse(
333
+ removeNoCode(
334
+ handleUnbalancedQuotes(
335
+ handleUnbalancedParens(deSuggarSource(source))
336
+ )
337
+ )
338
+ )
339
+ ),
340
+ std
341
+ )
342
+ )
343
+ export const debug = (ast) => {
344
+ try {
345
+ const debugEnv = {
346
+ ...keywords,
347
+ [DEBUG.LOG]: (args, env) => {
348
+ if (args.length !== 1 && args.length !== 2)
349
+ throw new RangeError(
350
+ `Invalid number of arguments to (${DEBUG.LOG}) (or (= 1) (= 2)) (${
351
+ DEBUG.LOG
352
+ } ${stringifyArgs(args)})`
353
+ )
354
+ const expression = evaluate(args[0], env)
355
+ if (args.length === 2) {
356
+ const option = evaluate(args[1], env)
357
+ if (!Array.isArray(option)) {
358
+ throw new TypeError(
359
+ `Second argument of (${DEBUG.LOG}) must be an (${
360
+ RUNTIME_TYPES.ARRAY
361
+ }) but got (${expression}) (${DEBUG.LOG} ${stringifyArgs(args)})`
362
+ )
363
+ }
364
+ const type = option.map((x) => String.fromCharCode(x)).join('')
365
+ switch (type) {
366
+ case 'string':
367
+ case 'str':
368
+ {
369
+ if (!Array.isArray(expression))
370
+ throw new TypeError(
371
+ `Argument of (${DEBUG.LOG}) must be an (${
372
+ RUNTIME_TYPES.ARRAY
373
+ }) in the case ${type} but got (${expression}) (${
374
+ DEBUG.LOG
375
+ } ${stringifyArgs(args)})`
376
+ )
377
+ console.log(
378
+ expression.map((x) => String.fromCharCode(x)).join('')
379
+ )
380
+ }
381
+ break
382
+ case 'char':
383
+ case 'ch':
384
+ {
385
+ if (typeof expression !== 'number')
386
+ throw new TypeError(
387
+ `Argument argument of (${DEBUG.LOG}) must be a (${
388
+ RUNTIME_TYPES.NUMBER
389
+ }) in the case ${type} but got (${expression}) (${
390
+ DEBUG.LOG
391
+ } ${stringifyArgs(args)})`
392
+ )
393
+ console.log(String.fromCharCode(expression))
394
+ }
395
+
396
+ break
397
+ case '*':
398
+ console.log(expression)
399
+ break
400
+ default:
401
+ throw new TypeError(
402
+ `Invalid number of option to (${
403
+ DEBUG.LOG
404
+ }) got ${option} ${stringifyArgs(args)})`
405
+ )
406
+ }
407
+ } else console.log(expression)
408
+ return expression
409
+ },
410
+ [DEBUG.ERROR]: (args, env) => {
411
+ if (args.length !== 1)
412
+ throw new RangeError(
413
+ `Invalid number of arguments to (${DEBUG.ERROR}) (= 1 required) (${
414
+ DEBUG.ERROR
415
+ } ${stringifyArgs(args)})`
416
+ )
417
+ const expression = evaluate(args[0], env)
418
+ if (!Array.isArray(expression))
419
+ throw new TypeError(
420
+ `Argument of (${DEBUG.ERROR}) must be an (${
421
+ DEBUG.ARRAY_TYPE
422
+ }) but got (${expression}) (${DEBUG.ERROR} ${stringifyArgs(args)})`
423
+ )
424
+ throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
425
+ },
426
+ [DEBUG.ASSERT]: (args, env) => {
427
+ if (args.length < 2)
428
+ throw new RangeError(
429
+ `Invalid number of arguments for (${
430
+ DEBUG.ASSERT
431
+ }), expected (> 2 required) but got ${args.length} (${
432
+ DEBUG.ASSERT
433
+ } ${stringifyArgs(args)})`
434
+ )
435
+ if (args.length % 2 !== 0)
436
+ throw new RangeError(
437
+ `Invalid number of arguments for (${
438
+ DEBUG.ASSERT
439
+ }), expected even number of arguments but got ${args.length} (${
440
+ DEBUG.ASSERT
441
+ } ${stringifyArgs(args)})`
442
+ )
443
+ for (let i = 0; i < args.length; i += 2) {
444
+ const condition = evaluate(args[i], env)
445
+ if (condition !== FALSE && condition !== TRUE)
446
+ throw new TypeError(
447
+ `Condition of (${
448
+ DEBUG.ASSERT
449
+ }) must be ${TRUE} or ${FALSE} but got (${
450
+ DEBUG.ASSERT
451
+ } ${stringifyArgs(args)})`
452
+ )
453
+ if (condition) {
454
+ const error = args[i + 1]
455
+ if (error[0][TYPE] === APPLY && error[0][VALUE] === DEBUG.ERROR)
456
+ return evaluate(error, env)
457
+ else
458
+ throw new TypeError(
459
+ `Concequence of (${DEBUG.ASSERT}) must be (${
460
+ DEBUG.ERROR
461
+ }) but got (${DEBUG.ASSERT} ${stringifyArgs(args)})`
462
+ )
463
+ }
464
+ }
465
+ return 0
466
+ }
467
+ }
468
+ evaluate(ast, debugEnv)
469
+ } 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)})`
476
+ throw error
477
+ } else logError(error.message)
478
+ }
479
+ const identity = (name) => [
480
+ [0, 'let'],
481
+ [1, name],
482
+ [
483
+ [0, 'lambda'],
484
+ [1, 'x'],
485
+ [1, 'x']
486
+ ]
487
+ ]
488
+ const block = ast[1][1]
489
+ const temp = block.shift()
490
+ block.unshift(
491
+ temp,
492
+ identity(DEBUG.LOG),
493
+ identity(DEBUG.ERROR),
494
+ identity(DEBUG.ASSERT)
495
+ )
496
+ return compile(ast)
497
+ }