fez-lisp 1.1.14 → 1.1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. package/index.js +1 -0
  2. package/package.json +1 -1
  3. package/src/utils.js +66 -61
package/index.js CHANGED
@@ -16,6 +16,7 @@ export {
16
16
  src,
17
17
  js,
18
18
  prep,
19
+ dependencies,
19
20
  LISP,
20
21
  AST
21
22
  }
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.1.14",
5
+ "version": "1.1.15",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/utils.js CHANGED
@@ -133,70 +133,68 @@ export const handleUnbalancedQuotes = (source) => {
133
133
  return source
134
134
  }
135
135
  export const removeMutation = (source) => source.replace(new RegExp(/!/g), 'ǃ')
136
- export const treeShake = (ast, libs) => {
137
- const deps = libs.reduce((a, x) => a.set(x.at(1)[VALUE], x), new Map())
138
- const visited = new Set()
139
- const dfs = (tree, ignore = new Set()) => {
140
- const type = tree[TYPE]
141
- const value = tree[VALUE]
142
- if (!isLeaf(tree)) {
143
- const [car, ...rest] = tree
144
- if (car == undefined) return
136
+ const isDefinition = (x) =>
137
+ x[TYPE] === APPLY &&
138
+ (x[VALUE] === KEYWORDS.DEFINE_VARIABLE ||
139
+ x[VALUE] === KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION)
140
+ const toDeps = (libs) =>
141
+ libs.reduce(
142
+ (a, x, i) => a.set(x.at(1)[VALUE], { value: x, index: i }),
143
+ new Map()
144
+ )
145
+ const deepShake = (tree, deps, visited = new Set(), ignored = new Set()) => {
146
+ const type = tree[TYPE]
147
+ const value = tree[VALUE]
148
+ if (!isLeaf(tree)) {
149
+ const [car, ...rest] = tree
150
+ if (car == undefined) return
151
+ if (isDefinition(car)) {
145
152
  if (
146
- car[TYPE] === APPLY &&
147
- (car[VALUE] === KEYWORDS.DEFINE_VARIABLE ||
148
- car[VALUE] === KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION)
153
+ !isLeaf(rest.at(-1)) &&
154
+ rest
155
+ .at(-1)
156
+ .some(
157
+ (x) => x[TYPE] === APPLY && x[VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
158
+ )
149
159
  ) {
150
- if (
151
- !isLeaf(rest.at(-1)) &&
152
- rest
153
- .at(-1)
154
- .some(
155
- (x) =>
156
- x[TYPE] === APPLY && x[VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
157
- )
158
- ) {
159
- const args = rest
160
- .at(-1)
161
- .filter(
162
- (x) =>
163
- !(
164
- x[TYPE] === APPLY &&
165
- (x[VALUE] === KEYWORDS.ANONYMOUS_FUNCTION ||
166
- x[VALUE] === KEYWORDS.IMMUTABLE_FUNCTION)
167
- )
168
- )
169
- const body = args.pop()
170
- const params = new Set(args.map((x) => x[VALUE]))
171
- dfs(body, params)
172
- } else rest.forEach((x) => dfs(x, ignore))
173
- } else tree.forEach((x) => dfs(x, ignore))
174
- } else if (
175
- (type === APPLY || type === WORD) &&
176
- deps.has(value) &&
177
- !visited.has(value) &&
178
- !ignore.has(value)
179
- ) {
180
- visited.add(value)
181
- // Recursively explore the dependencies of the current node
182
- dfs(deps.get(value), ignore)
183
- }
160
+ const args = rest.at(-1).filter((x) => !isDefinition(x))
161
+ const body = args.pop()
162
+ const params = new Set(args.map((x) => x[VALUE]))
163
+ deepShake(body, deps, visited, params)
164
+ } else rest.forEach((x) => deepShake(x, deps, visited, ignored))
165
+ } else tree.forEach((x) => deepShake(x, deps, visited, ignored))
166
+ } else if (
167
+ (type === APPLY || type === WORD) &&
168
+ deps.has(value) &&
169
+ !visited.has(value) &&
170
+ !ignored.has(value)
171
+ ) {
172
+ visited.add(value)
173
+ deepShake(deps.get(value).value, deps, visited, ignored)
184
174
  }
185
- dfs(
186
- ast,
187
- new Set(
188
- ast
189
- .filter(
190
- ([x]) =>
191
- x[TYPE] === APPLY &&
192
- (x[VALUE] === KEYWORDS.DEFINE_VARIABLE ||
193
- x[VALUE] === KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION)
194
- )
195
- .map(([_, x]) => x[VALUE])
196
- )
197
- )
198
- // Filter out libraries that are not in the visited set
199
- return [...visited].reverse().map((x) => deps.get(x))
175
+ }
176
+ const extractDeps = (visited, deps) =>
177
+ [...visited]
178
+ .map((x) => deps.get(x))
179
+ .sort((a, b) => a.index - b.index)
180
+ .map((x) => x.value)
181
+ const toIgnore = (ast) =>
182
+ ast.filter(([x]) => isDefinition(x)).map(([_, x]) => x[VALUE])
183
+ export const treeShake = (ast, libs) => {
184
+ const deps = toDeps(libs)
185
+ const visited = new Set()
186
+ const ignored = new Set(toIgnore(ast))
187
+ deepShake(ast, deps, visited, ignored)
188
+ return extractDeps(visited, deps)
189
+ }
190
+ export const shakedList = (ast, libs) => {
191
+ const deps = toDeps(libs)
192
+ const visited = new Set()
193
+ const ignored = new Set(toIgnore(ast))
194
+ deepShake(ast, deps, visited, ignored)
195
+ const out = []
196
+ for (const [key] of deps) if (visited.has(key)) out.push(key)
197
+ return out
200
198
  }
201
199
  export const dfs = (tree, callback) => {
202
200
  if (!isLeaf(tree)) for (const leaf of tree) dfs(leaf)
@@ -323,6 +321,13 @@ export const ast = (source, deps) => {
323
321
  ...source
324
322
  ]
325
323
  }
324
+ export const dependencies = (source, deps) => {
325
+ source = prep(source)
326
+ return shakedList(
327
+ source,
328
+ deps.reduce((a, b) => a.concat(b), [])
329
+ )
330
+ }
326
331
  export const js = (source, deps) => {
327
332
  source = prep(source)
328
333
  const { top, program } = comp([