-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathindex.js
54 lines (51 loc) · 1.74 KB
/
index.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
47
48
49
50
51
52
53
54
import { default as gram } from 'easygram'
export const read = gram(`
jam ::= obj | arr | str
obj ::= WS* '{' WS* (duo (WS* duo)*)? WS* '}' WS*
arr ::= WS* '[' WS* (jam (WS* jam)*)? WS* ']' WS*
duo ::= str WS+ jam
str ::= bare | WS* '"' quote* '"' WS*
bare ::= SAFE+
quote ::= ANY*
WS ::= [ \t\n\r]+
SYN ::= '{' | '}' | '[' | ']'
ANY ::= (SAFE | WS | SYN | #x5C)
SAFE ::= #x21 | [#x23-#x5A] | [#x5E-#x7A] | #x7C | #x7E
`)
// Expects a JAMS string, the leaves/strings within must be valid JSON strings.
export const jams =s=> {
const ast = read(s)
if (ast === null) throw new Error('Syntax error')
if (ast.errors.length > 0) throw ast.errors[0]
return _jams(ast)
}
const _jams =ast=> {
switch (ast.type) {
case 'jam': {
return _jams(ast.children[0])
}
case 'str': {
return (ast.text.includes('""') && ast.children.length === 0) ? "" : _jams(ast.children[0])
}
case 'bare':
case 'quote': {
const quoted = String.raw`"${ast.text}"`
const json = JSON.parse(quoted)
return String.raw`${json}`
}
case 'arr': {
return ast.children.map(child => _jams(child))
}
case 'obj': {
const out = {}
for (let duo of ast.children) {
const key = _jams(duo.children[0])
const val = _jams(duo.children[1])
if (out[key] !== undefined) throw new Error(`Parse error: duplicate keys are prohibited at parse time`)
out[key] = val
}
return out
}
}
throw new Error(`panic: unrecognized AST node ${ast.type}`)
}