fez-lisp 1.0.0

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.
@@ -0,0 +1,275 @@
1
+ (let E 2.718281828459045)
2
+ (let PI 3.141592653589793)
3
+
4
+ (let* iteration (lambda array callback
5
+ (when (length array)
6
+ (do (callback (car array))
7
+ (iteration (cdr array) callback)))))
8
+
9
+ (let scan (lambda array callback (do
10
+ (let* iterate (lambda array out
11
+ (if (length array)
12
+ (iterate (cdr array)
13
+ (merge out (Array (callback (car array)))))
14
+ out)))
15
+ (iterate array ()))))
16
+
17
+ (let select (lambda array callback (do
18
+ (let* iterate (lambda array out
19
+ (if (length array)
20
+ (iterate (cdr array)
21
+ (if (callback (car array))
22
+ (merge out (Array (car array)))
23
+ out))
24
+ out)))
25
+ (iterate array ()))))
26
+
27
+ (let exclude (lambda array callback (do
28
+ (let* iterate (lambda array out
29
+ (if (length array)
30
+ (iterate (cdr array)
31
+ (if (not (callback (car array)))
32
+ (merge out (Array (car array)))
33
+ out))
34
+ out)))
35
+ (iterate array ()))))
36
+
37
+ (let fold (lambda array callback initial (do
38
+ (let* iterate (lambda array out
39
+ (if (length array)
40
+ (iterate (cdr array) (callback out (car array)))
41
+ out)))
42
+ (iterate array initial))))
43
+
44
+ (let every? (lambda array callback (do
45
+ (let* iterate (lambda array
46
+ (if (and (length array) (callback (car array)))
47
+ (iterate (cdr array))
48
+ (not (length array)))))
49
+ (iterate array))))
50
+
51
+ (let some? (lambda array callback (do
52
+ (let* iterate (lambda array
53
+ (if (and (length array) (not (callback (car array))))
54
+ (iterate (cdr array))
55
+ (type (length array) Boolean))))
56
+ (iterate array))))
57
+
58
+ (let find (lambda array callback (do
59
+ (let* iterate (lambda array
60
+ (when (length array)
61
+ (if (callback (car array)) (car array) (iterate (cdr array))))))
62
+ (iterate array))))
63
+
64
+ (let has? (lambda array callback (do
65
+ (let* iterate (lambda array
66
+ (when (length array)
67
+ (if (callback (car array)) 1 (iterate (cdr array))))))
68
+ (iterate array))))
69
+
70
+ (let reverse (lambda array (do
71
+ (let* iterate (lambda array out
72
+ (if (length array)
73
+ (iterate (cdr array)
74
+ (merge (Array (car array)) out))
75
+ out)))
76
+ (iterate array ()))))
77
+
78
+ (let range (lambda start end (do
79
+ (let* iterate (lambda out count
80
+ (if (<= count end) (iterate (merge out (Array count)) (+ count 1)) out)))
81
+ (iterate () start))))
82
+
83
+ (let sequence (lambda array (do
84
+ (let end (length array))
85
+ (let* iterate (lambda out count
86
+ (if (< (length out) end) (iterate (merge out (Array count)) (+ count 1)) out)))
87
+ (iterate () 0))))
88
+
89
+ (let sequence-n (lambda n (do
90
+ (let* iterate (lambda out count
91
+ (if (< (length out) n) (iterate (merge out (Array count)) (+ count 1)) out)))
92
+ (iterate () 0))))
93
+
94
+ (let unique (lambda array (go
95
+ (let sorted (sort array (safety lambda a b (> a b))))
96
+ (zip (sequence sorted))
97
+ (select (lambda x
98
+ (or (not (let index (car (cdr x))))
99
+ (not (= (get sorted (- index 1)) (get sorted index))))))
100
+ (scan car))))
101
+
102
+ (let for-range (lambda start end callback (do
103
+ (let* iterate (lambda i
104
+ (when (< i end)
105
+ (do
106
+ (callback i)
107
+ (iterate (+ i 1))))))
108
+ (iterate start))))
109
+
110
+ (let list-range (lambda start end (do
111
+ (let range (lambda list start end
112
+ (if (< start end)
113
+ (Array (merge list (range (Array (Array (+ start 1))) (+ start 1) end)))
114
+ list)))
115
+ (car (car (range () start end))))))
116
+
117
+ (let traverse (lambda x callback
118
+ (if (Atom? x)
119
+ (callback x)
120
+ (iterate x (lambda y (traverse y callback))))))
121
+
122
+ (let summation (lambda array (fold array (safety lambda a b (+ a b)) 0)))
123
+ (let product (lambda array (fold array (safety lambda a b (* a b)) 1)))
124
+ (let maximum (lambda array (fold array (safety lambda a b (if (> a b) a b)) (car array))))
125
+ (let minimum (lambda array (fold array (safety lambda a b (if (< a b) a b)) (car array))))
126
+ (let max (lambda a b (if (> a b) a b)))
127
+ (let min (lambda a b (if (< a b) a b)))
128
+ (let count-of (lambda array callback (go array (select callback) (length))))
129
+ (let increment (safety lambda i (+ i 1)))
130
+ (let floor (safety lambda n (| n 0)))
131
+ (let round (safety lambda n (| (+ n 0.5) 0)))
132
+ (let empty? (safety lambda array (not (length array))))
133
+ (let array-in-bounds? (safety lambda array index (and (< index (length array)) (>= index 0))))
134
+
135
+ (let string->array (safety lambda string (type string Array)))
136
+ (let array->string (lambda array (fold array (safety lambda a x (concatenate a (type x String))) "")))
137
+ (let string->number (safety lambda string (type string Number)))
138
+ (let number->string (safety lambda number (type number String)))
139
+ (let strings->numbers (lambda array (scan array (safety lambda x (type x Number)))))
140
+ (let numbers->strings (lambda array (scan array (safety lambda x (type x String)))))
141
+ (let string->charcodes (lambda string (go string (type Array) (scan (lambda x (type x Char-Code))))))
142
+ (let chars->charcodes (lambda array (go array (scan (lambda x (type x Char-Code))))))
143
+ (let charcodes->chars (lambda array (go array (scan (lambda x (type x Char))))))
144
+ (let charcodes->string (lambda array (go array (scan (lambda x (type x Char))) (array->string))))
145
+
146
+ (let power (lambda base exp
147
+ (if (< exp 0)
148
+ (if (= base 0)
149
+ (throw "Attempting to divide by 0 in (power)")
150
+ (/ (* base (power base (- (* exp -1) 1)))))
151
+ (cond
152
+ (= exp 0) 1
153
+ (= exp 1) base
154
+ (*) (* base (power base (- exp 1)))))))
155
+
156
+ (let greatest-common-divisor (lambda a b (do
157
+ (let* gcd (lambda a b
158
+ (if (= b 0) a (gcd b (mod a b)))) (gcd a b)))))
159
+
160
+ (let least-common-divisor (lambda a b (* a b (/ (greatest-common-divisor a b)))))
161
+
162
+ (let sqrt (lambda x (do
163
+ (let is-good-enough (lambda g x (< (abs (- (square g) x)) 0.01))
164
+ improve-guess (lambda g x (average g (* x (/ g)))))
165
+ (let* sqrt-iter (lambda g x
166
+ (if (is-good-enough g x) g
167
+ (sqrt-iter (improve-guess g x) x))))
168
+ (sqrt-iter 1.0 x))))
169
+ (let circumference (lambda radius (* PI (* radius 2))))
170
+ (let hypotenuse (lambda a b (sqrt (+ (* a a) (* b b)))))
171
+ (let abs (safety lambda n (- (^ n (>> n 31)) (>> n 31))))
172
+ (let nth-digit (lambda digit n (| (mod (/ digit (power 10 (- n 1))) 10) 0.5)))
173
+ (let normalize (safety lambda value min max (* (- value min) (/ (- max min)))))
174
+ (let linear-interpolation (safety lambda a b n (+ (* (- 1 n) a) (* n b))))
175
+ (let gauss-sum (safety lambda n (* n (+ n 1) 0.5)))
176
+ (let gauss-sum-sequance (safety lambda a b (* (+ a b) (+ (- b a) 1) 0.5)))
177
+ (let clamp (safety lambda x limit (if (> x limit) limit x)))
178
+ (let odd? (safety lambda x (= (mod x 2) 1)))
179
+ (let even? (safety lambda x (= (mod x 2) 0)))
180
+ (let sign (safety lambda n (if (< n 0) -1 1)))
181
+ (let radians (lambda deg (* deg PI (/ 180))))
182
+ (let average (safety lambda x y (* (+ x y) 0.5)))
183
+ (let euclidean-mod (safety lambda a b (mod (+ (mod a b) b) b)))
184
+ (let euclidean-distance (lambda x1 y1 x2 y2 (do
185
+ (let a (- x1 x2))
186
+ (let b (- y1 y2))
187
+ (sqrt (+ (* a a) (* b b))))))
188
+ (let manhattan-distance (lambda x1 y1 x2 y2 (+ (abs (- x2 x1)) (abs (- y2 y1)))))
189
+ (let positive? (safety lambda num (> num 0)))
190
+ (let negative? (safety lambda num (< num 0)))
191
+ (let zero? (safety lambda num (= num 0)))
192
+ (let divisible? (safety lambda a b (= (mod a b) 0)))
193
+ (let prime? (lambda n
194
+ (cond
195
+ (= n 1) 0
196
+ (< n 0) 0
197
+ (*) (do
198
+ (let* iter (lambda i end (do
199
+ (let it-is (not (= (mod n i) 0)))
200
+ (if (and (<= i end) it-is) (iter (+ i 1) end) it-is))))
201
+ (or (= n 2) (iter 2 (sqrt n)))))))
202
+
203
+ (let slice (safety lambda array start end (do
204
+ (let bounds (- end start))
205
+ (let* iterate (lambda i out
206
+ (if (< i bounds)
207
+ (iterate (+ i 1) (merge out (Array (get array (+ start i)))))
208
+ out)))
209
+ (iterate 0 ()))))
210
+
211
+ (let binary-search
212
+ (lambda array target (do
213
+ (let* search
214
+ (lambda arr target start end (do
215
+ (when (<= start end) (do
216
+ (let index (floor (* (+ start end) 0.5)))
217
+ (let current (get arr index))
218
+ (if (= target current) target
219
+ (if (> current target)
220
+ (search arr target start (- index 1))
221
+ (search arr target (+ index 1) end))))))))
222
+ (search array target 0 (length array)))))
223
+
224
+ (let zip (safety lambda A B (do
225
+ (let* iterate (lambda a b output
226
+ (if (and (length a) (length b)) (iterate (cdr a) (cdr b) (merge output (Array (Array (car a) (car b))))) output)))
227
+ (iterate A B ()))))
228
+
229
+ (let cartesian-product (lambda a b (fold a (lambda p x (merge p (scan b (lambda y (Array x y))))) ())))
230
+
231
+ (let equal? (lambda a b
232
+ (or (and (Atom? a) (Atom? b) (= a b))
233
+ (and (Array? a)
234
+ (= (length a) (length b))
235
+ (not (some? (sequence a) (lambda i (not (equal? (get a i) (get b i))))))))))
236
+
237
+ (let split (lambda string delim (do
238
+ (let input (type (concatenate string delim) Array))
239
+ (let marks
240
+ (go
241
+ input
242
+ (zip (sequence input))
243
+ (scan (lambda x (if (= (car x) delim) (car (cdr x)) (car x))))))
244
+ (let first (find marks (lambda x (Number? x))))
245
+ (go
246
+ marks
247
+ (fold (lambda a b
248
+ (if (Number? b)
249
+ (merge a (Array (slice input (- b first) b)))
250
+ a)) ())
251
+ (scan (lambda x (array->string x)))))))
252
+
253
+ (let join (lambda array delim (fold (zip array (sequence array)) (lambda a b (if (> (car (cdr b)) 0) (concatenate a delim (type (car b) String)) (type (car b) String))) "")))
254
+
255
+ (let flat (lambda array (do
256
+ (let flatten (lambda item
257
+ (if (and (Array? item) (length item))
258
+ (fold item (lambda a b (merge a (flatten b))) ())
259
+ (Array item))))
260
+ (flatten array))))
261
+
262
+ (let sort (lambda arr callback (do
263
+ (if (<= (length arr) 1) arr (do
264
+ (let pivot (car arr))
265
+ (let* iterate (lambda i bounds a b (do
266
+ (let current (get arr i))
267
+ (let predicate (callback current pivot))
268
+ (let left (if (= predicate 0) (merge a (Array current)) a))
269
+ (let right (if (= predicate 1) (merge b (Array current)) b))
270
+ (if (< i bounds) (iterate (+ i 1) bounds left right)
271
+ (Array left right)))))
272
+ (let sorted (iterate 1 (- (length arr) 1) () ()))
273
+ (let left (car sorted))
274
+ (let right (car (cdr sorted)))
275
+ (merge (sort left callback) (Array pivot) (sort right callback)))))))
package/logo.svg ADDED
@@ -0,0 +1,8 @@
1
+ <svg width="144" height="128" viewBox="0 0 144 128" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M128 0H0V128H128V0Z" fill="#B44637"/>
3
+ <path d="M128 0H0V128H128V0Z" fill="#B44637"/>
4
+ <path d="M128 0H96V128H128V0Z" fill="#8E2F22"/>
5
+ <path d="M128 0H96V128H128V0Z" fill="#8E2F22"/>
6
+ <path d="M112 0H128V64H112V0Z" fill="#D6C096"/>
7
+ <path d="M128 64H144V80H128V64Z" fill="#D6C096"/>
8
+ </svg>
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "fez-lisp",
3
+ "description": "Immutable Lisp interpreted & compiled to JavaScript",
4
+ "author": "AT290690",
5
+ "version": "1.0.0",
6
+ "type": "module",
7
+ "main": "index.js",
8
+ "keywords": [
9
+ "lisp",
10
+ "expressions",
11
+ "programming-language",
12
+ "interpreter",
13
+ "compiler"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/AT-290690/fez.git"
18
+ },
19
+ "prettier": {
20
+ "semi": false,
21
+ "singleQuote": true
22
+ },
23
+ "scripts": {
24
+ "build": "node ./lib/builder.js",
25
+ "fez": "node main.js",
26
+ "test": "mocha"
27
+ },
28
+ "license": "MIT",
29
+ "devDependencies": {
30
+ "mocha": "^10.2.0"
31
+ },
32
+ "dependencies": {}
33
+ }
@@ -0,0 +1,361 @@
1
+ import {
2
+ APPLY,
3
+ ATOM,
4
+ PLACEHOLDER,
5
+ KEYWORDS,
6
+ TYPE,
7
+ VALUE,
8
+ WORD,
9
+ } from './enums.js'
10
+ import { deepRename, lispToJavaScriptVariableName } from './utils.js'
11
+ const Helpers = {
12
+ log: `var logEffect=(msg)=>{console.log(msg);return msg}`,
13
+ _merge: `_merge=(...arrays)=>arrays.reduce((a,b)=>a.concat(b),[])`,
14
+ tco: `tco=fn=>(...args)=>{
15
+ let result=fn(...args)
16
+ while(typeof result==='function')result=result()
17
+ return result
18
+ }`,
19
+ atom: `_isAtom=(value)=>typeof value==='number'||typeof value==='string'`,
20
+ error: `_error=(error)=>{
21
+ throw new Error(error)
22
+ }`,
23
+ serialise: `_serialise=(result)=>{
24
+ return typeof result==='function'?'(λ)':Array.isArray(result)?JSON.stringify(result,(_,value)=>{
25
+ switch(typeof value){
26
+ case 'number':
27
+ return Number(value)
28
+ case 'function':
29
+ return 'λ'
30
+ case 'undefined':
31
+ case 'symbol':
32
+ return 0
33
+ case 'boolean':
34
+ return +value
35
+ default:
36
+ return value
37
+ }
38
+ })
39
+ .replace(new RegExp(/\\[/g),"(Array ")
40
+ .replace(new RegExp(/\\]/g),')')
41
+ .replace(new RegExp(/\\,/g),' ')
42
+ .replace(new RegExp(/"λ"/g),'λ')
43
+ :typeof result==='string'
44
+ ?'"'+result+'"'
45
+ :result==undefined
46
+ ?'(void)'
47
+ :result
48
+ }`,
49
+ cast: `_cast=(type,value)=>{
50
+ switch (type) {
51
+ case 'Number':
52
+ return Number(value)
53
+ case 'String':
54
+ return value.toString()
55
+ case 'Array':
56
+ return typeof value==='number'?[...Number(value).toString()].map(Number):[...value]
57
+ case 'Bit':
58
+ return parseInt(value,2)
59
+ case 'Boolean':
60
+ return +!!value
61
+ case 'Function':
62
+ return ()=>value
63
+ case 'Char-Code':
64
+ return String.fromCharCode(value)
65
+ case 'Char':
66
+ return value.charCodeAt(0)
67
+ default:
68
+ return 0
69
+ }
70
+ }`,
71
+ }
72
+ const handleBoolean = (source) => `+${source}`
73
+ const semiColumnEdgeCases = new Set([
74
+ ';)',
75
+ ';-',
76
+ ';+',
77
+ ';*',
78
+ ';%',
79
+ ';&',
80
+ ';/',
81
+ ';:',
82
+ ';.',
83
+ ';=',
84
+ ';<',
85
+ ';>',
86
+ ';|',
87
+ ';,',
88
+ ';?',
89
+ ',,',
90
+ ';;',
91
+ ';]',
92
+ ])
93
+
94
+ const parse = (Arguments, Variables) =>
95
+ Arguments.map((x) => compile(x, Variables))
96
+ const parseArgs = (Arguments, Variables, separator = ',') =>
97
+ parse(Arguments, Variables).join(separator)
98
+ const compile = (tree, Variables) => {
99
+ if (!tree) return ''
100
+ const [first, ...Arguments] = Array.isArray(tree) ? tree : [tree]
101
+ if (first == undefined) return '[];'
102
+ const token = first[VALUE]
103
+ if (first[TYPE] === APPLY) {
104
+ switch (token) {
105
+ case KEYWORDS.BLOCK: {
106
+ if (Arguments.length > 1) {
107
+ return `(${Arguments.map((x) =>
108
+ (compile(x, Variables) ?? '').toString().trimStart()
109
+ )
110
+ .filter(Boolean)
111
+ .join(',')});`
112
+ } else {
113
+ const res = compile(Arguments[0], Variables)
114
+ return res !== undefined ? res.toString().trim() : ''
115
+ }
116
+ }
117
+ case KEYWORDS.CALL_FUNCTION: {
118
+ const [first, ...rest] = Arguments
119
+ const apply = compile(first, Variables)
120
+ return `${
121
+ apply[apply.length - 1] === ';'
122
+ ? apply.substring(0, apply.length - 1)
123
+ : apply
124
+ }(${parseArgs(rest, Variables)})`
125
+ }
126
+ case KEYWORDS.DEFINE_VARIABLE: {
127
+ let name,
128
+ out = '(('
129
+ if (Arguments[0][TYPE] === WORD) {
130
+ name = lispToJavaScriptVariableName(Arguments[0][VALUE])
131
+ Variables.add(name)
132
+ }
133
+ out += `${name}=${compile(Arguments[1], Variables)}`
134
+ out += `),${name});`
135
+ return out
136
+ }
137
+ case KEYWORDS.IS_STRING:
138
+ return handleBoolean(
139
+ `(typeof(${compile(Arguments[0], Variables)})==='string');`
140
+ )
141
+ case KEYWORDS.IS_NUMBER:
142
+ return handleBoolean(
143
+ `(typeof(${compile(Arguments[0], Variables)})==='number');`
144
+ )
145
+ case KEYWORDS.IS_FUNCTION:
146
+ return `(typeof(${compile(Arguments[0], Variables)})==='function');`
147
+ case KEYWORDS.IS_ARRAY:
148
+ return `(Array.isArray(${compile(Arguments[0], Variables)}));`
149
+ case KEYWORDS.NUMBER_TYPE:
150
+ return '0'
151
+ case KEYWORDS.INTEGER_TYPE:
152
+ return '0n'
153
+ case KEYWORDS.BOOLEAN_TYPE:
154
+ return '1'
155
+ case KEYWORDS.STRING_TYPE:
156
+ return '""'
157
+ case KEYWORDS.ARRAY_TYPE:
158
+ return Arguments.length === 2 &&
159
+ Arguments[1][TYPE] === WORD &&
160
+ Arguments[1][VALUE] === 'length'
161
+ ? `(new Array(${compile(Arguments[0], Variables)}).fill(0))`
162
+ : `[${parseArgs(Arguments, Variables)}];`
163
+ case KEYWORDS.FUNCTION_TYPE:
164
+ return '(()=>{});'
165
+ case KEYWORDS.ARRAY_OR_STRING_LENGTH:
166
+ return `(${compile(Arguments[0], Variables)}).length`
167
+ case KEYWORDS.IS_ATOM:
168
+ return handleBoolean(`_isAtom(${compile(Arguments[0], Variables)});`)
169
+ case KEYWORDS.FIRST_ARRAY:
170
+ return `${compile(Arguments[0], Variables)}.at(0);`
171
+ case KEYWORDS.REST_ARRAY:
172
+ return `${compile(Arguments[0], Variables)}.slice(1);`
173
+ case KEYWORDS.GET_ARRAY:
174
+ return `${compile(Arguments[0], Variables)}.at(${compile(
175
+ Arguments[1],
176
+ Variables
177
+ )});`
178
+ case KEYWORDS.MERGE:
179
+ return `_merge(${parseArgs(Arguments, Variables)});`
180
+ case KEYWORDS.ANONYMOUS_FUNCTION: {
181
+ const functionArgs = Arguments
182
+ const body = Arguments.pop()
183
+ const Variables = new Set()
184
+ const evaluatedBody = compile(body, Variables)
185
+ const vars = Variables.size ? `var ${[...Variables].join(',')};` : ''
186
+ return `((${parseArgs(
187
+ functionArgs.map((node, index) =>
188
+ node[VALUE] === PLACEHOLDER
189
+ ? { [TYPE]: node[TYPE], [VALUE]: `_${index}` }
190
+ : { [TYPE]: node[TYPE], [VALUE]: node[VALUE] }
191
+ ),
192
+ Variables
193
+ )})=>{${vars}return ${evaluatedBody.toString().trimStart()}});`
194
+ }
195
+ case KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION: {
196
+ let name,
197
+ newName,
198
+ out = '(('
199
+ const arg = Arguments[0]
200
+ name = lispToJavaScriptVariableName(arg[VALUE])
201
+ newName = `rec_${performance.now().toString().replace('.', 7)}`
202
+ Variables.add(name)
203
+ Variables.add(newName)
204
+ const functionArgs = Arguments[1].slice(1)
205
+ const body = functionArgs.pop()
206
+ const FunctionVariables = new Set()
207
+ deepRename(arg[VALUE], newName, body)
208
+ const evaluatedBody = compile(body, FunctionVariables)
209
+ const vars = FunctionVariables.size
210
+ ? `var ${[...FunctionVariables].join(',')};`
211
+ : ''
212
+ out += `${name}=(tco(${newName}=(${parseArgs(
213
+ functionArgs,
214
+ Variables
215
+ )})=>{${vars}return ${evaluatedBody.toString().trimStart()}};`
216
+ out += `, ${newName}))), ${name});`
217
+ return out
218
+ }
219
+ case KEYWORDS.AND:
220
+ return `(${parseArgs(Arguments, Variables, '&&')});`
221
+ case KEYWORDS.OR:
222
+ return `((${parseArgs(Arguments, Variables, '||')}) || 0);`
223
+ case KEYWORDS.CONCATENATION:
224
+ return '(' + parseArgs(Arguments, Variables, '+') + ');'
225
+ case KEYWORDS.EQUAL:
226
+ return handleBoolean(`(${parseArgs(Arguments, Variables, '===')});`)
227
+ case KEYWORDS.GREATHER_THAN_OR_EQUAL:
228
+ case KEYWORDS.LESS_THAN_OR_EQUAL:
229
+ case KEYWORDS.GREATHER_THAN:
230
+ case KEYWORDS.LESS_THAN:
231
+ return handleBoolean(`(${parseArgs(Arguments, Variables, token)});`)
232
+ case KEYWORDS.SUBTRACTION:
233
+ return Arguments.length === 1
234
+ ? `(-${compile(Arguments[0], Variables)});`
235
+ : `(${parse(Arguments, Variables)
236
+ // Add space so it doesn't consider it 2--1 but 2- -1
237
+ .map((x) => (typeof x === 'number' && x < 0 ? ` ${x}` : x))
238
+ .join(token)});`
239
+ case KEYWORDS.MULTIPLICATION:
240
+ return Arguments.length
241
+ ? `(${parseArgs(Arguments, Variables, token)});`
242
+ : `(1);`
243
+ case KEYWORDS.DIVISION:
244
+ return Arguments.length
245
+ ? Arguments.length === 1
246
+ ? `(1/${compile(Arguments[0], Variables)});`
247
+ : `(${parseArgs(Arguments, Variables, token)});`
248
+ : `(0);`
249
+ case KEYWORDS.ADDITION:
250
+ case KEYWORDS.BITWISE_AND:
251
+ case KEYWORDS.BITWISE_OR:
252
+ case KEYWORDS.BITWISE_XOR:
253
+ case KEYWORDS.BITWISE_LEFT_SHIFT:
254
+ case KEYWORDS.BITWISE_RIGHT_SHIFT:
255
+ case KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT:
256
+ return `(${parseArgs(Arguments, Variables, token)});`
257
+ case KEYWORDS.REMAINDER_OF_DIVISION:
258
+ return `(${compile(Arguments[0], Variables)}%${compile(
259
+ Arguments[1],
260
+ Variables
261
+ )});`
262
+ case KEYWORDS.BIT_TYPE:
263
+ return `(${compile(Arguments[0], Variables)}>>>0).toString(2)`
264
+ case KEYWORDS.BITWISE_NOT:
265
+ return `~(${compile(Arguments[0], Variables)})`
266
+ case KEYWORDS.NOT:
267
+ return `(${handleBoolean(`!${compile(Arguments[0], Variables)}`)})`
268
+ case KEYWORDS.IF: {
269
+ return `(${compile(Arguments[0], Variables)}?${compile(
270
+ Arguments[1],
271
+ Variables
272
+ )}:${compile(Arguments[2], Variables)});`
273
+ }
274
+ case KEYWORDS.WHEN: {
275
+ return `(${compile(Arguments[0], Variables)}?${compile(
276
+ Arguments[1],
277
+ Variables
278
+ )}:0);`
279
+ }
280
+ case KEYWORDS.UNLESS: {
281
+ return `(${compile(Arguments[0], Variables)}?${compile(
282
+ Arguments[2],
283
+ Variables
284
+ )}:${compile(Arguments[1], Variables)});`
285
+ }
286
+ case KEYWORDS.OTHERWISE: {
287
+ return `(${compile(Arguments[0], Variables)}?0:${compile(
288
+ Arguments[1],
289
+ Variables
290
+ )});`
291
+ }
292
+ case KEYWORDS.CONDITION: {
293
+ let out = '('
294
+ for (let i = 0; i < Arguments.length; i += 2)
295
+ out += `${compile(Arguments[i], Variables)}?${compile(
296
+ Arguments[i + 1],
297
+ Variables
298
+ )}:`
299
+ out += '0);'
300
+ return out
301
+ }
302
+ case KEYWORDS.CAST_TYPE:
303
+ return `_cast("${Arguments[1][VALUE]}", ${compile(
304
+ Arguments[0],
305
+ Variables
306
+ )})`
307
+ case KEYWORDS.PIPE: {
308
+ let inp = Arguments[0]
309
+ for (let i = 1; i < Arguments.length; ++i)
310
+ inp = [Arguments[i].shift(), inp, ...Arguments[i]]
311
+ return compile(inp, Variables)
312
+ }
313
+ case KEYWORDS.THROW_ERROR: {
314
+ return `_error(${compile(Arguments[0], Variables)})`
315
+ }
316
+ case KEYWORDS.IMMUTABLE_FUNCTION: {
317
+ const [first, ...rest] = Arguments
318
+ return compile(
319
+ [{ [TYPE]: APPLY, [VALUE]: first[VALUE] }, ...rest],
320
+ Variables
321
+ )
322
+ }
323
+ case KEYWORDS.SERIALISE:
324
+ return `_serialise(${compile(Arguments[0], Variables)});`
325
+ case KEYWORDS.NOT_COMPILED_BLOCK:
326
+ case KEYWORDS.ATOM:
327
+ case KEYWORDS.TEST_CASE:
328
+ case KEYWORDS.TEST_BED:
329
+ return ''
330
+ default: {
331
+ const camelCased = lispToJavaScriptVariableName(token)
332
+ return `${camelCased}(${parseArgs(Arguments, Variables)});`
333
+ }
334
+ }
335
+ } else if (first[TYPE] === ATOM)
336
+ return typeof first[VALUE] === 'string'
337
+ ? `\`${first[VALUE]}\``
338
+ : first[VALUE]
339
+ else if (first[TYPE] === WORD) return lispToJavaScriptVariableName(token)
340
+ }
341
+
342
+ const HelperSources = Object.values(Helpers).join(',')
343
+
344
+ export const comp = (ast) => {
345
+ const Variables = new Set()
346
+ const raw = ast
347
+ .map((tree) => compile(tree, Variables))
348
+ .filter(Boolean)
349
+ .join('\n')
350
+ let program = ''
351
+ for (let i = 0; i < raw.length; ++i) {
352
+ const current = raw[i]
353
+ const next = raw[i + 1]
354
+ if (!semiColumnEdgeCases.has(current + next)) program += current
355
+ }
356
+ const top = `${HelperSources};\n${
357
+ Variables.size ? `var ${[...Variables].join(',')};` : ''
358
+ }`
359
+
360
+ return { top, program }
361
+ }