fez-lisp 1.4.11 → 1.4.12

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.11",
5
+ "version": "1.4.12",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/compiler.js CHANGED
@@ -7,18 +7,15 @@ import {
7
7
  VALUE,
8
8
  WORD
9
9
  } from './keywords.js'
10
+ import { OPTIMIZATIONS } from './macros.js'
10
11
  import { leaf, isLeaf, AST } from './parser.js'
11
- export const OPTIMIZATIONS = {
12
- RECURSION: 'recursive',
13
- CACHE: 'memoized'
14
- }
15
12
  const deepRename = (name, newName, tree) => {
16
13
  if (!isLeaf(tree))
17
14
  for (const leaf of tree) {
18
15
  // Figure out a non mutable solution so
19
16
  // I can get rid of deep clone AST.parse(AST.stringify(ast))
20
17
  if (leaf[VALUE] === name) leaf[VALUE] = newName
21
- deepRename(name, newName, leaf)
18
+ else deepRename(name, newName, leaf)
22
19
  }
23
20
  }
24
21
  const earMuffsToLodashes = (name) => name.replace(new RegExp(/\*/g), '_')
@@ -181,28 +178,30 @@ const comp = (tree, Drill) => {
181
178
  case KEYWORDS.DEFINE_VARIABLE: {
182
179
  const n = tail[0][VALUE]
183
180
  const prefix = n.split(':')[0]
184
- if (prefix === OPTIMIZATIONS.RECURSION) {
185
- const name = lispToJavaScriptVariableName(n)
186
- const newName = `${OPTIMIZATIONS.RECURSION}_${performance
187
- .now()
188
- .toString()
189
- .replace('.', 7)}`
190
- Drill.Variables.add(name)
191
- Drill.Variables.add(newName)
192
- Drill.Helpers.add('__tco')
193
- const functionArgs = tail.at(-1).slice(1)
194
- const body = functionArgs.pop()
195
- const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
196
- deepRename(n, `()=>${newName}`, body)
197
- const evaluatedBody = comp(body, FunctionDrill)
198
- const vars = FunctionDrill.Variables.size
199
- ? `var ${[...FunctionDrill.Variables].join(',')};`
200
- : ''
201
- return `(${name}=(__tco(${newName}=(${parseArgs(
202
- functionArgs,
203
- Drill
204
- )})=>{${vars}return ${evaluatedBody.toString().trim()}})));`
205
- } else if (prefix === OPTIMIZATIONS.CACHE) {
181
+ // if (prefix === OPTIMIZATIONS.RECURSION) {
182
+ // const name = lispToJavaScriptVariableName(n)
183
+ // const newName = `${OPTIMIZATIONS.RECURSION}_${performance
184
+ // .now()
185
+ // .toString()
186
+ // .replace('.', 7)}`
187
+ // Drill.Variables.add(name)
188
+ // Drill.Variables.add(newName)
189
+ // Drill.Helpers.add('__tco')
190
+ // const functionArgs = tail.at(-1).slice(1)
191
+ // const body = functionArgs.pop()
192
+ // const FunctionDrill = { Variables: new Set(), Helpers: Drill.Helpers }
193
+ // deepRename(n, `()=>${newName}`, body)
194
+ // const evaluatedBody = comp(body, FunctionDrill)
195
+ // const vars = FunctionDrill.Variables.size
196
+ // ? `var ${[...FunctionDrill.Variables].join(',')};`
197
+ // : ''
198
+ // return `(${name}=(__tco(${newName}=(${parseArgs(
199
+ // functionArgs,
200
+ // Drill
201
+ // )})=>{${vars}return ${evaluatedBody.toString().trim()}})));`
202
+ // } else
203
+
204
+ if (prefix === OPTIMIZATIONS.CACHE) {
206
205
  // memoization here
207
206
  const name = lispToJavaScriptVariableName(n)
208
207
  const newName = name.substring(OPTIMIZATIONS.CACHE.length + 1)
@@ -306,6 +305,12 @@ const comp = (tree, Drill) => {
306
305
  tail.length === 3 ? comp(tail[2], Drill) : 0
307
306
  });`
308
307
  }
308
+ case KEYWORDS.LOOP: {
309
+ return `(()=>{while(${comp(tail[0], Drill)}){${comp(
310
+ tail[1],
311
+ Drill
312
+ )}}return 0})();`
313
+ }
309
314
  case KEYWORDS.ERROR: {
310
315
  Drill.Helpers.add('__error')
311
316
  return `__error(${compile(tail[0], Drill)})`
@@ -13,6 +13,12 @@ import { evaluate } from './evaluator.js'
13
13
  import { isForbiddenVariableName, stringifyArgs } from './utils.js'
14
14
  import { LISP } from './parser.js'
15
15
  export const keywords = {
16
+ [KEYWORDS.LOOP]: (args, env) => {
17
+ if (args.length != 2)
18
+ throw new RangeError(`Wrong number of args to ${KEYWORDS.LOOP}`)
19
+ while (evaluate(args[0], env) !== FALSE) evaluate(args[1], env)
20
+ return FALSE
21
+ },
16
22
  [KEYWORDS.ADDITION]: (args, env) => {
17
23
  if (args.length !== 2)
18
24
  throw new RangeError(
package/src/keywords.js CHANGED
@@ -7,6 +7,7 @@ export const TRUE = 1
7
7
  export const FALSE = 0
8
8
  export const PLACEHOLDER = '.'
9
9
  export const KEYWORDS = {
10
+ LOOP: 'loop',
10
11
  CREATE_ARRAY: 'array',
11
12
  ARRAY_LENGTH: 'length',
12
13
  IS_ATOM: 'atom?',
@@ -40,7 +41,7 @@ export const KEYWORDS = {
40
41
  DEFINE_VARIABLE: 'let',
41
42
 
42
43
  SET_ARRAY: 'set!',
43
- ERROR: 'throw',
44
+ ERROR: 'throw'
44
45
  }
45
46
 
46
47
  export const TYPES = {
@@ -56,7 +57,6 @@ export const DEBUG = {
56
57
  LOG: 'log',
57
58
  ASSERT: 'assert',
58
59
  CALLSTACK: '(CALLSTACK)' // so that you can't use it in the code
59
-
60
60
  }
61
61
 
62
62
  export const SPECIAL_FORMS_SET = new Set(Object.values(KEYWORDS))
package/src/macros.js CHANGED
@@ -29,6 +29,19 @@ export const SUGGAR = {
29
29
  INTEGER_DEVISION: '//',
30
30
  CONDITION: 'cond'
31
31
  }
32
+ export const OPTIMIZATIONS = {
33
+ RECURSION: 'recursive',
34
+ CACHE: 'memoized'
35
+ }
36
+ const deepTransform = (predicate, transform, tree) => {
37
+ if (!isLeaf(tree))
38
+ for (const leaf of tree) {
39
+ // Figure out a non mutable solution so
40
+ // I can get rid of deep clone AST.parse(AST.stringify(ast))
41
+ if (predicate(leaf)) transform(leaf)
42
+ else deepTransform(predicate, transform, leaf)
43
+ }
44
+ }
32
45
  export const deSuggarAst = (ast, scope) => {
33
46
  if (scope === undefined) scope = ast
34
47
  if (ast.length === 0) throw new SyntaxError(`No expressions...`)
@@ -489,6 +502,109 @@ export const deSuggarAst = (ast, scope) => {
489
502
  exp.iron = true
490
503
  exp.push(newScope)
491
504
  deSuggarAst(scope)
505
+ } else {
506
+ const last = exp.at(-1)
507
+ if (
508
+ !isLeaf(last) &&
509
+ Array.isArray(last) &&
510
+ last[0] &&
511
+ last[0][TYPE] === APPLY &&
512
+ last[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
513
+ ) {
514
+ const name = exp[1][VALUE]
515
+ const prefix = name.split(':')[0]
516
+ if (prefix === OPTIMIZATIONS.RECURSION) {
517
+ const args = last.slice(1, -1)
518
+ const newName = `*${performance
519
+ .now()
520
+ .toString()
521
+ .replace('.', 0)}*`
522
+ deepTransform(
523
+ (leaf) =>
524
+ Array.isArray(leaf) &&
525
+ leaf[0] &&
526
+ leaf[0][TYPE] === APPLY &&
527
+ leaf[0][VALUE] === name,
528
+ (leaf) => {
529
+ const copy = [...leaf]
530
+ leaf.length = 0
531
+ copy[0][VALUE] = newName
532
+ leaf.push(
533
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
534
+ copy
535
+ )
536
+ },
537
+ last
538
+ )
539
+ exp[exp.length - 1] = [
540
+ [APPLY, KEYWORDS.CALL_FUNCTION],
541
+ [
542
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
543
+ [
544
+ [APPLY, KEYWORDS.BLOCK],
545
+ [
546
+ [APPLY, KEYWORDS.DEFINE_VARIABLE],
547
+ [WORD, newName],
548
+ last
549
+ ],
550
+ [
551
+ [APPLY, KEYWORDS.CALL_FUNCTION],
552
+ [WORD, newName],
553
+ [
554
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
555
+ [WORD, '*fn*'],
556
+ [
557
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
558
+ ...args,
559
+ [
560
+ [APPLY, KEYWORDS.BLOCK],
561
+ [
562
+ [APPLY, KEYWORDS.DEFINE_VARIABLE],
563
+ [WORD, '*res*'],
564
+ [
565
+ [APPLY, KEYWORDS.CREATE_ARRAY],
566
+ [[APPLY, '*fn*'], ...args]
567
+ ]
568
+ ],
569
+ [
570
+ [APPLY, KEYWORDS.LOOP],
571
+ [
572
+ [APPLY, KEYWORDS.IS_LAMBDA],
573
+ [
574
+ [APPLY, KEYWORDS.GET_ARRAY],
575
+ [WORD, '*res*'],
576
+ [ATOM, 0]
577
+ ]
578
+ ],
579
+ [
580
+ [APPLY, KEYWORDS.SET_ARRAY],
581
+ [WORD, '*res*'],
582
+ [ATOM, 0],
583
+ [
584
+ [APPLY, KEYWORDS.CALL_FUNCTION],
585
+ [
586
+ [APPLY, KEYWORDS.GET_ARRAY],
587
+ [WORD, '*res*'],
588
+ [ATOM, 0]
589
+ ]
590
+ ]
591
+ ]
592
+ ],
593
+ [
594
+ [APPLY, KEYWORDS.GET_ARRAY],
595
+ [WORD, '*res*'],
596
+ [ATOM, 0]
597
+ ]
598
+ ]
599
+ ]
600
+ ]
601
+ ]
602
+ ]
603
+ ]
604
+ ]
605
+ deSuggarAst(exp[exp.length - 1])
606
+ }
607
+ }
492
608
  }
493
609
  }
494
610
  break
package/src/utils.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import std from '../lib/baked/std.js'
2
- import { compile, OPTIMIZATIONS } from './compiler.js'
2
+ import { compile } from './compiler.js'
3
3
  import {
4
4
  APPLY,
5
5
  ATOM,
@@ -17,7 +17,8 @@ import { isLeaf, LISP } from './parser.js'
17
17
  import {
18
18
  deSuggarAst,
19
19
  deSuggarSource,
20
- handleUnbalancedQuotes
20
+ handleUnbalancedQuotes,
21
+ OPTIMIZATIONS
21
22
  } from './macros.js'
22
23
  import { keywords } from './interpreter.js'
23
24
  export const logError = (error) =>