-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathjson.js
64 lines (51 loc) · 1.88 KB
/
json.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
55
56
57
58
59
60
61
62
63
64
var {And,Or,Maybe,Many,More,Join,Recurse,Group,Text,Expect,EOF} = require('../')
//white space
var _ = /^\s*/
//basic primitives
var boolean = Text(/^(?:true|false)/, function (t) { return 'true' === t })
var nul = Text(/^null/, () => null)
//numbers, fairly complex
var non_zero_int = /^[1-9][0-9]+/
var int = /^-?(?:0|[1-9][0-9]*)/
var fraction = /^\.[0-9]+/
var decimal = And(int, Maybe(fraction))
var number = Text(And(decimal, Maybe(And('e', /^[+-]?/, non_zero_int))), Number)
//strings, including escaped literals
function join (ary) {
return ary.join('')
}
function toUnescape (x) {
return (
x === 'n' ? '\n'
: x === '\\' ? '\\'
: x === 't' ? '\t'
: x === 'r' ? '\r'
: x
)
}
var escaped = And('\\', Text(/^./, toUnescape)), unescaped = Text(/^[^"\n\\]+/)
var string = And('"', Group(Many(Or(escaped, unescaped)), join), Expect('"'))
//note, matching unescaped string using "repeated non quote" because
//it makes it much much faster than matching each individual character
//then passing it to join.
function toObject (ary) {
var o = {}
for(var i = 0; i < ary.length; i++)
o[ary[i][0]] = ary[i][1]
return o
}
var value = Recurse(function (value) {
//objects and arrays.
var array = And('[', _, Group(Maybe(Join(value, ','))), _, Expect(']'))
//parse each key value pair into a two element array, [key, value]
//then this is passed to toObject in the map for object.
var keyValue = Group(And(_, string, _, Expect(":"), value))
var object = And('{', Group(Maybe(Join(keyValue, ',' )), toObject), Expect('}'))
//accept any valid json type at the top level, allow surrounding spaces.
return And(_, Or(object, string, number, nul, boolean, array), _)
})
module.exports = And(Expect(value, 'expected json value'), EOF)
//these might be useful in other parsers
module.exports.string = string
module.exports.number = number
module.exports.boolean = boolean