fez-lisp 1.2.49 → 1.2.53

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.2.49",
5
+ "version": "1.2.53",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/compiler.js CHANGED
@@ -5,7 +5,8 @@ import {
5
5
  KEYWORDS,
6
6
  TYPE,
7
7
  VALUE,
8
- WORD
8
+ WORD,
9
+ SUGGAR
9
10
  } from './keywords.js'
10
11
  import { leaf, isLeaf } from './parser.js'
11
12
  const deepRenameTco = (name, newName, tree) => {
@@ -176,9 +177,9 @@ const compile = (tree, Drill) => {
176
177
  case KEYWORDS.DEFINE_VARIABLE: {
177
178
  const n = Arguments[0][VALUE]
178
179
  const prefix = n.split(':')[0]
179
- if (prefix === KEYWORDS.RECURSION) {
180
+ if (prefix === SUGGAR.RECURSION) {
180
181
  const name = lispToJavaScriptVariableName(n)
181
- const newName = `recursive_${performance
182
+ const newName = `${SUGGAR.RECURSION}_${performance
182
183
  .now()
183
184
  .toString()
184
185
  .replace('.', 7)}`
@@ -199,10 +200,10 @@ const compile = (tree, Drill) => {
199
200
  )})=>{${vars}return ${evaluatedBody
200
201
  .toString()
201
202
  .trim()}}, ${newName})));`
202
- } else if (prefix === KEYWORDS.CACHE) {
203
+ } else if (prefix === SUGGAR.CACHE) {
203
204
  // memoization here
204
205
  const name = lispToJavaScriptVariableName(n)
205
- const newName = name.substring(KEYWORDS.CACHE.length + 1)
206
+ const newName = name.substring(SUGGAR.CACHE.length + 1)
206
207
  Drill.Variables.add(name)
207
208
  const functionArgs = Arguments.at(-1).slice(1)
208
209
  const body = functionArgs.pop()
@@ -312,16 +313,6 @@ const compile = (tree, Drill) => {
312
313
  Drill
313
314
  )}:${Arguments.length === 3 ? compile(Arguments[2], Drill) : 0});`
314
315
  }
315
- case KEYWORDS.CONDITION: {
316
- let out = '('
317
- for (let i = 0; i < Arguments.length; i += 2)
318
- out += `${compile(Arguments[i], Drill)}?${compile(
319
- Arguments[i + 1],
320
- Drill
321
- )}:`
322
- out += '0);'
323
- return out
324
- }
325
316
  case KEYWORDS.THROW: {
326
317
  Drill.Helpers.add('__error')
327
318
  return `__error(${compile(Arguments[0], Drill)})`
@@ -171,37 +171,6 @@ export const keywords = {
171
171
  ? evaluate(args[2], env)
172
172
  : 0
173
173
  },
174
- [KEYWORDS.CONDITION]: (args, env) => {
175
- if (args.length < 2)
176
- throw new RangeError(
177
- `Invalid number of arguments for (${
178
- KEYWORDS.CONDITION
179
- }), expected (> 2 required) but got ${args.length} (${
180
- KEYWORDS.CONDITION
181
- } ${stringifyArgs(args)})`
182
- )
183
- if (args.length % 2 !== 0)
184
- throw new RangeError(
185
- `Invalid number of arguments for (${
186
- KEYWORDS.CONDITION
187
- }), expected even number of arguments but got ${args.length} (${
188
- KEYWORDS.CONDITION
189
- } ${stringifyArgs(args)})`
190
- )
191
- for (let i = 0; i < args.length; i += 2) {
192
- const condition = evaluate(args[i], env)
193
- if (condition !== FALSE && condition !== TRUE)
194
- throw new TypeError(
195
- `Condition of (${
196
- KEYWORDS.CONDITION
197
- }) must be ${TRUE} or ${FALSE} but got (${
198
- KEYWORDS.CONDITION
199
- } ${stringifyArgs(args)})`
200
- )
201
- if (condition) return evaluate(args[i + 1], env)
202
- }
203
- return 0
204
- },
205
174
  [KEYWORDS.ARRAY_TYPE]: (args, env) => {
206
175
  return args.length ? args.map((x) => evaluate(x, env)) : []
207
176
  },
@@ -651,29 +620,6 @@ export const keywords = {
651
620
  )
652
621
  return operands.reduce((acc, x) => acc >>> x)
653
622
  },
654
- // [KEYWORDS.PIPE]: (args, env) => {
655
- // if (args.length < 1)
656
- // throw new RangeError(
657
- // `Invalid number of arguments to (${KEYWORDS.PIPE}) (>= 1 required). (${
658
- // KEYWORDS.PIPE
659
- // } ${stringifyArgs(args)})`
660
- // )
661
- // let inp = args[0]
662
- // for (let i = 1; i < args.length; ++i) {
663
- // if (!args[i].length || args[i][0][TYPE] !== APPLY)
664
- // throw new TypeError(
665
- // `Argument at position (${i}) of (${
666
- // KEYWORDS.PIPE
667
- // }) is not an invoked (${KEYWORDS.ANONYMOUS_FUNCTION}). (${
668
- // KEYWORDS.PIPE
669
- // } ${stringifyArgs(args)})`
670
- // )
671
- // const [first, ...rest] = args[i]
672
- // const arr = [first, inp, ...rest]
673
- // inp = arr
674
- // }
675
- // return evaluate(inp, env)
676
- // },
677
623
  [KEYWORDS.SET_ARRAY]: (args, env) => {
678
624
  if (args.length !== 1 && args.length !== 3)
679
625
  throw new RangeError(
package/src/keywords.js CHANGED
@@ -6,6 +6,19 @@ export const ATOM = 2
6
6
  export const TRUE = 1
7
7
  export const FALSE = 0
8
8
  export const PLACEHOLDER = '.'
9
+ export const SUGGAR = {
10
+ // Syntactic suggars
11
+ PIPE: '|>',
12
+ NOT_EQUAL_1: '!=',
13
+ NOT_EQUAL_2: '<>',
14
+ UNLESS: 'unless',
15
+ LIST_TYPE: 'list',
16
+ POWER: '**',
17
+ INTEGER_DEVISION: '//',
18
+ CONDITION: 'cond',
19
+ RECURSION: 'recursive',
20
+ CACHE: 'memoized'
21
+ }
9
22
  export const KEYWORDS = {
10
23
  NUMBER_TYPE: 'number',
11
24
  ARRAY_TYPE: 'array',
@@ -29,7 +42,6 @@ export const KEYWORDS = {
29
42
  BLOCK: 'do',
30
43
  ANONYMOUS_FUNCTION: 'lambda',
31
44
  IF: 'if',
32
- CONDITION: 'cond',
33
45
  NOT: 'not',
34
46
  EQUAL: '=',
35
47
  LESS_THAN: '<',
@@ -49,17 +61,7 @@ export const KEYWORDS = {
49
61
  LOG_CHAR: 'log-char!',
50
62
  CLEAR_CONSOLE: 'clear!',
51
63
 
52
- THROW: 'throw',
53
-
54
- // Syntactic suggars
55
- PIPE: '|>',
56
- NOT_EQUAL_1: '!=',
57
- NOT_EQUAL_2: '<>',
58
- UNLESS: 'unless',
59
- LIST_TYPE: 'list',
60
-
61
- RECURSION: 'recursive',
62
- CACHE: 'memoized'
64
+ THROW: 'throw'
63
65
  }
64
66
 
65
67
  export const TYPES = {
package/src/utils.js CHANGED
@@ -1,6 +1,16 @@
1
1
  import std from '../lib/baked/std.js'
2
2
  import { comp } from './compiler.js'
3
- import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
3
+ import {
4
+ APPLY,
5
+ ATOM,
6
+ FALSE,
7
+ KEYWORDS,
8
+ SUGGAR,
9
+ TRUE,
10
+ TYPE,
11
+ VALUE,
12
+ WORD
13
+ } from './keywords.js'
4
14
  import { evaluate, run } from './evaluator.js'
5
15
  import { AST, isLeaf, LISP } from './parser.js'
6
16
  export const logError = (error) =>
@@ -102,8 +112,8 @@ export const isForbiddenVariableName = (name) => {
102
112
  switch (name) {
103
113
  case '_':
104
114
  case KEYWORDS.DEFINE_VARIABLE:
105
- case KEYWORDS.RECURSION:
106
- case KEYWORDS.CACHE:
115
+ case SUGGAR.RECURSION:
116
+ case SUGGAR.CACHE:
107
117
  return true
108
118
  default:
109
119
  return !isNaN(name[0])
@@ -385,8 +395,8 @@ export const deSuggar = (ast) => {
385
395
  prev[TYPE] === APPLY &&
386
396
  prev[VALUE] !== KEYWORDS.ANONYMOUS_FUNCTION)
387
397
  ) {
388
- exp[0][1] = KEYWORDS.CALL_FUNCTION
389
- exp[0][0] = APPLY
398
+ exp[0][VALUE] = KEYWORDS.CALL_FUNCTION
399
+ exp[0][TYPE] = APPLY
390
400
  exp.length = 1
391
401
  exp[1] = [
392
402
  [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
@@ -410,13 +420,13 @@ export const deSuggar = (ast) => {
410
420
  // }
411
421
  // }
412
422
  // break
413
- case KEYWORDS.PIPE:
423
+ case SUGGAR.PIPE:
414
424
  {
415
425
  if (rest.length < 1)
416
426
  throw new RangeError(
417
427
  `Invalid number of arguments to (${
418
- KEYWORDS.PIPE
419
- }) (>= 1 required). (${KEYWORDS.PIPE} ${stringifyArgs(
428
+ SUGGAR.PIPE
429
+ }) (>= 1 required). (${SUGGAR.PIPE} ${stringifyArgs(
420
430
  rest
421
431
  )})`
422
432
  )
@@ -426,10 +436,10 @@ export const deSuggar = (ast) => {
426
436
  if (!rest[i].length || rest[i][0][TYPE] !== APPLY)
427
437
  throw new TypeError(
428
438
  `Argument at position (${i}) of (${
429
- KEYWORDS.PIPE
439
+ SUGGAR.PIPE
430
440
  }) is not an invoked (${
431
441
  KEYWORDS.ANONYMOUS_FUNCTION
432
- }). (${KEYWORDS.PIPE} ${stringifyArgs(rest)})`
442
+ }). (${SUGGAR.PIPE} ${stringifyArgs(rest)})`
433
443
  )
434
444
  inp = [rest[i].shift(), inp, ...rest[i]]
435
445
  }
@@ -437,51 +447,139 @@ export const deSuggar = (ast) => {
437
447
  deSuggar(exp)
438
448
  }
439
449
  break
440
- case KEYWORDS.LIST_TYPE:
450
+ case SUGGAR.CONDITION:
451
+ {
452
+ if (rest.length < 2)
453
+ throw new RangeError(
454
+ `Invalid number of arguments for (${
455
+ SUGGAR.CONDITION
456
+ }), expected (> 2 required) but got ${rest.length} (${
457
+ SUGGAR.CONDITION
458
+ } ${stringifyArgs(rest)})`
459
+ )
460
+ if (rest.length % 2 !== 0)
461
+ throw new RangeError(
462
+ `Invalid number of arguments for (${
463
+ SUGGAR.CONDITION
464
+ }), expected even number of arguments but got ${
465
+ rest.length
466
+ } (${SUGGAR.CONDITION} ${stringifyArgs(rest)})`
467
+ )
468
+ exp.length = 0
469
+ let temp = exp
470
+ for (let i = 0; i < rest.length; i += 2) {
471
+ if (i === rest.length - 2) {
472
+ temp.push([APPLY, KEYWORDS.IF], rest[i], rest.at(-1))
473
+ } else {
474
+ temp.push([APPLY, KEYWORDS.IF], rest[i], rest[i + 1], [])
475
+ temp = temp.at(-1)
476
+ }
477
+ }
478
+ deSuggar(exp)
479
+ }
480
+ break
481
+ case SUGGAR.LIST_TYPE:
441
482
  {
442
483
  exp.length = 0
443
484
  let temp = exp
444
485
  for (const item of rest) {
445
- temp.push([0, KEYWORDS.ARRAY_TYPE], item, [])
486
+ temp.push([APPLY, KEYWORDS.ARRAY_TYPE], item, [])
446
487
  temp = temp.at(-1)
447
488
  }
448
- temp.push([0, 'array'])
489
+ temp.push([APPLY, KEYWORDS.ARRAY_TYPE])
449
490
  deSuggar(exp)
450
491
  }
451
492
  break
493
+ case SUGGAR.INTEGER_DEVISION:
494
+ {
495
+ if (rest.some((x) => x[TYPE] === APPLY))
496
+ throw new TypeError(
497
+ `Arguments of (${
498
+ SUGGAR.INTEGER_DEVISION
499
+ }), must be (or atom word) (hint use (math:floor (${
500
+ KEYWORDS.DIVISION
501
+ } a b)) instead) (${
502
+ SUGGAR.INTEGER_DEVISION
503
+ } ${stringifyArgs(rest)})`
504
+ )
505
+ else {
506
+ exp.length = 1
507
+ exp[0] = [APPLY, KEYWORDS.BITWISE_OR]
508
+ exp.push([[APPLY, KEYWORDS.DIVISION], ...rest])
509
+ exp.push([ATOM, FALSE])
510
+ }
511
+ }
512
+ break
513
+ case SUGGAR.POWER:
514
+ {
515
+ if (rest.length !== 2)
516
+ throw new RangeError(
517
+ `Invalid number of arguments for (${
518
+ SUGGAR.POWER
519
+ }), expected (= 2) but got ${rest.length} (${
520
+ SUGGAR.POWER
521
+ } ${stringifyArgs(rest)})`
522
+ )
523
+ const isExponentAtom = exp[1][TYPE] === ATOM
524
+ const isPowerAtom = exp[2][TYPE] === ATOM
525
+ const isExponentWord = exp[1][TYPE] === WORD
526
+ if ((isExponentWord || isExponentAtom) && isPowerAtom) {
527
+ exp[0][VALUE] = KEYWORDS.MULTIPLICATION
528
+ const exponent = exp[1]
529
+ const power = exp[2][VALUE]
530
+ exp.length = 1
531
+ if (isExponentAtom) {
532
+ exp.push(exponent, [ATOM, exponent[VALUE] ** (power - 1)])
533
+ } else if (isExponentWord) {
534
+ exp.push(
535
+ ...Array.from({ length: power })
536
+ .fill(0)
537
+ .map(() => [exponent[TYPE], exponent[VALUE]])
538
+ )
539
+ }
540
+ } else
541
+ throw new TypeError(
542
+ `Second Arguments of (${
543
+ SUGGAR.POWER
544
+ }), must be (atom) (hint use math:power instead) (${
545
+ SUGGAR.POWER
546
+ } ${stringifyArgs(rest)})`
547
+ )
548
+ }
549
+ break
452
550
  case KEYWORDS.MULTIPLICATION:
453
551
  if (!rest.length) {
454
- exp[0][0] = 2
455
- exp[0][1] = 1
552
+ exp[0][TYPE] = ATOM
553
+ exp[0][VALUE] = TRUE
456
554
  }
457
555
  break
458
556
  case KEYWORDS.ADDITION:
459
557
  case KEYWORDS.DIVISION:
460
558
  if (!rest.length) {
461
- exp[0][0] = 2
462
- exp[0][1] = 0
559
+ exp[0][TYPE] = ATOM
560
+ exp[0][VALUE] = FALSE
463
561
  }
464
562
  break
465
- case KEYWORDS.UNLESS:
563
+ case SUGGAR.UNLESS:
466
564
  {
467
565
  if (rest.length > 3 || rest.length < 2)
468
566
  throw new RangeError(
469
567
  `Invalid number of arguments for (${
470
- KEYWORDS.UNLESS
568
+ SUGGAR.UNLESS
471
569
  }), expected (or (= 3) (= 2)) but got ${rest.length} (${
472
- KEYWORDS.UNLESS
570
+ SUGGAR.UNLESS
473
571
  } ${stringifyArgs(rest)})`
474
572
  )
475
- exp[0][1] = KEYWORDS.IF
573
+ exp[0][VALUE] = KEYWORDS.IF
476
574
  const temp = exp[2]
477
- exp[2] = exp[3] ?? [ATOM, 0]
575
+ exp[2] = exp[3] ?? [ATOM, FALSE]
478
576
  exp[3] = temp
479
577
  }
480
578
  deSuggar(exp)
481
579
  break
482
580
 
483
- case KEYWORDS.NOT_EQUAL_1:
484
- case KEYWORDS.NOT_EQUAL_2:
581
+ case SUGGAR.NOT_EQUAL_1:
582
+ case SUGGAR.NOT_EQUAL_2:
485
583
  {
486
584
  if (rest.length > 3 || rest.length < 2)
487
585
  throw new RangeError(
@@ -491,7 +589,7 @@ export const deSuggar = (ast) => {
491
589
  exp[0][1]
492
590
  } ${stringifyArgs(rest)})`
493
591
  )
494
- exp[0][1] = KEYWORDS.NOT
592
+ exp[0][VALUE] = KEYWORDS.NOT
495
593
  exp[1] = [[APPLY, KEYWORDS.EQUAL], exp[1], exp[2]]
496
594
  exp.length = 2
497
595
  deSuggar(exp)