fez-lisp 1.0.54 → 1.1.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.0.54",
5
+ "version": "1.1.1",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/compiler.js CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  import { leaf, isLeaf } from './parser.js'
11
11
  import { deepRename, lispToJavaScriptVariableName } from './utils.js'
12
12
  const Helpers = {
13
+ __string: `__string=(...args)=>{const str=args.flat();str.isString=true;return str}`,
13
14
  __add: `__add=(...numbers)=>{return numbers.reduce((a,b)=>a+b,0)}`,
14
15
  __sub: `__sub=(...numbers)=>{return numbers.reduce((a,b)=>a-b,0)}`,
15
16
  __mult: `__mult=(...numbers)=>{return numbers.reduce((a,b)=>a*b,1)}`,
@@ -46,13 +47,10 @@ const Helpers = {
46
47
  length: 'length=(arr)=>arr.length',
47
48
  __tco: `__tco=fn=>(...args)=>{let result=fn(...args);while(typeof result==='function')result=result();return result}`,
48
49
  numberPredicate: `numberPredicate=(number)=>+(typeof number==='number')`,
49
- stringPredicate: `stringPredicate=(string)=>+(typeof string==='string')`,
50
50
  lambdaPredicate: `lambdaPredicate=(lambda)=>+(typeof lambda==='function')`,
51
51
  arrayPredicate: `arrayPredicate=(array)=>+Array.isArray(array)`,
52
- atomPredicate: `atomPredicate=(value)=>+(typeof value==='number'||typeof value==='string')`,
53
52
  error: `error=(error)=>{throw new Error(error)}`,
54
- array_setEffect: `array_setEffect=(array,index,value)=>{if(index<0){const target=array.length+index;while(array.length!==target)array.pop()}else array[index] = value;return array}`,
55
- cast: `cast=(type,value)=>{switch(type){case '${KEYWORDS.NUMBER_TYPE}':return Number(value);case '${KEYWORDS.STRING_TYPE}':return value.toString();case '${KEYWORDS.ARRAY_TYPE}':return typeof value==='number'?[...Number(value).toString()].map(Number):[...value];case '${KEYWORDS.BOOLEAN_TYPE}':return +!!value;case '${KEYWORDS.ANONYMOUS_FUNCTION}':return ()=>value;case '${KEYWORDS.CHAR_CODE_TYPE}':return value.charCodeAt(0);case '${KEYWORDS.CHAR_TYPE}':return String.fromCharCode(value);default:return 0}}`
53
+ array_setEffect: `array_setEffect=(array,index,value)=>{if(index<0){const target=array.length+index;while(array.length!==target)array.pop()}else array[index] = value;return array}`
56
54
  }
57
55
  const semiColumnEdgeCases = new Set([
58
56
  ';)',
@@ -116,9 +114,6 @@ const compile = (tree, Drill) => {
116
114
  out += `),${name});`
117
115
  return out
118
116
  }
119
- case KEYWORDS.IS_STRING:
120
- Drill.Helpers.add('stringPredicate')
121
- return `stringPredicate(${compile(Arguments[0], Drill)});`
122
117
  case KEYWORDS.IS_NUMBER:
123
118
  Drill.Helpers.add('numberPredicate')
124
119
  return `numberPredicate(${compile(Arguments[0], Drill)});`
@@ -133,19 +128,17 @@ const compile = (tree, Drill) => {
133
128
  case KEYWORDS.BOOLEAN_TYPE:
134
129
  return '1'
135
130
  case KEYWORDS.STRING_TYPE:
136
- return '""'
131
+ Drill.Helpers.add('__string')
132
+ return `__string(${parseArgs(Arguments, Drill)});`
137
133
  case KEYWORDS.ARRAY_TYPE:
138
134
  return Arguments.length === 2 &&
139
135
  Arguments[1][TYPE] === WORD &&
140
136
  Arguments[1][VALUE] === 'length'
141
- ? `(new Array(${compile(Arguments[0], Drill)}).fill(0))`
137
+ ? `(new Array(${compile(Arguments[0], Drill)}).fill(0));`
142
138
  : `[${parseArgs(Arguments, Drill)}];`
143
- case KEYWORDS.ARRAY_OR_STRING_LENGTH:
139
+ case KEYWORDS.ARRAY_LENGTH:
144
140
  Drill.Helpers.add('length')
145
141
  return `length(${compile(Arguments[0], Drill)})`
146
- case KEYWORDS.IS_ATOM:
147
- Drill.Helpers.add('atomPredicate')
148
- return `atomPredicate(${compile(Arguments[0], Drill)});`
149
142
  case KEYWORDS.FIRST_ARRAY:
150
143
  Drill.Helpers.add('car')
151
144
  return `car(${compile(Arguments[0], Drill)});`
@@ -295,9 +288,6 @@ const compile = (tree, Drill) => {
295
288
  out += '0);'
296
289
  return out
297
290
  }
298
- case KEYWORDS.CAST_TYPE:
299
- Drill.Helpers.add('cast')
300
- return `cast("${Arguments[1][VALUE]}", ${compile(Arguments[0], Drill)})`
301
291
  case KEYWORDS.PIPE: {
302
292
  let inp = Arguments[0]
303
293
  for (let i = 1; i < Arguments.length; ++i)
package/src/evaluator.js CHANGED
@@ -36,7 +36,7 @@ export const isAtom = (arg, env) => {
36
36
  if (arg[TYPE] === ATOM) return 1
37
37
  else {
38
38
  const atom = evaluate(arg, env)
39
- return +(typeof atom === 'number' || typeof atom === 'string')
39
+ return +(typeof atom === 'number')
40
40
  }
41
41
  }
42
42
  export const run = (tree, env = {}) =>
@@ -8,26 +8,7 @@ import {
8
8
  isForbiddenVariableName,
9
9
  stringifyArgs
10
10
  } from './utils.js'
11
-
12
11
  const keywords = {
13
- [KEYWORDS.CONCATENATION]: (args, env) => {
14
- if (args.length < 2)
15
- throw new RangeError(
16
- `Invalid number of arguments for (${
17
- KEYWORDS.CONCATENATION
18
- }), expected > 1 but got ${args.length}. (${
19
- KEYWORDS.CONCATENATION
20
- } ${stringifyArgs(args)})`
21
- )
22
- const operands = args.map((x) => evaluate(x, env))
23
- if (operands.some((x) => typeof x !== 'string'))
24
- throw new TypeError(
25
- `Not all arguments of (${KEYWORDS.CONCATENATION}) are (${
26
- KEYWORDS.STRING_TYPE
27
- }) (${KEYWORDS.CONCATENATION} ${stringifyArgs(args)})`
28
- )
29
- return operands.reduce((a, b) => a + b, '')
30
- },
31
12
  [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
32
13
  if (args.length < 2)
33
14
  throw new RangeError(
@@ -92,23 +73,19 @@ const keywords = {
92
73
  )
93
74
  return operands.reduce((a, b) => a / b)
94
75
  },
95
- [KEYWORDS.ARRAY_OR_STRING_LENGTH]: (args, env) => {
76
+ [KEYWORDS.ARRAY_LENGTH]: (args, env) => {
96
77
  if (args.length !== 1)
97
78
  throw new RangeError(
98
79
  `Invalid number of arguments for (${
99
- KEYWORDS.ARRAY_OR_STRING_LENGTH
100
- }) (= 1 required) (${KEYWORDS.ARRAY_OR_STRING_LENGTH} ${stringifyArgs(
101
- args
102
- )})`
80
+ KEYWORDS.ARRAY_LENGTH
81
+ }) (= 1 required) (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
103
82
  )
104
83
  const array = evaluate(args[0], env)
105
- if (!(Array.isArray(array) || typeof array === 'string'))
84
+ if (!Array.isArray(array))
106
85
  throw new TypeError(
107
- `First argument of (${
108
- KEYWORDS.ARRAY_OR_STRING_LENGTH
109
- }) must be an (or ${KEYWORDS.ARRAY_TYPE} ${KEYWORDS.STRING_TYPE}) (${
110
- KEYWORDS.ARRAY_OR_STRING_LENGTH
111
- } ${stringifyArgs(args)})`
86
+ `First argument of (${KEYWORDS.ARRAY_LENGTH}) must be a ${
87
+ KEYWORDS.ARRAY_TYPE
88
+ } (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
112
89
  )
113
90
  return array.length
114
91
  },
@@ -131,15 +108,6 @@ const keywords = {
131
108
  )
132
109
  return +(typeof evaluate(args[0], env) === 'number')
133
110
  },
134
- [KEYWORDS.IS_STRING]: (args, env) => {
135
- if (args.length !== 1)
136
- throw new RangeError(
137
- `Invalid number of arguments for (${
138
- KEYWORDS.IS_STRING
139
- }) (= 1 required) (${KEYWORDS.IS_STRING} ${stringifyArgs(args)})`
140
- )
141
- return +(typeof evaluate(args[0], env) === 'string')
142
- },
143
111
  [KEYWORDS.IS_FUNCTION]: (args, env) => {
144
112
  if (args.length !== 1)
145
113
  throw new RangeError(
@@ -262,6 +230,11 @@ const keywords = {
262
230
  if (evaluate(args[i], env)) return evaluate(args[i + 1], env)
263
231
  return 0
264
232
  },
233
+ [KEYWORDS.STRING_TYPE]: (args, env) => {
234
+ const str = args.flatMap((x) => evaluate(x, env))
235
+ str.isString = true
236
+ return str
237
+ },
265
238
  [KEYWORDS.ARRAY_TYPE]: (args, env) => {
266
239
  if (!args.length) return []
267
240
  const isCapacity =
@@ -284,15 +257,6 @@ const keywords = {
284
257
  }
285
258
  return args.map((x) => evaluate(x, env))
286
259
  },
287
- [KEYWORDS.IS_ATOM]: (args, env) => {
288
- if (args.length !== 1)
289
- throw new RangeError(
290
- `Invalid number of arguments for (${
291
- KEYWORDS.IS_ATOM
292
- }) (= 1 required) (${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
293
- )
294
- return isAtom(args[0], env)
295
- },
296
260
  [KEYWORDS.FIRST_ARRAY]: (args, env) => {
297
261
  if (args.length !== 1)
298
262
  throw new RangeError(
@@ -439,7 +403,7 @@ const keywords = {
439
403
  const b = evaluate(args[1], env)
440
404
  if (typeof a !== 'number')
441
405
  throw new TypeError(
442
- `Invalid use of (${KEYWORDS.EQUAL}), first arguments are not an ${
406
+ `Invalid use of (${KEYWORDS.EQUAL}), first argument is not an ${
443
407
  KEYWORDS.NUMBER_TYPE
444
408
  } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
445
409
  )
@@ -462,7 +426,7 @@ const keywords = {
462
426
  const b = evaluate(args[1], env)
463
427
  if (typeof a !== 'number')
464
428
  throw new TypeError(
465
- `Invalid use of (${KEYWORDS.LESS_THAN}), first arguments are not an ${
429
+ `Invalid use of (${KEYWORDS.LESS_THAN}), first argument is not an ${
466
430
  KEYWORDS.NUMBER_TYPE
467
431
  } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
468
432
  )
@@ -485,11 +449,9 @@ const keywords = {
485
449
  const b = evaluate(args[1], env)
486
450
  if (typeof a !== 'number')
487
451
  throw new TypeError(
488
- `Invalid use of (${
489
- KEYWORDS.GREATHER_THAN
490
- }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
491
- KEYWORDS.GREATHER_THAN
492
- } ${stringifyArgs(args)})`
452
+ `Invalid use of (${KEYWORDS.GREATHER_THAN}), first argument is not an ${
453
+ KEYWORDS.NUMBER_TYPE
454
+ } (${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
493
455
  )
494
456
  if (typeof b !== 'number')
495
457
  throw new TypeError(
@@ -516,7 +478,7 @@ const keywords = {
516
478
  throw new TypeError(
517
479
  `Invalid use of (${
518
480
  KEYWORDS.GREATHER_THAN_OR_EQUAL
519
- }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
481
+ }), first argument is not an ${KEYWORDS.NUMBER_TYPE} (${
520
482
  KEYWORDS.GREATHER_THAN_OR_EQUAL
521
483
  } ${stringifyArgs(args)})`
522
484
  )
@@ -545,7 +507,7 @@ const keywords = {
545
507
  throw new TypeError(
546
508
  `Invalid use of (${
547
509
  KEYWORDS.LESS_THAN_OR_EQUAL
548
- }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
510
+ }), first argument is not an ${KEYWORDS.NUMBER_TYPE} (${
549
511
  KEYWORDS.LESS_THAN_OR_EQUAL
550
512
  } ${stringifyArgs(args)})`
551
513
  )
@@ -643,7 +605,6 @@ const keywords = {
643
605
  })
644
606
  return env[name]
645
607
  },
646
- [KEYWORDS.STRING_TYPE]: () => '',
647
608
  [KEYWORDS.NUMBER_TYPE]: () => 0,
648
609
  [KEYWORDS.BOOLEAN_TYPE]: () => 1,
649
610
  [KEYWORDS.CAST_TYPE]: (args, env) => {
@@ -671,60 +632,13 @@ const keywords = {
671
632
  )
672
633
  return num
673
634
  }
674
- case KEYWORDS.STRING_TYPE:
675
- return value.toString()
676
635
  case KEYWORDS.BOOLEAN_TYPE:
677
636
  return +!!value
678
- case KEYWORDS.ARRAY_TYPE: {
679
- if (typeof value === 'number')
680
- return [...Number(value).toString()].map(Number)
681
- else if (typeof value[Symbol.iterator] !== 'function')
682
- throw new TypeError(
683
- `Arguments are not iterable for ${KEYWORDS.ARRAY_TYPE} at (${
684
- KEYWORDS.CAST_TYPE
685
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
686
- )
687
- return [...value]
688
- }
689
- case KEYWORDS.CHAR_TYPE: {
690
- const index = evaluate(args[0], env)
691
- if (!Number.isInteger(index) || index < 0)
692
- throw new TypeError(
693
- `Arguments are not (+ ${KEYWORDS.NUMBER_TYPE}) for ${
694
- KEYWORDS.CHAR_TYPE
695
- } at (${KEYWORDS.CAST_TYPE}) (${
696
- KEYWORDS.CAST_TYPE
697
- } ${stringifyArgs(args)})`
698
- )
699
- return String.fromCharCode(index)
700
- }
701
- case KEYWORDS.CHAR_CODE_TYPE: {
702
- const string = evaluate(args[0], env)
703
- if (typeof string !== 'string')
704
- throw new TypeError(
705
- `Argument is not (${KEYWORDS.STRING_TYPE}) for ${
706
- KEYWORDS.CHAR_CODE_TYPE
707
- } at (${KEYWORDS.CAST_TYPE}) (${
708
- KEYWORDS.CAST_TYPE
709
- } ${stringifyArgs(args)})`
710
- )
711
- if (string.length !== 1)
712
- throw new RangeError(
713
- `Argument is not of (= (length ${KEYWORDS.STRING_TYPE}) 1) for ${
714
- KEYWORDS.CHAR_CODE_TYPE
715
- } at (${KEYWORDS.CAST_TYPE}) (${
716
- KEYWORDS.CAST_TYPE
717
- } ${stringifyArgs(args)})`
718
- )
719
- return string.charCodeAt(0)
720
- }
721
637
  default:
722
638
  throw new TypeError(
723
- `Can only cast (or ${KEYWORDS.NUMBER_TYPE} ${
724
- KEYWORDS.STRING_TYPE
725
- } ${KEYWORDS.ARRAY_TYPE} ${KEYWORDS.BOOLEAN_TYPE} ${
726
- KEYWORDS.CHAR_TYPE
727
- } ${KEYWORDS.CHAR_CODE_TYPE}) at (${KEYWORDS.CAST_TYPE}) (${
639
+ `Can only cast (or ${KEYWORDS.NUMBER_TYPE} ${KEYWORDS.ARRAY_TYPE} ${
640
+ KEYWORDS.BOOLEAN_TYPE
641
+ }) at (${KEYWORDS.CAST_TYPE}) (${
728
642
  KEYWORDS.CAST_TYPE
729
643
  } ${stringifyArgs(args)})`
730
644
  )
@@ -965,18 +879,17 @@ const keywords = {
965
879
  return keywords[KEYWORDS.DEFINE_VARIABLE](args, env)
966
880
  },
967
881
  [KEYWORDS.TEST_CASE]: (args, env) => {
968
- if (args.length !== 3)
882
+ if (args.length !== 2)
969
883
  throw new RangeError(
970
884
  `Invalid number of arguments to (${
971
885
  KEYWORDS.TEST_CASE
972
- }) (= 3 required) (${KEYWORDS.TEST_CASE} ${stringifyArgs(args)})`
886
+ }) (= 2 required) (${KEYWORDS.TEST_CASE} ${stringifyArgs(args)})`
973
887
  )
974
- const description = evaluate(args[0], env)
975
- const a = evaluate(args[1], env)
976
- const b = evaluate(args[2], env)
888
+ const a = evaluate(args[0], env)
889
+ const b = evaluate(args[1], env)
977
890
  return !isEqualTypes(a, b) || !isEqual(a, b)
978
- ? [0, description, stringifyArgs([args[1]]), b, a]
979
- : [1, description, stringifyArgs([args[1]]), a]
891
+ ? [0, stringifyArgs([args[0]]), b, a]
892
+ : [1, stringifyArgs([args[0]]), a]
980
893
  },
981
894
  [KEYWORDS.TEST_BED]: (args, env) => {
982
895
  let tests = []
@@ -994,15 +907,13 @@ const keywords = {
994
907
  )
995
908
  tests = args.map((x) => evaluate(x, env))
996
909
  res = tests.reduce(
997
- (acc, [state, describe, ...rest]) =>
910
+ (acc, [state, ...rest]) =>
998
911
  `${acc}${
999
912
  !state
1000
- ? `x ${describe} Failed:\n ${rest[0]}\n + ${LISP.stringify(
913
+ ? `x ${rest[0]}\n + ${LISP.stringify(
1001
914
  rest[1]
1002
915
  )}\n - ${LISP.stringify(rest[2])}\n`
1003
- : `✓ ${describe} Passed:\n ${rest[0]}\n + ${LISP.stringify(
1004
- rest[1]
1005
- )}\n`
916
+ : `✓ ${rest[0]}\n + ${LISP.stringify(rest[1])}\n`
1006
917
  }`,
1007
918
  ''
1008
919
  )
package/src/keywords.js CHANGED
@@ -9,20 +9,13 @@ export const ATOM = 2
9
9
  export const PLACEHOLDER = '.'
10
10
  // keywords aliases
11
11
  export const KEYWORDS = {
12
- STRING_TYPE: 'string',
13
12
  NUMBER_TYPE: 'number',
14
- BOOLEAN_TYPE: 'boolean',
13
+ STRING_TYPE: 'string',
15
14
  ARRAY_TYPE: 'array',
16
- CHAR_CODE_TYPE: 'char-code',
17
- CHAR_TYPE: 'char',
18
- CAST_TYPE: 'type',
19
- CONCATENATION: 'string:merge',
20
- ARRAY_OR_STRING_LENGTH: 'length',
15
+ ARRAY_LENGTH: 'length',
21
16
  IS_ARRAY: 'array?',
22
17
  IS_NUMBER: 'number?',
23
- IS_STRING: 'string?',
24
18
  IS_FUNCTION: 'lambda?',
25
- IS_ATOM: 'atom?',
26
19
  ADDITION: '+',
27
20
  SUBTRACTION: '-',
28
21
  MULTIPLICATION: '*',
package/src/parser.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { APPLY, ATOM, TYPE, WORD, VALUE } from './keywords.js'
2
- import { escape, preserveEscape } from './utils.js'
3
2
  export const leaf = (type, value) => [type, value]
4
3
  export const isLeaf = ([car]) => car === APPLY || car === ATOM || car === WORD
5
4
  export const LISP = {
@@ -10,15 +9,6 @@ export const LISP = {
10
9
  acc = ''
11
10
  for (let i = 0; i < source.length; ++i) {
12
11
  const cursor = source[i]
13
- if (cursor === '"') {
14
- acc += '"'
15
- ++i
16
- while (source[i] !== '"') {
17
- if (source[i] === '\\') acc += escape(source[++i])
18
- else acc += source[i]
19
- ++i
20
- }
21
- }
22
12
  if (cursor === '(') {
23
13
  head.push([])
24
14
  stack.push(head)
@@ -28,8 +18,6 @@ export const LISP = {
28
18
  acc = ''
29
19
  if (token) {
30
20
  if (!head.length) head.push(leaf(APPLY, token))
31
- else if (token.match(/^"([^"]*)"/))
32
- head.push(leaf(ATOM, token.substring(1, token.length - 1)))
33
21
  else if (token.match(/^-?[0-9]\d*(\.\d+)?$/))
34
22
  head.push(leaf(ATOM, Number(token)))
35
23
  else head.push(leaf(WORD, token))
@@ -50,7 +38,6 @@ export const LISP = {
50
38
  return `(array ${array
51
39
  .map(([key, value]) => `("${key}" ${LISP.stringify(value)})`)
52
40
  .join(' ')})`
53
- else if (typeof array === 'string') return `"${array}"`
54
41
  else if (typeof array === 'function') return '()'
55
42
  else if (typeof array === 'boolean') return +array
56
43
  else return array
@@ -65,10 +52,7 @@ export const LISP = {
65
52
  out += first[VALUE]
66
53
  break
67
54
  case ATOM:
68
- out +=
69
- typeof first[VALUE] === 'string'
70
- ? `"${preserveEscape(first[VALUE])}"`
71
- : first[VALUE]
55
+ out += first[VALUE]
72
56
  break
73
57
  case APPLY:
74
58
  out += `(${first[VALUE]} ${rest.map(dfs).join(' ')})`
@@ -117,6 +101,6 @@ export const AST = {
117
101
  typeof ast === 'object'
118
102
  ? `[${ast.map(AST.stringify).join(',')}]`
119
103
  : typeof ast === 'string'
120
- ? `"${preserveEscape(ast)}"`
104
+ ? `"${ast}"`
121
105
  : ast
122
106
  }
package/src/utils.js CHANGED
@@ -5,16 +5,29 @@ import { run } from './evaluator.js'
5
5
  import { AST, isLeaf, LISP } from './parser.js'
6
6
  export const logError = (error) => console.log('\x1b[31m', error, '\x1b[0m')
7
7
  export const logSuccess = (output) => console.log(output, '\x1b[0m')
8
+ export const replaceStrings = (source) => {
9
+ const quotes = source.match(/"(.*?)"/g)
10
+ if (quotes)
11
+ for (const q of quotes)
12
+ source = source.replaceAll(
13
+ q,
14
+ `(string ${[...q]
15
+ .slice(1, -1)
16
+ .map((x) => x.charCodeAt(0))
17
+ .join(' ')})`
18
+ )
19
+ return source
20
+ }
8
21
  export const removeNoCode = (source) =>
9
22
  source
10
- // .replace(/;.+/g, '')
11
- .replace(/;(?=(?:(?:[^"]*"){2})*[^"]*$).+/g, '')
12
- .replace(/[\s\s]+(?=[^"]*(?:"[^"]*"[^"]*)*$)/g, ' ')
23
+ .replace(/;.+/g, '')
24
+ .replace(/[\s\s]/g, ' ')
13
25
  .trim()
26
+
14
27
  export const isBalancedParenthesis = (sourceCode) => {
15
28
  let count = 0
16
29
  const stack = []
17
- const str = sourceCode.match(/[/\(|\)](?=[^"]*(?:"[^"]*"[^"]*)*$)/g) ?? []
30
+ const str = sourceCode.match(/[/\(|\)]/g) ?? []
18
31
  for (let i = 0; i < str.length; ++i)
19
32
  if (str[i] === '(') stack.push(str[i])
20
33
  else if (str[i] === ')') if (stack.pop() !== '(') ++count
@@ -38,15 +51,6 @@ export const escape = (Char) => {
38
51
  return ''
39
52
  }
40
53
  }
41
- const escapeChars = {
42
- '\n': '\\n',
43
- '\r': '\\r',
44
- '\t': '\\t',
45
- s: '\\s',
46
- '"': '\\"'
47
- }
48
- export const preserveEscape = (str) =>
49
- str.replace(/[\n\r\t\s\"]/g, (match) => escapeChars[match] || match)
50
54
  export const stringifyType = (type) =>
51
55
  !isLeaf(type)
52
56
  ? `(array ${type.map((t) => stringifyType(t)).join(' ')})`
@@ -156,9 +160,10 @@ export const dfs = (tree, callback) => {
156
160
  }
157
161
  export const deepClone = (ast) => AST.parse(AST.stringify(ast))
158
162
  export const fez = (source, options = {}) => {
159
- const env = options.env ?? {}
163
+ const env = Object.create(null)
160
164
  try {
161
165
  if (typeof source === 'string') {
166
+ if (options.strings) source = replaceStrings(source)
162
167
  let code
163
168
  if (!options.compile)
164
169
  code = handleUnbalancedQuotes(
@@ -172,7 +177,7 @@ export const fez = (source, options = {}) => {
172
177
  throw new Error(
173
178
  'Top level expressions need to be wrapped in a (do) block'
174
179
  )
175
- const ast = [...(options.std ? treeShake(parsed, std) : []), ...parsed]
180
+ const ast = [...treeShake(parsed, std), ...parsed]
176
181
  if (options.compile) {
177
182
  const js = Object.values(comp(deepClone(ast))).join('')
178
183
  return options.eval ? eval(js) : js