fez-lisp 1.0.37 → 1.0.38

Sign up to get free protection for your applications and to get access to all the features.
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('')