From 7332c1eb0257b593b4057bba35146011f95551ed Mon Sep 17 00:00:00 2001 From: Eric Vergnaud Date: Sun, 4 Dec 2016 14:23:30 +0800 Subject: [PATCH] fix various hashing issues --- runtime/JavaScript/src/antlr4/Lexer.js | 11 +- runtime/JavaScript/src/antlr4/Utils.js | 127 ++++++++++++++++-- .../JavaScript/src/antlr4/atn/ATNConfigSet.js | 20 +-- .../src/antlr4/atn/LexerActionExecutor.js | 5 + .../src/antlr4/atn/ParserATNSimulator.js | 5 +- .../src/antlr4/atn/PredictionMode.js | 36 ++--- 6 files changed, 156 insertions(+), 48 deletions(-) diff --git a/runtime/JavaScript/src/antlr4/Lexer.js b/runtime/JavaScript/src/antlr4/Lexer.js index 63f5e9841..4502d8619 100644 --- a/runtime/JavaScript/src/antlr4/Lexer.js +++ b/runtime/JavaScript/src/antlr4/Lexer.js @@ -35,6 +35,7 @@ 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() { @@ -150,9 +151,13 @@ Lexer.prototype.nextToken = function() { try { ttype = this._interp.match(this._input, this._mode); } catch (e) { - console.log(e.stack); - 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; diff --git a/runtime/JavaScript/src/antlr4/Utils.js b/runtime/JavaScript/src/antlr4/Utils.js index 1e2c0561c..ea61cdd78 100644 --- a/runtime/JavaScript/src/antlr4/Utils.js +++ b/runtime/JavaScript/src/antlr4/Utils.js @@ -64,13 +64,13 @@ function standardEqualsFunction(a, b) { return a.equals(b); } -function standardHashFunction(a) { +function standardHashCodeFunction(a) { return a.hashCode(); } function Set(hashFunction, equalsFunction) { this.data = {}; - this.hashFunction = hashFunction || standardHashFunction; + this.hashFunction = hashFunction || standardHashCodeFunction; this.equalsFunction = equalsFunction || standardEqualsFunction; return this; } @@ -91,9 +91,8 @@ Set.prototype.add = function (value) { var hash = this.hashFunction(value); var key = "hash_" + hash; if (key in this.data) { - var i; var values = this.data[key]; - for (i = 0; i < values.length; i++) { + for (var i = 0; i < values.length; i++) { if (this.equalsFunction(value, values[i])) { return values[i]; } @@ -114,9 +113,8 @@ Set.prototype.get = function (value) { var hash = this.hashFunction(value); var key = "hash_" + hash; if (key in this.data) { - var i; var values = this.data[key]; - for (i = 0; i < values.length; i++) { + for (var i = 0; i < values.length; i++) { if (this.equalsFunction(value, values[i])) { return values[i]; } @@ -194,11 +192,110 @@ BitSet.prototype.toString = function () { return "{" + this.values().join(", ") + "}"; }; +function Map(hashFunction, equalsFunction) { + this.data = {}; + this.hashFunction = hashFunction || standardHashCodeFunction; + this.equalsFunction = equalsFunction || standardEqualsFunction; + return this; +} + +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; + } +}; + +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; +}; + +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) { @@ -248,8 +345,12 @@ Hash.prototype.update = function () { case 'boolean': k = value; break; - default: + case 'string': k = value.hashCode(); + break; + default: + value.updateHashCode(this); + continue; } k = k * 0xCC9E2D51; k = (k << 15) | (k >>> (32 - 15)); @@ -273,7 +374,7 @@ Hash.prototype.finish = function () { return hash; } -exports.hashStuff = function() { +function hashStuff() { var hash = new Hash(); hash.update.apply(arguments); return hash.finish(); @@ -304,13 +405,13 @@ function escapeWhitespace(s, escapeSpaces) { return s; } -exports.titleCase = function (str) { +function titleCase(str) { return str.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1); }); }; -exports.equalArrays = function(a, b) +function equalArrays(a, b) { if (!Array.isArray(a) || !Array.isArray(b)) return false; @@ -327,10 +428,14 @@ exports.equalArrays = function(a, b) 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.Hash = Hash; \ No newline at end of file +exports.titleCase = titleCase; +exports.equalArrays = equalArrays; \ No newline at end of file diff --git a/runtime/JavaScript/src/antlr4/atn/ATNConfigSet.js b/runtime/JavaScript/src/antlr4/atn/ATNConfigSet.js index 2016b02bb..ba9ec2b76 100644 --- a/runtime/JavaScript/src/antlr4/atn/ATNConfigSet.js +++ b/runtime/JavaScript/src/antlr4/atn/ATNConfigSet.js @@ -198,21 +198,25 @@ ATNConfigSet.prototype.equals = function(other) { }; ATNConfigSet.prototype.hashCode = function() { + var hash = new Hash(); + this.updateHashCode(hash); + return hash.finish(); +}; + + +ATNConfigSet.prototype.updateHashCode = function(hash) { if (this.readOnly) { if (this.cachedHashCode === -1) { - this.cachedHashCode = this.hashConfigs(); + var hash = new Hash(); + hash.update(this.configs); + this.cachedHashCode = hash.finish(); } - return this.cachedHashCode; + hash.update(this.cachedHashCode); } else { - return this.hashConfigs(); + hash.update(this.configs); } }; -ATNConfigSet.prototype.hashConfigs = function() { - var hash = new Hash(); - hash.update(this.configs); - return hash.finish(); -}; Object.defineProperty(ATNConfigSet.prototype, "length", { get : function() { diff --git a/runtime/JavaScript/src/antlr4/atn/LexerActionExecutor.js b/runtime/JavaScript/src/antlr4/atn/LexerActionExecutor.js index a7db897b8..48502f931 100644 --- a/runtime/JavaScript/src/antlr4/atn/LexerActionExecutor.js +++ b/runtime/JavaScript/src/antlr4/atn/LexerActionExecutor.js @@ -162,6 +162,11 @@ 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; diff --git a/runtime/JavaScript/src/antlr4/atn/ParserATNSimulator.js b/runtime/JavaScript/src/antlr4/atn/ParserATNSimulator.js index fd2c531e0..5d591438d 100644 --- a/runtime/JavaScript/src/antlr4/atn/ParserATNSimulator.js +++ b/runtime/JavaScript/src/antlr4/atn/ParserATNSimulator.js @@ -1703,8 +1703,7 @@ ParserATNSimulator.prototype.addDFAState = function(dfa, D) { if (D == ATNSimulator.ERROR) { return D; } - var hash = "key_" + D.hashCode(); - var existing = dfa.states[hash] || null; + var existing = dfa.states.get(D); if(existing!==null) { return existing; } @@ -1713,7 +1712,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); } diff --git a/runtime/JavaScript/src/antlr4/atn/PredictionMode.js b/runtime/JavaScript/src/antlr4/atn/PredictionMode.js index 42a7f81fe..011037b20 100644 --- a/runtime/JavaScript/src/antlr4/atn/PredictionMode.js +++ b/runtime/JavaScript/src/antlr4/atn/PredictionMode.js @@ -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; @@ -42,6 +43,8 @@ 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; @@ -516,33 +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 // -// + PredictionMode.getConflictingAltSubsets = function(configs) { - var configToAlts = {}; - for(var i=0;i