links-notation 0.21.2 → 0.21.3
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/dist/index.js +295 -118
- package/package.json +1 -1
- package/src/grammar.pegjs +46 -3
- package/src/parser-generated.js +297 -113
- package/tests/NestingDepth.test.js +124 -0
- package/tests/support/nestingDepthWorker.js +15 -0
package/package.json
CHANGED
package/src/grammar.pegjs
CHANGED
|
@@ -9,14 +9,27 @@
|
|
|
9
9
|
// group opens a nested context that starts fresh at indentation level zero,
|
|
10
10
|
// so line breaks and indentation mean the same thing at every depth.
|
|
11
11
|
let contextStack = [];
|
|
12
|
+
// Lines already found unreadable, keyed by where they start and whether they
|
|
13
|
+
// are inside a parenthesised group. Reading a line depends on nothing else: a
|
|
14
|
+
// group starts a fresh indentation context, and indentation only decides
|
|
15
|
+
// which lines become children, so a line that could not be read once never
|
|
16
|
+
// can be. A line that does not parse as the first child of the line above it
|
|
17
|
+
// is tried again as a sibling at every enclosing indentation level, and
|
|
18
|
+
// without this each of those attempts would read the whole line again.
|
|
19
|
+
let unreadableLines = new Set();
|
|
12
20
|
|
|
13
21
|
function resetState() {
|
|
14
22
|
indentationStack = [0];
|
|
15
23
|
baseIndentation = null;
|
|
16
24
|
contextStack = [];
|
|
25
|
+
unreadableLines = new Set();
|
|
17
26
|
return true;
|
|
18
27
|
}
|
|
19
28
|
|
|
29
|
+
function lineKey(position) {
|
|
30
|
+
return contextStack.length > 0 ? -1 - position : position;
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
function enterNestedContext() {
|
|
21
34
|
contextStack.push({ indentationStack, baseIndentation });
|
|
22
35
|
indentationStack = [0];
|
|
@@ -100,14 +113,39 @@ firstLine = SET_BASE_INDENTATION l:element { return l; }
|
|
|
100
113
|
|
|
101
114
|
line = CHECK_INDENTATION l:element { return l; }
|
|
102
115
|
|
|
103
|
-
|
|
116
|
+
// A line is read once, whether or not indented children follow it: reading it
|
|
117
|
+
// again after looking for children doubled the work at every level of nesting.
|
|
118
|
+
element = &{ return !unreadableLines.has(lineKey(offset())); }
|
|
119
|
+
e:anyLink saved:SAVE_INDENTATION l:(PUSH_INDENTATION @links)? {
|
|
120
|
+
if (l === null) {
|
|
121
|
+
// No child line followed the indentation. Forget what looking for one
|
|
122
|
+
// pushed, so the next line is compared with this line's indentation.
|
|
123
|
+
indentationStack = saved;
|
|
124
|
+
return e;
|
|
125
|
+
}
|
|
104
126
|
return Object.assign({}, e, { children: l });
|
|
105
127
|
}
|
|
106
|
-
|
|
128
|
+
// Remember that this line could not be read. The predicate always fails, so
|
|
129
|
+
// the "." is never reached; it only tells Peggy that this alternative cannot
|
|
130
|
+
// succeed without consuming input.
|
|
131
|
+
/ &{ unreadableLines.add(lineKey(offset())); return false; } .
|
|
107
132
|
|
|
108
133
|
referenceOrLink = l:multiLineAnyLink { return l; } / i:reference { return { id: i }; }
|
|
109
134
|
|
|
110
|
-
|
|
135
|
+
// A line that starts with a parenthesised group reads that group once and then
|
|
136
|
+
// branches on what follows it: the end of the line makes the group the whole
|
|
137
|
+
// link, and more values make it the first value of a value link. Neither an
|
|
138
|
+
// indented ID nor a single-line link can start with a parenthesis, so nothing
|
|
139
|
+
// else is tried for such a line; trying them read the group again, doubling
|
|
140
|
+
// the work at every level of nesting.
|
|
141
|
+
anyLink = &"(" @groupLink / !"(" @(indentedIdLink / singleLineAnyLink)
|
|
142
|
+
|
|
143
|
+
groupLink = g:multiLineAnyLink rest:groupLinkRest {
|
|
144
|
+
return rest === null ? g : { values: [g].concat(rest) };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
groupLinkRest = eol { return null; }
|
|
148
|
+
/ @singleLineValueAndWhitespace* eol
|
|
111
149
|
|
|
112
150
|
multiLineAnyLink = nestedGroup
|
|
113
151
|
|
|
@@ -121,6 +159,9 @@ nestedGroup = "(" ENTER_NESTED_CONTEXT body:nestedGroupBody {
|
|
|
121
159
|
exitNestedContext();
|
|
122
160
|
return body;
|
|
123
161
|
}
|
|
162
|
+
// The group was opened but its body did not parse: restore the context it
|
|
163
|
+
// was opened in before failing, just as a parsed group does.
|
|
164
|
+
/ "(" &{ exitNestedContext(); return false; }
|
|
124
165
|
|
|
125
166
|
nestedGroupBody = skipEmptyLines l:links _ ")" { return { nested: l }; }
|
|
126
167
|
/ _ ")" { return { nested: [] }; }
|
|
@@ -193,6 +234,8 @@ backtickQuotedUniversal = &'`' &{
|
|
|
193
234
|
consumeBacktick = c:. cs:consumeBacktickMore* { return [c].concat(cs).join(''); }
|
|
194
235
|
consumeBacktickMore = &{ return parsedLength > 1 && (parsedLength--, true); } c:. { return c; }
|
|
195
236
|
|
|
237
|
+
SAVE_INDENTATION = "" { return indentationStack.slice(); }
|
|
238
|
+
|
|
196
239
|
SET_BASE_INDENTATION = spaces:" "* { setBaseIndentation(spaces); }
|
|
197
240
|
|
|
198
241
|
PUSH_INDENTATION = spaces:" "* &{ return normalizeIndentation(spaces) > getCurrentIndentation(); } { pushIndentation(spaces); }
|