pyret-npm 0.1.22 → 0.1.23
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 +5 -2
- package/pyret-lang/lib/jglr/cyclicJSON.js +174 -0
- package/pyret-lang/lib/jglr/jglr.js +341 -0
- package/pyret-lang/lib/jglr/rnglr.js +2687 -0
- package/pyret-lang/src/js/base/js-numbers.js +4311 -0
- package/pyret-lang/src/js/base/pyret-tokenizer.js +579 -0
- package/pyret-lang/src/js/base/type-util.js +553 -0
|
@@ -0,0 +1,2687 @@
|
|
|
1
|
+
define("jglr/rnglr", ["jglr/cyclicJSON"], function(cycle) {
|
|
2
|
+
function SrcLoc(startRow, startCol, startChar, endRow, endCol, endChar) {
|
|
3
|
+
this.startRow = startRow;
|
|
4
|
+
this.startCol = startCol;
|
|
5
|
+
this.startChar = startChar;
|
|
6
|
+
this.endRow = endRow;
|
|
7
|
+
this.endCol = endCol;
|
|
8
|
+
this.endChar = endChar;
|
|
9
|
+
}
|
|
10
|
+
SrcLoc.cache = {};
|
|
11
|
+
SrcLoc.reset = function() { SrcLoc.cache = {}; }
|
|
12
|
+
SrcLoc.make = function(startRow, startCol, startChar, endRow, endCol, endChar) {
|
|
13
|
+
var byStartChar = SrcLoc.cache[startChar];
|
|
14
|
+
if (byStartChar === undefined)
|
|
15
|
+
byStartChar = SrcLoc.cache[startChar] = {};
|
|
16
|
+
var byEndChar = byStartChar[endChar];
|
|
17
|
+
if (byEndChar === undefined)
|
|
18
|
+
byEndChar = byStartChar[endChar] = new SrcLoc(startRow, startCol, startChar, endRow, endCol, endChar);
|
|
19
|
+
return byEndChar;
|
|
20
|
+
}
|
|
21
|
+
SrcLoc.prototype.toString = function(show_span) {
|
|
22
|
+
var ret = this.startRow + ":" + this.startCol;
|
|
23
|
+
if (show_span)
|
|
24
|
+
ret += "-" + this.endRow + ":" + this.endCol;
|
|
25
|
+
return ret;
|
|
26
|
+
}
|
|
27
|
+
SrcLoc.prototype.combine = function(that) {
|
|
28
|
+
if (this.startChar < that.startChar) {
|
|
29
|
+
if (this.endChar < that.endChar) {
|
|
30
|
+
return SrcLoc.make(this.startRow, this.startCol, this.startChar, that.endRow, that.endCol, that.endChar);
|
|
31
|
+
} else {
|
|
32
|
+
return SrcLoc.make(this.startRow, this.startCol, this.startChar, this.endRow, this.endCol, this.endChar);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
if (this.endChar < that.endChar) {
|
|
36
|
+
return SrcLoc.make(that.startRow, that.startCol, that.startChar, that.endRow, that.endCol, that.endChar);
|
|
37
|
+
} else {
|
|
38
|
+
return SrcLoc.make(that.startRow, that.startCol, that.startChar, this.endRow, this.endCol, this.endChar);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
SrcLoc.prototype.posAtStart = function() {
|
|
43
|
+
return SrcLoc.make(this.startRow, this.startCol, this.startChar, this.startRow, this.startCol, this.startChar);
|
|
44
|
+
}
|
|
45
|
+
SrcLoc.prototype.posAtEnd = function() {
|
|
46
|
+
return SrcLoc.make(this.endRow, this.endCol, this.endChar, this.endRow, this.endCol, this.endChar);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//////////////////////////////////
|
|
50
|
+
////////// Various Sets //////////
|
|
51
|
+
//////////////////////////////////
|
|
52
|
+
function IntSet(items) {
|
|
53
|
+
this.elements = {};
|
|
54
|
+
this.ordered = [];
|
|
55
|
+
if (items instanceof IntSet) {
|
|
56
|
+
for (var i = 0; i < items.ordered.length; i++)
|
|
57
|
+
this.add(items.ordered[i]);
|
|
58
|
+
} else if (items) {
|
|
59
|
+
for (var i = 0; i < items.length; i++)
|
|
60
|
+
this.add(items[i]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
IntSet.prototype.add = function(item) {
|
|
64
|
+
if (this.elements[item] === undefined) {
|
|
65
|
+
this.elements[item] = item;
|
|
66
|
+
this.ordered.push(item);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
IntSet.prototype.contains = function(item) { return this.elements[item] !== undefined; }
|
|
72
|
+
IntSet.prototype.size = function() { return this.ordered.length; }
|
|
73
|
+
IntSet.prototype.get = function(index) { return this.ordered[index]; }
|
|
74
|
+
IntSet.prototype.toString = function() {
|
|
75
|
+
var items = this.ordered.slice(0);
|
|
76
|
+
items.sort();
|
|
77
|
+
return "{" + JSON.stringify(items) + "}";
|
|
78
|
+
}
|
|
79
|
+
IntSet.prototype.equals = function(that) {
|
|
80
|
+
if (this.size() !== that.size()) return false;
|
|
81
|
+
if (!(that instanceof IntSet)) return false;
|
|
82
|
+
for (var i = 0; i < this.ordered.length; i++)
|
|
83
|
+
if (that.elements[this.ordered[i]] === undefined)
|
|
84
|
+
return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
function KeyedSet(key, items) {
|
|
90
|
+
this.elements = {};
|
|
91
|
+
this.ordered = [];
|
|
92
|
+
this.uniqueId = "KS" + (++KeyedSet.nextSetId);
|
|
93
|
+
this.byKey = key;
|
|
94
|
+
if (key instanceof KeyedSet) {
|
|
95
|
+
items = key;
|
|
96
|
+
this.byKey = items.byKey;
|
|
97
|
+
for (var i = 0; i < items.ordered.length; i++)
|
|
98
|
+
this.add(items.ordered[i]);
|
|
99
|
+
} else if (items) {
|
|
100
|
+
for (var i = 0; i < items.length; i++)
|
|
101
|
+
this.add(items[i]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
KeyedSet.nextSetId = 0;
|
|
105
|
+
KeyedSet.equals = function(thiz, that) { return thiz.equals(that); }
|
|
106
|
+
KeyedSet.prototype.add = function(item) {
|
|
107
|
+
var key = item[this.byKey];
|
|
108
|
+
if (this.elements[key] === undefined) {
|
|
109
|
+
this.elements[key] = item;
|
|
110
|
+
this.ordered.push(item);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
KeyedSet.prototype.size = function() { return this.ordered.length; }
|
|
116
|
+
KeyedSet.prototype.contains = function(item) { return this.elements[item[this.byKey]] !== undefined; }
|
|
117
|
+
KeyedSet.prototype.equals = function(that) {
|
|
118
|
+
if (this.size() !== that.size()) return false;
|
|
119
|
+
if (this.byKey !== that.byKey) return false;
|
|
120
|
+
for (var i = 0; i < this.ordered.length; i++)
|
|
121
|
+
if (that.elements[this.ordered[i][this.byKey]] === undefined)
|
|
122
|
+
return false;
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
KeyedSet.prototype.get = function(index) { return this.ordered[index]; }
|
|
126
|
+
KeyedSet.prototype.itemForKey = function(key) { return this.elements[key]; }
|
|
127
|
+
KeyedSet.prototype.merge = function(that) {
|
|
128
|
+
var ret = false;
|
|
129
|
+
for (var i = 0; i < that.ordered.length; i++)
|
|
130
|
+
ret = this.add(that.ordered[i]) || ret;
|
|
131
|
+
return ret;
|
|
132
|
+
}
|
|
133
|
+
KeyedSet.prototype.toString = function() {
|
|
134
|
+
var keys = [];
|
|
135
|
+
for (var i = 0; i < this.ordered.length; i++)
|
|
136
|
+
keys.push(this.ordered[i][this.byKey]);
|
|
137
|
+
keys.sort();
|
|
138
|
+
var s = "";
|
|
139
|
+
for (var i = 0; i < keys.length; i++) {
|
|
140
|
+
if (s !== "") s += ", ";
|
|
141
|
+
var elt = this.elements[keys[i]];
|
|
142
|
+
s += elt.asString ? elt.asString : elt.toString();
|
|
143
|
+
}
|
|
144
|
+
return "{" + s + "}";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function LR1Set(rules) {
|
|
148
|
+
this.uniqueId = "LR" + ++LR1Set.nextId;
|
|
149
|
+
this.ruleIdx = {}; // maps rules-as-strings to indices in coreRules
|
|
150
|
+
this.coreRules = []; // array of core rules
|
|
151
|
+
this.core = []; // maps indices to sets of lookahead tokens
|
|
152
|
+
this.noLook = []; // true iff we have an LR0 item in this set
|
|
153
|
+
if (rules instanceof KeyedSet) {
|
|
154
|
+
for (var i = 0; i < rules.size(); i++)
|
|
155
|
+
this.addRule(rules.get(i));
|
|
156
|
+
} else if (rules instanceof Array) {
|
|
157
|
+
for (var i = 0; i < rules.length; i++)
|
|
158
|
+
this.addRule(rules[i]);
|
|
159
|
+
} else if (rules instanceof LR1Set) {
|
|
160
|
+
this.coreRules = rules.coreRules.slice(0);
|
|
161
|
+
this.noLook = rules.noLook.slice(0);
|
|
162
|
+
for (var r in rules.ruleIdx)
|
|
163
|
+
this.ruleIdx[r] = rules.ruleIdx[r];
|
|
164
|
+
for (var i = 0; i < rules.core.length; i++)
|
|
165
|
+
this.core[i] = new KeyedSet(rules.core[i]);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
LR1Set.nextId = 0;
|
|
169
|
+
LR1Set.prototype.exhaustive = function() {
|
|
170
|
+
var ret = [];
|
|
171
|
+
for (var i = 0; i < this.coreRules.length; i++) {
|
|
172
|
+
if (this.noLook[i])
|
|
173
|
+
ret.push(this.coreRules[i]);
|
|
174
|
+
for (var j = 0; j < this.core[i].size(); j++) {
|
|
175
|
+
ret.push(this.coreRules[i].withLookahead(this.core[i].get(j)));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return ret;
|
|
179
|
+
}
|
|
180
|
+
LR1Set.prototype.coreSize = function() { return this.coreRules.length; }
|
|
181
|
+
LR1Set.prototype.getCore = function(i) { return this.coreRules[i]; }
|
|
182
|
+
LR1Set.prototype.getLookaheads = function(i) { return this.core[i]; }
|
|
183
|
+
LR1Set.prototype.addRule = function(rule) {
|
|
184
|
+
var ret = false;
|
|
185
|
+
var noLookahead = rule.withLookahead(undefined);
|
|
186
|
+
ruleKey = noLookahead.toString();
|
|
187
|
+
var idx = this.ruleIdx[ruleKey];
|
|
188
|
+
if (idx === undefined) {
|
|
189
|
+
ret = true;
|
|
190
|
+
idx = this.ruleIdx[ruleKey] = this.coreRules.push(noLookahead) - 1;
|
|
191
|
+
}
|
|
192
|
+
if (rule.lookahead === undefined) {
|
|
193
|
+
ret = ret || !this.noLook[idx];
|
|
194
|
+
this.noLook[idx] = true;
|
|
195
|
+
} else {
|
|
196
|
+
if (this.core[idx] === undefined)
|
|
197
|
+
this.core[idx] = new KeyedSet("key");
|
|
198
|
+
ret = this.core[idx].add(rule.lookahead) || ret;
|
|
199
|
+
}
|
|
200
|
+
return ret; // Return true if something's been added
|
|
201
|
+
}
|
|
202
|
+
LR1Set.prototype.addRuleWithLookaheads = function(rule, lookaheads) {
|
|
203
|
+
var noLookahead = rule.withLookahead(undefined);
|
|
204
|
+
ruleKey = noLookahead.toString();
|
|
205
|
+
var idx = this.ruleIdx[ruleKey];
|
|
206
|
+
if (idx === undefined) {
|
|
207
|
+
idx = this.ruleIdx[ruleKey] = this.coreRules.push(noLookahead) - 1;
|
|
208
|
+
}
|
|
209
|
+
if (lookaheads.size() === 0) {
|
|
210
|
+
this.noLook[idx] = true;
|
|
211
|
+
} else {
|
|
212
|
+
if (this.core[idx] === undefined)
|
|
213
|
+
this.core[idx] = new KeyedSet("key");
|
|
214
|
+
this.core[idx].merge(lookaheads);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
LR1Set.prototype.toString = function(multiLine) {
|
|
218
|
+
var s = "";
|
|
219
|
+
var sep = (multiLine ? "\n" : ", ");
|
|
220
|
+
var leader = (multiLine ? " " : "");
|
|
221
|
+
for (var i = 0; i < this.coreRules.length; i++) {
|
|
222
|
+
if (this.noLook[i]) {
|
|
223
|
+
if (s !== "") s += sep;
|
|
224
|
+
s += leader + this.coreRules[i].toString();
|
|
225
|
+
}
|
|
226
|
+
if (this.core[i] !== undefined) {
|
|
227
|
+
if (s !== "") s += sep;
|
|
228
|
+
s += leader + "[" + this.coreRules[i].toString() + ", " + this.core[i].toString() + "]";
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return "{" + (multiLine ? "\n" : "") + s + "}";
|
|
232
|
+
}
|
|
233
|
+
LR1Set.equals = function(thiz, that) { return thiz.equalsCore(that); }
|
|
234
|
+
LR1Set.prototype.equalsCore = function(that) {
|
|
235
|
+
ret = true
|
|
236
|
+
if (this.core.length !== that.core.length) ret = false;
|
|
237
|
+
for (var r in this.ruleIdx)
|
|
238
|
+
if (that.ruleIdx[r] === undefined) ret = false;
|
|
239
|
+
return ret;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
function SetOfSets(items, comparison) {
|
|
244
|
+
this.ordered = [];
|
|
245
|
+
this.comparison = comparison
|
|
246
|
+
if (items instanceof SetOfSets) {
|
|
247
|
+
if (!this.comparison)
|
|
248
|
+
this.comparison = items.comparison;
|
|
249
|
+
for (var i = 0; i < items.ordered.length; i++)
|
|
250
|
+
this.add(items.ordered[i]);
|
|
251
|
+
} else if (items) {
|
|
252
|
+
for (var i = 0; i < items.length; i++)
|
|
253
|
+
this.add(items[i]);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
SetOfSets.prototype.toString = function(sep_lines, sorted) {
|
|
257
|
+
var s = "";
|
|
258
|
+
var items_strs = []
|
|
259
|
+
for (var i = 0; i < this.ordered.length; i++)
|
|
260
|
+
items_strs[i] = this.ordered[i].toString();
|
|
261
|
+
if (sorted)
|
|
262
|
+
items_strs.sort();
|
|
263
|
+
for (var i = 0; i < items_strs.length; i++) {
|
|
264
|
+
if (s == "")
|
|
265
|
+
s += "{" + items_strs[i]
|
|
266
|
+
else
|
|
267
|
+
s += (sep_lines ? ",\n " : ", ") + items_strs[i];
|
|
268
|
+
}
|
|
269
|
+
if (s == "")
|
|
270
|
+
return "{}";
|
|
271
|
+
return s + "}";
|
|
272
|
+
}
|
|
273
|
+
SetOfSets.prototype.add = function(item) {
|
|
274
|
+
var key = item.toString();
|
|
275
|
+
if (this.indexOf(item) === -1) {
|
|
276
|
+
this.ordered.push(item);
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
SetOfSets.prototype.indexOf = function(item) {
|
|
282
|
+
return this.indexOfHelp(this.ordered, item);
|
|
283
|
+
}
|
|
284
|
+
SetOfSets.prototype.indexOfHelp = function(items, item) {
|
|
285
|
+
for (var i = 0; i < items.length; i++) {
|
|
286
|
+
if ((this.comparison && this.comparison(items[i], item)) ||
|
|
287
|
+
((!this.comparison) && (items[i] == item))) {
|
|
288
|
+
return i;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return -1;
|
|
292
|
+
}
|
|
293
|
+
SetOfSets.prototype.size = function() { return this.ordered.length; }
|
|
294
|
+
SetOfSets.prototype.get = function(index) { return this.ordered[index]; }
|
|
295
|
+
|
|
296
|
+
//////////////////////////////////
|
|
297
|
+
///////////// Queues /////////////
|
|
298
|
+
//////////////////////////////////
|
|
299
|
+
|
|
300
|
+
function Queue(items) {
|
|
301
|
+
this.items = items.slice(0);
|
|
302
|
+
this.start = 0;
|
|
303
|
+
this.end = items.length;
|
|
304
|
+
this.length = items.length;
|
|
305
|
+
}
|
|
306
|
+
Queue.prototype.push = function(item) {
|
|
307
|
+
this.items[this.end] = item;
|
|
308
|
+
this.end++;
|
|
309
|
+
this.length++;
|
|
310
|
+
}
|
|
311
|
+
Queue.prototype.shift = function() {
|
|
312
|
+
if (this.length === 0) return undefined;
|
|
313
|
+
var ret = this.items[this.start];
|
|
314
|
+
this.start++;
|
|
315
|
+
this.length--;
|
|
316
|
+
return ret;
|
|
317
|
+
}
|
|
318
|
+
Queue.prototype.get = function(idx) {
|
|
319
|
+
if (this.start + idx < this.end) return this.items[this.start + idx];
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
Queue.prototype.insertAt = function(idx, item) {
|
|
323
|
+
if (this.start + idx < this.end) {
|
|
324
|
+
this.items.splice(this.start + idx, 0, item);
|
|
325
|
+
this.end++;
|
|
326
|
+
this.length++;
|
|
327
|
+
} else
|
|
328
|
+
this.push(item);
|
|
329
|
+
}
|
|
330
|
+
Queue.prototype.debugPrint = function() {
|
|
331
|
+
console.log("********** Debug print of queue: start = " + this.start + ", end = " + this.end + ", length = " + this.length);
|
|
332
|
+
for (var i = this.start; i < this.end; i++) {
|
|
333
|
+
if (this.end === i) console.log("<<-- END");
|
|
334
|
+
if (this.start === i) console.log("-->> START");
|
|
335
|
+
if (this.items[i].hasOwnProperty("debugPrint"))
|
|
336
|
+
console.log(i + ": " + this.items[i].debugPrint());
|
|
337
|
+
else
|
|
338
|
+
console.log(i + ": " + this.items[i].toString(true));
|
|
339
|
+
}
|
|
340
|
+
if (this.items.length === this.start) console.log("-->> START");
|
|
341
|
+
if (this.items.length === this.end) console.log("<<-- END");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
//////////////////////////////////
|
|
346
|
+
///////////// Atoms //////////////
|
|
347
|
+
//////////////////////////////////
|
|
348
|
+
|
|
349
|
+
function Atom() {}
|
|
350
|
+
Atom.equals = function(thiz, that) {
|
|
351
|
+
if (thiz === that) return true;
|
|
352
|
+
if ((thiz instanceof Nonterm) && (that instanceof Nonterm) && (thiz.name == that.name)) return true;
|
|
353
|
+
if ((thiz instanceof Token) && (that instanceof Token) && (thiz.name == that.name)) return true;
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
Atom.equals.toString = function() { return "Atom.equals" };
|
|
357
|
+
Atom.fromSerializable = function(obj) {
|
|
358
|
+
if (obj === undefined) return undefined;
|
|
359
|
+
if (typeof obj === "string") {
|
|
360
|
+
if (obj === "EOF") return EOF;
|
|
361
|
+
if (obj === "EPSILON") return EPSILON;
|
|
362
|
+
if (obj === "HASH") return HASH;
|
|
363
|
+
var c = obj.charAt(0);
|
|
364
|
+
if (c === "'") return new Token(obj.substring(1));
|
|
365
|
+
if (c === "@") return new Nonterm(obj.substring(1));
|
|
366
|
+
}
|
|
367
|
+
if (obj.type === "Nonterm") return new Nonterm(obj.name);
|
|
368
|
+
if (obj.type === "Token") return new Token(obj.name, obj.value);
|
|
369
|
+
if (obj.type === "EOF") return EOF;
|
|
370
|
+
if (obj.type === "EPSILON") return EPSILON;
|
|
371
|
+
if (obj.type === "HASH") return HASH;
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
function Nonterm(name) {
|
|
375
|
+
this.name = name;
|
|
376
|
+
this.key = "@" + this.name;
|
|
377
|
+
this.asString = this.name;
|
|
378
|
+
}
|
|
379
|
+
Nonterm.prototype = Object.create(Atom.prototype);
|
|
380
|
+
Nonterm.prototype.toString = function() { /*throw new Error("Don't call me!");*/ return this.name; }
|
|
381
|
+
Nonterm.prototype.toSerializable = function() { return this.key; }
|
|
382
|
+
function Token(name, value) {
|
|
383
|
+
this.name = name;
|
|
384
|
+
if (value !== undefined) {
|
|
385
|
+
this.value = value;
|
|
386
|
+
this.key = "'" + this.name + ":" + this.value;
|
|
387
|
+
this.asString = "'" + this.name;
|
|
388
|
+
} else {
|
|
389
|
+
this.value = name;
|
|
390
|
+
this.key = "'" + this.name;
|
|
391
|
+
this.asString = this.key;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
Token.prototype = Object.create(Atom.prototype);
|
|
395
|
+
Token.prototype.toRepr = function(showVal) {
|
|
396
|
+
if (showVal && this.name !== this.value)
|
|
397
|
+
return "('" + this.name + " " + JSON.stringify(this.value) + ")";
|
|
398
|
+
else
|
|
399
|
+
return this.asString;
|
|
400
|
+
}
|
|
401
|
+
Token.prototype.toString = function() { /*throw new Error("Don't call me!");*/ return this.asString; }
|
|
402
|
+
Token.prototype.toSerializable = function() {
|
|
403
|
+
if (this.name !== this.value)
|
|
404
|
+
return {type: "Token", name: this.name, value: this.value};
|
|
405
|
+
else
|
|
406
|
+
return "'" + this.name;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const EOF = Object.create(Token.prototype,
|
|
410
|
+
{name: {enumerable: true, value: "EOF"},
|
|
411
|
+
asString: {enumerable: true, value: "$"},
|
|
412
|
+
toString: {value: function() { /*throw new Error("Don't call me!");*/ return "$"; }},
|
|
413
|
+
toRepr: {value: function(showVal) {
|
|
414
|
+
if (showVal) return "<end of file>";
|
|
415
|
+
return "$";
|
|
416
|
+
}},
|
|
417
|
+
key: {enumerable: true, value: "$"},
|
|
418
|
+
toSerializable: {value: function() { return "EOF"; } }});
|
|
419
|
+
const EPSILON = Object.create(Atom.prototype,
|
|
420
|
+
{name: {enumerable: true, value: "EPSILON"},
|
|
421
|
+
asString: {enumerable: true, value: "ε"},
|
|
422
|
+
toString: {value: function() { /*throw new Error("Don't call me!");*/ return this.key; }},
|
|
423
|
+
toRepr: {value: function() { return "ε"; }},
|
|
424
|
+
key: {enumerable: true, value: "ε"},
|
|
425
|
+
toSerializable: {value: function() { return "EPSILON"; } }});
|
|
426
|
+
const HASH = Object.create(Atom.prototype,
|
|
427
|
+
{name: {enumerable: true, value: "HASH"},
|
|
428
|
+
asString: {enumerable: true, value: "#"},
|
|
429
|
+
toString: {value: function() { /*throw new Error("Don't call me!");*/ return "#"; }},
|
|
430
|
+
toRepr: {value: function() { return "#"; }},
|
|
431
|
+
key: {enumerable: true, value: "#"},
|
|
432
|
+
toSerializable: {value: function() { return "HASH"; } }});
|
|
433
|
+
|
|
434
|
+
//////////////////////////////////
|
|
435
|
+
//////////// Actions /////////////
|
|
436
|
+
//////////////////////////////////
|
|
437
|
+
|
|
438
|
+
function Action() { }
|
|
439
|
+
Action.equals = function actionEquals(thiz, that) {
|
|
440
|
+
return (thiz.type === that.type && Rule.equals(thiz.rule, that.rule) && thiz.dest == that.dest);
|
|
441
|
+
}
|
|
442
|
+
Action.equals.toString = function() { return "Action.equals"; }
|
|
443
|
+
function ReduceAction(rule, f) {
|
|
444
|
+
this.type = "Reduce";
|
|
445
|
+
this.rule = rule;
|
|
446
|
+
this.f = f;
|
|
447
|
+
//assert.notEqual(f, undefined, "Bad f value for rule " + rule);
|
|
448
|
+
this.key = rule.id + "#" + f
|
|
449
|
+
}
|
|
450
|
+
ReduceAction.prototype = Object.create(Action.prototype);
|
|
451
|
+
ReduceAction.prototype.toString = function(hideRule) {
|
|
452
|
+
if (hideRule)
|
|
453
|
+
return "Reduce " + this.rule.id;
|
|
454
|
+
else
|
|
455
|
+
return "Reduce(" + this.rule.id + ":" + this.rule.asString + ", m" + this.rule.position + ", f" + this.f + ")";
|
|
456
|
+
}
|
|
457
|
+
ReduceAction.prototype.equals = function(that) { return (that instanceof ReduceAction) && (this.rule == that.rule); }
|
|
458
|
+
|
|
459
|
+
//////////////////////////////////
|
|
460
|
+
///////////// Rules //////////////
|
|
461
|
+
//////////////////////////////////
|
|
462
|
+
|
|
463
|
+
// name :: string
|
|
464
|
+
// symbols :: array of Atoms
|
|
465
|
+
// lookahead :: Atom or undefined
|
|
466
|
+
// position :: Number or undefined
|
|
467
|
+
function Rule(name, symbols, lookahead, position) {
|
|
468
|
+
this.id = Rule.NextRuleId++;
|
|
469
|
+
this.name = name;
|
|
470
|
+
this.symbols = symbols;
|
|
471
|
+
this.lookahead = lookahead
|
|
472
|
+
this.position = position || 0;
|
|
473
|
+
var s = this.name.toString() + " =>";
|
|
474
|
+
var c = s
|
|
475
|
+
for (var i = 0; i < this.symbols.length; i++) {
|
|
476
|
+
if (i === this.position)
|
|
477
|
+
s += " .";
|
|
478
|
+
s += " " + this.symbols[i].asString;
|
|
479
|
+
c += " " + this.symbols[i].asString;
|
|
480
|
+
}
|
|
481
|
+
this.coreString = c;
|
|
482
|
+
if (this.position === this.symbols.length)
|
|
483
|
+
s += " .";
|
|
484
|
+
if (this.lookahead)
|
|
485
|
+
s = "[" + s + ", " + this.lookahead.asString + "]";
|
|
486
|
+
this.asString = s;
|
|
487
|
+
}
|
|
488
|
+
Rule.semanticActions = {};
|
|
489
|
+
Rule.defaultASTToString = function(show_pos) {
|
|
490
|
+
var toStr = "(" + this.name;
|
|
491
|
+
if (show_pos)
|
|
492
|
+
toStr += "@" + this.pos.toString(true);
|
|
493
|
+
for (var i = 0; i < this.kids.length; i++) {
|
|
494
|
+
if (this.kids[i].toRepr)
|
|
495
|
+
toStr += " " + this.kids[i].toRepr(true);
|
|
496
|
+
else if (this.kids[i].asString)
|
|
497
|
+
toStr += " " + this.kids[i].asString
|
|
498
|
+
else
|
|
499
|
+
toStr += " " + this.kids[i].toString(true);
|
|
500
|
+
}
|
|
501
|
+
toStr += ")";
|
|
502
|
+
return toStr;
|
|
503
|
+
}
|
|
504
|
+
Rule.defaultAction = function(kids, curPos, semActions) {
|
|
505
|
+
var useful_kids = [];
|
|
506
|
+
for (var i = 0; i < kids.length; i++) {
|
|
507
|
+
if (kids[i].shouldInline === true) useful_kids = useful_kids.concat(kids[i].kids);
|
|
508
|
+
else useful_kids.push(kids[i]);
|
|
509
|
+
}
|
|
510
|
+
var pos = (kids.length > 0 ? kids[0].pos.combine(kids[kids.length - 1].pos) : curPos);
|
|
511
|
+
if (semActions !== undefined && semActions[this.name] !== undefined)
|
|
512
|
+
return semActions[this.name](useful_kids, pos);
|
|
513
|
+
else
|
|
514
|
+
return { name: this.name, kids: useful_kids, toString: Rule.defaultASTToString, pos: pos };
|
|
515
|
+
}
|
|
516
|
+
Rule.defaultAction.toString = function() { return "Rule.defaultAction"; }
|
|
517
|
+
Rule.defaultAction.toSerializable = function() { return "dA"; }
|
|
518
|
+
Rule.semanticActions["dA"] = Rule.defaultAction;
|
|
519
|
+
|
|
520
|
+
Rule.ListSnoc = function(tl, hd, shouldInline) {
|
|
521
|
+
var ret = function(kids, curPos, ignoredSemActions) {
|
|
522
|
+
var useful_kids = [];
|
|
523
|
+
for (var i = 0; i < kids.length; i++) {
|
|
524
|
+
if (kids[i].name === hd) {
|
|
525
|
+
if (kids[i].shouldInline === true)
|
|
526
|
+
useful_kids = useful_kids.concat(kids[i].kids);
|
|
527
|
+
else
|
|
528
|
+
useful_kids.push(kids[i]);
|
|
529
|
+
} else if (kids[i].name === tl) useful_kids = useful_kids.concat(kids[i].kids);
|
|
530
|
+
}
|
|
531
|
+
var pos = (kids.length > 0 ? kids[0].pos.combine(kids[kids.length - 1].pos) : curPos);
|
|
532
|
+
return { name: tl, kids: useful_kids, toString: Rule.defaultASTToString, pos: pos,
|
|
533
|
+
shouldInline: shouldInline };
|
|
534
|
+
}
|
|
535
|
+
if (shouldInline) {
|
|
536
|
+
ret.toString = function() { return "Rule.ListSnoc(" + JSON.stringify(tl) + ", " + JSON.stringify(hd) + ", true)"; }
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
ret.toString = function() { return "Rule.ListSnoc(" + JSON.stringify(tl) + ", " + JSON.stringify(hd) + ")"; }
|
|
540
|
+
}
|
|
541
|
+
ret.toSerializable = function() { return ["ListSnoc", tl, hd, shouldInline]; }
|
|
542
|
+
return ret;
|
|
543
|
+
}
|
|
544
|
+
Rule.semanticActions["ListSnoc"] = Rule.ListSnoc;
|
|
545
|
+
|
|
546
|
+
Rule.Inline = function(kids, curPos, semActions) {
|
|
547
|
+
var ret = Rule.defaultAction.call(this, kids, curPos, semActions);
|
|
548
|
+
ret.shouldInline = true;
|
|
549
|
+
return ret;
|
|
550
|
+
}
|
|
551
|
+
Rule.Inline.toString = function() { return "Rule.Inline"; }
|
|
552
|
+
Rule.Inline.toSerializable = function() { return "Inline"; }
|
|
553
|
+
Rule.semanticActions["Inline"] = Rule.Inline;
|
|
554
|
+
|
|
555
|
+
Rule.KeepOnly = function(names, shouldInline) {
|
|
556
|
+
var name_dict = {};
|
|
557
|
+
for (var i = 0; i < names.length; i++)
|
|
558
|
+
name_dict[names[i]] = true;
|
|
559
|
+
var ret = function(kids, curPos, ignoredSemActions) {
|
|
560
|
+
var useful_kids = [];
|
|
561
|
+
for (var i = 0; i < kids.length; i++) {
|
|
562
|
+
if (name_dict[kids[i].name] === true) {
|
|
563
|
+
if (kids[i].shouldInline === true)
|
|
564
|
+
useful_kids = useful_kids.concat(kids[i].kids);
|
|
565
|
+
else
|
|
566
|
+
useful_kids.push(kids[i]);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
var pos = (kids.length > 0 ? kids[0].pos.combine(kids[kids.length - 1].pos) : curPos);
|
|
570
|
+
return { name: this.name, kids: useful_kids, toString: Rule.defaultASTToString, pos: pos,
|
|
571
|
+
shouldInline: shouldInline };
|
|
572
|
+
}
|
|
573
|
+
if (shouldInline) {
|
|
574
|
+
ret.toString = function() { return "Rule.KeepOnly(" + JSON.stringify(names) + ", true)"; };
|
|
575
|
+
} else {
|
|
576
|
+
ret.toString = function() { return "Rule.KeepOnly(" + JSON.stringify(names) + ")"; };
|
|
577
|
+
}
|
|
578
|
+
ret.toSerializable = function() { return ["KeepOnly", names, shouldInline]; }
|
|
579
|
+
return ret;
|
|
580
|
+
}
|
|
581
|
+
Rule.semanticActions["KeepOnly"] = Rule.KeepOnly;
|
|
582
|
+
|
|
583
|
+
var RuleFactory = {};
|
|
584
|
+
RuleFactory.cache = {};
|
|
585
|
+
RuleFactory.byId = {};
|
|
586
|
+
RuleFactory.make = function(name, symbols, lookahead, pos) {
|
|
587
|
+
pos = pos || 0;
|
|
588
|
+
var findByName = RuleFactory.cache[name];
|
|
589
|
+
var symbolsStr = "" + symbols.map((s) => s.asString);
|
|
590
|
+
if (findByName) {
|
|
591
|
+
var findBySymbols = findByName[symbolsStr];
|
|
592
|
+
if (findBySymbols) {
|
|
593
|
+
var findByLookahead = findBySymbols[lookahead ? lookahead.asString : undefined];
|
|
594
|
+
if (findByLookahead) {
|
|
595
|
+
var findByPos = findByLookahead[pos];
|
|
596
|
+
if (findByPos) return findByPos;
|
|
597
|
+
else {
|
|
598
|
+
var rule = new Rule(name, symbols, lookahead, pos);
|
|
599
|
+
RuleFactory.byId[rule.id] = rule;
|
|
600
|
+
findByLookahead[pos] = rule;
|
|
601
|
+
return rule;
|
|
602
|
+
}
|
|
603
|
+
} else {
|
|
604
|
+
var rule = new Rule(name, symbols, lookahead, pos);
|
|
605
|
+
RuleFactory.byId[rule.id] = rule;
|
|
606
|
+
var byPos = {}; byPos[pos] = rule;
|
|
607
|
+
findBySymbols[lookahead ? lookahead.asString : undefined] = byPos;
|
|
608
|
+
return rule;
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
var rule = new Rule(name, symbols, lookahead, pos);
|
|
612
|
+
RuleFactory.byId[rule.id] = rule;
|
|
613
|
+
var byPos = {}; byPos[pos] = rule;
|
|
614
|
+
var byLookahead = {}; byLookahead[lookahead ? lookahead.asString : undefined] = byPos;
|
|
615
|
+
findByName[symbolsStr] = byLookahead;
|
|
616
|
+
return rule;
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
var rule = new Rule(name, symbols, lookahead, pos);
|
|
620
|
+
RuleFactory.byId[rule.id] = rule;
|
|
621
|
+
var byPos = {}; byPos[pos] = rule;
|
|
622
|
+
var byLookahead = {}; byLookahead[lookahead ? lookahead.asString : undefined] = byPos;
|
|
623
|
+
var bySymbols = {}; bySymbols[symbolsStr] = byLookahead;
|
|
624
|
+
RuleFactory.cache[name] = {}; RuleFactory.cache[name] = bySymbols;
|
|
625
|
+
return rule;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
Rule.fromSerializable = function(rulesByOldId, id) {
|
|
629
|
+
var obj = rulesByOldId[id];
|
|
630
|
+
if (obj.hasOwnProperty("like")) {
|
|
631
|
+
var base = Rule.fromSerializable(rulesByOldId, obj.like);
|
|
632
|
+
var lookahead = obj.lookahead;
|
|
633
|
+
var pos = obj.position;
|
|
634
|
+
return RuleFactory.make(base.name, base.symbols, Atom.fromSerializable(lookahead), pos);
|
|
635
|
+
} else {
|
|
636
|
+
var sym = [];
|
|
637
|
+
for (var i = 0; i < obj.symbols.length; i++) {
|
|
638
|
+
sym[i] = Atom.fromSerializable(obj.symbols[i]);
|
|
639
|
+
}
|
|
640
|
+
return RuleFactory.make(obj.name, sym, Atom.fromSerializable(obj.lookahead), obj.position);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
Rule.NextRuleId = 0;
|
|
645
|
+
Rule.equals = function(thiz, that) {
|
|
646
|
+
if (thiz === that) return true;
|
|
647
|
+
if (thiz === undefined || that === undefined) return false;
|
|
648
|
+
if (thiz.id === that.id) return true;
|
|
649
|
+
if (!(thiz.name == that.name &&
|
|
650
|
+
thiz.symbols == that.symbols &&
|
|
651
|
+
thiz.lookahead == that.lookahead &&
|
|
652
|
+
thiz.position == that.position)) return false;
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
Rule.equalsCore = function(thiz, that) {
|
|
656
|
+
if (thiz === that) return true;
|
|
657
|
+
if (thiz === undefined || that === undefined) return false;
|
|
658
|
+
if (!(thiz.name == that.name &&
|
|
659
|
+
thiz.symbols == that.symbols &&
|
|
660
|
+
thiz.position == that.position)) return false;
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
Rule.prototype = {
|
|
664
|
+
toString: function() { return this.asString; },
|
|
665
|
+
withPosition: function(pos) {
|
|
666
|
+
return RuleFactory.make(this.name, this.symbols, this.lookahead, pos);
|
|
667
|
+
},
|
|
668
|
+
withLookahead: function(lookahead) {
|
|
669
|
+
return RuleFactory.make(this.name, this.symbols, lookahead, this.position);
|
|
670
|
+
},
|
|
671
|
+
withLookaheadPosition: function(lookahead, pos) {
|
|
672
|
+
return RuleFactory.make(this.name, this.symbols, lookahead, pos);
|
|
673
|
+
},
|
|
674
|
+
toSerializable: function() {
|
|
675
|
+
var ret = {};
|
|
676
|
+
if (this.lookahead || this.position) {
|
|
677
|
+
if (this.lookahead)
|
|
678
|
+
ret.lookahead = this.lookahead.toSerializable();
|
|
679
|
+
if (this.position)
|
|
680
|
+
ret.position = this.position;
|
|
681
|
+
ret.like = this.withLookaheadPosition(undefined, 0).id;
|
|
682
|
+
return ret;
|
|
683
|
+
}
|
|
684
|
+
ret.name = this.name;
|
|
685
|
+
if (this.position)
|
|
686
|
+
ret.position = this.position;
|
|
687
|
+
ret.symbols = [];
|
|
688
|
+
for (var i = 0; i < this.symbols.length; i++)
|
|
689
|
+
ret.symbols[i] = this.symbols[i].toSerializable();
|
|
690
|
+
return ret;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
function Link(prev, val) {
|
|
697
|
+
this.prev = prev;
|
|
698
|
+
this.val = val;
|
|
699
|
+
this.linkId = Link.NextLinkId++;
|
|
700
|
+
}
|
|
701
|
+
Link.NextLinkId = 0;
|
|
702
|
+
Link.prototype.toString = function() {
|
|
703
|
+
return this.prev.state + "<-(" + this.linkId + (this.reduced ? "r" : "") + ")-" + this.val;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
function ShiftPair(gssNode, state) {
|
|
709
|
+
this.gssNode = gssNode;
|
|
710
|
+
this.state = state;
|
|
711
|
+
}
|
|
712
|
+
ShiftPair.prototype.toString = function() { return "Shift(" + this.gssNode.toString() + ", " + this.state + ")"; }
|
|
713
|
+
function ReductionItem(gssNode, rule, m, f, label) {
|
|
714
|
+
this.gssNode = gssNode;
|
|
715
|
+
this.rule = rule;
|
|
716
|
+
this.m = m;
|
|
717
|
+
this.f = f;
|
|
718
|
+
this.label = label;
|
|
719
|
+
}
|
|
720
|
+
ReductionItem.prototype.toString = function() {
|
|
721
|
+
return "RedItem(" + this.gssNode + ", " + this.rule + ", " + this.m + ", " + this.f + ", " + this.label + ")";
|
|
722
|
+
}
|
|
723
|
+
function GSSNode(label) {
|
|
724
|
+
this.gssId = GSSNode.NextNodeId++;
|
|
725
|
+
this.label = label;
|
|
726
|
+
this.links = [];
|
|
727
|
+
// GSSNode.allNodes.push(this);
|
|
728
|
+
}
|
|
729
|
+
GSSNode.NextNodeId = 0;
|
|
730
|
+
// GSSNode.allNodes = [];
|
|
731
|
+
// GSSNode.reset = function() {
|
|
732
|
+
// GSSNode.NextNodeId = 0;
|
|
733
|
+
// GSSNode.allNodes = [];
|
|
734
|
+
// }
|
|
735
|
+
GSSNode.prototype.toString = function() {
|
|
736
|
+
return "GSSNode(#" + this.gssId + ",s" + this.parentSetId + ":st" + this.label + ")";
|
|
737
|
+
}
|
|
738
|
+
GSSNode.prototype.forPathsOfLength = function(len, callback) {
|
|
739
|
+
if (len === 0) {
|
|
740
|
+
callback({labels: [], leftSib: this});
|
|
741
|
+
} else {
|
|
742
|
+
//assert(this.links.length > 0, "Can't find any paths of length " + len + " from " + this)
|
|
743
|
+
for (var i = 0; i < this.links.length; i++)
|
|
744
|
+
pathLengthHelp(this.links[i], len, [], /*[this.toString()], */callback);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
function pathLengthHelp(link, len, labels, /*stack, */callback) {
|
|
748
|
+
labels[len - 1] = link.val;
|
|
749
|
+
//stack.push(link.prev.toString());
|
|
750
|
+
if (len == 1) {
|
|
751
|
+
// console.log("Constructed path via [" + stack + "]");
|
|
752
|
+
// console.log("Calling callback with [" + labels + "] and leftSib.state " + link.prev.label);
|
|
753
|
+
callback({labels: labels, leftSib: link.prev});
|
|
754
|
+
} else {
|
|
755
|
+
var prev_links = link.prev.links;
|
|
756
|
+
//assert(prev_links.length > 0, "Can't find any paths of length " + len + " from " + this)
|
|
757
|
+
for (var i = 0; i < prev_links.length; i++)
|
|
758
|
+
pathLengthHelp(prev_links[i], len - 1, labels, /*stack, */callback);
|
|
759
|
+
}
|
|
760
|
+
//stack.pop();
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
var allowNull = false;
|
|
766
|
+
function SPPFNode(label, pos) {
|
|
767
|
+
//if (!allowNull)
|
|
768
|
+
//assert(pos !== undefined && pos !== null);
|
|
769
|
+
this.sppfId = SPPFNode.NextId++;
|
|
770
|
+
this.label = label;
|
|
771
|
+
this.pos = pos;
|
|
772
|
+
this.rule = undefined;
|
|
773
|
+
this.kids = undefined;
|
|
774
|
+
this.ambig = undefined;
|
|
775
|
+
// SPPFNode.allNodes.push(this);
|
|
776
|
+
}
|
|
777
|
+
SPPFNode.NextId = 0;
|
|
778
|
+
// SPPFNode.allNodes = [];
|
|
779
|
+
// SPPFNode.reset = function() {
|
|
780
|
+
// SPPFNode.NextId = 0;
|
|
781
|
+
// SPPFNode.allNodes = [];
|
|
782
|
+
// }
|
|
783
|
+
SPPFNode.prototype.toString = function() {
|
|
784
|
+
var posString = "null";
|
|
785
|
+
if (this.pos)
|
|
786
|
+
posString = this.pos.toString(true);
|
|
787
|
+
var ruleAmbig = "";
|
|
788
|
+
if (this.rule)
|
|
789
|
+
ruleAmbig = this.rule.toString();
|
|
790
|
+
else if (this.ambig)
|
|
791
|
+
ruleAmbig = "ambig";
|
|
792
|
+
else if (this.label instanceof Token)
|
|
793
|
+
ruleAmbig = "<Token " + this.label.toString(true) + ">";
|
|
794
|
+
else
|
|
795
|
+
ruleAmbig = "<unknown>";
|
|
796
|
+
return "SPPFNode(" + this.sppfId + ", " + this.label.toString(true) + "@" + posString + " " + ruleAmbig + ")";
|
|
797
|
+
}
|
|
798
|
+
SPPFNode.prototype.addChildren = function(rule, kids, grammar) {
|
|
799
|
+
if (this.kids === undefined && this.ambig === undefined) {
|
|
800
|
+
this.kids = kids;
|
|
801
|
+
this.rule = rule;
|
|
802
|
+
} else if (this.ambig === undefined) {
|
|
803
|
+
this.ambig = [];
|
|
804
|
+
this.ambig.push({kids: this.kids, rule: this.rule});
|
|
805
|
+
this.ambig.push({kids: kids, rule: rule});
|
|
806
|
+
delete this.kids; delete this.rule;
|
|
807
|
+
} else {
|
|
808
|
+
var ruleFlags = grammar.getFlags(rule);
|
|
809
|
+
var sortingFlag = grammar.ambiguitySortingFlag;
|
|
810
|
+
if (sortingFlag === undefined || ruleFlags === undefined || ruleFlags[sortingFlag] === undefined) {
|
|
811
|
+
this.ambig.push({kids: kids, rule: rule});
|
|
812
|
+
} else {
|
|
813
|
+
var newFlag = ruleFlags[sortingFlag];
|
|
814
|
+
for (var i = 0; i < this.ambig.length; i++) {
|
|
815
|
+
var flags = grammar.getFlags(this.ambig[i].rule);
|
|
816
|
+
var relevantFlag = flags ? flags[sortingFlag] : undefined;
|
|
817
|
+
if (relevantFlag > newFlag) {
|
|
818
|
+
this.ambig.splice(i, 0, {kids: kids, rule: rule});
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
this.ambig.push({kids: kids, rule: rule});
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
//////////////////////////////////
|
|
828
|
+
//////////// Grammars ////////////
|
|
829
|
+
//////////////////////////////////
|
|
830
|
+
|
|
831
|
+
function Grammar(name, start) {
|
|
832
|
+
this.name = name;
|
|
833
|
+
this.rules = {};
|
|
834
|
+
this.actions = {};
|
|
835
|
+
this.flags = {};
|
|
836
|
+
this.start = start;
|
|
837
|
+
this.rnTable = [];
|
|
838
|
+
this.acceptStates = [];
|
|
839
|
+
this.atoms = new KeyedSet("key", [EOF, EPSILON]);
|
|
840
|
+
this.tokens = new KeyedSet("key", [EOF, EPSILON]);
|
|
841
|
+
this.nonterms = new KeyedSet("key");
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
Grammar.fromSerializable = function(obj) {
|
|
845
|
+
switch(obj.version || 0) {
|
|
846
|
+
case 1: return Grammar.fromSerializableV1(obj);
|
|
847
|
+
case 0:
|
|
848
|
+
default: return Grammar.fromSerializableV0(obj);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
Grammar.fromSerializableV1 = function(obj) {
|
|
852
|
+
const rawTime = ((typeof process !== "undefined") && process.hrtime) ? process.hrtime
|
|
853
|
+
: (((typeof performance !== "undefined") && performance.now) ? performance.now.bind(performance) : Date.now);
|
|
854
|
+
var startTime = rawTime();
|
|
855
|
+
function getTime() { return rawTime(startTime); }
|
|
856
|
+
var times = []
|
|
857
|
+
times.push({"Start ": getTime()});
|
|
858
|
+
var g = new Grammar(obj.name, obj.start);
|
|
859
|
+
times.push({"Constr ": getTime()});
|
|
860
|
+
var rulesByOldId = {};
|
|
861
|
+
var actionsByOldId = {};
|
|
862
|
+
var flagsByOldId = {};
|
|
863
|
+
GSSNode.NextNodeId = 0;
|
|
864
|
+
Link.NextLinkId = 0;
|
|
865
|
+
SPPFNode.NextId = 0
|
|
866
|
+
for (var id in obj.rulesByOldId) {
|
|
867
|
+
rulesByOldId[id] = Rule.fromSerializable(obj.rulesByOldId, id);
|
|
868
|
+
var action = obj.actionsByOldId[id]
|
|
869
|
+
if (typeof action === "string" || action instanceof String) {
|
|
870
|
+
actionsByOldId[id] = Rule.semanticActions[action];
|
|
871
|
+
} else if (action instanceof Array) {
|
|
872
|
+
var actionMaker = Rule.semanticActions[action.shift()];
|
|
873
|
+
actionsByOldId[id] = actionMaker.apply(Rule, action);
|
|
874
|
+
}
|
|
875
|
+
flagsByOldId[id] = obj.flagsByOldId[id];
|
|
876
|
+
}
|
|
877
|
+
times.push({"rulesByOldId ": getTime()});
|
|
878
|
+
for (var i = 0; i < obj.rules.length; i++) {
|
|
879
|
+
g.addRule(rulesByOldId[obj.rules[i]], actionsByOldId[obj.rules[i]], flagsByOldId[obj.rules[i]]);
|
|
880
|
+
}
|
|
881
|
+
times.push({"addRules ": getTime()});
|
|
882
|
+
g.rnTable = [];
|
|
883
|
+
var reduceActions = [];
|
|
884
|
+
for (var i = 0; i < obj.reduceActions.length; i += 2)
|
|
885
|
+
reduceActions[i] = new ReduceAction(rulesByOldId[obj.reduceActions[i]], obj.reduceActions[i + 1]);
|
|
886
|
+
times.push({"new redActs ": getTime(), numRedActs: reduceActions.length});
|
|
887
|
+
var emptyActions = {push: undefined, reductions: new Set()};
|
|
888
|
+
for (var i = 0; i < obj.rnTable.length; i++) {
|
|
889
|
+
var tableRow = obj.rnTable[i];
|
|
890
|
+
var newRow = g.rnTable[i] = {};
|
|
891
|
+
for (var j = 0; j < g.atoms.size(); j++) {
|
|
892
|
+
var atom = g.atoms.get(j).asString;
|
|
893
|
+
if (atom in tableRow) {
|
|
894
|
+
var nr = newRow[atom] = {push: undefined, reductions: new Set()};
|
|
895
|
+
var tr = tableRow[atom];
|
|
896
|
+
if (tr[0] >= 0)
|
|
897
|
+
nr.push = tr[0];
|
|
898
|
+
var last = tr.length;
|
|
899
|
+
if (tr.length > 1 && tr[tr.length - 1] === -1) {
|
|
900
|
+
last--;
|
|
901
|
+
nr.accept = true;
|
|
902
|
+
}
|
|
903
|
+
for (var k = 1; k < last; k++) {
|
|
904
|
+
nr.reductions.add(reduceActions[tr[k]]);
|
|
905
|
+
}
|
|
906
|
+
} else {
|
|
907
|
+
newRow[atom] = emptyActions;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
times.push({"rnTable ": getTime(), numAtoms: g.atoms.size(), tableLen: obj.rnTable.length});
|
|
912
|
+
g.acceptStates = [];
|
|
913
|
+
for (var i = 0; i < obj.acceptStates.length; i++)
|
|
914
|
+
g.acceptStates[obj.acceptStates[i]] = true;
|
|
915
|
+
g.ambiguitySortingFlag = obj.ambiguitySortingFlag;
|
|
916
|
+
g.mode = obj.mode;
|
|
917
|
+
g.eSPPFs = [];
|
|
918
|
+
g.I = obj.I;
|
|
919
|
+
allowNull = true;
|
|
920
|
+
for (var i = 0; i < obj.eSPPFs.length; i++) {
|
|
921
|
+
var label = obj.eSPPFs[i].label;
|
|
922
|
+
if (label === "EPSILON")
|
|
923
|
+
label = EPSILON;
|
|
924
|
+
g.eSPPFs[i] = {null: new SPPFNode(label, null)};
|
|
925
|
+
}
|
|
926
|
+
times.push({"bareSPPFs ": getTime()});
|
|
927
|
+
allowNull = false;
|
|
928
|
+
for (var i = 0; i < obj.eSPPFs.length; i++) {
|
|
929
|
+
var src = obj.eSPPFs[i];
|
|
930
|
+
var dest = g.eSPPFs[i].null;
|
|
931
|
+
if (src.kids) {
|
|
932
|
+
var kids = [];
|
|
933
|
+
for (var j = 0; j < src.kids.length; j++)
|
|
934
|
+
kids.push(g.eSPPFs[src.kids[j]].null);
|
|
935
|
+
dest.addChildren(rulesByOldId[src.rule], kids, this);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
times.push({"finished ": getTime()});
|
|
939
|
+
var end = rawTime(startTime);
|
|
940
|
+
const NS_PER_SEC = 1e9;
|
|
941
|
+
var cur = 0;
|
|
942
|
+
for (var i = 0; i < times.length; i++) {
|
|
943
|
+
for (var k in times[i]) {
|
|
944
|
+
if (times[i][k] instanceof Array) {
|
|
945
|
+
var next = (times[i][k][0] * NS_PER_SEC + times[i][k][1]) / NS_PER_SEC;
|
|
946
|
+
times[i][k] = (next - cur).toFixed(10);
|
|
947
|
+
cur = next;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
times.push({"TOTAL ": ((end[0] * NS_PER_SEC + end[1]) / NS_PER_SEC).toFixed(10)});
|
|
952
|
+
//console.log(times);
|
|
953
|
+
return g;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
Grammar.fromSerializableV0 = function(obj) {
|
|
957
|
+
const rawTime = ((typeof process !== "undefined") && process.hrtime) ? process.hrtime
|
|
958
|
+
: (((typeof performance !== "undefined") && performance.now) ? performance.now.bind(performance) : Date.now);
|
|
959
|
+
var startTime = rawTime();
|
|
960
|
+
function getTime() { return rawTime(startTime); }
|
|
961
|
+
var g = new Grammar(obj.name, obj.start);
|
|
962
|
+
var rulesByOldId = {};
|
|
963
|
+
var actionsByOldId = {};
|
|
964
|
+
var flagsByOldId = {};
|
|
965
|
+
GSSNode.NextNodeId = 0;
|
|
966
|
+
Link.NextLinkId = 0;
|
|
967
|
+
SPPFNode.NextId = 0
|
|
968
|
+
for (var id in obj.rulesByOldId) {
|
|
969
|
+
rulesByOldId[id] = Rule.fromSerializable(obj.rulesByOldId, id);
|
|
970
|
+
actionsByOldId[id] = obj.actionsByOldId[id] ? eval(obj.actionsByOldId[id]) : undefined;
|
|
971
|
+
flagsByOldId[id] = obj.flagsByOldId[id];
|
|
972
|
+
}
|
|
973
|
+
for (var i = 0; i < obj.rules.length; i++) {
|
|
974
|
+
g.addRule(rulesByOldId[obj.rules[i]], actionsByOldId[obj.rules[i]], flagsByOldId[obj.rules[i]]);
|
|
975
|
+
}
|
|
976
|
+
g.rnTable = [];
|
|
977
|
+
for (var i = 0; i < obj.rnTable.length; i++) {
|
|
978
|
+
var tableRow = obj.rnTable[i];
|
|
979
|
+
var newRow = g.rnTable[i] = {};
|
|
980
|
+
for (var j = 0; j < g.atoms.size(); j++) {
|
|
981
|
+
var atom = g.atoms.get(j);
|
|
982
|
+
newRow[atom] = {push: undefined, reductions: new Set()};
|
|
983
|
+
if (atom in tableRow) {
|
|
984
|
+
if (tableRow[atom].accept)
|
|
985
|
+
newRow[atom].accept = true;
|
|
986
|
+
if (tableRow[atom].push) {
|
|
987
|
+
//assert.equal(newRow[atom].push, undefined, "Already have a push action for atom " + atom);
|
|
988
|
+
newRow[atom].push = tableRow[atom].push;
|
|
989
|
+
}
|
|
990
|
+
if (tableRow[atom].reductions) {
|
|
991
|
+
for (var k = 0; k < tableRow[atom].reductions.length; k++) {
|
|
992
|
+
var red = tableRow[atom].reductions[k];
|
|
993
|
+
newRow[atom].reductions.add(new ReduceAction(rulesByOldId[red[0]], red[1]));
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
g.acceptStates = [];
|
|
1000
|
+
for (var i = 0; i < obj.acceptStates.length; i++)
|
|
1001
|
+
g.acceptStates[obj.acceptStates[i]] = true;
|
|
1002
|
+
g.derivable = {};
|
|
1003
|
+
for (var name in obj.derivable) {
|
|
1004
|
+
g.derivable[name] = {};
|
|
1005
|
+
for (var i = 0; i < obj.derivable[name].length; i++)
|
|
1006
|
+
g.derivable[name][obj.derivable[name][i]] = true;
|
|
1007
|
+
}
|
|
1008
|
+
g.ambiguitySortingFlag = obj.ambiguitySortingFlag;
|
|
1009
|
+
g.mode = obj.mode;
|
|
1010
|
+
g.eSPPFs = [];
|
|
1011
|
+
g.I = obj.I;
|
|
1012
|
+
allowNull = true;
|
|
1013
|
+
for (var i = 0; i < obj.eSPPFs.length; i++) {
|
|
1014
|
+
var label = obj.eSPPFs[i].label;
|
|
1015
|
+
if (label === "EPSILON")
|
|
1016
|
+
label = EPSILON;
|
|
1017
|
+
g.eSPPFs[i] = {null: new SPPFNode(label, null)};
|
|
1018
|
+
}
|
|
1019
|
+
allowNull = false;
|
|
1020
|
+
for (var i = 0; i < obj.eSPPFs.length; i++) {
|
|
1021
|
+
var src = obj.eSPPFs[i];
|
|
1022
|
+
var dest = g.eSPPFs[i].null;
|
|
1023
|
+
if (src.kids) {
|
|
1024
|
+
var kids = [];
|
|
1025
|
+
for (var j = 0; j < src.kids.length; j++)
|
|
1026
|
+
kids.push(g.eSPPFs[src.kids[j]].null);
|
|
1027
|
+
dest.addChildren(rulesByOldId[src.rule], kids, this);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
var end = rawTime(startTime);
|
|
1031
|
+
const NS_PER_SEC = 1e9;
|
|
1032
|
+
var cur = 0;
|
|
1033
|
+
console.log({"TOTAL ": ((end[0] * NS_PER_SEC + end[1]) / NS_PER_SEC).toFixed(10)});
|
|
1034
|
+
return g;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
Grammar.prototype = {
|
|
1040
|
+
resetParser: function() {
|
|
1041
|
+
this.rnTable = [];
|
|
1042
|
+
this.acceptStates = [];
|
|
1043
|
+
delete this.first;
|
|
1044
|
+
delete this.nontermFirst;
|
|
1045
|
+
delete this.states;
|
|
1046
|
+
this.firstStringCache = {};
|
|
1047
|
+
this.closureCache = {};
|
|
1048
|
+
},
|
|
1049
|
+
initializeParser: function(verbose) {
|
|
1050
|
+
console.log("Initializing " + this.name);
|
|
1051
|
+
var new_start;
|
|
1052
|
+
if (!this.initialized) {
|
|
1053
|
+
new_start = "START";
|
|
1054
|
+
while (this.rules.hasOwnProperty(new_start))
|
|
1055
|
+
new_start += "_";
|
|
1056
|
+
this.addRule(new_start, [new Nonterm(this.start)]);
|
|
1057
|
+
this.start = new_start;
|
|
1058
|
+
this.initialized = true;
|
|
1059
|
+
}
|
|
1060
|
+
var orig_start = this.rules[this.start][0].symbols[0];
|
|
1061
|
+
if (verbose) {
|
|
1062
|
+
console.log("Grammar productions:");
|
|
1063
|
+
for (var name in this.rules)
|
|
1064
|
+
for (var i = 0; i < this.rules[name].length; i++)
|
|
1065
|
+
console.log(" " + this.rules[name][i].toString(true));
|
|
1066
|
+
}
|
|
1067
|
+
console.log("Computing first sets");
|
|
1068
|
+
this.resetParser();
|
|
1069
|
+
this.computeFirstSets();
|
|
1070
|
+
console.log("Computing derivability");
|
|
1071
|
+
this.computeDerivability();
|
|
1072
|
+
console.log("Computing states");
|
|
1073
|
+
this.computeStateKernels();
|
|
1074
|
+
console.log("Computing required nullable parts");
|
|
1075
|
+
this.computeRequiredNullableParts();
|
|
1076
|
+
console.log("Computing RN Table");
|
|
1077
|
+
this.computeRNTable();
|
|
1078
|
+
// console.log(this.printTables());
|
|
1079
|
+
this.mode = "RNGLR";
|
|
1080
|
+
console.log("Done initializing " + this.name);
|
|
1081
|
+
},
|
|
1082
|
+
parse: function(token_stream) {
|
|
1083
|
+
this.resetESPPFs();
|
|
1084
|
+
if (this.mode === "RNGLR")
|
|
1085
|
+
return this.parseRNGLR(token_stream);
|
|
1086
|
+
return "Unknown parsing mode -- can't actually parse!"
|
|
1087
|
+
},
|
|
1088
|
+
toString: function() {
|
|
1089
|
+
var s = "Grammar " + this.name + ": (initial rule " + this.start + ")\n";
|
|
1090
|
+
for (var name in this.rules) {
|
|
1091
|
+
var rules = this.rules[name];
|
|
1092
|
+
for (var i = 0; i < rules.length; i++)
|
|
1093
|
+
s += rules[i].toString() + "\n";
|
|
1094
|
+
}
|
|
1095
|
+
return s;
|
|
1096
|
+
},
|
|
1097
|
+
sortAmbiguitiesBy: function(s) {
|
|
1098
|
+
this.ambiguitySortingFlag = s;
|
|
1099
|
+
},
|
|
1100
|
+
toSerializable: function(version) {
|
|
1101
|
+
switch(version || 0) {
|
|
1102
|
+
case 1: return this.toSerializableV1();
|
|
1103
|
+
case 0:
|
|
1104
|
+
default: return this.toSerializableV0();
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
toSerializableV1: function() {
|
|
1110
|
+
var ret = {};
|
|
1111
|
+
ret.version = 1;
|
|
1112
|
+
ret.start = this.start;
|
|
1113
|
+
ret.name = this.name;
|
|
1114
|
+
ret.acceptStates = [];
|
|
1115
|
+
for (var i = 0; i < this.acceptStates.length; i++)
|
|
1116
|
+
if (this.acceptStates[i])
|
|
1117
|
+
ret.acceptStates.push(i);
|
|
1118
|
+
if (this.ambiguitySortingFlag)
|
|
1119
|
+
ret.ambiguitySortingFlag = this.ambiguitySortingFlag;
|
|
1120
|
+
ret.mode = this.mode;
|
|
1121
|
+
ret.rulesByOldId = {};
|
|
1122
|
+
ret.actionsByOldId = {};
|
|
1123
|
+
ret.flagsByOldId = {};
|
|
1124
|
+
ret.rules = [];
|
|
1125
|
+
for (var name in this.rules) {
|
|
1126
|
+
for (var i = 0; i < this.rules[name].length; i++) {
|
|
1127
|
+
var rule = this.rules[name][i];
|
|
1128
|
+
var id = rule.id;
|
|
1129
|
+
ret.rulesByOldId[id] = rule.toSerializable();
|
|
1130
|
+
ret.rules.push(id);
|
|
1131
|
+
var rule_noLookahead = rule.withLookahead(undefined);
|
|
1132
|
+
ret.rulesByOldId[rule_noLookahead.id] = rule_noLookahead.toSerializable();
|
|
1133
|
+
ret.actionsByOldId[rule_noLookahead.id] = this.getAction(rule_noLookahead);
|
|
1134
|
+
if (ret.actionsByOldId[rule_noLookahead.id] !== undefined) {
|
|
1135
|
+
ret.actionsByOldId[rule_noLookahead.id] = ret.actionsByOldId[rule_noLookahead.id].toSerializable();
|
|
1136
|
+
}
|
|
1137
|
+
ret.flagsByOldId[rule_noLookahead.id] = this.getFlags(rule_noLookahead);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
ret.reduceActions = [];
|
|
1141
|
+
var reduceActionsCache = {};
|
|
1142
|
+
ret.rnTable = []; // TODO: Fix this
|
|
1143
|
+
for (var i = 0; i < this.rnTable.length; i++) {
|
|
1144
|
+
var tableRow = this.rnTable[i];
|
|
1145
|
+
ret.rnTable[i] = {};
|
|
1146
|
+
for (var name in tableRow) {
|
|
1147
|
+
if (tableRow[name].push === undefined && !tableRow[name].accept && tableRow[name].reductions.size === 0) {
|
|
1148
|
+
//ret.rnTable[i][name] = "empty";
|
|
1149
|
+
} else {
|
|
1150
|
+
var entry = tableRow[name];
|
|
1151
|
+
var dest = ret.rnTable[i][name] = [];
|
|
1152
|
+
dest.push(entry.push === undefined ? -1 : entry.push);
|
|
1153
|
+
entry.reductions.forEach(function(red) {
|
|
1154
|
+
if (reduceActionsCache[red.rule.id] === undefined)
|
|
1155
|
+
reduceActionsCache[red.rule.id] = {};
|
|
1156
|
+
if (reduceActionsCache[red.rule.id][red.f] === undefined) {
|
|
1157
|
+
reduceActionsCache[red.rule.id][red.f] = ret.reduceActions.length;
|
|
1158
|
+
ret.reduceActions.push(red.rule.id, red.f);
|
|
1159
|
+
}
|
|
1160
|
+
dest.push(reduceActionsCache[red.rule.id][red.f]);
|
|
1161
|
+
ret.rulesByOldId[red.rule.id] = red.rule.toSerializable();
|
|
1162
|
+
var rule_noLookahead = red.rule.withLookahead(undefined);
|
|
1163
|
+
ret.rulesByOldId[rule_noLookahead.id] = rule_noLookahead.toSerializable();
|
|
1164
|
+
});
|
|
1165
|
+
if (entry.accept) dest.push(-1);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
ret.I = this.I;
|
|
1170
|
+
ret.eSPPFs = [];
|
|
1171
|
+
for (var i = 0; i < this.eSPPFs.length; i++) {
|
|
1172
|
+
var null_eSPPF = this.eSPPFs[i].null;
|
|
1173
|
+
var label = null_eSPPF.label;
|
|
1174
|
+
if (label === EPSILON) {
|
|
1175
|
+
label = "EPSILON";
|
|
1176
|
+
}
|
|
1177
|
+
if (null_eSPPF.kids) {
|
|
1178
|
+
var kids = [];
|
|
1179
|
+
for (var j = 0; j < null_eSPPF.kids.length; j++)
|
|
1180
|
+
kids.push(null_eSPPF.kids[j].sppfId);
|
|
1181
|
+
if (null_eSPPF.rule)
|
|
1182
|
+
ret.eSPPFs[i] = {label: label, kids: kids, rule: null_eSPPF.rule.id};
|
|
1183
|
+
else
|
|
1184
|
+
ret.eSPPFs[i] = {label: label, kids: kids};
|
|
1185
|
+
} else {
|
|
1186
|
+
if (null_eSPPF.rule)
|
|
1187
|
+
ret.eSPPFs[i] = {label: label, rule: null_eSPPF.rule.id};
|
|
1188
|
+
else
|
|
1189
|
+
ret.eSPPFs[i] = {label: label};
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return ret;
|
|
1193
|
+
},
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
toSerializableV0: function() {
|
|
1197
|
+
var ret = {};
|
|
1198
|
+
ret.start = this.start;
|
|
1199
|
+
ret.name = this.name;
|
|
1200
|
+
ret.acceptStates = [];
|
|
1201
|
+
for (var i = 0; i < this.acceptStates.length; i++)
|
|
1202
|
+
if (this.acceptStates[i])
|
|
1203
|
+
ret.acceptStates.push(i);
|
|
1204
|
+
if (this.ambiguitySortingFlag)
|
|
1205
|
+
ret.ambiguitySortingFlag = this.ambiguitySortingFlag;
|
|
1206
|
+
ret.mode = this.mode;
|
|
1207
|
+
ret.derivable = {};
|
|
1208
|
+
for (var name in this.derivable) {
|
|
1209
|
+
ret.derivable[name] = [];
|
|
1210
|
+
for (var der in this.derivable[name])
|
|
1211
|
+
ret.derivable[name].push(der);
|
|
1212
|
+
}
|
|
1213
|
+
ret.rulesByOldId = {};
|
|
1214
|
+
ret.actionsByOldId = {};
|
|
1215
|
+
ret.flagsByOldId = {};
|
|
1216
|
+
ret.rules = [];
|
|
1217
|
+
for (var name in this.rules) {
|
|
1218
|
+
for (var i = 0; i < this.rules[name].length; i++) {
|
|
1219
|
+
var rule = this.rules[name][i];
|
|
1220
|
+
var id = rule.id;
|
|
1221
|
+
ret.rulesByOldId[id] = rule.toSerializable();
|
|
1222
|
+
ret.rules.push(id);
|
|
1223
|
+
var rule_noLookahead = rule.withLookahead(undefined);
|
|
1224
|
+
ret.rulesByOldId[rule_noLookahead.id] = rule_noLookahead.toSerializable();
|
|
1225
|
+
ret.actionsByOldId[rule_noLookahead.id] = this.getAction(rule_noLookahead);
|
|
1226
|
+
if (ret.actionsByOldId[rule_noLookahead.id] !== undefined) {
|
|
1227
|
+
ret.actionsByOldId[rule_noLookahead.id] = ret.actionsByOldId[rule_noLookahead.id].toString();
|
|
1228
|
+
}
|
|
1229
|
+
ret.flagsByOldId[rule_noLookahead.id] = this.getFlags(rule_noLookahead);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
ret.rnTable = []; // TODO: Fix this
|
|
1233
|
+
for (var i = 0; i < this.rnTable.length; i++) {
|
|
1234
|
+
var tableRow = this.rnTable[i];
|
|
1235
|
+
ret.rnTable[i] = {};
|
|
1236
|
+
for (var name in tableRow) {
|
|
1237
|
+
if (tableRow[name].push === undefined && !tableRow[name].accept && tableRow[name].reductions.size === 0) {
|
|
1238
|
+
//ret.rnTable[i][name] = "empty";
|
|
1239
|
+
} else {
|
|
1240
|
+
var entry = tableRow[name];
|
|
1241
|
+
var dest = ret.rnTable[i][name] = {};
|
|
1242
|
+
if (entry.accept) dest.accept = true;
|
|
1243
|
+
if (entry.push !== undefined) {
|
|
1244
|
+
dest.push = entry.push;
|
|
1245
|
+
}
|
|
1246
|
+
if (entry.reductions.size > 0) {
|
|
1247
|
+
dest.reductions = [];
|
|
1248
|
+
entry.reductions.forEach(function(red) {
|
|
1249
|
+
dest.reductions.push([red.rule.id, red.f]);
|
|
1250
|
+
ret.rulesByOldId[red.rule.id] = red.rule.toSerializable();
|
|
1251
|
+
var rule_noLookahead = red.rule.withLookahead(undefined);
|
|
1252
|
+
ret.rulesByOldId[rule_noLookahead.id] = rule_noLookahead.toSerializable();
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
ret.I = this.I;
|
|
1259
|
+
ret.eSPPFs = [];
|
|
1260
|
+
for (var i = 0; i < this.eSPPFs.length; i++) {
|
|
1261
|
+
var null_eSPPF = this.eSPPFs[i].null;
|
|
1262
|
+
var label = null_eSPPF.label;
|
|
1263
|
+
if (label === EPSILON) {
|
|
1264
|
+
label = "EPSILON";
|
|
1265
|
+
}
|
|
1266
|
+
if (null_eSPPF.kids) {
|
|
1267
|
+
var kids = [];
|
|
1268
|
+
for (var j = 0; j < null_eSPPF.kids.length; j++)
|
|
1269
|
+
kids.push(null_eSPPF.kids[j].sppfId);
|
|
1270
|
+
if (null_eSPPF.rule)
|
|
1271
|
+
ret.eSPPFs[i] = {label: label, kids: kids, rule: null_eSPPF.rule.id};
|
|
1272
|
+
else
|
|
1273
|
+
ret.eSPPFs[i] = {label: label, kids: kids};
|
|
1274
|
+
} else {
|
|
1275
|
+
if (null_eSPPF.rule)
|
|
1276
|
+
ret.eSPPFs[i] = {label: label, rule: null_eSPPF.rule.id};
|
|
1277
|
+
else
|
|
1278
|
+
ret.eSPPFs[i] = {label: label};
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return ret;
|
|
1282
|
+
},
|
|
1283
|
+
|
|
1284
|
+
addRule: function(name, symbols, action, flags) {
|
|
1285
|
+
var new_rule;
|
|
1286
|
+
if (name instanceof Rule) {
|
|
1287
|
+
new_rule = name;
|
|
1288
|
+
name = new_rule.name;
|
|
1289
|
+
flags = action; // slide arguments over by one
|
|
1290
|
+
action = symbols;
|
|
1291
|
+
symbols = new_rule.symbols;
|
|
1292
|
+
} else {
|
|
1293
|
+
new_rule = RuleFactory.make(name, symbols, undefined, undefined);
|
|
1294
|
+
}
|
|
1295
|
+
if (action === undefined)
|
|
1296
|
+
action = Rule.defaultAction;
|
|
1297
|
+
this.actions[new_rule.id] = action;
|
|
1298
|
+
this.flags[new_rule.id] = flags;
|
|
1299
|
+
if (!(this.rules.hasOwnProperty(name)))
|
|
1300
|
+
this.rules[name] = [];
|
|
1301
|
+
this.rules[name].push(new_rule);
|
|
1302
|
+
this.atoms.add(new Nonterm(name));
|
|
1303
|
+
this.nonterms.add(new Nonterm(name));
|
|
1304
|
+
for (var i = 0; i < symbols.length; i++) {
|
|
1305
|
+
this.atoms.add(symbols[i]);
|
|
1306
|
+
if (symbols[i] instanceof Nonterm)
|
|
1307
|
+
this.nonterms.add(symbols[i])
|
|
1308
|
+
else
|
|
1309
|
+
this.tokens.add(symbols[i])
|
|
1310
|
+
}
|
|
1311
|
+
return new_rule;
|
|
1312
|
+
},
|
|
1313
|
+
|
|
1314
|
+
getAction: function(rule) {
|
|
1315
|
+
var baseRule = rule.withLookaheadPosition(undefined, 0);
|
|
1316
|
+
var action = this.actions[baseRule.id];
|
|
1317
|
+
return action;
|
|
1318
|
+
},
|
|
1319
|
+
applyAction: function(rule, kids, pos, semActions) {
|
|
1320
|
+
var action = this.getAction(rule);
|
|
1321
|
+
return action.call(rule, kids, pos, semActions);
|
|
1322
|
+
},
|
|
1323
|
+
getFlags: function(rule) {
|
|
1324
|
+
return this.flags[rule.withLookaheadPosition(undefined, 0).id];
|
|
1325
|
+
},
|
|
1326
|
+
|
|
1327
|
+
//////////////////////////////////
|
|
1328
|
+
// Computes what nonterminals can derive other nonterminals in one or more steps,
|
|
1329
|
+
// i.e. A ->+ B for two nonterminals A and B (possibly the same)
|
|
1330
|
+
//////////////////////////////////
|
|
1331
|
+
computeDerivability: function() {
|
|
1332
|
+
this.derivable = {}
|
|
1333
|
+
for (var i = 0; i < this.nonterms.size(); i++)
|
|
1334
|
+
this.derivable[this.nonterms.get(i).asString] = {};
|
|
1335
|
+
var changed = true;
|
|
1336
|
+
while(changed) {
|
|
1337
|
+
changed = false;
|
|
1338
|
+
// console.log("\nNew loop...");
|
|
1339
|
+
for (var name in this.rules) {
|
|
1340
|
+
var rules = this.rules[name]
|
|
1341
|
+
for (var i = 0; i < rules.length; i++) {
|
|
1342
|
+
var rule = rules[i];
|
|
1343
|
+
// console.log("Processing rule [" + rule + "]");
|
|
1344
|
+
if (rule.symbols.length === 0) {
|
|
1345
|
+
// if (!this.derivable[name][EPSILON.asString])
|
|
1346
|
+
// console.log(" " + name + " can derive EPSILON via rule " + rule);
|
|
1347
|
+
changed = changed || (!this.derivable[name][EPSILON.asString]);
|
|
1348
|
+
this.derivable[name][EPSILON.asString] = true; // Rule <name> is nullable
|
|
1349
|
+
}
|
|
1350
|
+
for (var j = 0; j < rule.symbols.length; j++) {
|
|
1351
|
+
var sym = rule.symbols[j]
|
|
1352
|
+
if ((sym instanceof Token) && (sym !== EOF)) {
|
|
1353
|
+
// console.log(" Rule [" + rule + "] isn't nullable due to " + sym.asString + " so skipping rest");
|
|
1354
|
+
break; // A token in the RHS of a rule means it can't derive a nonterminal on its own
|
|
1355
|
+
}
|
|
1356
|
+
var restNullable = true;
|
|
1357
|
+
for (var k = j + 1; k < rule.symbols.length; k++) {
|
|
1358
|
+
if (rule.symbols[k] === EOF) continue;
|
|
1359
|
+
if ((rule.symbols[k] instanceof Token) ||
|
|
1360
|
+
(this.derivable[rule.symbols[k].asString][EPSILON.asString] !== true)) {
|
|
1361
|
+
restNullable = false;
|
|
1362
|
+
break;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
if (restNullable) {
|
|
1366
|
+
// if (!this.derivable[name][sym.asString])
|
|
1367
|
+
// console.log(" " + name + " can derive " + sym.asString + " via [" + rule + "]");
|
|
1368
|
+
changed = changed || (!this.derivable[name][sym.asString]);
|
|
1369
|
+
this.derivable[name][sym.asString] = true;
|
|
1370
|
+
}
|
|
1371
|
+
if ((!this.derivable[sym.asString]) || this.derivable[sym.asString][EPSILON.asString] !== true) {
|
|
1372
|
+
// console.log("Rule [" + rule + "] isn't nullable after " + sym.asString + " so skipping rest");
|
|
1373
|
+
break; // This nonterminal isn't nullable, so skip the rest of the rule
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
for (var i = 0; i < this.nonterms.size(); i++) {
|
|
1380
|
+
var term_i = this.nonterms.get(i).asString;
|
|
1381
|
+
for (var j = 0; j < this.nonterms.size(); j++) {
|
|
1382
|
+
var term_j = this.nonterms.get(j).asString;
|
|
1383
|
+
if (i == j || !this.derivable[term_i][term_j]) continue;
|
|
1384
|
+
if (this.derivable[term_j][EPSILON.asString] && !this.derivable[term_i][EPSILON.asString]) {
|
|
1385
|
+
// console.log(term_i + " can derive EPSILON via " + term_j);
|
|
1386
|
+
this.derivable[term_i][EPSILON.asString] = true;
|
|
1387
|
+
}
|
|
1388
|
+
for (var k = 0; k < this.nonterms.size(); k++) {
|
|
1389
|
+
var term_k = this.nonterms.get(k);
|
|
1390
|
+
if (j == k || !this.derivable[term_j][term_k]) continue;
|
|
1391
|
+
// if (!this.derivable[term_i][term_k])
|
|
1392
|
+
// console.log(term_i + " can derive " + term_k + " via " + term_j);
|
|
1393
|
+
changed = changed || (!this.derivable[term_i][term_k])
|
|
1394
|
+
this.derivable[term_i][term_k] = true;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
// console.log("Done");
|
|
1400
|
+
},
|
|
1401
|
+
|
|
1402
|
+
//////////////////////////////////
|
|
1403
|
+
// Computes the set of first tokens in a rule
|
|
1404
|
+
// If a rule is nullable, then EPSILON is one possible token
|
|
1405
|
+
//////////////////////////////////
|
|
1406
|
+
computeFirstSets: function() {
|
|
1407
|
+
var thiz = this;
|
|
1408
|
+
var changed = true;
|
|
1409
|
+
function addFirst(name, token) {
|
|
1410
|
+
var ret = !(token.asString in thiz.first[name])
|
|
1411
|
+
thiz.first[name][token.asString] = token;
|
|
1412
|
+
return ret;
|
|
1413
|
+
}
|
|
1414
|
+
function merge(dest, source) {
|
|
1415
|
+
var ret = false;
|
|
1416
|
+
for (var tok in thiz.first[source])
|
|
1417
|
+
if (thiz.first[source][tok] !== EPSILON)
|
|
1418
|
+
ret = addFirst(dest, thiz.first[source][tok]) || ret;
|
|
1419
|
+
return ret;
|
|
1420
|
+
}
|
|
1421
|
+
this.first = {};
|
|
1422
|
+
this.nontermFirst = {};
|
|
1423
|
+
for (var name in this.rules) {
|
|
1424
|
+
if (this.rules.hasOwnProperty(name)) {
|
|
1425
|
+
this.first[name] = {};
|
|
1426
|
+
this.nontermFirst[name] = new KeyedSet("key", [new Nonterm(name)]);
|
|
1427
|
+
for (var i = 0; i < this.rules[name].length; i++)
|
|
1428
|
+
if (this.rules[name][i].symbols.length === 0)
|
|
1429
|
+
addFirst(name, EPSILON);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
while (changed) {
|
|
1433
|
+
changed = false;
|
|
1434
|
+
for (var name in this.rules) {
|
|
1435
|
+
var name_rules = this.rules[name];
|
|
1436
|
+
for (var i = 0; i < name_rules.length; i++) {
|
|
1437
|
+
var name_rule = name_rules[i];
|
|
1438
|
+
var allNullable = true;
|
|
1439
|
+
for (var j = 0; j < name_rule.symbols.length; j++) {
|
|
1440
|
+
if (name_rule.symbols[j] instanceof Nonterm) {
|
|
1441
|
+
changed = merge(name, name_rule.symbols[j].asString) || changed;
|
|
1442
|
+
//if (this.nontermFirst[name_rule.symbols[j]] === undefined)
|
|
1443
|
+
//assert(false, "Couldn't find a nontermFirst for " + name_rule.symbols[j]);
|
|
1444
|
+
this.nontermFirst[name].merge(this.nontermFirst[name_rule.symbols[j].asString]);
|
|
1445
|
+
if (this.first[name_rule.symbols[j].asString][EPSILON.asString] !== EPSILON) {
|
|
1446
|
+
allNullable = false;
|
|
1447
|
+
break;
|
|
1448
|
+
}
|
|
1449
|
+
} else {
|
|
1450
|
+
changed = addFirst(name, name_rule.symbols[j]) || changed;
|
|
1451
|
+
allNullable = false;
|
|
1452
|
+
break;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
if (allNullable) {
|
|
1456
|
+
addFirst(name, EPSILON);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
},
|
|
1462
|
+
|
|
1463
|
+
|
|
1464
|
+
//////////////////////////////////
|
|
1465
|
+
// Computes the tokens that can immediately follow the specified position
|
|
1466
|
+
// in the current rule. This is a subset of the Follow set for the given
|
|
1467
|
+
// nonterminal, and is therefore more precise and less prone to producing
|
|
1468
|
+
// parsing conflicts.
|
|
1469
|
+
//////////////////////////////////
|
|
1470
|
+
computeFollowAtPosition: function(rule, pos) {
|
|
1471
|
+
if (rule.lookahead)
|
|
1472
|
+
return this.computeFirstOfStrings(rule.symbols.slice(pos).concat(rule.lookahead));
|
|
1473
|
+
else
|
|
1474
|
+
return this.computeFirstOfStrings(rule.symbols.slice(pos));
|
|
1475
|
+
},
|
|
1476
|
+
|
|
1477
|
+
//////////////////////////////////
|
|
1478
|
+
// Lifts the first relation from non-terminals to strings of grammar symbols
|
|
1479
|
+
computeFirstOfStrings: function(string) {
|
|
1480
|
+
var joinedStrings = "" + string.map((s) => s.asString);
|
|
1481
|
+
var ret = this.firstStringCache[joinedStrings];
|
|
1482
|
+
if (ret !== undefined) return ret;
|
|
1483
|
+
ret = this.firstStringCache[joinedStrings] = new KeyedSet("key");
|
|
1484
|
+
var nullable = true;
|
|
1485
|
+
// console.log("syms[" + i + "] = [" + string + "], length = " + string.length);
|
|
1486
|
+
for (var j = 0; j < string.length; j++) {
|
|
1487
|
+
if (string[j] instanceof Token || string[j] === HASH) { // Tokens aren't nullable, so we're done
|
|
1488
|
+
ret.add(string[j]);
|
|
1489
|
+
nullable = false;
|
|
1490
|
+
break;
|
|
1491
|
+
} else {
|
|
1492
|
+
var first = this.first[string[j].asString];
|
|
1493
|
+
if (first === undefined) {
|
|
1494
|
+
console.log("Internal error! string[j] = " + JSON.stringify(string[j]) + " but first is undefined");
|
|
1495
|
+
}
|
|
1496
|
+
for (var name in first) {
|
|
1497
|
+
if (first[name] !== EPSILON)
|
|
1498
|
+
ret.add(first[name]);
|
|
1499
|
+
}
|
|
1500
|
+
if (first[EPSILON.asString] === undefined) { // This nonterminal isn't nullable, so we're done
|
|
1501
|
+
nullable = false;
|
|
1502
|
+
break;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
if (nullable)
|
|
1507
|
+
ret.add(EPSILON);
|
|
1508
|
+
return ret;
|
|
1509
|
+
},
|
|
1510
|
+
|
|
1511
|
+
//////////////////////////////////
|
|
1512
|
+
// Computes the LR(1) closure of a rule set:
|
|
1513
|
+
// For a given rule [A -> a.Bb, x] in the set, it adds [B -> .g, y]
|
|
1514
|
+
// for all [B -> g] in the grammar, and all y in FIRST(bx).
|
|
1515
|
+
//
|
|
1516
|
+
// If inline = true, then it mutates the provided argument
|
|
1517
|
+
// otherwise it constructs a new set and returns that.
|
|
1518
|
+
// Dragon book 2ed, p261
|
|
1519
|
+
completeClosure: function(lrSet, inline) {
|
|
1520
|
+
var ret = inline ? lrSet : new LR1Set(lrSet);
|
|
1521
|
+
var worklist = new Queue(ret.exhaustive());
|
|
1522
|
+
while (worklist.length > 0) {
|
|
1523
|
+
var rule = worklist.shift();
|
|
1524
|
+
if (rule.position < rule.symbols.length) {
|
|
1525
|
+
var next_symbol = rule.symbols[rule.position];
|
|
1526
|
+
if (next_symbol instanceof Nonterm) {
|
|
1527
|
+
var next = this.computeFollowAtPosition(rule, rule.position + 1);
|
|
1528
|
+
// console.log(" next(" + rule + ") = " + next);
|
|
1529
|
+
var rules_to_add = this.rules[next_symbol.asString]
|
|
1530
|
+
if (rules_to_add === undefined) {
|
|
1531
|
+
throw("No rules known for symbol " + next_symbol.asString);
|
|
1532
|
+
}
|
|
1533
|
+
for (var j = 0; j < rules_to_add.length; j++) {
|
|
1534
|
+
var rule_to_add = rules_to_add[j];
|
|
1535
|
+
for (var k = 0; k < next.size(); k++) {
|
|
1536
|
+
var new_rule = RuleFactory.make(rule_to_add.name, rule_to_add.symbols, next.get(k), 0)
|
|
1537
|
+
if (ret.addRule(new_rule)) {
|
|
1538
|
+
worklist.push(new_rule);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return ret;
|
|
1546
|
+
},
|
|
1547
|
+
|
|
1548
|
+
//////////////////////////////////
|
|
1549
|
+
// Computes the kernel of the LR(1) Goto set for a given kernel and symbol
|
|
1550
|
+
// Dragon book 2ed, p261
|
|
1551
|
+
computeGotoKernel: function(setNum, lrSet, symbol) {
|
|
1552
|
+
// console.log("--> Rule_set #" + setNum + " = " + lrSet + ", symbol = " + symbol);
|
|
1553
|
+
var ret = new LR1Set();
|
|
1554
|
+
for (var i = 0; i < lrSet.coreSize(); i++) {
|
|
1555
|
+
var rule = lrSet.getCore(i);
|
|
1556
|
+
// console.log(" Processing rule " + rule);
|
|
1557
|
+
if (rule.position < rule.symbols.length && rule.symbols[rule.position].asString == symbol.asString) {
|
|
1558
|
+
// console.log(" Pushing " + symbol + " over in rule " + rule);
|
|
1559
|
+
var new_rule = rule.withPosition(rule.position + 1);
|
|
1560
|
+
// console.log(" new_rule = " + new_rule + " and lookaheads = " + lrSet.getLookaheads(i));
|
|
1561
|
+
ret.addRuleWithLookaheads(new_rule, lrSet.getLookaheads(i));
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
this.completeClosure(ret, true);
|
|
1565
|
+
// console.log("<-- Result = " + ret);
|
|
1566
|
+
return ret;
|
|
1567
|
+
},
|
|
1568
|
+
|
|
1569
|
+
reducer: function(U, R, Q, N, i, cur_tok, skipped_WS_loc) {
|
|
1570
|
+
// cur_tok = token #i+1: i starts at index 0, and tokens start at index 1
|
|
1571
|
+
// U is an array of sets of GSS nodes
|
|
1572
|
+
// R is the worklist of pending reductions
|
|
1573
|
+
// Q is the set of (GSS node, token) pairs of pending shifts
|
|
1574
|
+
// N is the set of SPPF nodes created in this step
|
|
1575
|
+
// cur_tok is the current token
|
|
1576
|
+
var item = R.shift();
|
|
1577
|
+
// console.log("In reducer, i = " + i + ", cur_tok = " + cur_tok.toString(true) + ", and item = " + item);
|
|
1578
|
+
var v = item.gssNode; // GSS node from which the reduction is to be applied
|
|
1579
|
+
var X = item.rule.name; // the name of the reduction rule
|
|
1580
|
+
var m = item.m; // the length of the RHS of the reduction rule (maybe just item.rule.position?)
|
|
1581
|
+
var f = item.f; // the index of the required nullable part at the righthand end of the reduction
|
|
1582
|
+
// or 0 if the reduction isn't right-nullable
|
|
1583
|
+
var y = item.label; // the SPPF node labels the first edge of the path down which the reduction is applied
|
|
1584
|
+
// (if m = 0 then y = epsilon) [sic]
|
|
1585
|
+
var y_m = (m !== 0 ? y : undefined)
|
|
1586
|
+
var U_i = U[i]
|
|
1587
|
+
const thiz = this;
|
|
1588
|
+
v.forPathsOfLength(m > 0 ? (m - 1) : 0, function(p) {
|
|
1589
|
+
// console.log("Found path " + JSON.stringify(p, null, " "));
|
|
1590
|
+
// p.labels contain the edge labels of the path
|
|
1591
|
+
var u = p.leftSib;
|
|
1592
|
+
var k = u.label;
|
|
1593
|
+
var l = thiz.rnTable[k][X].push;
|
|
1594
|
+
if (l !== undefined) {
|
|
1595
|
+
// console.log("k = " + k + ", X = " + X + ", l = " + l);
|
|
1596
|
+
var z = undefined;
|
|
1597
|
+
if (m === 0)
|
|
1598
|
+
z = thiz.getEpsilonSPPF(f, cur_tok.pos.posAtStart());
|
|
1599
|
+
else {
|
|
1600
|
+
var c = u.parentSetId;
|
|
1601
|
+
var nodes_X = N[X];
|
|
1602
|
+
if (nodes_X === undefined)
|
|
1603
|
+
nodes_X = N[X] = {};
|
|
1604
|
+
z = nodes_X[c];
|
|
1605
|
+
if (z === undefined) {
|
|
1606
|
+
var pos;
|
|
1607
|
+
if (skipped_WS_loc !== undefined) {
|
|
1608
|
+
pos = skipped_WS_loc.posAtStart();
|
|
1609
|
+
} else {
|
|
1610
|
+
pos = cur_tok.pos;
|
|
1611
|
+
}
|
|
1612
|
+
if (p.labels.length > 0) {
|
|
1613
|
+
pos = pos.combine(p.labels[0].pos);
|
|
1614
|
+
}
|
|
1615
|
+
z = nodes_X[c] = new SPPFNode(X, pos);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
// console.log("z = " + z); // XXX Serializing of eSPPFs isn't working
|
|
1619
|
+
var w = U_i.itemForKey(l);
|
|
1620
|
+
if (w !== undefined) {
|
|
1621
|
+
// console.log("1. Adding link from " + w + " to " + u + " labelled " + z);
|
|
1622
|
+
if (thiz.addLink(/*from*/w, /*to*/u, /*labelled*/z)) {
|
|
1623
|
+
if (m !== 0) {
|
|
1624
|
+
var actions = thiz.getActions(l, cur_tok);
|
|
1625
|
+
if (actions !== undefined) {
|
|
1626
|
+
var reductions = actions.reductions;
|
|
1627
|
+
reductions.forEach(function(red) {
|
|
1628
|
+
if (red.rule.position !== 0)
|
|
1629
|
+
R.push(new ReductionItem(u, red.rule, red.rule.position, red.f, z));
|
|
1630
|
+
});
|
|
1631
|
+
} else {
|
|
1632
|
+
// Possibly shouldn't throw?
|
|
1633
|
+
// throw("No actions found in state " + l + " for token " + next_tok.toString(true) + " at " +
|
|
1634
|
+
// next_tok.pos.toString(true));
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
} else {
|
|
1639
|
+
w = new GSSNode(/*labelled*/l);
|
|
1640
|
+
w.parentSetId = U_i.id;
|
|
1641
|
+
U_i.add(w);
|
|
1642
|
+
// console.log("Added " + w + " to U[" + i + "] ==> " + U_i);
|
|
1643
|
+
// console.log("2. Adding link from " + w + " to " + u + " labelled " + z);
|
|
1644
|
+
thiz.addLink(/*from*/w,/*to*/u,/*labelled*/z);
|
|
1645
|
+
var actions = thiz.getActions(l, cur_tok);
|
|
1646
|
+
if (actions !== undefined) {
|
|
1647
|
+
var ph = actions.push;
|
|
1648
|
+
if (ph !== undefined)
|
|
1649
|
+
Q.push(new ShiftPair(w, ph));
|
|
1650
|
+
var reductions = actions.reductions;
|
|
1651
|
+
// console.log("reductions(" + l + ", " + cur_tok.toString(true) + ") = " + reductions);
|
|
1652
|
+
reductions.forEach(function(red) {
|
|
1653
|
+
if (red.rule.position === 0)
|
|
1654
|
+
// the label here is irrelevant, because m == 0 means the rest of the rule derives EPSILON
|
|
1655
|
+
R.push(new ReductionItem(w, red.rule, 0, red.f, EPSILON));
|
|
1656
|
+
});
|
|
1657
|
+
if (m !== 0) {
|
|
1658
|
+
reductions.forEach(function(red) {
|
|
1659
|
+
if (red.rule.position !== 0)
|
|
1660
|
+
R.push(new ReductionItem(u, red.rule, red.rule.position, red.f, z));
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
} else {
|
|
1664
|
+
// Possibly shouldn't throw?
|
|
1665
|
+
// throw("No actions found in state " + l + " for token " + next_tok.toString(true) + " at " +
|
|
1666
|
+
// next_tok.pos.toString(true));
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
// console.log("R.length = " + R.length);
|
|
1670
|
+
// R.debugPrint();
|
|
1671
|
+
if (m !== 0) {
|
|
1672
|
+
var labels = p.labels.slice(0);
|
|
1673
|
+
labels.push(y_m);
|
|
1674
|
+
thiz.addChildren(item.rule, z, labels, f, skipped_WS_loc !== undefined ? skipped_WS_loc.posAtStart() : cur_tok.pos.posAtStart());
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
},
|
|
1679
|
+
|
|
1680
|
+
addLink: function(rightSib, leftSib, val) {
|
|
1681
|
+
var link = undefined;
|
|
1682
|
+
for (var i = 0; i < rightSib.links.length; i++) {
|
|
1683
|
+
if (rightSib.links[i].prev === leftSib) {
|
|
1684
|
+
link = rightSib.links[i];
|
|
1685
|
+
break;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
if (link === undefined) {
|
|
1689
|
+
link = new Link(leftSib, val);
|
|
1690
|
+
rightSib.links.push(link);
|
|
1691
|
+
// console.log("Linking " + leftSib.toString() + " <-- " + rightSib.toString() + " with val " + val + "@" + val.pos);
|
|
1692
|
+
return link;
|
|
1693
|
+
} else {
|
|
1694
|
+
// console.log("Link already exists between " + leftSib.toString() + " <-- " + rightSib.toString());
|
|
1695
|
+
return undefined;
|
|
1696
|
+
}
|
|
1697
|
+
},
|
|
1698
|
+
|
|
1699
|
+
shifter: function(U, R, Q, N, i, cur_tok, next_tok) {
|
|
1700
|
+
// cur_tok = token #i+1: i starts at index 0, and tokens start at index 1
|
|
1701
|
+
// next_tok = token #i+2
|
|
1702
|
+
// U is an array of sets of GSS nodes
|
|
1703
|
+
// R is the worklist of pending reductions
|
|
1704
|
+
// Q is the set of (GSS node, token) pairs of pending shifts
|
|
1705
|
+
// N is the set of SPPF nodes created in this step
|
|
1706
|
+
var success = false;
|
|
1707
|
+
if (cur_tok !== EOF) { // if i != d, in the paper, where d is the last token number
|
|
1708
|
+
// Q.debugPrint();
|
|
1709
|
+
var Qprime = new Queue([]);
|
|
1710
|
+
var z = new SPPFNode(cur_tok, cur_tok.pos);
|
|
1711
|
+
var U_i1 = U[i+1] = new KeyedSet("label");
|
|
1712
|
+
U_i1.id = i + 1;
|
|
1713
|
+
while (Q.length > 0) {
|
|
1714
|
+
var item = Q.shift();
|
|
1715
|
+
var v = item.gssNode;
|
|
1716
|
+
var k = item.state;
|
|
1717
|
+
var w = U_i1.itemForKey(k);
|
|
1718
|
+
// console.log("item = " + item + ", k = " + k + " and therefore w = " + w);
|
|
1719
|
+
if (w !== undefined) {
|
|
1720
|
+
success = true;
|
|
1721
|
+
this.addLink(/*from*/w, /*to*/v, /*labelled*/z);
|
|
1722
|
+
var actions = this.getActions(k, next_tok);
|
|
1723
|
+
if (actions !== undefined) {
|
|
1724
|
+
var reductions = actions.reductions;
|
|
1725
|
+
reductions.forEach(function(red) {
|
|
1726
|
+
if (red.rule.position !== 0)
|
|
1727
|
+
R.push(new ReductionItem(v, red.rule, red.rule.position, red.f, z));
|
|
1728
|
+
});
|
|
1729
|
+
} else {
|
|
1730
|
+
// Possibly shouldn't throw?
|
|
1731
|
+
// throw("No actions found in state " + k + " for token " + next_tok.toString(true) + " at " +
|
|
1732
|
+
// next_tok.pos.toString(true));
|
|
1733
|
+
}
|
|
1734
|
+
} else {
|
|
1735
|
+
w = new GSSNode(/*labelled*/k);
|
|
1736
|
+
w.parentSetId = U_i1.id;
|
|
1737
|
+
U_i1.add(w);
|
|
1738
|
+
// console.log("Added " + w + " to U[" + (i + 1) + "] ==> " + U_i1);
|
|
1739
|
+
this.addLink(/*from*/w, /*to*/v, /*labelled*/z);
|
|
1740
|
+
|
|
1741
|
+
var actions = this.getActions(k, next_tok);
|
|
1742
|
+
// console.log("next_tok = " + next_tok.toString(true) + ", k = " + k + ", actions = " + JSON.stringify(actions));
|
|
1743
|
+
if (actions !== undefined) {
|
|
1744
|
+
success = true;
|
|
1745
|
+
var ph = actions.push;
|
|
1746
|
+
if (ph !== undefined) {
|
|
1747
|
+
var sp = new ShiftPair(w, ph);
|
|
1748
|
+
// console.log("Pushing " + sp + " onto Q'");
|
|
1749
|
+
Qprime.push(sp);
|
|
1750
|
+
}
|
|
1751
|
+
var reductions = actions.reductions;
|
|
1752
|
+
// console.log("Reductions for k = " + k + " next_tok = " + next_tok + " are " + reductions);
|
|
1753
|
+
reductions.forEach(function(red) {
|
|
1754
|
+
// console.log("red.f = " + red.f + ", red.rule.position = " + red.rule.position);
|
|
1755
|
+
if (red.rule.position !== 0) {
|
|
1756
|
+
R.push(new ReductionItem(v, red.rule, red.rule.position, red.f, z));
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
reductions.forEach(function(red) {
|
|
1760
|
+
if (red.rule.position === 0) {
|
|
1761
|
+
// the label here is irrelevant, because m == 0 means the rest of the rule derives EPSILON
|
|
1762
|
+
R.push(new ReductionItem(w, red.rule, 0, red.f, EPSILON));
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1765
|
+
// console.log("R = ");
|
|
1766
|
+
// R.debugPrint();
|
|
1767
|
+
} else {
|
|
1768
|
+
// Possibly shouldn't throw?
|
|
1769
|
+
// throw("No actions found in state " + k + " for token " + next_tok.toString(true) + " at " +
|
|
1770
|
+
// next_tok.pos.toString(true));
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
while (Qprime.length > 0)
|
|
1775
|
+
Q.push(Qprime.shift());
|
|
1776
|
+
// console.log("At the end of shifter(" + i + "), Q = ");
|
|
1777
|
+
// Q.debugPrint();
|
|
1778
|
+
}
|
|
1779
|
+
return success;
|
|
1780
|
+
},
|
|
1781
|
+
|
|
1782
|
+
addChildren: function(rule, y, kids, f, pos) {
|
|
1783
|
+
var lambda = kids.slice(0);
|
|
1784
|
+
if (f !== 0)
|
|
1785
|
+
lambda.push(this.getEpsilonSPPF(f, pos));
|
|
1786
|
+
// Find lambda in the kids of y
|
|
1787
|
+
function examine(y_rule, y_kids) {
|
|
1788
|
+
if (y_rule !== rule) return false;
|
|
1789
|
+
if (y_kids.length !== lambda.length) return false;
|
|
1790
|
+
for (var i = 0; i < y_kids.length; i++)
|
|
1791
|
+
if (y_kids[i] !== lambda[i]) return false;
|
|
1792
|
+
return true;
|
|
1793
|
+
}
|
|
1794
|
+
var found = false;
|
|
1795
|
+
if (y.kids) {
|
|
1796
|
+
found = examine(y.rule, y.kids);
|
|
1797
|
+
} else if (y.ambig) {
|
|
1798
|
+
for (var i = 0; i < y.ambig.length; i++)
|
|
1799
|
+
if (examine(y.ambig[i].rule, y.ambig[i].kids)) {
|
|
1800
|
+
found = true;
|
|
1801
|
+
break;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
if (!found)
|
|
1805
|
+
y.addChildren(rule, lambda, this);
|
|
1806
|
+
},
|
|
1807
|
+
|
|
1808
|
+
getActions: function(state, tok) {
|
|
1809
|
+
var tableRow = this.rnTable[state];
|
|
1810
|
+
var actions1 = tableRow[tok.asString];
|
|
1811
|
+
return actions1;
|
|
1812
|
+
},
|
|
1813
|
+
/*
|
|
1814
|
+
printSPPFasDot: function() {
|
|
1815
|
+
var ret = [];
|
|
1816
|
+
ret.push("digraph " + this.name + "_SPPF {");
|
|
1817
|
+
ret.push(" rankdir=RL; clusterrank=local;");
|
|
1818
|
+
ret.push(" // Nodes");
|
|
1819
|
+
for (var i = 0; i < SPPFNode.allNodes.length; i++) {
|
|
1820
|
+
var node = SPPFNode.allNodes[i];
|
|
1821
|
+
var style = "";
|
|
1822
|
+
if (node.inline)
|
|
1823
|
+
style = ", style=dashed";
|
|
1824
|
+
var label = "SPPFNode #" + node.sppfId;
|
|
1825
|
+
if (node.inline)
|
|
1826
|
+
label += "\nInlined e-SPPF for " + node.label;
|
|
1827
|
+
else
|
|
1828
|
+
label += "\nLabel: " + node.label.toString(true);
|
|
1829
|
+
if (node.rule)
|
|
1830
|
+
label += "\nRule: " + node.rule.toString();
|
|
1831
|
+
else if (node.ambig)
|
|
1832
|
+
label += "\nMultiple derivations";
|
|
1833
|
+
|
|
1834
|
+
ret.push(" " + node.sppfId + " [label=" + JSON.stringify(label) + style + "];");
|
|
1835
|
+
if (node.ambig !== undefined) {
|
|
1836
|
+
for (var j = 0; j < node.ambig.length; j++) {
|
|
1837
|
+
ret.push(" \"" + node.sppfId + "_" + j
|
|
1838
|
+
+ "\" [label=" + JSON.stringify(node.ambig[j].rule.toString()) +", shape=box];");
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
ret.push(" // Edges");
|
|
1843
|
+
for (var i = 0; i < SPPFNode.allNodes.length; i++) {
|
|
1844
|
+
var node = SPPFNode.allNodes[i];
|
|
1845
|
+
if (node.kids !== undefined)
|
|
1846
|
+
for (var j = 0; j < node.kids.length; j++)
|
|
1847
|
+
ret.push(" " + node.sppfId + " -> " + node.kids[j].sppfId
|
|
1848
|
+
+ " [label=\"" + j + "\"];");
|
|
1849
|
+
else if (node.ambig !== undefined) {
|
|
1850
|
+
for (var j = 0; j < node.ambig.length; j++) {
|
|
1851
|
+
ret.push(" " + node.sppfId + " -> \"" + node.sppfId + "_" + j + "\";");
|
|
1852
|
+
for (var k = 0; k < node.ambig[j].kids.length; k++)
|
|
1853
|
+
ret.push(" \"" + node.sppfId + "_" + j + "\" -> " + node.ambig[j].kids[k].sppfId
|
|
1854
|
+
+ " [label=\"" + k + "\"];");
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
ret.push("}");
|
|
1859
|
+
return ret.join("\n");
|
|
1860
|
+
},
|
|
1861
|
+
|
|
1862
|
+
printGSSasDot: function() {
|
|
1863
|
+
var ret = [];
|
|
1864
|
+
ret.push("digraph " + this.name + "_GSS {");
|
|
1865
|
+
ret.push(" rankdir=RL; clusterrank=local;");
|
|
1866
|
+
ret.push(" // Nodes");
|
|
1867
|
+
for (var i = 0; i < GSSNode.allNodes.length; i++) {
|
|
1868
|
+
var node = GSSNode.allNodes[i];
|
|
1869
|
+
ret.push(" " + node.gssId + "[label=" + JSON.stringify(node.toString()) + "];");
|
|
1870
|
+
}
|
|
1871
|
+
ret.push(" // Ranks");
|
|
1872
|
+
for (var i = 0; i < this.U.length; i++) {
|
|
1873
|
+
var s = "";
|
|
1874
|
+
for (var j = 0; j < this.U[i].size(); j++)
|
|
1875
|
+
s += " " + this.U[i].get(j).gssId + ";";
|
|
1876
|
+
ret.push(" subgraph cluster" + i + " {");
|
|
1877
|
+
ret.push(" rank = same; color=black;");
|
|
1878
|
+
if (i > 0)
|
|
1879
|
+
ret.push(" label=\"Token " + i + "\"");
|
|
1880
|
+
ret.push(" " + s);
|
|
1881
|
+
ret.push(" }");
|
|
1882
|
+
}
|
|
1883
|
+
ret.push(" // Edges");
|
|
1884
|
+
for (var i = 0; i < GSSNode.allNodes.length; i++) {
|
|
1885
|
+
var node = GSSNode.allNodes[i];
|
|
1886
|
+
for (var j = 0; j < node.links.length; j++)
|
|
1887
|
+
ret.push(" " + node.gssId + " -> " + node.links[j].prev.gssId
|
|
1888
|
+
+ "[label=" + JSON.stringify(node.links[j].val.toString()) + "]"
|
|
1889
|
+
//+ "[label=" + JSON.stringify(JSON.decycle(node.links[j].val), null, " ") + "]"
|
|
1890
|
+
+ ";");
|
|
1891
|
+
}
|
|
1892
|
+
ret.push("}");
|
|
1893
|
+
return ret.join("\n");
|
|
1894
|
+
},
|
|
1895
|
+
*/
|
|
1896
|
+
|
|
1897
|
+
//////////////////////////////////
|
|
1898
|
+
// The RNGLR algorithm
|
|
1899
|
+
// Following Scott & Johnstone '06, TOPLAS 28:4
|
|
1900
|
+
//////////////////////////////////
|
|
1901
|
+
parseRNGLR: function(token_source) {
|
|
1902
|
+
if (token_source.isEmpty()) {
|
|
1903
|
+
if (this.acceptStates[0])
|
|
1904
|
+
return this.getEpsilonSPPF(this.I[this.start.asString], SrcLoc.make(0,0,0,0,0,0));
|
|
1905
|
+
else {
|
|
1906
|
+
console.log("There are zero tokens available, but the grammar does not accept the empty string");
|
|
1907
|
+
return undefined;
|
|
1908
|
+
}
|
|
1909
|
+
} else {
|
|
1910
|
+
var v0 = new GSSNode(0);
|
|
1911
|
+
var U0 = new KeyedSet("label", [v0]);
|
|
1912
|
+
U0.id = 0;
|
|
1913
|
+
v0.parentSetId = U0.id;
|
|
1914
|
+
this.U = [];
|
|
1915
|
+
this.U[0] = U0;
|
|
1916
|
+
var R = new Queue([]);
|
|
1917
|
+
var Q = new Queue([]);
|
|
1918
|
+
var hasNext = true;
|
|
1919
|
+
var cur_tok = token_source.next(); // need to peek at first token
|
|
1920
|
+
var actions = this.getActions(0, cur_tok);
|
|
1921
|
+
// console.log("Actions[0][" + cur_tok.toRepr(true) + "] = " + JSON.stringify(actions));
|
|
1922
|
+
if (actions !== undefined) {
|
|
1923
|
+
var pk = actions.push;
|
|
1924
|
+
if (pk !== undefined)
|
|
1925
|
+
Q.push(new ShiftPair(v0, pk));
|
|
1926
|
+
// console.log("Q = ");
|
|
1927
|
+
// Q.debugPrint();
|
|
1928
|
+
var reductions = actions.reductions;
|
|
1929
|
+
reductions.forEach(function(red) {
|
|
1930
|
+
if (red.rule.position === 0)
|
|
1931
|
+
// Again, label shouldn't matter because length is 0
|
|
1932
|
+
R.push(new ReductionItem(v0, red.rule, 0, red.f, EPSILON));
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
// console.log("R = ");
|
|
1936
|
+
// R.debugPrint();
|
|
1937
|
+
var i = 0;
|
|
1938
|
+
// try {
|
|
1939
|
+
while (hasNext && this.U[i].size() > 0) {
|
|
1940
|
+
var N = new Queue([]);
|
|
1941
|
+
// console.log("Phase 1: reducing due to token #" + i + ": " + cur_tok.toRepr(true));
|
|
1942
|
+
while (R.length > 0) {
|
|
1943
|
+
this.reducer(this.U, R, Q, N, i, cur_tok, token_source.skippedWhitespace);
|
|
1944
|
+
}
|
|
1945
|
+
hasNext = token_source.hasNext();
|
|
1946
|
+
var next_tok = hasNext ? token_source.next() : undefined;
|
|
1947
|
+
// console.log("Phase 2: shifting token #" + i + ": " + cur_tok.toRepr(true));
|
|
1948
|
+
hasNext = this.shifter(this.U, R, Q, N, i, cur_tok, next_tok) && hasNext;
|
|
1949
|
+
if (hasNext) {
|
|
1950
|
+
cur_tok = next_tok;
|
|
1951
|
+
} else {
|
|
1952
|
+
token_source.unshiftToken(cur_tok);
|
|
1953
|
+
}
|
|
1954
|
+
i++;
|
|
1955
|
+
}
|
|
1956
|
+
// console.log("DONE WITH LOOP, i = " + i
|
|
1957
|
+
// + ", last token = " + cur_tok.toString(true) + "@" + cur_tok.pos.toString(true)
|
|
1958
|
+
// + ", hasNext = " + hasNext + ", final set emptied out: " + (this.U[i].size() == 0));
|
|
1959
|
+
if (!hasNext) i--;
|
|
1960
|
+
// console.log("Finalizing: i = " + i + " and U[i] = " + this.U[i]);
|
|
1961
|
+
for (var acc = 0; acc < this.acceptStates.length; acc++) {
|
|
1962
|
+
if (this.acceptStates[acc]) {
|
|
1963
|
+
//console.log("Searching for " + acc);
|
|
1964
|
+
var t = this.U[i].itemForKey(acc);
|
|
1965
|
+
if (t !== undefined) {
|
|
1966
|
+
//console.log("Parse success!");
|
|
1967
|
+
var link = undefined;
|
|
1968
|
+
for (var j = 0; j < t.links.length; j++) {
|
|
1969
|
+
if (t.links[j].prev === v0) {
|
|
1970
|
+
link = t.links[j];
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
if (link !== undefined) {
|
|
1975
|
+
return link.val;
|
|
1976
|
+
} else
|
|
1977
|
+
console.log("Couldn't find correct link in " + JSON.stringify(JSON.decycle(t), null, " "));
|
|
1978
|
+
} else {
|
|
1979
|
+
//console.log("Parse failure");
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
// // Collect error information
|
|
1984
|
+
// if (i > 0) {
|
|
1985
|
+
// var acc = undefined;
|
|
1986
|
+
// for (var j = 0; j < this.U[i - 1].size(); j++) {
|
|
1987
|
+
// var head = this.U[i - 1].get(j);
|
|
1988
|
+
// console.log("For token " + i + ", " + cur_tok + ", head is in state " + head.label);
|
|
1989
|
+
// acc = this.plausibleTokensForState(head.label, acc);
|
|
1990
|
+
// }
|
|
1991
|
+
// throw(acc);
|
|
1992
|
+
// }
|
|
1993
|
+
// } catch(e) {
|
|
1994
|
+
// console.log(e);
|
|
1995
|
+
// return undefined;
|
|
1996
|
+
// }
|
|
1997
|
+
}
|
|
1998
|
+
},
|
|
1999
|
+
|
|
2000
|
+
plausibleTokensForState: function(state, ret) {
|
|
2001
|
+
if (ret === undefined)
|
|
2002
|
+
ret = {};
|
|
2003
|
+
for (var j = 0; j < this.tokens.size(); j++) {
|
|
2004
|
+
var tok = this.tokens.get(j);
|
|
2005
|
+
var actions = this.getActions(state, tok);
|
|
2006
|
+
if (tok !== EPSILON && actions !== undefined &&
|
|
2007
|
+
(actions.push !== undefined || (actions.reductions !== undefined && actions.reductions.size > 0))) {
|
|
2008
|
+
console.log("In state " + state + " for token " + tok + ", actions = " + JSON.stringify([...actions.reductions]));
|
|
2009
|
+
ret[tok] = true;
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
return ret;
|
|
2013
|
+
},
|
|
2014
|
+
|
|
2015
|
+
constructAllParses: function(sppfNode, semActions) {
|
|
2016
|
+
if (sppfNode === undefined) return undefined;
|
|
2017
|
+
if (sppfNode.label instanceof Token) {
|
|
2018
|
+
return [sppfNode.label];
|
|
2019
|
+
}
|
|
2020
|
+
var options = undefined;
|
|
2021
|
+
if (sppfNode.ambig)
|
|
2022
|
+
options = sppfNode.ambig;
|
|
2023
|
+
else
|
|
2024
|
+
options = [{kids: sppfNode.kids, rule: sppfNode.rule}];
|
|
2025
|
+
var ret = [];
|
|
2026
|
+
for (var i = 0; i < options.length; i++) {
|
|
2027
|
+
var kids = options[i].kids;
|
|
2028
|
+
var rule = options[i].rule;
|
|
2029
|
+
var kidsParses = [];
|
|
2030
|
+
for (var j = 0; j < kids.length; j++) {
|
|
2031
|
+
if (kids[j].rule === undefined && kids[j].ambig === undefined && kids[j].inline === true) {
|
|
2032
|
+
for (var k = 0; k < kids[j].kids.length; k++) {
|
|
2033
|
+
kidsParses.push([this.applyAction(kids[j].kids[k].rule, kids[j].kids[k].kids, kids[j].kids[k].pos, semActions)]);
|
|
2034
|
+
}
|
|
2035
|
+
} else if (kids[j].rule === undefined && kids[j].kids !== undefined && kids[j].label.indexOf(',') > -1) {
|
|
2036
|
+
for (var k = 0; k < kids[j].kids.length; k++) {
|
|
2037
|
+
kidsParses.push(this.constructAllParses(kids[j].kids[k], semActions));
|
|
2038
|
+
}
|
|
2039
|
+
} else {
|
|
2040
|
+
kidsParses.push(this.constructAllParses(kids[j], semActions));
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
const thiz = this;
|
|
2044
|
+
ret = ret.concat(this.cartesian(kidsParses, 0, [],
|
|
2045
|
+
function(kids) { return thiz.applyAction(rule, kids, sppfNode.pos, semActions); }));
|
|
2046
|
+
}
|
|
2047
|
+
return ret;
|
|
2048
|
+
},
|
|
2049
|
+
cartesian: function(arrays, idx, arr, callback) {
|
|
2050
|
+
if (arrays.length == idx) return callback(arr);
|
|
2051
|
+
var ret = [];
|
|
2052
|
+
for (var i = 0; i < arrays[idx].length; i++) {
|
|
2053
|
+
ret = ret.concat(this.cartesian(arrays, idx+1, arr.concat(arrays[idx][i]), callback));
|
|
2054
|
+
}
|
|
2055
|
+
return ret;
|
|
2056
|
+
},
|
|
2057
|
+
|
|
2058
|
+
countAllParses: function(sppfNode) {
|
|
2059
|
+
if (sppfNode === undefined) return 0;
|
|
2060
|
+
var todo = [[[sppfNode]]]; // stack of alternate lists of children
|
|
2061
|
+
var count = [[[]], [[]]]; // stack of sums of factors
|
|
2062
|
+
while (todo.length > 0) {
|
|
2063
|
+
var top = todo[todo.length - 1];
|
|
2064
|
+
var topCount = count[count.length - 1];
|
|
2065
|
+
if (top.length === 0) { // done with all parses of a given node
|
|
2066
|
+
todo.pop();
|
|
2067
|
+
count.pop();
|
|
2068
|
+
var tot = 0;
|
|
2069
|
+
for (var i = 0; i < topCount.length; i++) {
|
|
2070
|
+
var prod = 1;
|
|
2071
|
+
for (var j = 0; j < topCount[i].length; j++)
|
|
2072
|
+
prod *= topCount[i][j];
|
|
2073
|
+
tot += prod;
|
|
2074
|
+
}
|
|
2075
|
+
var newTopCount = count[count.length - 1];
|
|
2076
|
+
newTopCount[newTopCount.length - 1].push(tot);
|
|
2077
|
+
} else if (top[top.length - 1].length === 0) { // done with one alternative
|
|
2078
|
+
top.pop();
|
|
2079
|
+
if (top.length > 0) {
|
|
2080
|
+
topCount.push([]);
|
|
2081
|
+
}
|
|
2082
|
+
} else {
|
|
2083
|
+
var node = top[top.length - 1].pop();
|
|
2084
|
+
if (node.label instanceof Token) {
|
|
2085
|
+
topCount[topCount.length - 1].push(1);
|
|
2086
|
+
} else if (node.ambig && node.ambig.length > 0) {
|
|
2087
|
+
count.push([[]]);
|
|
2088
|
+
todo.push(node.ambig.map(function(d) { return d.kids.slice(0); }));
|
|
2089
|
+
} else if (node.kids && node.kids.length > 0) {
|
|
2090
|
+
count.push([[]]);
|
|
2091
|
+
todo.push([node.kids.slice(0)]);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
if (count.length > 0 && count[0].length > 0 && count[0][0].length > 0)
|
|
2096
|
+
return count[0][0][0];
|
|
2097
|
+
else
|
|
2098
|
+
throw count;
|
|
2099
|
+
},
|
|
2100
|
+
|
|
2101
|
+
constructUniqueParse: function(sppfNode, semActions) {
|
|
2102
|
+
if (sppfNode === undefined) return undefined;
|
|
2103
|
+
// Each stack item is a pair {todo, done}, where todo is a list of children
|
|
2104
|
+
// in reverse order (so that pop goes from left-to-right in actual tree order)
|
|
2105
|
+
// and done is a list of children in tree order
|
|
2106
|
+
// If there are nodes todo:
|
|
2107
|
+
// We examine the pop()ed node from stack[TOP].todo:
|
|
2108
|
+
// if it has kids, we push a new stack item
|
|
2109
|
+
// otherwise, we move it over
|
|
2110
|
+
// Otherwise we reduce
|
|
2111
|
+
var stack = [{todo: [sppfNode], done: []}];
|
|
2112
|
+
while (stack.length > 0 && stack[0].todo.length > 0) {
|
|
2113
|
+
var curr = stack[stack.length - 1];
|
|
2114
|
+
if (curr.todo.length > 0) {
|
|
2115
|
+
var next = curr.todo[curr.todo.length - 1];
|
|
2116
|
+
if (next.label instanceof Token) {
|
|
2117
|
+
curr.todo.pop();
|
|
2118
|
+
curr.done.push(next.label);
|
|
2119
|
+
} else if (next.ambig) {
|
|
2120
|
+
throw("Not a unique parse");
|
|
2121
|
+
} else if (next.rule === undefined && next.label.indexOf(',') > -1) {
|
|
2122
|
+
curr.todo.pop();
|
|
2123
|
+
for (var k = next.kids.length - 1; k >= 0; k--)
|
|
2124
|
+
curr.todo.unshift(next.kids[k]);
|
|
2125
|
+
} else if (next.kids.length == 0) {
|
|
2126
|
+
// Optimization for nullary nonterminals
|
|
2127
|
+
curr.todo.pop();
|
|
2128
|
+
var pos = curr.done.length > 0 ? curr.done[curr.done.length - 1].pos : next.pos;
|
|
2129
|
+
curr.done.push(this.applyAction(next.rule, [], pos, semActions))
|
|
2130
|
+
} else {
|
|
2131
|
+
stack.push({todo: next.kids.slice(0).reverse(), done: []});
|
|
2132
|
+
}
|
|
2133
|
+
} else {
|
|
2134
|
+
if (stack.length > 1) {
|
|
2135
|
+
stack.pop();
|
|
2136
|
+
var prev = stack[stack.length - 1];
|
|
2137
|
+
var toReduce = prev.todo.pop();
|
|
2138
|
+
if (toReduce.rule === undefined) {
|
|
2139
|
+
function jsonPos(key, value) {
|
|
2140
|
+
if (key === "pos") { return "SrcLoc(" + value.toString(true) + ")"; }
|
|
2141
|
+
else { return value; }
|
|
2142
|
+
}
|
|
2143
|
+
throw("Cannot find a reduction rule on " + JSON.stringify(toReduce, jsonPos, " "));
|
|
2144
|
+
} else {
|
|
2145
|
+
prev.done.push(this.applyAction(toReduce.rule, curr.done, toReduce.pos, semActions));
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return stack[0].done[0];
|
|
2151
|
+
},
|
|
2152
|
+
|
|
2153
|
+
constructNextParse: function(sppfNode, semActions, directions) {
|
|
2154
|
+
if (sppfNode === undefined) return undefined;
|
|
2155
|
+
// Directions contains an array of pairs {choice, of}
|
|
2156
|
+
// saying which index choice (out of how many choices) at an ambig node
|
|
2157
|
+
// was taken by the previous parse.
|
|
2158
|
+
// To compute the next parse, remove all trailing pairs for which choice == of,
|
|
2159
|
+
// then increment the last remaining choice
|
|
2160
|
+
var newDirs = [];
|
|
2161
|
+
if (directions) {
|
|
2162
|
+
var lastIndex = directions.length - 1;
|
|
2163
|
+
while (lastIndex >= directions[lastIndex].choice == directions[lastIndex].of)
|
|
2164
|
+
lastIndex--;
|
|
2165
|
+
if (lastIndex < 0) return undefined;
|
|
2166
|
+
for (var i = 0; i < lastIndex; i++)
|
|
2167
|
+
newDirs[i] = directions[i];
|
|
2168
|
+
newDirs[lastIndex] = {choice: directions[i].choice + 1, of: directions[i].of};
|
|
2169
|
+
}
|
|
2170
|
+
var stack = [{todo: [sppfNode], done: []}];
|
|
2171
|
+
var curDir = 0;
|
|
2172
|
+
while (stack.length > 0 && stack[0].todo.length > 0) {
|
|
2173
|
+
var curr = stack[stack.length - 1];
|
|
2174
|
+
if (curr.todo.length > 0) {
|
|
2175
|
+
var next = curr.todo[curr.todo.length - 1];
|
|
2176
|
+
if (next.label instanceof Token) {
|
|
2177
|
+
curr.todo.pop();
|
|
2178
|
+
curr.done.push(next.label);
|
|
2179
|
+
} else if (next.rule === undefined && next.label.indexOf(',') > -1) {
|
|
2180
|
+
curr.todo.pop();
|
|
2181
|
+
for (var k = next.kids.length - 1; k >= 0; k--)
|
|
2182
|
+
curr.todo.unshift(next.kids[k]);
|
|
2183
|
+
} else if (next.ambig) {
|
|
2184
|
+
if (curDir < newDirs.length) {
|
|
2185
|
+
next = next.ambig[newDirs[curDir++].choice];
|
|
2186
|
+
} else {
|
|
2187
|
+
newDirs.push({choice: 0, of: next.ambig.length})
|
|
2188
|
+
next = next.ambig[0];
|
|
2189
|
+
}
|
|
2190
|
+
if (next.kids.length == 0) {
|
|
2191
|
+
// Optimization for nullary nonterminals
|
|
2192
|
+
curr.todo.pop();
|
|
2193
|
+
var pos = curr.done.length > 0 ? curr.done[curr.done.length - 1].pos : next.pos;
|
|
2194
|
+
curr.done.push(this.applyAction(next.rule, [], pos, semActions))
|
|
2195
|
+
} else {
|
|
2196
|
+
stack.push({todo: next.kids.slice(0).reverse(), done: []});
|
|
2197
|
+
}
|
|
2198
|
+
} else if (next.kids.length == 0) {
|
|
2199
|
+
// Optimization for nullary nonterminals
|
|
2200
|
+
curr.todo.pop();
|
|
2201
|
+
var pos = curr.done.length > 0 ? curr.done[curr.done.length - 1].pos : next.pos;
|
|
2202
|
+
curr.done.push(this.applyAction(next.rule, [], pos, semActions))
|
|
2203
|
+
} else {
|
|
2204
|
+
stack.push({todo: next.kids.slice(0).reverse(), done: []});
|
|
2205
|
+
}
|
|
2206
|
+
} else {
|
|
2207
|
+
if (stack.length > 1) {
|
|
2208
|
+
stack.pop();
|
|
2209
|
+
var prev = stack[stack.length - 1];
|
|
2210
|
+
var toReduce = prev.todo.pop();
|
|
2211
|
+
if (toReduce.rule === undefined) {
|
|
2212
|
+
function jsonPos(key, value) {
|
|
2213
|
+
if (key === "pos") { return "SrcLoc(" + value.toString(true) + ")"; }
|
|
2214
|
+
else { return value; }
|
|
2215
|
+
}
|
|
2216
|
+
throw("Cannot find a reduction rule on " + JSON.stringify(toReduce, jsonPos, " "));
|
|
2217
|
+
} else {
|
|
2218
|
+
prev.done.push(this.applyAction(toReduce.rule, curr.done, toReduce.pos, semActions));
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
return {parse: stack[0].done[0], directions: newDirs};
|
|
2224
|
+
},
|
|
2225
|
+
checkPositionContainment: function(sppfNode) {
|
|
2226
|
+
if (sppfNode === undefined) return undefined;
|
|
2227
|
+
var violations = [];
|
|
2228
|
+
//var worklist = [sppfNode];
|
|
2229
|
+
function helper(node) {
|
|
2230
|
+
var pos = node.pos;
|
|
2231
|
+
if (node.kids) {
|
|
2232
|
+
for (var i = 0; i < node.kids.length; i++) {
|
|
2233
|
+
var kidPos = node.kids[i].pos;
|
|
2234
|
+
if (kidPos.startChar < pos.startChar || kidPos.endChar > pos.endChar) {
|
|
2235
|
+
violations.push(node);
|
|
2236
|
+
break;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
} else if (node.ambig) {
|
|
2240
|
+
for (var i = 0; i < node.ambig.length; i++) {
|
|
2241
|
+
var kids = node.ambig[i].kids;
|
|
2242
|
+
var shouldBreak = false
|
|
2243
|
+
for (var j = 0; j < kids.length; j++) {
|
|
2244
|
+
var kidPos = kids[j].pos;
|
|
2245
|
+
if (kidPos.startChar < pos.startChar || kidPos.endChar > pos.endChar) {
|
|
2246
|
+
violations.push(node);
|
|
2247
|
+
shouldBreak = true;
|
|
2248
|
+
break;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
if (shouldBreak) break;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
helper(sppfNode);
|
|
2256
|
+
if (violations.length > 0) return violations;
|
|
2257
|
+
return false;
|
|
2258
|
+
},
|
|
2259
|
+
|
|
2260
|
+
computeRequiredNullableParts: function() {
|
|
2261
|
+
// The I dictionary is an index of all nullable nonterminals and (nonempty) strings of
|
|
2262
|
+
// nonterminals that appear as right-hand tails in rules in the grammar.
|
|
2263
|
+
// The eSPPFs table is a dictionary indexed first by I value and second by position.
|
|
2264
|
+
// We already ensure that position objects are singletons, and this second-level
|
|
2265
|
+
// dictionary ensures that e-SPPFs are singletons too, for each position in the
|
|
2266
|
+
// parse tree for which they are needed. This helps ensure that finding existing links
|
|
2267
|
+
// doesn't create duplicates and therefore does't cause duplicate parses, later.
|
|
2268
|
+
allowNull = true;
|
|
2269
|
+
this.I = {};
|
|
2270
|
+
this.I[EPSILON.asString] = 0;
|
|
2271
|
+
this.eSPPFs = [];
|
|
2272
|
+
this.eSPPFs[0] = {null: new SPPFNode(EPSILON, null)};
|
|
2273
|
+
// Initialize all eSPPFs to empty nodes
|
|
2274
|
+
for (var name in this.rules) {
|
|
2275
|
+
if (this.derivable[name][EPSILON.asString] !== true) continue;
|
|
2276
|
+
var name_eSPPF = new SPPFNode(name, null);
|
|
2277
|
+
this.I[name] = this.eSPPFs.length;
|
|
2278
|
+
this.eSPPFs.push({null: name_eSPPF});
|
|
2279
|
+
}
|
|
2280
|
+
// Compute the e-closure of the rules
|
|
2281
|
+
for (var name in this.rules) {
|
|
2282
|
+
if (this.derivable[name][EPSILON.asString] !== true) continue;
|
|
2283
|
+
var rules_name = this.rules[name];
|
|
2284
|
+
var name_eSPPF = this.eSPPFs[this.I[name]].null;
|
|
2285
|
+
for (var i = 0; i < rules_name.length; i++) {
|
|
2286
|
+
var rule = rules_name[i];
|
|
2287
|
+
if (this.computeFirstOfStrings(rule.symbols).contains(EPSILON)) {
|
|
2288
|
+
var kids = [];
|
|
2289
|
+
for (var j = 0; j < rule.symbols.length; j++) {
|
|
2290
|
+
kids.push(this.eSPPFs[this.I[rule.symbols[j].asString]].null);
|
|
2291
|
+
}
|
|
2292
|
+
name_eSPPF.addChildren(rule, kids, this);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
// Compute required nullable parts
|
|
2297
|
+
for (var name in this.rules) {
|
|
2298
|
+
var rules_name = this.rules[name];
|
|
2299
|
+
for (var i = 0; i < rules_name.length; i++) {
|
|
2300
|
+
var rule = rules_name[i];
|
|
2301
|
+
for (var j = 1/*note: not 0*/; j < rule.symbols.length; j++) {
|
|
2302
|
+
var slice = rule.symbols.slice(j);
|
|
2303
|
+
var sliceStrs = slice.map((s) => s.asString);
|
|
2304
|
+
var sliceStr = "" + sliceStrs;
|
|
2305
|
+
if (this.computeFirstOfStrings(slice).contains(EPSILON) && this.I[sliceStr] === undefined) {
|
|
2306
|
+
var eSPPF_slice = new SPPFNode(sliceStr, null);
|
|
2307
|
+
eSPPF_slice.inline = true;
|
|
2308
|
+
var kids = [];
|
|
2309
|
+
for (var k = 0; k < slice.length; k++)
|
|
2310
|
+
kids[k] = this.eSPPFs[this.I[sliceStrs[k]]].null;
|
|
2311
|
+
eSPPF_slice.kids = kids;
|
|
2312
|
+
this.I[sliceStrs] = this.eSPPFs.length;
|
|
2313
|
+
this.eSPPFs.push({null: eSPPF_slice});
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
allowNull = false;
|
|
2319
|
+
},
|
|
2320
|
+
getI: function(rule) {
|
|
2321
|
+
var ret = undefined;
|
|
2322
|
+
if (rule.position === 0) ret = this.I[rule.name];
|
|
2323
|
+
else if (rule.position === rule.symbols.length) ret = this.I[EPSILON.asString];
|
|
2324
|
+
else ret = this.I[rule.symbols.slice(rule.position).map((s) => s.asString)];
|
|
2325
|
+
return ret;
|
|
2326
|
+
},
|
|
2327
|
+
getEpsilonSPPF: function(i, pos) {
|
|
2328
|
+
function find(node, cache) {
|
|
2329
|
+
for (var i = 0; i < cache.length; i++) {
|
|
2330
|
+
if (cache[i].key === node) {
|
|
2331
|
+
return cache[i].value;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
return undefined;
|
|
2335
|
+
}
|
|
2336
|
+
function clone(node, cache) {
|
|
2337
|
+
var ret = find(node, cache);
|
|
2338
|
+
if (ret !== undefined) return ret;
|
|
2339
|
+
ret = {};
|
|
2340
|
+
cache.push({key: node, value: ret});
|
|
2341
|
+
ret.sppfId = node.sppfId;
|
|
2342
|
+
ret.name = node.name;
|
|
2343
|
+
ret.label = node.label;
|
|
2344
|
+
ret.pos = pos;
|
|
2345
|
+
ret.toString = node.toString;
|
|
2346
|
+
ret.rule = node.rule;
|
|
2347
|
+
ret.inline = node.inline;
|
|
2348
|
+
if (node.kids !== undefined) {
|
|
2349
|
+
ret.kids = [];
|
|
2350
|
+
for (var i = 0; i < node.kids.length; i++) {
|
|
2351
|
+
ret.kids[i] = clone(node.kids[i], cache);
|
|
2352
|
+
}
|
|
2353
|
+
} else if (node.ambig !== undefined) {
|
|
2354
|
+
ret.ambig = [];
|
|
2355
|
+
for (var i = 0; i < node.ambig.length; i++) {
|
|
2356
|
+
var kids = [];
|
|
2357
|
+
ret.ambig.push({kids: kids, rule: node.ambig[i].rule});
|
|
2358
|
+
for (var j = 0; j < node.ambig[i].kids.length; j++) {
|
|
2359
|
+
kids[j] = clone(node.ambig[i].kids[j], cache);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
return ret;
|
|
2364
|
+
}
|
|
2365
|
+
var byI = this.eSPPFs[i];
|
|
2366
|
+
var ret = byI[pos];
|
|
2367
|
+
if (ret === undefined)
|
|
2368
|
+
ret = byI[pos] = clone(byI[null], []);
|
|
2369
|
+
return ret;
|
|
2370
|
+
},
|
|
2371
|
+
resetESPPFs: function() {
|
|
2372
|
+
for (var i = 0; i < this.eSPPFs.length; i++) {
|
|
2373
|
+
this.eSPPFs[i] = {null: this.eSPPFs[i].null};
|
|
2374
|
+
}
|
|
2375
|
+
},
|
|
2376
|
+
|
|
2377
|
+
computeRNTable: function() {
|
|
2378
|
+
const thiz = this;
|
|
2379
|
+
function initTables(index) {
|
|
2380
|
+
var tableRow = thiz.rnTable[index];
|
|
2381
|
+
if (tableRow === undefined)
|
|
2382
|
+
tableRow = thiz.rnTable[index] = {};
|
|
2383
|
+
for (var k = 0; k < thiz.atoms.size(); k++) {
|
|
2384
|
+
if (tableRow[thiz.atoms.get(k).asString] === undefined)
|
|
2385
|
+
tableRow[thiz.atoms.get(k).asString] = {push: undefined, reductions: new Set()};
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
|
|
2390
|
+
initTables(0);
|
|
2391
|
+
// This doesn't seem to be needed, because we always explicitly shift the EOF token
|
|
2392
|
+
// if (this.derivable[this.start][EPSILON] === true) {
|
|
2393
|
+
// this.acceptStates[0] = true;
|
|
2394
|
+
// this.rnTable[0][EOF].accept = true;
|
|
2395
|
+
// }
|
|
2396
|
+
for (var i = 0; i < this.states.size(); i++) {
|
|
2397
|
+
var state_i = this.states.get(i);
|
|
2398
|
+
initTables(i);
|
|
2399
|
+
// console.log("State " + i + " = " + state_i.toString());
|
|
2400
|
+
var full_state = this.completeClosure(state_i);
|
|
2401
|
+
// console.log("FullState " + i + " = " + full_state.toString());
|
|
2402
|
+
for (var j = 0; j < full_state.coreSize(); j++) {
|
|
2403
|
+
var rule_j = full_state.getCore(j);
|
|
2404
|
+
if (rule_j.name === this.start) {
|
|
2405
|
+
if (rule_j.position === rule_j.symbols.length && full_state.getLookaheads(j).contains(EOF)) {
|
|
2406
|
+
this.acceptStates[i] = true;
|
|
2407
|
+
this.rnTable[i][EOF.asString].accept = true;
|
|
2408
|
+
}
|
|
2409
|
+
} else {
|
|
2410
|
+
if (this.computeFollowAtPosition(rule_j, rule_j.position).contains(EPSILON)) {
|
|
2411
|
+
var lookaheads = full_state.getLookaheads(j);
|
|
2412
|
+
for (var k = 0; k < lookaheads.size(); k++) {
|
|
2413
|
+
if (this.rnTable[i][lookaheads.get(k).asString] === undefined) {
|
|
2414
|
+
throw("Can't get rnTable actions for i = " + i + " and symbol = " + lookaheads.get(k).asString + " in rule " + rule_j.toString(true));
|
|
2415
|
+
}
|
|
2416
|
+
this.rnTable[i][lookaheads.get(k).asString].reductions.add(new ReduceAction(rule_j, this.getI(rule_j)));
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
},
|
|
2423
|
+
|
|
2424
|
+
//////////////////////////////////
|
|
2425
|
+
//
|
|
2426
|
+
|
|
2427
|
+
|
|
2428
|
+
//////////////////////////////////
|
|
2429
|
+
// Algorithm 4.13 (p242-243) in Dragon book
|
|
2430
|
+
computeStateKernels: function() {
|
|
2431
|
+
var init_rule = this.rules[this.start][0].withLookahead(EOF);
|
|
2432
|
+
this.init_set = new LR1Set([init_rule]);
|
|
2433
|
+
this.completeClosure(this.init_set, true);
|
|
2434
|
+
var kernelStates = new SetOfSets([this.init_set], LR1Set.equals);
|
|
2435
|
+
this.rnTable = [];
|
|
2436
|
+
// Step 1
|
|
2437
|
+
var worklist = new Queue([this.init_set]);
|
|
2438
|
+
var state_num = -1;
|
|
2439
|
+
while (worklist.length > 0) {
|
|
2440
|
+
var set = worklist.shift();
|
|
2441
|
+
state_num++;
|
|
2442
|
+
this.rnTable[state_num] = undefined;
|
|
2443
|
+
for (var j = 0; j < this.atoms.size(); j++) {
|
|
2444
|
+
var atom_j = this.atoms.get(j);
|
|
2445
|
+
var new_set = this.computeGotoKernel(state_num, set, atom_j);
|
|
2446
|
+
if (new_set.coreSize() > 0) {
|
|
2447
|
+
var gotoStateNum = undefined;
|
|
2448
|
+
if (kernelStates.add(new_set)) {
|
|
2449
|
+
gotoStateNum = kernelStates.size() - 1;
|
|
2450
|
+
// console.log("\nAdded new_set at index " + gotoStateNum + ": " + new_set.toString() + "\n");
|
|
2451
|
+
// console.log("Added new_set at index " + gotoStateNum);
|
|
2452
|
+
worklist.push(new_set);
|
|
2453
|
+
} else {
|
|
2454
|
+
gotoStateNum = kernelStates.indexOf(new_set);
|
|
2455
|
+
// console.log("Set already exists at index " + gotoStateNum + ": " + new_set.toString());
|
|
2456
|
+
}
|
|
2457
|
+
// console.log(state_num + ":" + set + " goes to " + gotoStateNum + ":" + new_set + " via symbol " + atom_j);
|
|
2458
|
+
var tableRow = this.rnTable[state_num];
|
|
2459
|
+
if (tableRow === undefined)
|
|
2460
|
+
tableRow = this.rnTable[state_num] = {};
|
|
2461
|
+
var tableCell = tableRow[atom_j.asString];
|
|
2462
|
+
if (tableCell === undefined)
|
|
2463
|
+
tableCell = tableRow[atom_j.asString] = {push: undefined, reductions: new Set()};
|
|
2464
|
+
if (tableCell.push !== undefined && tableCell.push !== gotoStateNum)
|
|
2465
|
+
throw ("Already have a push action for atom " + atom_j.asString + " in state " + state_num + ": supposed to goto state " + tableCell.push + " and now need to go to " + gotoStateNum);
|
|
2466
|
+
tableCell.push = gotoStateNum;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
console.log("Done with step 1");
|
|
2471
|
+
// console.log("There are " + kernelStates.size() + " kernel states");
|
|
2472
|
+
// console.log(kernelStates.toString(true));
|
|
2473
|
+
// Step 2
|
|
2474
|
+
this.states = [];
|
|
2475
|
+
var spontLookaheads = {}; // Map from goto state number -> rule id -> setOf(lookaheads)
|
|
2476
|
+
var propLookaheads = {}; // Map from state number -> goto state num -> rule id -> setOf(rule ids)
|
|
2477
|
+
for (var i = 0; i < kernelStates.size(); i++) {
|
|
2478
|
+
this.states.push(new LR1Set());
|
|
2479
|
+
spontLookaheads[i] = {};
|
|
2480
|
+
propLookaheads[i] = {};
|
|
2481
|
+
}
|
|
2482
|
+
init_rule = this.rules[this.start][0];
|
|
2483
|
+
spontLookaheads[0][init_rule.id] = new KeyedSet("key", [EOF]);
|
|
2484
|
+
for (var i = 0; i < kernelStates.size(); i++) {
|
|
2485
|
+
// if (i > 0 && i % 100 == 0) { console.log("Processing state " + i); }
|
|
2486
|
+
this.applyLookaheads(spontLookaheads, propLookaheads, kernelStates.get(i), i, this.atoms.get(j));
|
|
2487
|
+
}
|
|
2488
|
+
console.log("Done with step 2");
|
|
2489
|
+
// Step 3
|
|
2490
|
+
var allLookaheads = {}; // Map from goto state num -> rule id -> setOf(lookaheads)
|
|
2491
|
+
for (var i = 0; i < kernelStates.size(); i++) {
|
|
2492
|
+
allLookaheads[i] = {};
|
|
2493
|
+
for (var j in spontLookaheads[i]) {
|
|
2494
|
+
// console.log("i = " + i + ", j = " + j + ", spontLookaheads[i][j] = " + spontLookaheads[i][j]);
|
|
2495
|
+
allLookaheads[i][j] = new KeyedSet(spontLookaheads[i][j]);
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
console.log("Done with step 3");
|
|
2499
|
+
// Step 4
|
|
2500
|
+
// console.log("\n\n\n");
|
|
2501
|
+
function printSets(k, v) {
|
|
2502
|
+
if (v instanceof KeyedSet || v instanceof IntSet || v instanceof LR1Set)
|
|
2503
|
+
return v.toString();
|
|
2504
|
+
else
|
|
2505
|
+
return v;
|
|
2506
|
+
}
|
|
2507
|
+
// console.log("spontLookaheads = " + JSON.stringify(spontLookaheads, printSets, " "));
|
|
2508
|
+
// console.log("propLookaheads = " + JSON.stringify(propLookaheads, printSets, " "));
|
|
2509
|
+
var changed = true;
|
|
2510
|
+
var pass = 0;
|
|
2511
|
+
while (changed) {
|
|
2512
|
+
changed = false;
|
|
2513
|
+
pass++;
|
|
2514
|
+
for (var i = 0; i < kernelStates.size(); i++) {
|
|
2515
|
+
var state_i = kernelStates.get(i);
|
|
2516
|
+
var rnTable_i = this.rnTable[i];
|
|
2517
|
+
for (var x in rnTable_i) {
|
|
2518
|
+
var gotoState = rnTable_i[x].push;
|
|
2519
|
+
if (gotoState !== undefined) {
|
|
2520
|
+
for (var j = 0; j < state_i.coreSize(); j++) {
|
|
2521
|
+
var rule_j = state_i.getCore(j);
|
|
2522
|
+
var prop = propLookaheads[i][gotoState] ? propLookaheads[i][gotoState][rule_j.id] : undefined;
|
|
2523
|
+
var look = allLookaheads[i][rule_j.id];
|
|
2524
|
+
if (prop !== undefined && look !== undefined) {
|
|
2525
|
+
// console.log("Propagating " + look + " from state " + i + " to all rules " + prop.toString() + " in state " + gotoState);
|
|
2526
|
+
for (var k = 0; k < prop.size(); k++) {
|
|
2527
|
+
var id_k = prop.get(k);
|
|
2528
|
+
if (allLookaheads[gotoState][id_k] === undefined)
|
|
2529
|
+
allLookaheads[gotoState][id_k] = new KeyedSet("key");
|
|
2530
|
+
changed = allLookaheads[gotoState][id_k].merge(look) || changed;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
console.log("Done with step 4");
|
|
2539
|
+
// console.log("allLookaheads = " + JSON.stringify(allLookaheads, printSets, " "));
|
|
2540
|
+
// console.log("All rules:")
|
|
2541
|
+
// for (var r in RuleFactory.byId)
|
|
2542
|
+
// console.log(r + ": " + RuleFactory.byId[r]);
|
|
2543
|
+
// Step 5 -- expand
|
|
2544
|
+
for (var i = 0; i < kernelStates.size(); i++) {
|
|
2545
|
+
var kernelState_i = kernelStates.get(i);
|
|
2546
|
+
var state_i = this.states[i];
|
|
2547
|
+
for (var j = 0; j < kernelState_i.coreSize(); j++) {
|
|
2548
|
+
var rule_j = kernelState_i.getCore(j);
|
|
2549
|
+
var lookahead = allLookaheads[i][rule_j.id];
|
|
2550
|
+
// console.log("Lookaheads in state " + i + " for rule #" + rule_j.id + " " + rule_j.toString(true) + ": " + lookahead);
|
|
2551
|
+
if (lookahead) {
|
|
2552
|
+
state_i.addRuleWithLookaheads(rule_j, lookahead);
|
|
2553
|
+
// for (var k = 0; k < lookahead.size(); k++)
|
|
2554
|
+
// state_i.addRule(RuleFactory.make(rule_j.name, rule_j.symbols, lookahead.get(k), rule_j.position));
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
this.states = new SetOfSets(this.states, LR1Set.equals);
|
|
2559
|
+
},
|
|
2560
|
+
|
|
2561
|
+
//////////////////////////////////
|
|
2562
|
+
// Algorithm 4.12 (p242) in Dragon book
|
|
2563
|
+
applyLookaheads: function(spont, prop, rule_set, set_num) {
|
|
2564
|
+
// console.log("-----------------------------\nRuleSet #" + set_num + " = " + rule_set);
|
|
2565
|
+
for (var i = 0; i < rule_set.coreSize(); i++) {
|
|
2566
|
+
var rule = rule_set.getCore(i);
|
|
2567
|
+
var jPrime_rule = RuleFactory.make(rule.name, rule.symbols, HASH, rule.position);
|
|
2568
|
+
var jPrime = this.closureCache[jPrime_rule];
|
|
2569
|
+
if (jPrime === undefined)
|
|
2570
|
+
jPrime = this.closureCache[jPrime_rule] = this.completeClosure(new LR1Set([jPrime_rule]), true);
|
|
2571
|
+
// console.log("\nClosure(" + jPrime_rule.toString(true) + ") = " + jPrime.toString());
|
|
2572
|
+
for (var a = 0; a < this.atoms.size(); a++) {
|
|
2573
|
+
var symbol = this.atoms.get(a);
|
|
2574
|
+
if (this.rnTable[set_num] === undefined || this.rnTable[set_num][symbol.asString] === undefined) {
|
|
2575
|
+
continue;
|
|
2576
|
+
}
|
|
2577
|
+
var goto_set_num = this.rnTable[set_num][symbol.asString].push;
|
|
2578
|
+
// console.log("GOTO(" + set_num + ", " + symbol + ") = " + goto_set_num);
|
|
2579
|
+
|
|
2580
|
+
for (var j = 0; j < jPrime.coreSize(); j++) {
|
|
2581
|
+
var rule_j = jPrime.getCore(j);
|
|
2582
|
+
if (rule_j.position < rule_j.symbols.length && rule_j.symbols[rule_j.position].asString == symbol.asString) {
|
|
2583
|
+
var lookaheads = jPrime.getLookaheads(j);
|
|
2584
|
+
if (lookaheads !== undefined) {
|
|
2585
|
+
for (var k = 0; k < lookaheads.size(); k++) {
|
|
2586
|
+
if (lookaheads.get(k) !== HASH) {
|
|
2587
|
+
var new_rule = RuleFactory.make(rule_j.name, rule_j.symbols, undefined, rule_j.position + 1);
|
|
2588
|
+
if (spont[goto_set_num][new_rule.id] === undefined)
|
|
2589
|
+
spont[goto_set_num][new_rule.id] = new KeyedSet("key");
|
|
2590
|
+
if (spont[goto_set_num][new_rule.id].add(lookaheads.get(k))) {
|
|
2591
|
+
// console.log("Added " + lookaheads.get(k) + " to rule " + new_rule + " in set " + goto_set_num);
|
|
2592
|
+
}
|
|
2593
|
+
} else {
|
|
2594
|
+
var new_rule = RuleFactory.make(rule_j.name, rule_j.symbols, undefined, rule_j.position + 1);
|
|
2595
|
+
if (prop[set_num][goto_set_num] === undefined)
|
|
2596
|
+
prop[set_num][goto_set_num] = {};
|
|
2597
|
+
if (prop[set_num][goto_set_num][rule.id] === undefined)
|
|
2598
|
+
prop[set_num][goto_set_num][rule.id] = new IntSet();
|
|
2599
|
+
if (prop[set_num][goto_set_num][rule.id].add(new_rule.id)) {
|
|
2600
|
+
// console.log("Propagating from " + rule + " in state " + set_num + " to " + new_rule + " in state " + goto_set_num);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
},
|
|
2610
|
+
|
|
2611
|
+
|
|
2612
|
+
|
|
2613
|
+
|
|
2614
|
+
printTables: function() {
|
|
2615
|
+
var ret = "";
|
|
2616
|
+
for (var i = 0; i < this.rnTable.length; i++) {
|
|
2617
|
+
var str_action = ""
|
|
2618
|
+
rnTable_i = this.rnTable[i];
|
|
2619
|
+
if (rnTable_i === undefined) {
|
|
2620
|
+
var state = this.states.get(i);
|
|
2621
|
+
ret += "No actions in state #" + i + ":" + (state ? state.toString() : "undefined!") + "\n";
|
|
2622
|
+
continue;
|
|
2623
|
+
}
|
|
2624
|
+
for (var j = 0; j < this.atoms.size(); j++) {
|
|
2625
|
+
actions = this.rnTable[i][this.atoms.get(j)]
|
|
2626
|
+
if (actions.accept)
|
|
2627
|
+
str_action += "\n On " + this.atoms.get(j) + ", accept";
|
|
2628
|
+
if (actions.push !== undefined)
|
|
2629
|
+
str_action += "\n On " + this.atoms.get(j) + ", " + actions.push;
|
|
2630
|
+
if (actions.reductions && actions.reductions.size > 0)
|
|
2631
|
+
str_action += "\n On " + this.atoms.get(j) + ", " + [...actions.reductions];
|
|
2632
|
+
}
|
|
2633
|
+
var s = "In state #" + i + ":" + this.states.get(i).toString();
|
|
2634
|
+
if (this.acceptStates[i])
|
|
2635
|
+
s += " (ACCEPT STATE)";
|
|
2636
|
+
if (str_action)
|
|
2637
|
+
s += "\n Actions:" + str_action;
|
|
2638
|
+
if (s !== "") s += "\n";
|
|
2639
|
+
ret += s;
|
|
2640
|
+
}
|
|
2641
|
+
return ret;
|
|
2642
|
+
},
|
|
2643
|
+
|
|
2644
|
+
checkForCycles: function() {
|
|
2645
|
+
var cyclic = []
|
|
2646
|
+
for (var name in this.rules)
|
|
2647
|
+
if (this.derivable[name][name])
|
|
2648
|
+
cyclic.push(name);
|
|
2649
|
+
if (cyclic.length === 0) return false;
|
|
2650
|
+
return cyclic;
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
// //////////////////////////////////
|
|
2654
|
+
// // A LALR(1) ambiguity is a state/token pair that has multiple enabled actions
|
|
2655
|
+
// // Returns a list of warning messages
|
|
2656
|
+
// //////////////////////////////////
|
|
2657
|
+
// checkForLALRAmbiguity: function() {
|
|
2658
|
+
// var ambiguities = []
|
|
2659
|
+
// for (var i = 0; i < this.rnTable.length; i++) {
|
|
2660
|
+
// var tableRow = this.rnTable[i];
|
|
2661
|
+
// for (var name in tableRow) {
|
|
2662
|
+
// if (tableRow.hasOwnProperty(name)) {
|
|
2663
|
+
// var actions = tableRow[name];
|
|
2664
|
+
// if (actions.size() > 1) {
|
|
2665
|
+
// ambiguities.push("In state #" + i + ", conflicting actions on token " + name + ": " + actions);
|
|
2666
|
+
// }
|
|
2667
|
+
// }
|
|
2668
|
+
// }
|
|
2669
|
+
// }
|
|
2670
|
+
// return ambiguities;
|
|
2671
|
+
// },
|
|
2672
|
+
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
|
|
2676
|
+
return {
|
|
2677
|
+
Atom: Atom,
|
|
2678
|
+
Nonterm: Nonterm,
|
|
2679
|
+
Token: Token,
|
|
2680
|
+
Rule: Rule,
|
|
2681
|
+
Grammar: Grammar,
|
|
2682
|
+
SetOfSets: SetOfSets,
|
|
2683
|
+
EOF: EOF,
|
|
2684
|
+
EPSILON: EPSILON,
|
|
2685
|
+
SrcLoc: SrcLoc
|
|
2686
|
+
};
|
|
2687
|
+
});
|