-
Notifications
You must be signed in to change notification settings - Fork 9
/
quasi-json.js.ts
121 lines (89 loc) · 3.15 KB
/
quasi-json.js.ts
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Subsets of JavaScript, starting from the grammar as defined at
// http://www.ecma-international.org/ecma-262/9.0/#sec-grammar-summary
// Defined to be extended into the Jessie grammar.
// See https://github.com/Agoric/Jessie/blob/master/README.md
// for documentation of the Jessie grammar.
// See also json.org
/// <reference path="peg.d.ts"/>
const makeJSON = (peg: IPegTag<IParserTag<any>>) => {
const {FAIL, HOLE, SKIP} = peg;
return peg`
# to be overridden or inherited
start <- _WS assignExpr _EOF ${v => (..._a: any[]) => v};
# to be extended
primaryExpr <- dataStructure;
dataStructure <-
dataLiteral ${n => ['data', JSON.parse(n)]}
/ array
/ record
/ HOLE ${h => ['exprHole', h]};
# An expression without side-effects.
# to be extended
pureExpr <-
dataLiteral ${n => ['data', JSON.parse(n)]}
/ pureArray
/ pureRecord
/ HOLE ${h => ['exprHole', h]};
dataLiteral <- (("null" / "false" / "true") _WSN / NUMBER / STRING) _WS;
pureArray <-
LEFT_BRACKET pureExpr ** _COMMA _COMMA? RIGHT_BRACKET ${(_, es, _2) => ['array', es]};
array <-
LEFT_BRACKET element ** _COMMA _COMMA? RIGHT_BRACKET ${(_, es, _2) => ['array', es]};
# to be extended
element <- assignExpr;
# The JavaScript and JSON grammars calls records "objects"
pureRecord <-
LEFT_BRACE purePropDef ** _COMMA _COMMA? RIGHT_BRACE ${(_, ps, _2) => ['record', ps]};
record <-
LEFT_BRACE propDef ** _COMMA _COMMA? RIGHT_BRACE ${(_, ps, _2) => ['record', ps]};
# to be extended
purePropDef <- propName COLON pureExpr ${(k, _, e) => ['prop', k, e]};
# to be extended
propDef <- propName COLON assignExpr ${(k, _, e) => ['prop', k, e]};
# to be extended
propName <- STRING ${(str) => {
const js = JSON.parse(str);
if (js === '__proto__') {
// Don't allow __proto__ behaviour attacks.
return FAIL;
}
return ['data', js];
}};
# to be overridden
assignExpr <- primaryExpr;
# Lexical syntax
_EOF <- ~.;
LEFT_BRACKET <- "[" _WS;
RIGHT_BRACKET <- "]" _WS;
LEFT_BRACE <- "{" _WS;
RIGHT_BRACE <- "}" _WS;
_COMMA <- "," _WS ${_ => SKIP};
COLON <- ":" _WS;
MINUS <- "-" _WS;
HOLE <- &${HOLE} _WS;
STRING <- < '"' (~'"' character)* '"' > _WS;
utf8 <-
[\xc2-\xdf] utf8cont
/ [\xe0-\xef] utf8cont utf8cont
/ [\xf0-\xf4] utf8cont utf8cont utf8cont;
utf8cont <- [\x80-\xbf];
character <-
escape
/ '\\u' hex hex hex hex
/ ~'\\' ([\x20-\x7f] / utf8);
escape <- '\\' ['"\\bfnrt];
hex <- digit / [a-fA-F];
NUMBER <- < int frac? exp? > _WSN;
int <- [1-9] digit+
/ digit
/ MINUS [1-9] digit+
/ MINUS digit;
digit <- [0-9];
frac <- '.' digit+;
exp <- [Ee] [+\-]? digit+;
# _WSN is whitespace or a non-ident character.
_WSN <- ~[$A-Za-z_] _WS ${_ => SKIP};
_WS <- [\t\n\r ]* ${_ => SKIP};
`;
};
export default makeJSON;