fez-lisp 1.3.8 → 1.3.10

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.3.8",
5
+ "version": "1.3.10",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/compiler.js CHANGED
@@ -121,8 +121,7 @@ const Helpers = {
121
121
  __tco: `__tco=fn=>(...args)=>{let result=fn(...args);while(typeof result==='function')result=result();return result}`,
122
122
  atom_predicate: `atom_predicate=(number)=>+(typeof number==='number')`,
123
123
  lambda_predicate: `lambda_predicate=(fm)=>+(typeof fn==='function')`,
124
- set_effect: `set_effect=function(array,index,value){if(arguments.length===1){array.pop()}else{array[index] = value};return array}`,
125
- __error: `__error=(error)=>{throw new Error(error.map((x)=>String.fromCharCode(x)).join(''))}`
124
+ set_effect: `set_effect=function(array,index,value){if(arguments.length===1){array.pop()}else{array[index] = value};return array}`
126
125
  }
127
126
  const semiColumnEdgeCases = new Set([
128
127
  ';)',
@@ -313,10 +312,6 @@ const compile = (tree, Drill) => {
313
312
  Drill
314
313
  )}:${Arguments.length === 3 ? compile(Arguments[2], Drill) : 0});`
315
314
  }
316
- case KEYWORDS.THROW: {
317
- Drill.Helpers.add('__error')
318
- return `__error(${compile(Arguments[0], Drill)})`
319
- }
320
315
  default: {
321
316
  const camelCased = lispToJavaScriptVariableName(token)
322
317
  if (camelCased in Helpers) Drill.Helpers.add(camelCased)
package/src/evaluator.js CHANGED
@@ -33,5 +33,3 @@ export const evaluate = (exp, env) => {
33
33
  )
34
34
  }
35
35
  }
36
- export const run = (tree, env = {}) =>
37
- keywords[KEYWORDS.BLOCK](tree, { ...keywords, ...env })
@@ -702,23 +702,6 @@ export const keywords = {
702
702
  )
703
703
  return +(typeof evaluate(args[0], env) === 'function')
704
704
  },
705
- // Not sure about these
706
- [KEYWORDS.THROW]: (args, env) => {
707
- if (args.length !== 1)
708
- throw new RangeError(
709
- `Invalid number of arguments to (${KEYWORDS.THROW}) (= 1 required) (${
710
- KEYWORDS.THROW
711
- } ${stringifyArgs(args)})`
712
- )
713
- const expression = evaluate(args[0], env)
714
- if (!Array.isArray(expression))
715
- throw new TypeError(
716
- `Argument of (${KEYWORDS.THROW}) must be an (${
717
- RUNTIME_TYPES.ARRAY
718
- }) but got (${expression}) (${KEYWORDS.THROW} ${stringifyArgs(args)})`
719
- )
720
- throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
721
- },
722
705
  [KEYWORDS.LOG]: (args, env) => {
723
706
  if (args.length !== 1)
724
707
  throw new RangeError(
package/src/keywords.js CHANGED
@@ -44,9 +44,7 @@ export const KEYWORDS = {
44
44
  LOG: 'log!',
45
45
  LOG_STRING: 'log-string!',
46
46
  LOG_CHAR: 'log-char!',
47
- CLEAR_CONSOLE: 'clear!',
48
-
49
- THROW: 'throw'
47
+ CLEAR_CONSOLE: 'clear!'
50
48
  }
51
49
 
52
50
  export const TYPES = {
package/src/parser.js CHANGED
@@ -1,138 +1,138 @@
1
- import { APPLY, ATOM, TYPE, WORD, VALUE } from './keywords.js'
2
- export const leaf = (type, value) => [type, value]
3
- export const isLeaf = ([car]) => car === APPLY || car === ATOM || car === WORD
4
- export const LISP = {
5
- parse: (source) => {
6
- const tree = []
7
- const stack = [tree]
8
- let head = tree
9
- let acc = ''
10
- for (let i = 0; i < source.length; ++i) {
11
- const cursor = source[i]
12
- if (cursor === '(') {
13
- const temp = []
14
- head.push(temp)
15
- stack.push(head)
16
- head = temp
17
- } else if (cursor === ')' || cursor === ' ') {
18
- let token = acc
19
- acc = ''
20
- if (token) {
21
- if (!head.length) head.push(leaf(APPLY, token))
22
- else if (token.match(/^-?[0-9]\d*(\.\d+)?$/))
23
- head.push(leaf(ATOM, Number(token)))
24
- else head.push(leaf(WORD, token))
25
- }
26
- if (cursor === ')') head = stack.pop()
27
- } else acc += cursor
28
- }
29
- return tree
30
- },
31
- stringify: (array) => {
32
- if (array == undefined) return '()'
33
- else if (typeof array === 'object')
34
- if (Array.isArray(array))
35
- return array.length
36
- ? `(array ${array.map(LISP.stringify).join(' ')})`
37
- : '()'
38
- else
39
- return `(array ${array
40
- .map(([key, value]) => `("${key}" ${LISP.stringify(value)})`)
41
- .join(' ')})`
42
- else if (typeof array === 'function') return '()'
43
- else if (typeof array === 'boolean') return +array
44
- else return array
45
- },
46
- source: (ast) => {
47
- const dfs = (exp) => {
48
- let out = ''
49
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
50
- if (first == undefined) return (out += '()')
51
- switch (first[TYPE]) {
52
- case WORD:
53
- out += first[VALUE]
54
- break
55
- case ATOM:
56
- out += first[VALUE]
57
- break
58
- case APPLY:
59
- out += `(${first[VALUE]} ${rest.map(dfs).join(' ')})`
60
- break
61
- }
62
- return out
63
- }
64
- return ast.map(dfs).join(' ')
65
- }
66
- }
67
- export const AST = {
68
- parse: (source) => {
69
- const tree = []
70
- const stack = [tree]
71
- let head = tree
72
- let acc = ''
73
- for (let i = 0; i < source.length; ++i) {
74
- const cursor = source[i]
75
- if (cursor === '"') {
76
- acc += '"'
77
- ++i
78
- while (source[i] !== '"') {
79
- acc += source[i]
80
- ++i
81
- }
82
- }
83
- if (cursor === '[') {
84
- const temp = []
85
- head.push(temp)
86
- stack.push(head)
87
- head = temp
88
- } else if (cursor === ']' || cursor === ',') {
89
- let token = acc
90
- acc = ''
91
- if (token) {
92
- if (!head.length) head.push(Number(token))
93
- else if (token[0] === '"' && token[token.length - 1] === '"')
94
- head.push(token.substring(1, token.length - 1))
95
- else head.push(Number(token))
96
- }
97
- if (cursor === ']') head = stack.pop()
98
- } else acc += cursor
99
- }
100
- return tree[0]
101
- },
102
- stringify: (ast) =>
103
- typeof ast === 'object'
104
- ? `[${ast.map(AST.stringify).join(',')}]`
105
- : typeof ast === 'string'
106
- ? `"${ast}"`
107
- : ast,
108
- struct: (ast) => {
109
- const dfs = (exp) => {
110
- let out = ''
111
- const [first, ...rest] = isLeaf(exp) ? [exp] : exp
112
- if (first == undefined)
113
- return (out +=
114
- '(Expression::Apply(vec![Expression::Word("array".to_string())]))')
115
- switch (first[TYPE]) {
116
- case WORD:
117
- out += `Expression::Word("${first[VALUE]}".to_string())`
118
- break
119
- case ATOM:
120
- out += `Expression::Atom(${
121
- Number.isInteger(first[VALUE])
122
- ? `${first[VALUE]}.0`
123
- : first[VALUE].toString()
124
- })`
125
- break
126
- case APPLY:
127
- out += `Expression::Apply(vec![Expression::Word("${
128
- first[VALUE]
129
- }".to_string()),${rest.map(dfs).join(',')}])`
130
- break
131
- }
132
- return out
133
- }
134
- return `Expression::Apply(vec![Expression::Word("do".to_string()),${ast
135
- .map(dfs)
136
- .join(',')}])`
137
- }
138
- }
1
+ import { APPLY, ATOM, TYPE, WORD, VALUE } from './keywords.js'
2
+ export const leaf = (type, value) => [type, value]
3
+ export const isLeaf = ([car]) => car === APPLY || car === ATOM || car === WORD
4
+ export const LISP = {
5
+ parse: (source) => {
6
+ const tree = []
7
+ const stack = [tree]
8
+ let head = tree
9
+ let acc = ''
10
+ for (let i = 0; i < source.length; ++i) {
11
+ const cursor = source[i]
12
+ if (cursor === '(') {
13
+ const temp = []
14
+ head.push(temp)
15
+ stack.push(head)
16
+ head = temp
17
+ } else if (cursor === ')' || cursor === ' ') {
18
+ let token = acc
19
+ acc = ''
20
+ if (token) {
21
+ if (!head.length) head.push(leaf(APPLY, token))
22
+ else if (token.match(/^-?[0-9]\d*(\.\d+)?$/))
23
+ head.push(leaf(ATOM, Number(token)))
24
+ else head.push(leaf(WORD, token))
25
+ }
26
+ if (cursor === ')') head = stack.pop()
27
+ } else acc += cursor
28
+ }
29
+ return tree
30
+ },
31
+ stringify: (array) => {
32
+ if (array == undefined) return '()'
33
+ else if (typeof array === 'object')
34
+ if (Array.isArray(array))
35
+ return array.length
36
+ ? `(array ${array.map(LISP.stringify).join(' ')})`
37
+ : '()'
38
+ else
39
+ return `(array ${array
40
+ .map(([key, value]) => `("${key}" ${LISP.stringify(value)})`)
41
+ .join(' ')})`
42
+ else if (typeof array === 'function') return '()'
43
+ else if (typeof array === 'boolean') return +array
44
+ else return array
45
+ },
46
+ source: (ast) => {
47
+ const dfs = (exp) => {
48
+ let out = ''
49
+ const [first, ...rest] = isLeaf(exp) ? [exp] : exp
50
+ if (first == undefined) return (out += '()')
51
+ switch (first[TYPE]) {
52
+ case WORD:
53
+ out += first[VALUE]
54
+ break
55
+ case ATOM:
56
+ out += first[VALUE]
57
+ break
58
+ case APPLY:
59
+ out += `(${first[VALUE]} ${rest.map(dfs).join(' ')})`
60
+ break
61
+ }
62
+ return out
63
+ }
64
+ return ast.map(dfs).join(' ')
65
+ }
66
+ }
67
+ export const AST = {
68
+ parse: (source) => {
69
+ const tree = []
70
+ const stack = [tree]
71
+ let head = tree
72
+ let acc = ''
73
+ for (let i = 0; i < source.length; ++i) {
74
+ const cursor = source[i]
75
+ if (cursor === '"') {
76
+ acc += '"'
77
+ ++i
78
+ while (source[i] !== '"') {
79
+ acc += source[i]
80
+ ++i
81
+ }
82
+ }
83
+ if (cursor === '[') {
84
+ const temp = []
85
+ head.push(temp)
86
+ stack.push(head)
87
+ head = temp
88
+ } else if (cursor === ']' || cursor === ',') {
89
+ let token = acc
90
+ acc = ''
91
+ if (token) {
92
+ if (!head.length) head.push(Number(token))
93
+ else if (token[0] === '"' && token[token.length - 1] === '"')
94
+ head.push(token.substring(1, token.length - 1))
95
+ else head.push(Number(token))
96
+ }
97
+ if (cursor === ']') head = stack.pop()
98
+ } else acc += cursor
99
+ }
100
+ return tree
101
+ },
102
+ stringify: (ast) =>
103
+ typeof ast === 'object'
104
+ ? `[${ast.map(AST.stringify).join(',')}]`
105
+ : typeof ast === 'string'
106
+ ? `"${ast}"`
107
+ : ast,
108
+ struct: (ast) => {
109
+ const dfs = (exp) => {
110
+ let out = ''
111
+ const [first, ...rest] = isLeaf(exp) ? [exp] : exp
112
+ if (first == undefined)
113
+ return (out +=
114
+ '(Expression::Apply(vec![Expression::Word("array".to_string())]))')
115
+ switch (first[TYPE]) {
116
+ case WORD:
117
+ out += `Expression::Word("${first[VALUE]}".to_string())`
118
+ break
119
+ case ATOM:
120
+ out += `Expression::Atom(${
121
+ Number.isInteger(first[VALUE])
122
+ ? `${first[VALUE]}.0`
123
+ : first[VALUE].toString()
124
+ })`
125
+ break
126
+ case APPLY:
127
+ out += `Expression::Apply(vec![Expression::Word("${
128
+ first[VALUE]
129
+ }".to_string()),${rest.map(dfs).join(',')}])`
130
+ break
131
+ }
132
+ return out
133
+ }
134
+ return `Expression::Apply(vec![Expression::Word("do".to_string()),${ast
135
+ .map(dfs)
136
+ .join(',')}])`
137
+ }
138
+ }
package/src/utils.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import std from '../lib/baked/std.js'
2
2
  import { comp, OPTIMIZATIONS } from './compiler.js'
3
3
  import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
4
- import { evaluate, run } from './evaluator.js'
4
+ import { evaluate } from './evaluator.js'
5
5
  import { AST, isLeaf, LISP } from './parser.js'
6
6
  import {
7
7
  deSuggarAst,
8
8
  deSuggarSource,
9
9
  handleUnbalancedQuotes
10
10
  } from './macros.js'
11
+ import { keywords } from './interpreter.js'
11
12
  export const logError = (error) =>
12
13
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
13
14
  export const logSuccess = (output) => console.log(output, '\x1b[0m')
@@ -212,10 +213,17 @@ export const dfs = (tree, callback) => {
212
213
  if (!isLeaf(tree)) for (const leaf of tree) dfs(leaf)
213
214
  else callback(tree)
214
215
  }
216
+ export const wrapInBlock = (ast) => [
217
+ [APPLY, KEYWORDS.CALL_FUNCTION],
218
+ [
219
+ [APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
220
+ [[APPLY, KEYWORDS.BLOCK], ...ast]
221
+ ]
222
+ ]
215
223
  export const interpret = (ast, keywords) =>
216
224
  ast.reduce((_, x) => evaluate(x, keywords), 0)
217
225
  export const fez = (source, options = {}) => {
218
- const env = Object.create(null)
226
+ const env = { ...keywords }
219
227
  try {
220
228
  if (typeof source === 'string') {
221
229
  source = deSuggarSource(source)
@@ -225,16 +233,16 @@ export const fez = (source, options = {}) => {
225
233
  const code = !options.mutation ? removeMutation(valid) : valid
226
234
  if (!code.length && options.throw) throw new Error('Nothing to parse!')
227
235
  const parsed = deSuggarAst(LISP.parse(code))
228
- const ast = [...treeShake(parsed, std), ...parsed]
236
+ const ast = wrapInBlock(shake(parsed, std))
229
237
  // if (options.check) typeCheck(ast)
230
238
  if (options.compile) return comp(ast)
231
- return run(ast, env)
239
+ return evaluate(ast, env)
232
240
  } else if (Array.isArray(source)) {
233
241
  const ast = !options.mutation
234
242
  ? AST.parse(AST.stringify(source).replace(new RegExp(/!/g), 'ǃ'))
235
243
  : source
236
244
  if (options.compile) return comp(ast)
237
- return run(ast, env)
245
+ return evaluate(ast, env)
238
246
  } else {
239
247
  throw new Error('Source has to be either a lisp source code or an AST')
240
248
  }
@@ -279,7 +287,7 @@ export const decompress = (raw) => {
279
287
  return result
280
288
  }
281
289
  // shake(LISP.parse(removeNoCode(source)), std)
282
- export const shake = (parsed, std) => [...treeShake(parsed, std), ...parsed]
290
+ export const shake = (parsed, std) => treeShake(parsed, std).concat(parsed)
283
291
  export const tree = (source, std) =>
284
292
  std
285
293
  ? shake(LISP.parse(deSuggarSource(removeNoCode(source))), std)
@@ -288,45 +296,20 @@ export const minify = (source) =>
288
296
  LISP.source(deSuggarAst(LISP.parse(deSuggarSource(removeNoCode(source)))))
289
297
  export const prep = (source) =>
290
298
  deSuggarAst(LISP.parse(removeNoCode(deSuggarSource(source))))
291
- export const src = (source, deps) => {
292
- source = prep(source)
293
- return LISP.source([
294
- ...treeShake(
295
- source,
296
- deps.reduce((a, b) => a.concat(b), [])
297
- ),
298
- ...source
299
- ])
300
- }
301
- export const ast = (source, deps) => {
302
- source = prep(source)
303
- return [
304
- ...treeShake(
305
- source,
306
- deps.reduce((a, b) => a.concat(b), [])
307
- ),
308
- ...source
309
- ]
310
- }
311
- export const astWithStd = (source) => {
312
- const parsed = prep(source)
313
- return [...treeShake(parsed, std), ...parsed]
314
- }
315
- export const dependencies = (source, deps) => {
316
- source = prep(source)
317
- return shakedList(
318
- source,
319
- deps.reduce((a, b) => a.concat(b), [])
299
+ export const src = (source, deps) =>
300
+ LISP.source(
301
+ wrapInBlock(
302
+ shake(
303
+ prep(source),
304
+ deps.reduce((a, b) => a.concat(b), [])
305
+ )
306
+ )
320
307
  )
321
- }
322
- export const js = (source, deps) => {
323
- source = prep(source)
324
- const { top, program } = comp([
325
- ...treeShake(
326
- source,
308
+ export const ast = (source, deps) =>
309
+ wrapInBlock(
310
+ shake(
311
+ prep(source),
327
312
  deps.reduce((a, b) => a.concat(b), [])
328
- ),
329
- ...source
330
- ])
331
- return `${top}${program}`
332
- }
313
+ )
314
+ )
315
+ export const astWithStd = (source) => wrapInBlock(shake(prep(source), std))