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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "links-notation",
3
- "version": "0.21.2",
3
+ "version": "0.21.3",
4
4
  "description": "Links Notation parser for JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "types": "index.d.ts",
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
- element = e:anyLink PUSH_INDENTATION l:links {
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
- / e:anyLink { return e; }
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
- anyLink = ml:multiLineAnyLink eol { return ml; } / il:indentedIdLink { return il; } / sl:singleLineAnyLink { return sl; }
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); }