fez-lisp 1.0.38 → 1.0.40

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -171,7 +171,7 @@ console.log(
171
171
  Pass tree source as text:
172
172
 
173
173
  ```js
174
- import { fez, parse } from '../index.js'
174
+ import { fez } from '../index.js'
175
175
  const source = `(|>
176
176
  (array 1 2 3 4)
177
177
  (math:permutations)
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { evaluate } from './src/interpreter.js'
2
- import { parse, stringify, AST } from './src/parser.js'
2
+ import { LISP, AST } from './src/parser.js'
3
3
  import { fez, tree } from './src/utils.js'
4
4
  import std from './lib/baked/std.js'
5
5
  import { keywords } from './src/tokeniser.js'
6
6
  import { WORD, APPLY, ATOM, VALUE, TYPE } from './src/enums.js'
7
7
  const types = { WORD, APPLY, ATOM, VALUE, TYPE }
8
- export { fez, parse, stringify, keywords, evaluate, std, types, tree, AST }
8
+ export { fez, keywords, evaluate, std, types, tree, LISP, AST }
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.38",
5
+ "version": "1.0.40",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/formatter.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './enums.js'
2
- import { isLeaf, parse } from './parser.js'
2
+ import { isLeaf, LISP } from './parser.js'
3
3
  import { removeNoCode } from './utils.js'
4
4
  const tops = []
5
5
  const indent = (level) => ' '.repeat(level)
@@ -70,7 +70,7 @@ export const formatWithPreservedComments = (source) => {
70
70
  )
71
71
  .join('\n')
72
72
 
73
- return format(parse(removeNoCode(value)))
73
+ return format(LISP.parse(removeNoCode(value)))
74
74
  .split('\n')
75
75
  .map((x) => {
76
76
  if (x.includes(commentIdentifier)) {
package/src/parser.js CHANGED
@@ -2,55 +2,59 @@ import { APPLY, ATOM, WORD } from './enums.js'
2
2
  import { escape } from './utils.js'
3
3
  export const leaf = (type, value) => [type, value]
4
4
  export const isLeaf = ([car]) => car === APPLY || car === ATOM || car === WORD
5
- export const parse = (source) => {
6
- const tree = []
7
- let head = tree,
8
- stack = [tree],
9
- acc = ''
10
- for (let i = 0; i < source.length; ++i) {
11
- const cursor = source[i]
12
- if (cursor === '"') {
13
- acc += '"'
14
- ++i
15
- while (source[i] !== '"') {
16
- if (source[i] === '\\') acc += escape(source[++i])
17
- else acc += source[i]
5
+ export const LISP = {
6
+ parse: (source) => {
7
+ const tree = []
8
+ let head = tree,
9
+ stack = [tree],
10
+ acc = ''
11
+ for (let i = 0; i < source.length; ++i) {
12
+ const cursor = source[i]
13
+ if (cursor === '"') {
14
+ acc += '"'
18
15
  ++i
16
+ while (source[i] !== '"') {
17
+ if (source[i] === '\\') acc += escape(source[++i])
18
+ else acc += source[i]
19
+ ++i
20
+ }
19
21
  }
22
+ if (cursor === '(') {
23
+ head.push([])
24
+ stack.push(head)
25
+ head = head.at(-1)
26
+ } else if (cursor === ')' || cursor === ' ') {
27
+ let token = acc
28
+ acc = ''
29
+ if (token) {
30
+ 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
+ else if (token.match(/^-?[0-9]\d*(\.\d+)?$/))
34
+ head.push(leaf(ATOM, Number(token)))
35
+ else head.push(leaf(WORD, token))
36
+ }
37
+ if (cursor === ')') head = stack.pop()
38
+ } else acc += cursor
20
39
  }
21
- if (cursor === '(') {
22
- head.push([])
23
- stack.push(head)
24
- head = head.at(-1)
25
- } else if (cursor === ')' || cursor === ' ') {
26
- let token = acc
27
- acc = ''
28
- if (token) {
29
- if (!head.length) head.push(leaf(APPLY, token))
30
- else if (token.match(/^"([^"]*)"/))
31
- head.push(leaf(ATOM, token.substring(1, token.length - 1)))
32
- else if (token.match(/^-?[0-9]\d*(\.\d+)?$/))
33
- head.push(leaf(ATOM, Number(token)))
34
- else head.push(leaf(WORD, token))
35
- }
36
- if (cursor === ')') head = stack.pop()
37
- } else acc += cursor
40
+ return tree
41
+ },
42
+ stringify: (ast) => {
43
+ if (ast == undefined) return '()'
44
+ else if (typeof ast === 'object')
45
+ if (Array.isArray(ast))
46
+ return ast.length
47
+ ? `(array ${ast.map(LISP.stringify).join(' ')})`
48
+ : '()'
49
+ else
50
+ return `(array ${ast
51
+ .map(([key, value]) => `("${key}" ${LISP.stringify(value)})`)
52
+ .join(' ')})`
53
+ else if (typeof ast === 'string') return `"${ast}"`
54
+ else if (typeof ast === 'function') return '()'
55
+ else if (typeof ast === 'boolean') return +ast
56
+ else return ast
38
57
  }
39
- return tree
40
- }
41
- export const stringify = (ast) => {
42
- if (ast == undefined) return '()'
43
- else if (typeof ast === 'object')
44
- if (Array.isArray(ast))
45
- return ast.length ? `(array ${ast.map(stringify).join(' ')})` : '()'
46
- else
47
- return `(array ${ast
48
- .map(([key, value]) => `("${key}" ${stringify(value)})`)
49
- .join(' ')})`
50
- else if (typeof ast === 'string') return `"${ast}"`
51
- else if (typeof ast === 'function') return '()'
52
- else if (typeof ast === 'boolean') return +ast
53
- else return ast
54
58
  }
55
59
  export const AST = {
56
60
  parse: (source) => {
package/src/tokeniser.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import std from '../lib/baked/std.js'
2
2
  import { TYPE, VALUE, WORD, KEYWORDS, APPLY } from './enums.js'
3
3
  import { evaluate, isAtom } from './interpreter.js'
4
- import { stringify } from './parser.js'
4
+ import { LISP } from './parser.js'
5
5
  import {
6
6
  isEqual,
7
7
  isEqualTypes,
@@ -990,14 +990,16 @@ const keywords = {
990
990
  ? console.log(
991
991
  '\x1b[31m',
992
992
  `${describe} Failed:\n`,
993
- `${rest[0]} => ${stringify(rest[1])} != ${stringify(rest[2])}`,
993
+ `${rest[0]} => ${LISP.stringify(rest[1])} != ${LISP.stringify(
994
+ rest[2]
995
+ )}`,
994
996
  '\n',
995
997
  '\x1b[0m'
996
998
  )
997
999
  : console.log(
998
1000
  '\x1b[32m',
999
1001
  `${describe} Passed:\n`,
1000
- `${rest[0]} => ${stringify(rest[1])}`,
1002
+ `${rest[0]} => ${LISP.stringify(rest[1])}`,
1001
1003
  '\n',
1002
1004
  '\x1b[0m'
1003
1005
  )
@@ -1017,7 +1019,7 @@ const keywords = {
1017
1019
  `Invalid number of arguments for (${KEYWORDS.SERIALISE})`
1018
1020
  )
1019
1021
  const data = evaluate(args[0], env)
1020
- return stringify(data)
1022
+ return LISP.stringify(data)
1021
1023
  },
1022
1024
  [KEYWORDS.SET_ARRAY]: (args, env) => {
1023
1025
  if (args.length !== 2 && args.length !== 3)
package/src/utils.js CHANGED
@@ -2,7 +2,7 @@ import std from '../lib/baked/std.js'
2
2
  import { comp } from './compiler.js'
3
3
  import { APPLY, KEYWORDS, TYPE, VALUE, WORD } from './enums.js'
4
4
  import { run } from './interpreter.js'
5
- import { AST, isLeaf, parse } from './parser.js'
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
8
  export const removeNoCode = (source) =>
@@ -142,21 +142,6 @@ export const treeShake = (ast, libs) => {
142
142
  // Filter out libraries that are not in the visited set
143
143
  return libs.filter((x) => visited.has(x.at(1)[VALUE]))
144
144
  }
145
-
146
- export const runFromCompiled = (source) => {
147
- const tree = parse(
148
- handleUnbalancedQuotes(handleUnbalancedParens(removeNoCode(source)))
149
- )
150
- const compiled = comp(tree)
151
- const JavaScript = `${compiled.top}${compiled.program}`
152
- return eval(JavaScript)
153
- }
154
- export const runFromInterpreted = (source, env = {}) => {
155
- const tree = parse(
156
- handleUnbalancedQuotes(handleUnbalancedParens(removeNoCode(source)))
157
- )
158
- run(tree, env)
159
- }
160
145
  export const dfs = (tree, callback) => {
161
146
  if (!isLeaf(tree)) for (const leaf of tree) dfs(leaf)
162
147
  else callback(tree)
@@ -174,7 +159,7 @@ export const fez = (source, options = {}) => {
174
159
  else code = removeNoCode(source)
175
160
  if (!options.mutation) code = removeMutation(code)
176
161
  if (!code.length && options.throw) throw new Error('Nothing to parse!')
177
- const parsed = parse(code)
162
+ const parsed = LISP.parse(code)
178
163
  if (parsed.length === 0 && options.throw)
179
164
  throw new Error(
180
165
  'Top level expressions need to be wrapped in a (do) block'
@@ -292,10 +277,12 @@ export const decompress = (raw) => {
292
277
  for (const tok of runes) result += tok
293
278
  return result
294
279
  }
295
- // shake(parse(removeNoCode(source)), std)
280
+ // shake(LISP.parse(removeNoCode(source)), std)
296
281
  export const shake = (parsed, std) => [...treeShake(parsed, std), ...parsed]
297
282
  export const tree = (source, std) =>
298
- std ? shake(parse(removeNoCode(source)), std) : parse(removeNoCode(source))
283
+ std
284
+ ? shake(LISP.parse(removeNoCode(source)), std)
285
+ : LISP.parse(removeNoCode(source))
299
286
  export const lispToJavaScriptVariableName = (name) =>
300
287
  toCamelCase(
301
288
  arrowFromTo(