grammar-composer 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/GrammarComposer.d.ts +1 -2
- package/dist/GrammarComposer.js +3 -5
- package/dist/GrammarComposer.js.map +1 -1
- package/dist/Test.js +26 -12
- package/dist/Test.js.map +1 -1
- package/dist/TopDownParser.js +5 -9
- package/dist/TopDownParser.js.map +1 -1
- package/dist/test-data/TestData.js +1 -1
- package/dist/test-data/TestData.js.map +1 -1
- package/dist/test-grammars/JsonGrammar.d.ts +4 -4
- package/dist/test-grammars/JsonGrammar.js +31 -31
- package/dist/test-grammars/JsonGrammar.js.map +1 -1
- package/dist/test-grammars/RegExpGrammar.d.ts +47 -0
- package/dist/test-grammars/RegExpGrammar.js +191 -0
- package/dist/test-grammars/RegExpGrammar.js.map +1 -0
- package/package.json +2 -2
- package/src/GrammarComposer.ts +9 -9
- package/src/Test.ts +36 -13
- package/src/TopDownParser.ts +4 -9
- package/src/test-data/TestData.ts +1 -1
- package/src/test-grammars/JsonGrammar.ts +44 -47
- package/src/test-grammars/RegExpGrammar.ts +301 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import * as G from '../GrammarComposer.js';
|
|
2
|
+
import * as R from 'regexp-composer';
|
|
3
|
+
export class RegExpGrammar {
|
|
4
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
// High level productions
|
|
6
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
|
+
disjunction = () => [
|
|
8
|
+
this.sequence,
|
|
9
|
+
G.possibly([
|
|
10
|
+
this.disjunctionSeparator,
|
|
11
|
+
this.disjunction,
|
|
12
|
+
])
|
|
13
|
+
];
|
|
14
|
+
sequence = () => G.oneOrMore(this.element);
|
|
15
|
+
element = () => G.anyOf(this.anchor, this.lookaround, this.possiblyQuantifiedExpression);
|
|
16
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
17
|
+
// Quantifed expressions
|
|
18
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
19
|
+
possiblyQuantifiedExpression = () => [
|
|
20
|
+
G.anyOf(this.group, this.backReference, this.singleCharExpression),
|
|
21
|
+
G.possibly(G.anyOf(this.starQuantifier, this.plusQuantifier, this.exactCountQuantifier, this.countRangeQuantifier)),
|
|
22
|
+
G.possibly(this.nongreedyQuantifier), // Nongreedy quantifier
|
|
23
|
+
];
|
|
24
|
+
exactCountQuantifier = () => G.pattern([
|
|
25
|
+
'{',
|
|
26
|
+
R.captureAs('count', R.oneOrMore(digit)),
|
|
27
|
+
'}',
|
|
28
|
+
]);
|
|
29
|
+
countRangeQuantifier = () => G.pattern([
|
|
30
|
+
'{',
|
|
31
|
+
R.captureAs('start', R.oneOrMore(digit)),
|
|
32
|
+
',',
|
|
33
|
+
R.possibly(R.captureAs('end', R.oneOrMore(digit))),
|
|
34
|
+
'}',
|
|
35
|
+
]);
|
|
36
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
37
|
+
// Group expressions
|
|
38
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
39
|
+
group = () => G.anyOf(this.uncapturedGroup, this.namedCaptureGroup, this.unnamedCaptureGroup);
|
|
40
|
+
uncapturedGroup = () => [
|
|
41
|
+
'(:',
|
|
42
|
+
this.disjunction,
|
|
43
|
+
')',
|
|
44
|
+
];
|
|
45
|
+
namedCaptureGroup = () => [
|
|
46
|
+
'(?<',
|
|
47
|
+
G.pattern(R.captureAs('name', R.oneOrMore(letter))),
|
|
48
|
+
'>',
|
|
49
|
+
this.disjunction,
|
|
50
|
+
')',
|
|
51
|
+
];
|
|
52
|
+
unnamedCaptureGroup = () => [
|
|
53
|
+
'(',
|
|
54
|
+
this.disjunction,
|
|
55
|
+
')',
|
|
56
|
+
];
|
|
57
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
58
|
+
// Backreferences
|
|
59
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
60
|
+
unnamedBackreference = () => G.pattern([
|
|
61
|
+
'\\',
|
|
62
|
+
R.captureAs('index', digit),
|
|
63
|
+
]);
|
|
64
|
+
namedBackreference = () => G.pattern([
|
|
65
|
+
'\\k<',
|
|
66
|
+
R.captureAs('name', digit),
|
|
67
|
+
'>',
|
|
68
|
+
]);
|
|
69
|
+
backReference = G.anyOf(this.unnamedBackreference, this.namedBackreference);
|
|
70
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
71
|
+
// Lookahead and lookbehind expressions
|
|
72
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
73
|
+
positiveLookahead = () => [
|
|
74
|
+
'(?=',
|
|
75
|
+
this.disjunction,
|
|
76
|
+
')',
|
|
77
|
+
];
|
|
78
|
+
negativeLookahead = () => [
|
|
79
|
+
'(?!',
|
|
80
|
+
this.disjunction,
|
|
81
|
+
')',
|
|
82
|
+
];
|
|
83
|
+
positiveLookbehind = () => [
|
|
84
|
+
'(?<=',
|
|
85
|
+
this.disjunction,
|
|
86
|
+
')',
|
|
87
|
+
];
|
|
88
|
+
negativeLookbehind = () => [
|
|
89
|
+
'(?<!',
|
|
90
|
+
this.disjunction,
|
|
91
|
+
')',
|
|
92
|
+
];
|
|
93
|
+
lookaround = G.anyOf(this.positiveLookahead, this.negativeLookahead, this.positiveLookbehind, this.negativeLookbehind);
|
|
94
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
95
|
+
// Single character expressions
|
|
96
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
97
|
+
singleCharExpression = () => G.anyOf(this.anyCharWildcard, this.charClass, this.unicodeProperty, this.notUnicodeProperty, this.charcodeOrEscapedChar, this.unreservedCharLiteral);
|
|
98
|
+
unreservedCharLiteral = () => G.pattern(R.notAnyOfChars('[', '.', '*', '+', '?', '^', '$', '{', '}', '(', ')', '|', ']', '\\'));
|
|
99
|
+
escapedCharLiteral = () => G.pattern([
|
|
100
|
+
'\\',
|
|
101
|
+
R.anyChar
|
|
102
|
+
]);
|
|
103
|
+
hexCharcode = () => G.pattern([
|
|
104
|
+
'\\x',
|
|
105
|
+
hexDigit,
|
|
106
|
+
hexDigit
|
|
107
|
+
]);
|
|
108
|
+
controlCharcode = () => G.pattern([
|
|
109
|
+
'\\c',
|
|
110
|
+
R.charRange('A', 'Z'),
|
|
111
|
+
]);
|
|
112
|
+
codepoint = () => G.pattern([
|
|
113
|
+
'\\u',
|
|
114
|
+
'{',
|
|
115
|
+
R.captureAs('value', R.oneOrMore(hexDigit)),
|
|
116
|
+
'}',
|
|
117
|
+
]);
|
|
118
|
+
codepointRange = () => G.pattern([
|
|
119
|
+
'\\u',
|
|
120
|
+
'{',
|
|
121
|
+
R.captureAs('start', R.oneOrMore(hexDigit)),
|
|
122
|
+
'-',
|
|
123
|
+
R.captureAs('end', R.oneOrMore(hexDigit)),
|
|
124
|
+
'}',
|
|
125
|
+
]);
|
|
126
|
+
unicodeProperty = () => G.pattern([
|
|
127
|
+
'\\p',
|
|
128
|
+
this.unicodePropertyBodyPattern,
|
|
129
|
+
]);
|
|
130
|
+
notUnicodeProperty = () => G.pattern([
|
|
131
|
+
'\\P',
|
|
132
|
+
this.unicodePropertyBodyPattern,
|
|
133
|
+
]);
|
|
134
|
+
unicodePropertyBodyPattern = [
|
|
135
|
+
'{',
|
|
136
|
+
R.captureAs('property', R.oneOrMore(letterOrDigit)),
|
|
137
|
+
R.possibly([
|
|
138
|
+
'=',
|
|
139
|
+
R.captureAs('value', R.oneOrMore(letterOrDigit)),
|
|
140
|
+
]),
|
|
141
|
+
'}',
|
|
142
|
+
];
|
|
143
|
+
charClassChar = () => G.pattern(R.notAnyOfChars(']'));
|
|
144
|
+
charClass = () => [
|
|
145
|
+
'[',
|
|
146
|
+
G.possibly(this.charClassNegator),
|
|
147
|
+
G.oneOrMore(G.anyOf(this.charRange, this.codepointRange, this.charClass, this.unicodeProperty, this.notUnicodeProperty, this.charcodeOrEscapedChar, this.charClassChar)),
|
|
148
|
+
']',
|
|
149
|
+
];
|
|
150
|
+
charcodeOrEscapedChar = G.anyOf(this.codepoint, this.hexCharcode, this.controlCharcode, this.escapedCharLiteral);
|
|
151
|
+
charRangeElement = G.anyOf(this.charcodeOrEscapedChar, G.pattern(R.anyChar));
|
|
152
|
+
charRange = () => [
|
|
153
|
+
this.charRangeElement,
|
|
154
|
+
'-',
|
|
155
|
+
this.charRangeElement,
|
|
156
|
+
];
|
|
157
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
158
|
+
// Special symbols
|
|
159
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
160
|
+
starQuantifier = () => '*';
|
|
161
|
+
plusQuantifier = () => '+';
|
|
162
|
+
nongreedyQuantifier = () => '?';
|
|
163
|
+
charClassNegator = () => '^';
|
|
164
|
+
inputStartAnchor = () => '^';
|
|
165
|
+
inputEndAnchor = () => '$';
|
|
166
|
+
anyCharWildcard = () => '.';
|
|
167
|
+
disjunctionSeparator = () => '|';
|
|
168
|
+
anchor = G.anyOf(this.inputStartAnchor, this.inputEndAnchor);
|
|
169
|
+
escapedCharacterClass = () => G.pattern(R.anyOf(R.captureAs('whitespace', escapedCharString.whitespace), R.captureAs('nonWhitespace', escapedCharString.nonWhitespace), R.captureAs('digit', escapedCharString.digit), R.captureAs('nonDigit', escapedCharString.nonDigit), R.captureAs('wordBoundary', escapedCharString.wordBoundary), R.captureAs('nonWordBoundary', escapedCharString.nonWordBoundary), R.captureAs('formFeed', escapedCharString.formFeed), R.captureAs('carriageReturn', escapedCharString.carriageReturn), R.captureAs('lineFeed', escapedCharString.lineFeed), R.captureAs('tab', escapedCharString.tab), R.captureAs('verticalTab', escapedCharString.verticalTab), R.captureAs('backwardSlash', escapedCharString.backwardSlash)));
|
|
170
|
+
}
|
|
171
|
+
const digit = R.charRange('0', '9');
|
|
172
|
+
const letter = R.anyOf(R.charRange('a', 'z'), R.charRange('A', 'Z'));
|
|
173
|
+
const letterOrDigit = R.anyOf(letter, digit);
|
|
174
|
+
const hexDigit = R.anyOf(digit, R.charRange('a', 'f'), R.charRange('A', 'F'));
|
|
175
|
+
const escapedCharString = {
|
|
176
|
+
whitespace: '\\s',
|
|
177
|
+
nonWhitespace: '\\S',
|
|
178
|
+
digit: '\\d',
|
|
179
|
+
nonDigit: '\\D',
|
|
180
|
+
word: '\\d',
|
|
181
|
+
nonWord: '\\D',
|
|
182
|
+
wordBoundary: '\\b',
|
|
183
|
+
nonWordBoundary: '\\B',
|
|
184
|
+
formFeed: '\\f',
|
|
185
|
+
carriageReturn: '\\r',
|
|
186
|
+
lineFeed: '\\n',
|
|
187
|
+
tab: '\\t',
|
|
188
|
+
verticalTab: '\\v',
|
|
189
|
+
backwardSlash: '\\\\'
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=RegExpGrammar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RegExpGrammar.js","sourceRoot":"","sources":["../../src/test-grammars/RegExpGrammar.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grammar-composer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Defines and generates parsers from composable grammar definitions. Includes advanced features like lexer-free parsing, selective packrat memoization and static analysis.",
|
|
5
5
|
"author": "Rotem Dan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"test": "node dist/Test.js"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"regexp-composer": "^0.2.
|
|
35
|
+
"regexp-composer": "^0.2.2"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^22.10.1"
|
package/src/GrammarComposer.ts
CHANGED
|
@@ -38,7 +38,11 @@ export function buildGrammar<T extends { [key: string]: any }>(obj: T | (new ()
|
|
|
38
38
|
const uniqueIdSource = () => uniqueIdCounter++
|
|
39
39
|
|
|
40
40
|
for (const [func, nonterminal] of nonterminalLookup) {
|
|
41
|
-
const preparedContent = prepareGrammarElement(
|
|
41
|
+
const preparedContent = prepareGrammarElement(
|
|
42
|
+
nonterminal.content,
|
|
43
|
+
nonterminalLookup,
|
|
44
|
+
optionalNonterminalLookup,
|
|
45
|
+
uniqueIdSource)
|
|
42
46
|
|
|
43
47
|
nonterminal.content = preparedContent
|
|
44
48
|
|
|
@@ -46,7 +50,7 @@ export function buildGrammar<T extends { [key: string]: any }>(obj: T | (new ()
|
|
|
46
50
|
optionalNonterminal.content = preparedContent
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
const startNonterminal = nonterminalLookup.get(obj[startProductionName] as Function)
|
|
50
54
|
|
|
51
55
|
if (!startNonterminal) {
|
|
52
56
|
throw new Error(`Couldn't find a start production named '${startProductionName as string}'.`)
|
|
@@ -61,16 +65,15 @@ export function buildGrammar<T extends { [key: string]: any }>(obj: T | (new ()
|
|
|
61
65
|
nonterminals[nameLookup.get(key)!] = nonterminal
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
return new Grammar(
|
|
68
|
+
return new Grammar<T>(
|
|
65
69
|
nonterminals[startProductionName],
|
|
66
70
|
nonterminals,
|
|
67
71
|
uniqueIdCounter
|
|
68
|
-
)
|
|
72
|
+
)
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
function prepareGrammarElement(
|
|
72
76
|
rootElement: GrammarElement,
|
|
73
|
-
nameLookup: Map<any, string>,
|
|
74
77
|
nonterminalLookup: Map<Function, Nonterminal>,
|
|
75
78
|
optionalNonterminalLookup: Map<Function, Nonterminal>,
|
|
76
79
|
getUniqueId: () => number
|
|
@@ -89,7 +92,6 @@ function prepareGrammarElement(
|
|
|
89
92
|
case 'PatternTerminal': {
|
|
90
93
|
return {
|
|
91
94
|
...element,
|
|
92
|
-
name: nameLookup.get(element) ?? '',
|
|
93
95
|
uniqueId: getUniqueId()
|
|
94
96
|
}
|
|
95
97
|
}
|
|
@@ -399,7 +401,6 @@ export function pattern(pattern: Pattern): PatternTerminal {
|
|
|
399
401
|
|
|
400
402
|
return {
|
|
401
403
|
type: 'PatternTerminal',
|
|
402
|
-
name: '[Pattern]',
|
|
403
404
|
pattern,
|
|
404
405
|
regExp,
|
|
405
406
|
optional,
|
|
@@ -518,8 +519,7 @@ export interface StringTerminal extends GrammarElementBase {
|
|
|
518
519
|
|
|
519
520
|
export interface PatternTerminal extends GrammarElementBase {
|
|
520
521
|
type: 'PatternTerminal'
|
|
521
|
-
|
|
522
|
-
pattern: Pattern | Pattern[]
|
|
522
|
+
pattern: Pattern
|
|
523
523
|
regExp: RegExp
|
|
524
524
|
}
|
|
525
525
|
|
package/src/Test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Timer } from "./utilities/Timer.js"
|
|
2
|
-
import { jsonSample2 } from "./test-data/TestData.js"
|
|
2
|
+
import { jsonSample1, jsonSample2 } from "./test-data/TestData.js"
|
|
3
3
|
import { anyOf, buildGrammar } from "./GrammarComposer.js"
|
|
4
4
|
import { JsonGrammar } from "./test-grammars/JsonGrammar.js"
|
|
5
5
|
import { XmlGrammar } from "./test-grammars/XmlGrammar.js"
|
|
6
|
+
import { RegExpGrammar } from "./test-grammars/RegExpGrammar.js"
|
|
6
7
|
|
|
7
8
|
const log = console.log
|
|
8
9
|
|
|
@@ -24,26 +25,29 @@ function testBasic() {
|
|
|
24
25
|
console.log(JSON.stringify(result, undefined, 4))
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
28
|
function testJsonParser() {
|
|
29
|
-
const jsonString =
|
|
29
|
+
const jsonString = jsonSample1
|
|
30
30
|
|
|
31
31
|
const grammar = buildGrammar(JsonGrammar, 'expression')
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const iterations = 1000
|
|
34
|
+
|
|
35
|
+
let result1: any
|
|
36
|
+
let result2: any
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
timer.logAndRestart('JSON.Parse')
|
|
38
|
+
const timer = new Timer()
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
for (let i = 0; i < iterations; i++) {
|
|
41
|
+
result1 = grammar.parse(jsonString)
|
|
42
42
|
}
|
|
43
|
+
timer.logAndRestart('grammar.Parse')
|
|
43
44
|
|
|
44
|
-
for (let i = 0; i <
|
|
45
|
-
|
|
45
|
+
for (let i = 0; i < iterations; i++) {
|
|
46
|
+
result2 = JSON.parse(jsonString)
|
|
46
47
|
}
|
|
48
|
+
timer.logAndRestart('JSON.Parse')
|
|
49
|
+
|
|
50
|
+
log(JSON.stringify(result1, undefined, 4))
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
function testXmlParser() {
|
|
@@ -77,6 +81,23 @@ function testXmlParser() {
|
|
|
77
81
|
log(JSON.stringify(parseTree, undefined, 4))
|
|
78
82
|
}
|
|
79
83
|
|
|
84
|
+
async function testRegExpParser() {
|
|
85
|
+
//const regExpString = /^([+]?[1]?(1 )?[-.+]?\(?\d{1}[- .+]*\d{1}[- .+]*\d{1}\)?[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1})$/.source
|
|
86
|
+
const regExpString = /^asdf{$/.source
|
|
87
|
+
|
|
88
|
+
const grammar = buildGrammar(RegExpGrammar, 'disjunction')
|
|
89
|
+
|
|
90
|
+
const parseTree = grammar.parse(regExpString)
|
|
91
|
+
|
|
92
|
+
const parseTreeJson = JSON.stringify(parseTree, undefined, 4)
|
|
93
|
+
|
|
94
|
+
log(parseTreeJson)
|
|
95
|
+
|
|
96
|
+
const { writeFile } = await import('fs/promises')
|
|
97
|
+
|
|
98
|
+
await writeFile('out/out.json', parseTreeJson)
|
|
99
|
+
}
|
|
100
|
+
|
|
80
101
|
|
|
81
102
|
async function testParserError1() {
|
|
82
103
|
const xmlData = `<hello> wo rld <!!! `
|
|
@@ -98,4 +119,6 @@ async function testParserError2() {
|
|
|
98
119
|
console.log(JSON.stringify(result, undefined, 4))
|
|
99
120
|
}
|
|
100
121
|
|
|
101
|
-
|
|
122
|
+
//testJsonParser()
|
|
123
|
+
|
|
124
|
+
testRegExpParser()
|
package/src/TopDownParser.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { Grammar, GrammarElement, Terminal } from "./GrammarComposer.js"
|
|
|
2
2
|
|
|
3
3
|
export function parse(inputString: string, grammar: Grammar<any>) {
|
|
4
4
|
const inputLength = inputString.length
|
|
5
|
-
const maxElementId = grammar.maxElementId
|
|
6
5
|
|
|
7
6
|
let bestFailedMatches: Terminal[] = []
|
|
8
7
|
let bestFailedMatchesOffset = -1
|
|
@@ -134,13 +133,7 @@ export function parse(inputString: string, grammar: Grammar<any>) {
|
|
|
134
133
|
})
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
nodes =
|
|
138
|
-
name: grammarElement.name,
|
|
139
|
-
startOffset: matchStartOffset,
|
|
140
|
-
endOffset: matchEndOffset,
|
|
141
|
-
sourceText: inputString.substring(matchStartOffset, matchEndOffset),
|
|
142
|
-
children
|
|
143
|
-
}]
|
|
136
|
+
nodes = children
|
|
144
137
|
}
|
|
145
138
|
|
|
146
139
|
const parseResult: ParseResult = {
|
|
@@ -268,8 +261,10 @@ export function parse(inputString: string, grammar: Grammar<any>) {
|
|
|
268
261
|
const possibleMatches = bestFailedMatches.map(match => {
|
|
269
262
|
if (match.type === 'StringTerminal') {
|
|
270
263
|
return `'${match.content}'`
|
|
264
|
+
} else if (match.type === 'PatternTerminal') {
|
|
265
|
+
return `/${match.regExp.source}/`
|
|
271
266
|
} else {
|
|
272
|
-
|
|
267
|
+
throw new Error(`Invalid match type: '${(match as any).type}'`)
|
|
273
268
|
}
|
|
274
269
|
})
|
|
275
270
|
|
|
@@ -11,58 +11,18 @@ export class JsonGrammar {
|
|
|
11
11
|
this.arrayExpression
|
|
12
12
|
)
|
|
13
13
|
|
|
14
|
-
objectExpression = () => [
|
|
15
|
-
this.openingCurlyBrace,
|
|
16
|
-
|
|
17
|
-
G.possibly([
|
|
18
|
-
this.objectPropertyExpression,
|
|
19
|
-
G.zeroOrMore([this.comma, this.objectPropertyExpression])
|
|
20
|
-
]),
|
|
21
|
-
|
|
22
|
-
this.closingCurlyBrace,
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
objectPropertyExpression = () => [
|
|
26
|
-
this.stringLiteral,
|
|
27
|
-
this.colons,
|
|
28
|
-
this.expression,
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
arrayExpression = () => [
|
|
32
|
-
this.openingSquareBracket,
|
|
33
|
-
|
|
34
|
-
G.possibly([
|
|
35
|
-
this.expression,
|
|
36
|
-
G.zeroOrMore([this.comma, this.expression])
|
|
37
|
-
]),
|
|
38
|
-
|
|
39
|
-
this.closingSquareBracket
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
openingCurlyBrace = createPatternWithClearedWhitespace('{')
|
|
43
|
-
closingCurlyBrace = createPatternWithClearedWhitespace('}')
|
|
44
|
-
|
|
45
|
-
openingSquareBracket = createPatternWithClearedWhitespace('[')
|
|
46
|
-
closingSquareBracket = createPatternWithClearedWhitespace(']')
|
|
47
|
-
|
|
48
|
-
comma = createPatternWithClearedWhitespace(',')
|
|
49
|
-
colons = createPatternWithClearedWhitespace(':')
|
|
50
|
-
|
|
51
14
|
stringLiteral = G.pattern([
|
|
52
15
|
zeroOrMoreWhitespace,
|
|
53
16
|
|
|
54
17
|
'"',
|
|
55
18
|
|
|
56
|
-
R.
|
|
57
|
-
R.
|
|
58
|
-
R.zeroOrMoreNonGreedy(R.anyChar)
|
|
59
|
-
),
|
|
60
|
-
{
|
|
61
|
-
ifNotPrecededBy: '\\'
|
|
62
|
-
}
|
|
19
|
+
R.captureAs('value',
|
|
20
|
+
R.zeroOrMoreNonGreedy(R.anyChar)
|
|
63
21
|
),
|
|
64
22
|
|
|
65
|
-
'"',
|
|
23
|
+
R.matches('"', {
|
|
24
|
+
ifNotPrecededBy: '\\'
|
|
25
|
+
}),
|
|
66
26
|
|
|
67
27
|
zeroOrMoreWhitespace,
|
|
68
28
|
])
|
|
@@ -103,13 +63,50 @@ export class JsonGrammar {
|
|
|
103
63
|
|
|
104
64
|
zeroOrMoreWhitespace,
|
|
105
65
|
])
|
|
66
|
+
|
|
67
|
+
objectExpression = () => [
|
|
68
|
+
this.openingCurlyBrace,
|
|
69
|
+
|
|
70
|
+
G.possibly([
|
|
71
|
+
this.objectPropertyExpression,
|
|
72
|
+
G.zeroOrMore([this.comma, this.objectPropertyExpression])
|
|
73
|
+
]),
|
|
74
|
+
|
|
75
|
+
this.closingCurlyBrace,
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
objectPropertyExpression = () => [
|
|
79
|
+
this.stringLiteral,
|
|
80
|
+
this.colons,
|
|
81
|
+
this.expression,
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
arrayExpression = () => [
|
|
85
|
+
this.openingSquareBracket,
|
|
86
|
+
|
|
87
|
+
G.possibly([
|
|
88
|
+
this.expression,
|
|
89
|
+
G.zeroOrMore([this.comma, this.expression])
|
|
90
|
+
]),
|
|
91
|
+
|
|
92
|
+
this.closingSquareBracket
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
openingCurlyBrace = createPatternWithClearedWhitespace('{')
|
|
96
|
+
closingCurlyBrace = createPatternWithClearedWhitespace('}')
|
|
97
|
+
|
|
98
|
+
openingSquareBracket = createPatternWithClearedWhitespace('[')
|
|
99
|
+
closingSquareBracket = createPatternWithClearedWhitespace(']')
|
|
100
|
+
|
|
101
|
+
comma = createPatternWithClearedWhitespace(',')
|
|
102
|
+
colons = createPatternWithClearedWhitespace(':')
|
|
106
103
|
}
|
|
107
104
|
|
|
108
|
-
function createPatternWithClearedWhitespace(
|
|
105
|
+
function createPatternWithClearedWhitespace(subpattern: R.Pattern) {
|
|
109
106
|
return G.pattern([
|
|
110
107
|
zeroOrMoreWhitespace,
|
|
111
108
|
|
|
112
|
-
|
|
109
|
+
subpattern,
|
|
113
110
|
|
|
114
111
|
zeroOrMoreWhitespace
|
|
115
112
|
])
|