fez-lisp 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }