Merge pull request #1448 from ericvergnaud/optimize-javascript-runtime

Optimize javascript runtime
This commit is contained in:
Terence Parr 2016-12-05 18:41:08 -08:00 committed by GitHub
commit 7f4bb06adf
15 changed files with 567 additions and 349 deletions

View File

@ -30,13 +30,12 @@
// A lexer is recognizer that draws input symbols from a character stream.
// lexer grammars result in a subclass of this object. A Lexer object
// uses simplified match() and error recovery mechanisms in the interest
// of speed.
///
// uses simplified match() and error recovery mechanisms in the interest of speed.
var Token = require('./Token').Token;
var Recognizer = require('./Recognizer').Recognizer;
var CommonTokenFactory = require('./CommonTokenFactory').CommonTokenFactory;
var RecognitionException = require('./error/Errors').RecognitionException;
var LexerNoViableAltException = require('./error/Errors').LexerNoViableAltException;
function TokenSource() {
@ -152,8 +151,13 @@ Lexer.prototype.nextToken = function() {
try {
ttype = this._interp.match(this._input, this._mode);
} catch (e) {
this.notifyListeners(e); // report error
this.recover(e);
if(e instanceof RecognitionException) {
this.notifyListeners(e); // report error
this.recover(e);
} else {
console.log(e.stack);
throw e;
}
}
if (this._input.LA(1) === Token.EOF) {
this._hitEOF = true;

View File

@ -30,9 +30,10 @@
///
var RuleContext = require('./RuleContext').RuleContext;
var Hash = require('./Utils').Hash;
function PredictionContext(cachedHashString) {
this.cachedHashString = cachedHashString;
function PredictionContext(cachedHashCode) {
this.cachedHashCode = cachedHashCode;
}
// Represents {@code $} in local context prediction, which means wildcard.
@ -83,17 +84,19 @@ PredictionContext.prototype.hasEmptyPath = function() {
return this.getReturnState(this.length - 1) === PredictionContext.EMPTY_RETURN_STATE;
};
PredictionContext.prototype.hashString = function() {
return this.cachedHashString;
PredictionContext.prototype.hashCode = function() {
return this.cachedHashCode;
};
PredictionContext.prototype.updateHashCode = function(hash) {
hash.update(this.cachedHashCode);
};
/*
function calculateHashString(parent, returnState) {
return "" + parent + returnState;
}
function calculateEmptyHashString() {
return "";
}
*/
// Used to cache {@link PredictionContext} objects. Its used for the shared
// context cash associated with contexts in DFA states. This cache
@ -131,9 +134,13 @@ Object.defineProperty(PredictionContextCache.prototype, "length", {
});
function SingletonPredictionContext(parent, returnState) {
var hashString = parent !== null ? calculateHashString(parent, returnState)
: calculateEmptyHashString();
PredictionContext.call(this, hashString);
var hashCode = 0;
if(parent !== null) {
var hash = new Hash();
hash.update(parent, returnState);
hashCode = hash.finish();
}
PredictionContext.call(this, hashCode);
this.parentCtx = parent;
this.returnState = returnState;
}
@ -169,7 +176,7 @@ SingletonPredictionContext.prototype.equals = function(other) {
return true;
} else if (!(other instanceof SingletonPredictionContext)) {
return false;
} else if (this.hashString() !== other.hashString()) {
} else if (this.hashCode() !== other.hashCode()) {
return false; // can't be same if hash is different
} else {
if(this.returnState !== other.returnState)
@ -181,10 +188,6 @@ SingletonPredictionContext.prototype.equals = function(other) {
}
};
SingletonPredictionContext.prototype.hashString = function() {
return this.cachedHashString;
};
SingletonPredictionContext.prototype.toString = function() {
var up = this.parentCtx === null ? "" : this.parentCtx.toString();
if (up.length === 0) {
@ -233,8 +236,10 @@ function ArrayPredictionContext(parents, returnStates) {
// from {@link //EMPTY} and non-empty. We merge {@link //EMPTY} by using
// null parent and
// returnState == {@link //EMPTY_RETURN_STATE}.
var hash = calculateHashString(parents, returnStates);
PredictionContext.call(this, hash);
var h = new Hash();
h.update(parents, returnStates);
var hashCode = h.finish();
PredictionContext.call(this, hashCode);
this.parents = parents;
this.returnStates = returnStates;
return this;
@ -268,7 +273,7 @@ ArrayPredictionContext.prototype.equals = function(other) {
return true;
} else if (!(other instanceof ArrayPredictionContext)) {
return false;
} else if (this.hashString !== other.hashString()) {
} else if (this.hashCode() !== other.hashCode()) {
return false; // can't be same if hash is different
} else {
return this.returnStates === other.returnStates &&
@ -318,7 +323,7 @@ function predictionContextFromRuleContext(atn, outerContext) {
var transition = state.transitions[0];
return SingletonPredictionContext.create(parent, transition.followState.stateNumber);
}
/*
function calculateListsHashString(parents, returnStates) {
var s = "";
parents.map(function(p) {
@ -329,7 +334,7 @@ function calculateListsHashString(parents, returnStates) {
});
return s;
}
*/
function merge(a, b, rootIsWildcard, mergeCache) {
// share same graph if both same
if (a === b) {

View File

@ -78,7 +78,7 @@ Recognizer.prototype.getTokenTypeMap = function() {
// <p>Used for XPath and tree pattern compilation.</p>
//
Recognizer.prototype.getRuleIndexMap = function() {
var ruleNames = this.getRuleNames();
var ruleNames = this.ruleNames;
if (ruleNames===null) {
throw("The current recognizer does not provide a list of rule names.");
}

View File

@ -1,252 +1,441 @@
function arrayToString(a) {
return "[" + a.join(", ") + "]";
return "[" + a.join(", ") + "]";
}
String.prototype.seed = String.prototype.seed || Math.round(Math.random() * Math.pow(2, 32));;
String.prototype.seed = String.prototype.seed || Math.round(Math.random() * Math.pow(2, 32));
String.prototype.hashCode = function () {
var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i,
key = this.toString();
String.prototype.hashCode = function () {
var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i,
key = this.toString();
remainder = key.length & 3; // key.length % 4
bytes = key.length - remainder;
h1 = String.prototype.seed;
c1 = 0xcc9e2d51;
c2 = 0x1b873593;
i = 0;
remainder = key.length & 3; // key.length % 4
bytes = key.length - remainder;
h1 = String.prototype.seed;
c1 = 0xcc9e2d51;
c2 = 0x1b873593;
i = 0;
while (i < bytes) {
k1 =
((key.charCodeAt(i) & 0xff)) |
((key.charCodeAt(++i) & 0xff) << 8) |
((key.charCodeAt(++i) & 0xff) << 16) |
((key.charCodeAt(++i) & 0xff) << 24);
++i;
while (i < bytes) {
k1 =
((key.charCodeAt(i) & 0xff)) |
((key.charCodeAt(++i) & 0xff) << 8) |
((key.charCodeAt(++i) & 0xff) << 16) |
((key.charCodeAt(++i) & 0xff) << 24);
++i;
k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
}
k1 = 0;
switch (remainder) {
case 3:
k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
case 2:
k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
case 1:
k1 ^= (key.charCodeAt(i) & 0xff);
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
}
}
k1 = 0;
h1 ^= key.length;
switch (remainder) {
case 3:
k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
case 2:
k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
case 1:
k1 ^= (key.charCodeAt(i) & 0xff);
h1 ^= h1 >>> 16;
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 13;
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
h1 ^= h1 >>> 16;
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
}
return h1 >>> 0;
};
h1 ^= key.length;
h1 ^= h1 >>> 16;
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 13;
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
h1 ^= h1 >>> 16;
return h1 >>> 0;
};
function standardEqualsFunction(a,b) {
return a.equals(b);
function standardEqualsFunction(a, b) {
return a.equals(b);
}
function standardHashFunction(a) {
return a.hashString();
function standardHashCodeFunction(a) {
return a.hashCode();
}
function Set(hashFunction, equalsFunction) {
this.data = {};
this.hashFunction = hashFunction || standardHashFunction;
this.equalsFunction = equalsFunction || standardEqualsFunction;
return this;
this.data = {};
this.hashFunction = hashFunction || standardHashCodeFunction;
this.equalsFunction = equalsFunction || standardEqualsFunction;
return this;
}
Object.defineProperty(Set.prototype, "length", {
get : function() {
return this.values().length;
}
get: function () {
var l = 0;
for (var key in this.data) {
if (key.indexOf("hash_") === 0) {
l = l + this.data[key].length;
}
}
return l;
}
});
Set.prototype.add = function(value) {
var hash = this.hashFunction(value);
var key = "hash_" + hash.hashCode();
if(key in this.data) {
var i;
var values = this.data[key];
for(i=0;i<values.length; i++) {
if(this.equalsFunction(value, values[i])) {
return values[i];
}
}
values.push(value);
return value;
} else {
this.data[key] = [ value ];
return value;
}
Set.prototype.add = function (value) {
var hash = this.hashFunction(value);
var key = "hash_" + hash;
if (key in this.data) {
var values = this.data[key];
for (var i = 0; i < values.length; i++) {
if (this.equalsFunction(value, values[i])) {
return values[i];
}
}
values.push(value);
return value;
} else {
this.data[key] = [value];
return value;
}
};
Set.prototype.contains = function(value) {
var hash = this.hashFunction(value);
var key = hash.hashCode();
if(key in this.data) {
var i;
var values = this.data[key];
for(i=0;i<values.length; i++) {
if(this.equalsFunction(value, values[i])) {
return true;
}
}
}
return false;
Set.prototype.contains = function (value) {
return this.get(value) != null;
};
Set.prototype.values = function() {
var l = [];
for(var key in this.data) {
if(key.indexOf("hash_")===0) {
l = l.concat(this.data[key]);
}
}
return l;
Set.prototype.get = function (value) {
var hash = this.hashFunction(value);
var key = "hash_" + hash;
if (key in this.data) {
var values = this.data[key];
for (var i = 0; i < values.length; i++) {
if (this.equalsFunction(value, values[i])) {
return values[i];
}
}
}
return null;
};
Set.prototype.toString = function() {
return arrayToString(this.values());
Set.prototype.values = function () {
var l = [];
for (var key in this.data) {
if (key.indexOf("hash_") === 0) {
l = l.concat(this.data[key]);
}
}
return l;
};
Set.prototype.toString = function () {
return arrayToString(this.values());
};
function BitSet() {
this.data = [];
return this;
this.data = [];
return this;
}
BitSet.prototype.add = function(value) {
this.data[value] = true;
BitSet.prototype.add = function (value) {
this.data[value] = true;
};
BitSet.prototype.or = function(set) {
var bits = this;
Object.keys(set.data).map( function(alt) { bits.add(alt); });
BitSet.prototype.or = function (set) {
var bits = this;
Object.keys(set.data).map(function (alt) {
bits.add(alt);
});
};
BitSet.prototype.remove = function(value) {
delete this.data[value];
BitSet.prototype.remove = function (value) {
delete this.data[value];
};
BitSet.prototype.contains = function(value) {
return this.data[value] === true;
BitSet.prototype.contains = function (value) {
return this.data[value] === true;
};
BitSet.prototype.values = function() {
return Object.keys(this.data);
BitSet.prototype.values = function () {
return Object.keys(this.data);
};
BitSet.prototype.minValue = function() {
return Math.min.apply(null, this.values());
BitSet.prototype.minValue = function () {
return Math.min.apply(null, this.values());
};
BitSet.prototype.hashString = function() {
return this.values().toString();
BitSet.prototype.hashCode = function () {
var hash = new Hash();
hash.update(this.values());
return hash.finish();
};
BitSet.prototype.equals = function(other) {
if(!(other instanceof BitSet)) {
return false;
}
return this.hashString()===other.hashString();
BitSet.prototype.equals = function (other) {
if (!(other instanceof BitSet)) {
return false;
}
return this.hashCode() === other.hashCode();
};
Object.defineProperty(BitSet.prototype, "length", {
get : function() {
return this.values().length;
}
get: function () {
return this.values().length;
}
});
BitSet.prototype.toString = function() {
return "{" + this.values().join(", ") + "}";
BitSet.prototype.toString = function () {
return "{" + this.values().join(", ") + "}";
};
function AltDict() {
this.data = {};
return this;
function Map(hashFunction, equalsFunction) {
this.data = {};
this.hashFunction = hashFunction || standardHashCodeFunction;
this.equalsFunction = equalsFunction || standardEqualsFunction;
return this;
}
AltDict.prototype.get = function(key) {
key = "k-" + key;
if(key in this.data){
return this.data[key];
} else {
return null;
}
Object.defineProperty(Map.prototype, "length", {
get: function () {
var l = 0;
for (var hashKey in this.data) {
if (hashKey.indexOf("hash_") === 0) {
l = l + this.data[hashKey].length;
}
}
return l;
}
});
Map.prototype.put = function (key, value) {
var hashKey = "hash_" + this.hashFunction(key);
if (hashKey in this.data) {
var entries = this.data[hashKey];
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
if (this.equalsFunction(key, entry.key)) {
var oldValue = entry.value;
entry.value = value;
return oldValue;
}
}
entries.push({key:key, value:value});
return value;
} else {
this.data[hashKey] = [{key:key, value:value}];
return value;
}
};
AltDict.prototype.put = function(key, value) {
key = "k-" + key;
this.data[key] = value;
Map.prototype.containsKey = function (key) {
var hashKey = "hash_" + this.hashFunction(key);
if(hashKey in this.data) {
var entries = this.data[hashKey];
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
if (this.equalsFunction(key, entry.key))
return true;
}
}
return false;
};
AltDict.prototype.values = function() {
var data = this.data;
var keys = Object.keys(this.data);
return keys.map(function(key) {
return data[key];
});
Map.prototype.get = function (key) {
var hashKey = "hash_" + this.hashFunction(key);
if(hashKey in this.data) {
var entries = this.data[hashKey];
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
if (this.equalsFunction(key, entry.key))
return entry.value;
}
}
return null;
};
Map.prototype.entries = function () {
var l = [];
for (var key in this.data) {
if (key.indexOf("hash_") === 0) {
l = l.concat(this.data[key]);
}
}
return l;
};
Map.prototype.getKeys = function () {
return this.entries().map(function(e) {
return e.key;
});
};
Map.prototype.getValues = function () {
return this.entries().map(function(e) {
return e.value;
});
};
Map.prototype.toString = function () {
var ss = this.entries().map(function(entry) {
return '{' + entry.key + ':' + entry.value + '}';
});
return '[' + ss.join(", ") + ']';
};
function AltDict() {
this.data = {};
return this;
}
AltDict.prototype.get = function (key) {
key = "k-" + key;
if (key in this.data) {
return this.data[key];
} else {
return null;
}
};
AltDict.prototype.put = function (key, value) {
key = "k-" + key;
this.data[key] = value;
};
AltDict.prototype.values = function () {
var data = this.data;
var keys = Object.keys(this.data);
return keys.map(function (key) {
return data[key];
});
};
function DoubleDict() {
return this;
return this;
}
DoubleDict.prototype.get = function(a, b) {
var d = this[a] || null;
return d===null ? null : (d[b] || null);
function Hash() {
this.count = 0;
this.hash = 0;
return this;
}
Hash.prototype.update = function () {
for(var i=0;i<arguments.length;i++) {
var value = arguments[i];
if (value == null)
continue;
if(Array.isArray(value))
this.update.apply(value);
else {
var k = 0;
switch (typeof(value)) {
case 'undefined':
case 'function':
continue;
case 'number':
case 'boolean':
k = value;
break;
case 'string':
k = value.hashCode();
break;
default:
value.updateHashCode(this);
continue;
}
k = k * 0xCC9E2D51;
k = (k << 15) | (k >>> (32 - 15));
k = k * 0x1B873593;
this.count = this.count + 1;
hash = this.hash ^ k;
hash = (hash << 13) | (hash >>> (32 - 13));
hash = hash * 5 + 0xE6546B64;
this.hash = hash;
}
}
}
Hash.prototype.finish = function () {
var hash = this.hash ^ (this.count * 4);
hash = hash ^ (hash >>> 16);
hash = hash * 0x85EBCA6B;
hash = hash ^ (hash >>> 13);
hash = hash * 0xC2B2AE35;
hash = hash ^ (hash >>> 16);
return hash;
}
function hashStuff() {
var hash = new Hash();
hash.update.apply(arguments);
return hash.finish();
}
DoubleDict.prototype.get = function (a, b) {
var d = this[a] || null;
return d === null ? null : (d[b] || null);
};
DoubleDict.prototype.set = function(a, b, o) {
var d = this[a] || null;
if(d===null) {
d = {};
this[a] = d;
}
d[b] = o;
DoubleDict.prototype.set = function (a, b, o) {
var d = this[a] || null;
if (d === null) {
d = {};
this[a] = d;
}
d[b] = o;
};
function escapeWhitespace(s, escapeSpaces) {
s = s.replace("\t","\\t");
s = s.replace("\n","\\n");
s = s.replace("\r","\\r");
if(escapeSpaces) {
s = s.replace(" ","\u00B7");
}
return s;
s = s.replace("\t", "\\t");
s = s.replace("\n", "\\n");
s = s.replace("\r", "\\r");
if (escapeSpaces) {
s = s.replace(" ", "\u00B7");
}
return s;
}
exports.isArray = function (entity) {
return Object.prototype.toString.call( entity ) === '[object Array]'
function titleCase(str) {
return str.replace(/\w\S*/g, function (txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1);
});
};
exports.titleCase = function(str) {
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1);});
function equalArrays(a, b)
{
if (!Array.isArray(a) || !Array.isArray(b))
return false;
if (a == b)
return true;
if (a.length != b.length)
return false;
for (var i = 0; i < a.length; i++) {
if (a[i] == b[i])
continue;
if (!a[i].equals(b[i]))
return false;
}
return true;
};
exports.Hash = Hash;
exports.Set = Set;
exports.Map = Map;
exports.BitSet = BitSet;
exports.AltDict = AltDict;
exports.DoubleDict = DoubleDict;
exports.hashStuff = hashStuff;
exports.escapeWhitespace = escapeWhitespace;
exports.arrayToString = arrayToString;
exports.titleCase = titleCase;
exports.equalArrays = equalArrays;

View File

@ -39,6 +39,8 @@
var DecisionState = require('./ATNState').DecisionState;
var SemanticContext = require('./SemanticContext').SemanticContext;
var Hash = require("../Utils").Hash;
function checkParams(params, isCfg) {
if(params===null) {
@ -96,10 +98,16 @@ ATNConfig.prototype.checkContext = function(params, config) {
}
};
ATNConfig.prototype.hashString = function() {
return "" + this.state.stateNumber + "/" + this.alt + "/" +
(this.context===null ? "" : this.context.hashString()) +
"/" + this.semanticContext.hashString();
ATNConfig.prototype.hashCode = function() {
var hash = new Hash();
this.updateHashCode(hash);
return hash.finish();
};
ATNConfig.prototype.updateHashCode = function(hash) {
hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext);
};
// An ATN configuration is equal to another if both have
@ -120,10 +128,14 @@ ATNConfig.prototype.equals = function(other) {
}
};
ATNConfig.prototype.hashStringForConfigSet = function() {
return "" + this.state.stateNumber + "/" + this.alt + "/" + this.semanticContext;
ATNConfig.prototype.hashCodeForConfigSet = function() {
var hash = new Hash();
hash.update(this.state.stateNumber, this.alt, this.semanticContext);
return hash.finish();
};
ATNConfig.prototype.equalsForConfigSet = function(other) {
if (this === other) {
return true;
@ -162,31 +174,21 @@ function LexerATNConfig(params, config) {
LexerATNConfig.prototype = Object.create(ATNConfig.prototype);
LexerATNConfig.prototype.constructor = LexerATNConfig;
LexerATNConfig.prototype.hashString = function() {
return "" + this.state.stateNumber + this.alt + this.context +
this.semanticContext + (this.passedThroughNonGreedyDecision ? 1 : 0) +
this.lexerActionExecutor;
LexerATNConfig.prototype.updateHashCode = function(hash) {
hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext, this.passedThroughNonGreedyDecision, this.lexerActionExecutor);
};
LexerATNConfig.prototype.equals = function(other) {
if (this === other) {
return true;
} else if (!(other instanceof LexerATNConfig)) {
return false;
} else if (this.passedThroughNonGreedyDecision !== other.passedThroughNonGreedyDecision) {
return false;
} else if (this.lexerActionExecutor ?
!this.lexerActionExecutor.equals(other.lexerActionExecutor)
: !other.lexerActionExecutor) {
return false;
} else {
return ATNConfig.prototype.equals.call(this, other);
}
return this === other ||
(other instanceof LexerATNConfig &&
this.passedThroughNonGreedyDecision == other.passedThroughNonGreedyDecision &&
(this.lexerActionExecutor ? this.lexerActionExecutor.equals(other.lexerActionExecutor) : !other.lexerActionExecutor) &&
ATNConfig.prototype.equals.call(this, other));
};
LexerATNConfig.prototype.hashStringForConfigSet = LexerATNConfig.prototype.hashString;
LexerATNConfig.prototype.hashCodeForConfigSet = LexerATNConfig.prototype.hashCode;
LexerATNConfig.prototype.equalsForConfigSet = LexerATNConfig.prototype.eqials;
LexerATNConfig.prototype.equalsForConfigSet = LexerATNConfig.prototype.equals;
LexerATNConfig.prototype.checkNonGreedyDecision = function(source, target) {

View File

@ -36,12 +36,13 @@
var ATN = require('./ATN').ATN;
var Utils = require('./../Utils');
var Hash = Utils.Hash;
var Set = Utils.Set;
var SemanticContext = require('./SemanticContext').SemanticContext;
var merge = require('./../PredictionContext').merge;
function hashATNConfig(c) {
return c.hashStringForConfigSet();
return c.hashCodeForConfigSet();
}
function equalATNConfigs(a, b) {
@ -92,7 +93,7 @@ function ATNConfigSet(fullCtx) {
this.hasSemanticContext = false;
this.dipsIntoOuterContext = false;
this.cachedHashString = "-1";
this.cachedHashCode = -1;
return this;
}
@ -121,7 +122,7 @@ ATNConfigSet.prototype.add = function(config, mergeCache) {
}
var existing = this.configLookup.add(config);
if (existing === config) {
this.cachedHashString = "-1";
this.cachedHashCode = -1;
this.configs.push(config); // track order here
return true;
}
@ -186,37 +187,36 @@ ATNConfigSet.prototype.addAll = function(coll) {
};
ATNConfigSet.prototype.equals = function(other) {
if (this === other) {
return true;
} else if (!(other instanceof ATNConfigSet)) {
return false;
}
return this.configs !== null && this.configs.equals(other.configs) &&
this.fullCtx === other.fullCtx &&
this.uniqueAlt === other.uniqueAlt &&
this.conflictingAlts === other.conflictingAlts &&
this.hasSemanticContext === other.hasSemanticContext &&
this.dipsIntoOuterContext === other.dipsIntoOuterContext;
return this === other ||
(other instanceof ATNConfigSet &&
Utils.equalArrays(this.configs, other.configs) &&
this.fullCtx === other.fullCtx &&
this.uniqueAlt === other.uniqueAlt &&
this.conflictingAlts === other.conflictingAlts &&
this.hasSemanticContext === other.hasSemanticContext &&
this.dipsIntoOuterContext === other.dipsIntoOuterContext);
};
ATNConfigSet.prototype.hashString = function() {
ATNConfigSet.prototype.hashCode = function() {
var hash = new Hash();
this.updateHashCode(hash);
return hash.finish();
};
ATNConfigSet.prototype.updateHashCode = function(hash) {
if (this.readOnly) {
if (this.cachedHashString === "-1") {
this.cachedHashString = this.hashConfigs();
if (this.cachedHashCode === -1) {
var hash = new Hash();
hash.update(this.configs);
this.cachedHashCode = hash.finish();
}
return this.cachedHashString;
hash.update(this.cachedHashCode);
} else {
return this.hashConfigs();
hash.update(this.configs);
}
};
ATNConfigSet.prototype.hashConfigs = function() {
var s = "";
this.configs.map(function(c) {
s += c.toString();
});
return s;
};
Object.defineProperty(ATNConfigSet.prototype, "length", {
get : function() {
@ -247,7 +247,7 @@ ATNConfigSet.prototype.clear = function() {
throw "This set is readonly";
}
this.configs = [];
this.cachedHashString = "-1";
this.cachedHashCode = -1;
this.configLookup = new Set();
};

View File

@ -145,7 +145,7 @@ LexerATNSimulator.prototype.reset = function() {
LexerATNSimulator.prototype.matchATN = function(input) {
var startState = this.atn.modeToStartState[this.mode];
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("matchATN mode " + this.mode + " start: " + startState);
}
var old_mode = this.mode;
@ -160,14 +160,14 @@ LexerATNSimulator.prototype.matchATN = function(input) {
var predict = this.execATN(input, next);
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("DFA after matchATN: " + this.decisionToDFA[old_mode].toLexerString());
}
return predict;
};
LexerATNSimulator.prototype.execATN = function(input, ds0) {
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("start state closure=" + ds0.configs);
}
if (ds0.isAcceptState) {
@ -178,7 +178,7 @@ LexerATNSimulator.prototype.execATN = function(input, ds0) {
var s = ds0; // s is current/from DFA state
while (true) { // while more work
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("execATN loop starting closure: " + s.configs);
}
@ -246,7 +246,7 @@ LexerATNSimulator.prototype.getExistingTargetState = function(s, t) {
if(target===undefined) {
target = null;
}
if (this.debug && target !== null) {
if (LexerATNSimulator.debug && target !== null) {
console.log("reuse state " + s.stateNumber + " edge to " + target.stateNumber);
}
return target;
@ -310,7 +310,7 @@ LexerATNSimulator.prototype.getReachableConfigSet = function(input, closure,
if (currentAltReachedAcceptState && cfg.passedThroughNonGreedyDecision) {
continue;
}
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("testing %s at %s\n", this.getTokenName(t), cfg
.toString(this.recog, true));
}
@ -337,7 +337,7 @@ LexerATNSimulator.prototype.getReachableConfigSet = function(input, closure,
LexerATNSimulator.prototype.accept = function(input, lexerActionExecutor,
startIndex, index, line, charPos) {
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("ACTION %s\n", lexerActionExecutor);
}
// seek to after last char in token
@ -379,13 +379,13 @@ LexerATNSimulator.prototype.computeStartState = function(input, p) {
LexerATNSimulator.prototype.closure = function(input, config, configs,
currentAltReachedAcceptState, speculative, treatEofAsEpsilon) {
var cfg = null;
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("closure(" + config.toString(this.recog, true) + ")");
}
if (config.state instanceof RuleStopState) {
if (this.debug) {
if (LexerATNSimulator.debug) {
if (this.recog !== null) {
console.log("closure at %s rule stop %s\n", this.recog.getRuleNames()[config.state.ruleIndex], config);
console.log("closure at %s rule stop %s\n", this.recog.ruleNames[config.state.ruleIndex], config);
} else {
console.log("closure at rule stop %s\n", config);
}
@ -458,7 +458,7 @@ LexerATNSimulator.prototype.getEpsilonTarget = function(input, config, trans,
// states reached by traversing predicates. Since this is when we
// test them, we cannot cash the DFA state target of ID.
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("EVAL rule " + trans.ruleIndex + ":" + trans.predIndex);
}
configs.hasSemanticContext = true;
@ -584,7 +584,7 @@ LexerATNSimulator.prototype.addDFAEdge = function(from_, tk, to, cfgs) {
// Only track edges within the DFA bounds
return to;
}
if (this.debug) {
if (LexerATNSimulator.debug) {
console.log("EDGE " + from_ + " -> " + to + " upon " + tk);
}
if (from_.edges === null) {
@ -615,9 +615,8 @@ LexerATNSimulator.prototype.addDFAState = function(configs) {
proposed.lexerActionExecutor = firstConfigWithRuleStopState.lexerActionExecutor;
proposed.prediction = this.atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex];
}
var hash = proposed.hashString();
var dfa = this.decisionToDFA[this.mode];
var existing = dfa.states[hash] || null;
var existing = dfa.states.get(proposed);
if (existing!==null) {
return existing;
}
@ -625,7 +624,7 @@ LexerATNSimulator.prototype.addDFAState = function(configs) {
newState.stateNumber = dfa.states.length;
configs.setReadonly(true);
newState.configs = configs;
dfa.states[hash] = newState;
dfa.states.add(newState);
return newState;
};

View File

@ -47,8 +47,14 @@ function LexerAction(action) {
return this;
}
LexerAction.prototype.hashString = function() {
return "" + this.actionType;
LexerAction.prototype.hashCode = function() {
var hash = new Hash();
this.updateHashCode(hash);
return hash.finish()
};
LexerAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType);
};
LexerAction.prototype.equals = function(other) {
@ -96,8 +102,8 @@ LexerTypeAction.prototype.execute = function(lexer) {
lexer.type = this.type;
};
LexerTypeAction.prototype.hashString = function() {
return "" + this.actionType + this.type;
LexerTypeAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType, this.type);
};
@ -132,8 +138,8 @@ LexerPushModeAction.prototype.execute = function(lexer) {
lexer.pushMode(this.mode);
};
LexerPushModeAction.prototype.hashString = function() {
return "" + this.actionType + this.mode;
LexerPushModeAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType, this.mode);
};
LexerPushModeAction.prototype.equals = function(other) {
@ -215,8 +221,8 @@ LexerModeAction.prototype.execute = function(lexer) {
lexer.mode(this.mode);
};
LexerModeAction.prototype.hashString = function() {
return "" + this.actionType + this.mode;
LexerModeAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType, this.mode);
};
LexerModeAction.prototype.equals = function(other) {
@ -268,8 +274,8 @@ LexerCustomAction.prototype.execute = function(lexer) {
lexer.action(null, this.ruleIndex, this.actionIndex);
};
LexerCustomAction.prototype.hashString = function() {
return "" + this.actionType + this.ruleIndex + this.actionIndex;
LexerCustomAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType, this.ruleIndex, this.actionIndex);
};
LexerCustomAction.prototype.equals = function(other) {
@ -301,8 +307,8 @@ LexerChannelAction.prototype.execute = function(lexer) {
lexer._channel = this.channel;
};
LexerChannelAction.prototype.hashString = function() {
return "" + this.actionType + this.channel;
LexerChannelAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType, this.channel);
};
LexerChannelAction.prototype.equals = function(other) {
@ -357,8 +363,8 @@ LexerIndexedCustomAction.prototype.execute = function(lexer) {
this.action.execute(lexer);
};
LexerIndexedCustomAction.prototype.hashString = function() {
return "" + this.actionType + this.offset + this.action;
LexerIndexedCustomAction.prototype.updateHashCode = function(hash) {
hash.update(this.actionType, this.offset, this.action);
};
LexerIndexedCustomAction.prototype.equals = function(other) {

View File

@ -36,13 +36,14 @@
// efficiently, ensuring that actions appearing only at the end of the rule do
// not cause bloating of the {@link DFA} created for the lexer.</p>
var hashStuff = require("../Utils").hashStuff;
var LexerIndexedCustomAction = require('./LexerAction').LexerIndexedCustomAction;
function LexerActionExecutor(lexerActions) {
this.lexerActions = lexerActions === null ? [] : lexerActions;
// Caches the result of {@link //hashCode} since the hash code is an element
// of the performance-critical {@link LexerATNConfig//hashCode} operation.
this._hashString = lexerActions.toString(); // "".join([str(la) for la in
this.cachedHashCode = hashStuff(lexerActions); // "".join([str(la) for la in
// lexerActions]))
return this;
}
@ -157,16 +158,21 @@ LexerActionExecutor.prototype.execute = function(lexer, input, startIndex) {
}
};
LexerActionExecutor.prototype.hashString = function() {
return this._hashString;
LexerActionExecutor.prototype.hashCode = function() {
return this.cachedHashCode;
};
LexerActionExecutor.prototype.updateHashCode = function(hash) {
hash.update(this.cachedHashCode);
};
LexerActionExecutor.prototype.equals = function(other) {
if (this === other) {
return true;
} else if (!(other instanceof LexerActionExecutor)) {
return false;
} else if (this._hashString != other._hashString) {
} else if (this.cachedHashCode != other.cachedHashCode) {
return false;
} else if (this.lexerActions.length != other.lexerActions.length) {
return false;

View File

@ -315,6 +315,8 @@ ParserATNSimulator.prototype = Object.create(ATNSimulator.prototype);
ParserATNSimulator.prototype.constructor = ParserATNSimulator;
ParserATNSimulator.prototype.debug = false;
ParserATNSimulator.prototype.debug_closure = false;
ParserATNSimulator.prototype.debug_add = false;
ParserATNSimulator.prototype.debug_list_atn_decisions = false;
ParserATNSimulator.prototype.dfa_debug = false;
ParserATNSimulator.prototype.retry_debug = false;
@ -746,7 +748,7 @@ ParserATNSimulator.prototype.computeReachSet = function(closure, t, fullCtx) {
// First figure out where we can reach on input t
for (var i=0; i<closure.items.length;i++) {
var c = closure.items[i];
if(this.debug) {
if(this.debug_add) {
console.log("testing " + this.getTokenName(t) + " at " + c);
}
if (c.state instanceof RuleStopState) {
@ -755,7 +757,7 @@ ParserATNSimulator.prototype.computeReachSet = function(closure, t, fullCtx) {
skippedStopStates = [];
}
skippedStopStates.push(c);
if(this.debug) {
if(this.debug_add) {
console.log("added " + c + " to skippedStopStates");
}
}
@ -767,7 +769,7 @@ ParserATNSimulator.prototype.computeReachSet = function(closure, t, fullCtx) {
if (target!==null) {
var cfg = new ATNConfig({state:target}, c);
intermediate.add(cfg, this.mergeCache);
if(this.debug) {
if(this.debug_add) {
console.log("added " + cfg + " to intermediate");
}
}
@ -1225,9 +1227,9 @@ ParserATNSimulator.prototype.closure = function(config, configs, closureBusy, co
ParserATNSimulator.prototype.closureCheckingStopState = function(config, configs, closureBusy, collectPredicates, fullCtx, depth, treatEofAsEpsilon) {
if (this.debug) {
if (this.debug || this.debug_closure) {
console.log("closure(" + config.toString(this.parser,true) + ")");
console.log("configs(" + configs.toString() + ")");
// console.log("configs(" + configs.toString() + ")");
if(config.reachesIntoOuterContext>50) {
throw "problem";
}
@ -1276,6 +1278,7 @@ ParserATNSimulator.prototype.closureCheckingStopState = function(config, configs
this.closure_(config, configs, closureBusy, collectPredicates, fullCtx, depth, treatEofAsEpsilon);
};
// Do the actual work of walking epsilon edges//
ParserATNSimulator.prototype.closure_ = function(config, configs, closureBusy, collectPredicates, fullCtx, depth, treatEofAsEpsilon) {
var p = config.state;
@ -1342,6 +1345,8 @@ ParserATNSimulator.prototype.canDropLoopEntryEdgeInLeftRecursiveRule = function(
// the context has an empty stack case. If so, it would mean
// global FOLLOW so we can't perform optimization
// Are we the special loop entry/exit state? or SLL wildcard
if(p.stateType != ATNState.STAR_LOOP_ENTRY)
return false;
if(p.stateType != ATNState.STAR_LOOP_ENTRY || !p.isPrecedenceDecision ||
config.context.isEmpty() || config.context.hasEmptyPath())
return false;
@ -1434,7 +1439,8 @@ ParserATNSimulator.prototype.getEpsilonTarget = function(config, t, collectPredi
ParserATNSimulator.prototype.actionTransition = function(config, t) {
if (this.debug) {
console.log("ACTION edge " + t.ruleIndex + ":" + t.actionIndex);
var index = t.actionIndex==-1 ? 65535 : t.actionIndex;
console.log("ACTION edge " + t.ruleIndex + ":" + index);
}
return new ATNConfig({state:t.target}, config);
};
@ -1575,11 +1581,12 @@ ParserATNSimulator.prototype.getTokenName = function( t) {
return "EOF";
}
if( this.parser!==null && this.parser.literalNames!==null) {
if (t >= this.parser.literalNames.length) {
if (t >= this.parser.literalNames.length && t >= this.parser.symbolicNames.length) {
console.log("" + t + " ttype out of range: " + this.parser.literalNames);
console.log("" + this.parser.getInputStream().getTokens());
} else {
return this.parser.literalNames[t] + "<" + t + ">";
var name = this.parser.literalNames[t] || this.parser.symbolicNames[t];
return name + "<" + t + ">";
}
}
return "" + t;
@ -1666,8 +1673,9 @@ ParserATNSimulator.prototype.addDFAEdge = function(dfa, from_, t, to) {
from_.edges[t+1] = to; // connect
if (this.debug) {
var names = this.parser===null ? null : this.parser.literalNames;
console.log("DFA=\n" + dfa.toString(names));
var literalNames = this.parser===null ? null : this.parser.literalNames;
var symbolicNames = this.parser===null ? null : this.parser.symbolicNames;
console.log("DFA=\n" + dfa.toString(literalNames, symbolicNames));
}
return to;
};
@ -1690,8 +1698,7 @@ ParserATNSimulator.prototype.addDFAState = function(dfa, D) {
if (D == ATNSimulator.ERROR) {
return D;
}
var hash = D.hashString();
var existing = dfa.states[hash] || null;
var existing = dfa.states.get(D);
if(existing!==null) {
return existing;
}
@ -1700,7 +1707,7 @@ ParserATNSimulator.prototype.addDFAState = function(dfa, D) {
D.configs.optimizeConfigs(this);
D.configs.setReadonly(true);
}
dfa.states[hash] = D;
dfa.states.add(D);
if (this.debug) {
console.log("adding new DFA state: " + D);
}

View File

@ -34,6 +34,7 @@
// ambiguities.
var Set = require('./../Utils').Set;
var Map = require('./../Utils').Map;
var BitSet = require('./../Utils').BitSet;
var AltDict = require('./../Utils').AltDict;
var ATN = require('./ATN').ATN;
@ -41,6 +42,9 @@ var RuleStopState = require('./ATNState').RuleStopState;
var ATNConfigSet = require('./ATNConfigSet').ATNConfigSet;
var ATNConfig = require('./ATNConfig').ATNConfig;
var SemanticContext = require('./SemanticContext').SemanticContext;
var Hash = require("../Utils").Hash;
var hashStuff = require('./../Utils').hashStuff;
var equalArrays = require('./../Utils').equalArrays;
function PredictionMode() {
return this;
@ -515,27 +519,20 @@ PredictionMode.getAlts = function(altsets) {
// map[c] U= c.{@link ATNConfig//alt alt} // map hash/equals uses s and x, not
// alt and not pred
// </pre>
//
PredictionMode.getConflictingAltSubsets = function(configs) {
var configToAlts = {};
for(var i=0;i<configs.items.length;i++) {
var c = configs.items[i];
var key = "key_" + c.state.stateNumber + "/" + c.context;
var alts = configToAlts[key] || null;
var configToAlts = new Map();
configToAlts.hashFunction = function(cfg) { hashStuff(cfg.state.stateNumber, cfg.context); };
configToAlts.equalsFunction = function(c1, c2) { return c1.state.stateNumber==c2.state.stateNumber && c1.context.equals(c2.context);}
configs.items.map(function(cfg) {
var alts = configToAlts.get(cfg);
if (alts === null) {
alts = new BitSet();
configToAlts[key] = alts;
configToAlts.put(cfg, alts);
}
alts.add(c.alt);
}
var values = [];
for(var k in configToAlts) {
if(k.indexOf("key_")!==0) {
continue;
}
values.push(configToAlts[k]);
}
return values;
alts.add(cfg.alt);
});
return configToAlts.getValues();
};
//

View File

@ -38,11 +38,18 @@
//
var Set = require('./../Utils').Set;
var Hash = require('./../Utils').Hash;
function SemanticContext() {
return this;
}
SemanticContext.prototype.hashCode = function() {
var hash = new Hash();
this.updateHashCode(hash);
return hash.finish();
};
// For context independent predicates, we evaluate them without a local
// context (i.e., null context). That way, we can evaluate them without
// having to create proper rule-specific context during prediction (as
@ -135,8 +142,8 @@ Predicate.prototype.evaluate = function(parser, outerContext) {
return parser.sempred(localctx, this.ruleIndex, this.predIndex);
};
Predicate.prototype.hashString = function() {
return "" + this.ruleIndex + "/" + this.predIndex + "/" + this.isCtxDependent;
Predicate.prototype.updateHashCode = function(hash) {
hash.update(this.ruleIndex, this.predIndex, this.isCtxDependent);
};
Predicate.prototype.equals = function(other) {
@ -179,8 +186,8 @@ PrecedencePredicate.prototype.compareTo = function(other) {
return this.precedence - other.precedence;
};
PrecedencePredicate.prototype.hashString = function() {
return "31";
PrecedencePredicate.prototype.updateHashCode = function(hash) {
hash.update(31);
};
PrecedencePredicate.prototype.equals = function(other) {
@ -258,8 +265,8 @@ AND.prototype.equals = function(other) {
}
};
AND.prototype.hashString = function() {
return "" + this.opnds + "/AND";
AND.prototype.updateHashCode = function(hash) {
hash.update(this.opnds, "AND");
};
//
// {@inheritDoc}
@ -362,8 +369,8 @@ OR.prototype.constructor = function(other) {
}
};
OR.prototype.hashString = function() {
return "" + this.opnds + "/OR";
OR.prototype.updateHashCode = function(hash) {
hash.update(this.opnds, "OR");
};
// <p>

View File

@ -28,21 +28,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var Set = require("../Utils").Set;
var DFAState = require('./DFAState').DFAState;
var StarLoopEntryState = require('../atn/ATNState').StarLoopEntryState;
var ATNConfigSet = require('./../atn/ATNConfigSet').ATNConfigSet;
var DFASerializer = require('./DFASerializer').DFASerializer;
var LexerDFASerializer = require('./DFASerializer').LexerDFASerializer;
function DFAStatesSet() {
return this;
}
Object.defineProperty(DFAStatesSet.prototype, "length", {
get : function() {
return Object.keys(this).length;
}
});
function DFA(atnStartState, decision) {
if (decision === undefined) {
@ -53,7 +46,7 @@ function DFA(atnStartState, decision) {
this.decision = decision;
// A set of all DFA states. Use {@link Map} so we can get old state back
// ({@link Set} only allows you to see if it's there).
this._states = new DFAStatesSet();
this._states = new Set();
this.s0 = null;
// {@code true} if this DFA is for a precedence decision; otherwise,
// {@code false}. This is the backing field for {@link //isPrecedenceDfa},
@ -157,12 +150,7 @@ Object.defineProperty(DFA.prototype, "states", {
// Return a list of all states in this DFA, ordered by state number.
DFA.prototype.sortedStates = function() {
// states_ is a map of state/state, where key=value
var keys = Object.keys(this._states);
var list = [];
for(var i=0;i<keys.length;i++) {
list.push(this._states[keys[i]]);
}
var list = this._states.values();
return list.sort(function(a, b) {
return a.stateNumber - b.stateNumber;
});

View File

@ -31,6 +31,7 @@
var ATNConfigSet = require('./../atn/ATNConfigSet').ATNConfigSet;
var Utils = require('./../Utils');
var Hash = Utils.Hash;
var Set = Utils.Set;
// Map a predicate to a predicted alternative.///
@ -142,26 +143,33 @@ DFAState.prototype.getAltSet = function() {
// {@link //stateNumber} is irrelevant.</p>
DFAState.prototype.equals = function(other) {
// compare set of ATN configurations in this set with other
if (this === other) {
return true;
} else if (!(other instanceof DFAState)) {
return false;
} else {
return this.configs.equals(other.configs);
}
return this === other ||
(other instanceof DFAState &&
this.configs.equals(other.configs));
};
DFAState.prototype.toString = function() {
return "" + this.stateNumber + ":" + this.hashString();
var s = "" + this.stateNumber + ":" + this.configs;
if(this.isAcceptState) {
s = s + "=>";
if (this.predicates !== null)
s = s + this.predicates;
else
s = s + this.prediction;
}
return s;
};
DFAState.prototype.hashString = function() {
return "" + this.configs +
(this.isAcceptState ?
"=>" + (this.predicates !== null ?
this.predicates :
this.prediction) :
"");
DFAState.prototype.hashCode = function() {
var hash = new Hash();
hash.update(this.configs);
if(this.isAcceptState) {
if (this.predicates !== null)
hash.update(this.predicates);
else
hash.update(this.prediction);
}
return hash.finish();
};
exports.DFAState = DFAState;

View File

@ -87,7 +87,7 @@ function ParseTreeVisitor() {
}
ParseTreeVisitor.prototype.visit = function(ctx) {
if (Utils.isArray(ctx)) {
if (Array.isArray(ctx)) {
return ctx.map(function(child) {
return ctx.accept(this);
}, this);