-
Notifications
You must be signed in to change notification settings - Fork 0
/
read.js
46 lines (42 loc) · 1.02 KB
/
read.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const regex = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g
const tokenize = (input = '') =>
input.match(regex)
.filter(token => !!token)
.map(token => token.replace(' ', ''))
const evalToken = token => {
if (!isNaN(token))
return Number(token)
if (token === 'true')
return true
if (token === 'false')
return false
if (token === 'nil')
return null
return { name: token }
}
const ast = (tokens = []) => {
const array = []
if (!tokens.length)
return array
let index = 0
if (tokens[index] === '(') {
while(tokens[++index] !== ')') {
if (index === tokens.length + 1)
throw new Error('invalid exp')
if (tokens[index] === '(') {
const innerAst = ast(tokens.slice(index))
array.push(innerAst.array)
index += innerAst.endIndex
} else {
array.push(tokens[index])
}
}
} else {
if (tokens.length > 1)
throw new Error('invalid exp')
return { array: [tokens[0]] }
}
return { array, endIndex: index }
}
export default (input = '') =>
ast(tokenize(input)).array