fez-lisp 1.0.37 → 1.0.38

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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { evaluate } from './src/interpreter.js'
2
- import { parse, stringify } from './src/parser.js'
2
+ import { parse, stringify, 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 }
8
+ export { fez, parse, stringify, keywords, evaluate, std, types, tree, 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.37",
5
+ "version": "1.0.38",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/parser.js CHANGED
@@ -52,3 +52,44 @@ export const stringify = (ast) => {
52
52
  else if (typeof ast === 'boolean') return +ast
53
53
  else return ast
54
54
  }
55
+ export const AST = {
56
+ parse: (source) => {
57
+ const tree = []
58
+ let head = tree,
59
+ stack = [tree],
60
+ acc = ''
61
+ for (let i = 0; i < source.length; ++i) {
62
+ const cursor = source[i]
63
+ if (cursor === '"') {
64
+ acc += '"'
65
+ ++i
66
+ while (source[i] !== '"') {
67
+ acc += source[i]
68
+ ++i
69
+ }
70
+ }
71
+ if (cursor === '[') {
72
+ head.push([])
73
+ stack.push(head)
74
+ head = head.at(-1)
75
+ } else if (cursor === ']' || cursor === ',') {
76
+ let token = acc
77
+ acc = ''
78
+ if (token) {
79
+ if (!head.length) head.push(Number(token))
80
+ else if (token[0] === '"' && token[token.length - 1] === '"')
81
+ head.push(token.substring(1, token.length - 1))
82
+ else head.push(Number(token))
83
+ }
84
+ if (cursor === ']') head = stack.pop()
85
+ } else acc += cursor
86
+ }
87
+ return tree[0]
88
+ },
89
+ stringify: (ast) =>
90
+ typeof ast === 'object'
91
+ ? `[${ast.map(AST.stringify).join(',')}]`
92
+ : typeof ast === 'string'
93
+ ? `"${ast}"`
94
+ : ast
95
+ }
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 { isLeaf, parse } from './parser.js'
5
+ import { AST, isLeaf, parse } 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) =>
@@ -161,7 +161,7 @@ export const dfs = (tree, callback) => {
161
161
  if (!isLeaf(tree)) for (const leaf of tree) dfs(leaf)
162
162
  else callback(tree)
163
163
  }
164
- export const deepClone = (ast) => JSON.parse(JSON.stringify(ast))
164
+ export const deepClone = (ast) => AST.parse(AST.stringify(ast))
165
165
  export const fez = (source, options = {}) => {
166
166
  const env = options.env ?? {}
167
167
  try {
@@ -187,7 +187,7 @@ export const fez = (source, options = {}) => {
187
187
  return run(ast, env)
188
188
  } else if (Array.isArray(source)) {
189
189
  const ast = !options.mutation
190
- ? JSON.parse(JSON.stringify(source).replace(new RegExp(/!/g), 'ǃ'))
190
+ ? AST.parse(AST.stringify(source).replace(new RegExp(/!/g), 'ǃ'))
191
191
  : source
192
192
  if (options.compile) {
193
193
  const js = Object.values(comp(deepClone(ast))).join('')