From 6ebe0d13170d2a09abda0765372b45ebb00530cb Mon Sep 17 00:00:00 2001 From: Camilo Roca Date: Sat, 7 Mar 2020 13:35:30 +0100 Subject: [PATCH] refactored SemanticContext.js.js to use es6 classes use const/let for better scoping use object destructuring use jsdoc --- .../src/antlr4/atn/SemanticContext.js | 708 +++++++++--------- 1 file changed, 352 insertions(+), 356 deletions(-) diff --git a/runtime/JavaScript/src/antlr4/atn/SemanticContext.js b/runtime/JavaScript/src/antlr4/atn/SemanticContext.js index 992183588..4c7e64bd1 100644 --- a/runtime/JavaScript/src/antlr4/atn/SemanticContext.js +++ b/runtime/JavaScript/src/antlr4/atn/SemanticContext.js @@ -1,404 +1,400 @@ -// /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. * Use of this file is governed by the BSD 3-clause license that * can be found in the LICENSE.txt file in the project root. */ -// -// A tree structure used to record the semantic context in which -// an ATN configuration is valid. It's either a single predicate, -// a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}. -// -//

I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of -// {@link SemanticContext} within the scope of this outer class.

-// +const {Set, Hash} = require('./../Utils'); -var Set = require('./../Utils').Set; -var Hash = require('./../Utils').Hash; +/** + * A tree structure used to record the semantic context in which + * an ATN configuration is valid. It's either a single predicate, + * a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}. + * + *

I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of + * {@link SemanticContext} within the scope of this outer class.

+ */ +class SemanticContext { + hashCode() { + const hash = new Hash(); + this.updateHashCode(hash); + return hash.finish(); + } -function SemanticContext() { - return this; + /** + * 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 + * opposed to the parser, which creates them naturally). In a practical + * sense, this avoids a cast exception from RuleContext to myruleContext. + * + *

For context dependent predicates, we must pass in a local context so that + * references such as $arg evaluate properly as _localctx.arg. We only + * capture context dependent predicates in the context in which we begin + * prediction, so we passed in the outer context here in case of context + * dependent predicate evaluation.

+ */ + evaluate(parser, outerContext) {} + + /** + * Evaluate the precedence predicates for the context and reduce the result. + * + * @param parser The parser instance. + * @param outerContext The current parser context object. + * @return The simplified semantic context after precedence predicates are + * evaluated, which will be one of the following values. + * + */ + evalPrecedence(parser, outerContext) { + return this; + } + + static andContext(a, b) { + if (a === null || a === SemanticContext.NONE) { + return b; + } + if (b === null || b === SemanticContext.NONE) { + return a; + } + const result = new AND(a, b); + if (result.opnds.length === 1) { + return result.opnds[0]; + } else { + return result; + } + } + + static orContext(a, b) { + if (a === null) { + return b; + } + if (b === null) { + return a; + } + if (a === SemanticContext.NONE || b === SemanticContext.NONE) { + return SemanticContext.NONE; + } + const result = new OR(a, b); + if (result.opnds.length === 1) { + return result.opnds[0]; + } else { + return result; + } + } } -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 -// opposed to the parser, which creates them naturally). In a practical -// sense, this avoids a cast exception from RuleContext to myruleContext. -// -//

For context dependent predicates, we must pass in a local context so that -// references such as $arg evaluate properly as _localctx.arg. We only -// capture context dependent predicates in the context in which we begin -// prediction, so we passed in the outer context here in case of context -// dependent predicate evaluation.

-// -SemanticContext.prototype.evaluate = function(parser, outerContext) { -}; +class Predicate extends SemanticContext { + constructor(ruleIndex, predIndex, isCtxDependent) { + super(); + this.ruleIndex = ruleIndex === undefined ? -1 : ruleIndex; + this.predIndex = predIndex === undefined ? -1 : predIndex; + this.isCtxDependent = isCtxDependent === undefined ? false : isCtxDependent; // e.g., $i ref in pred + return this; + } -// -// Evaluate the precedence predicates for the context and reduce the result. -// -// @param parser The parser instance. -// @param outerContext The current parser context object. -// @return The simplified semantic context after precedence predicates are -// evaluated, which will be one of the following values. -// -// -SemanticContext.prototype.evalPrecedence = function(parser, outerContext) { - return this; -}; + evaluate(parser, outerContext) { + const localctx = this.isCtxDependent ? outerContext : null; + return parser.sempred(localctx, this.ruleIndex, this.predIndex); + } -SemanticContext.andContext = function(a, b) { - if (a === null || a === SemanticContext.NONE) { - return b; + updateHashCode(hash) { + hash.update(this.ruleIndex, this.predIndex, this.isCtxDependent); } - if (b === null || b === SemanticContext.NONE) { - return a; - } - var result = new AND(a, b); - if (result.opnds.length === 1) { - return result.opnds[0]; - } else { - return result; - } -}; -SemanticContext.orContext = function(a, b) { - if (a === null) { - return b; + equals(other) { + if (this === other) { + return true; + } else if (!(other instanceof Predicate)) { + return false; + } else { + return this.ruleIndex === other.ruleIndex && + this.predIndex === other.predIndex && + this.isCtxDependent === other.isCtxDependent; + } } - if (b === null) { - return a; - } - if (a === SemanticContext.NONE || b === SemanticContext.NONE) { - return SemanticContext.NONE; - } - var result = new OR(a, b); - if (result.opnds.length === 1) { - return result.opnds[0]; - } else { - return result; - } -}; -function Predicate(ruleIndex, predIndex, isCtxDependent) { - SemanticContext.call(this); - this.ruleIndex = ruleIndex === undefined ? -1 : ruleIndex; - this.predIndex = predIndex === undefined ? -1 : predIndex; - this.isCtxDependent = isCtxDependent === undefined ? false : isCtxDependent; // e.g., $i ref in pred - return this; + toString() { + return "{" + this.ruleIndex + ":" + this.predIndex + "}?"; + } } -Predicate.prototype = Object.create(SemanticContext.prototype); -Predicate.prototype.constructor = Predicate; - -//The default {@link SemanticContext}, which is semantically equivalent to -//a predicate of the form {@code {true}?}. -// +/** + * The default {@link SemanticContext}, which is semantically equivalent to + * a predicate of the form {@code {true}?} + */ SemanticContext.NONE = new Predicate(); -Predicate.prototype.evaluate = function(parser, outerContext) { - var localctx = this.isCtxDependent ? outerContext : null; - return parser.sempred(localctx, this.ruleIndex, this.predIndex); -}; - -Predicate.prototype.updateHashCode = function(hash) { - hash.update(this.ruleIndex, this.predIndex, this.isCtxDependent); -}; - -Predicate.prototype.equals = function(other) { - if (this === other) { - return true; - } else if (!(other instanceof Predicate)) { - return false; - } else { - return this.ruleIndex === other.ruleIndex && - this.predIndex === other.predIndex && - this.isCtxDependent === other.isCtxDependent; +class PrecedencePredicate extends SemanticContext { + constructor(precedence) { + super(); + this.precedence = precedence === undefined ? 0 : precedence; } -}; -Predicate.prototype.toString = function() { - return "{" + this.ruleIndex + ":" + this.predIndex + "}?"; -}; - -function PrecedencePredicate(precedence) { - SemanticContext.call(this); - this.precedence = precedence === undefined ? 0 : precedence; -} - -PrecedencePredicate.prototype = Object.create(SemanticContext.prototype); -PrecedencePredicate.prototype.constructor = PrecedencePredicate; - -PrecedencePredicate.prototype.evaluate = function(parser, outerContext) { - return parser.precpred(outerContext, this.precedence); -}; - -PrecedencePredicate.prototype.evalPrecedence = function(parser, outerContext) { - if (parser.precpred(outerContext, this.precedence)) { - return SemanticContext.NONE; - } else { - return null; + evaluate(parser, outerContext) { + return parser.precpred(outerContext, this.precedence); } -}; -PrecedencePredicate.prototype.compareTo = function(other) { - return this.precedence - other.precedence; -}; - -PrecedencePredicate.prototype.updateHashCode = function(hash) { - hash.update(31); -}; - -PrecedencePredicate.prototype.equals = function(other) { - if (this === other) { - return true; - } else if (!(other instanceof PrecedencePredicate)) { - return false; - } else { - return this.precedence === other.precedence; - } -}; - -PrecedencePredicate.prototype.toString = function() { - return "{"+this.precedence+">=prec}?"; -}; - - - -PrecedencePredicate.filterPrecedencePredicates = function(set) { - var result = []; - set.values().map( function(context) { - if (context instanceof PrecedencePredicate) { - result.push(context); + evalPrecedence(parser, outerContext) { + if (parser.precpred(outerContext, this.precedence)) { + return SemanticContext.NONE; + } else { + return null; } - }); - return result; -}; - - -// A semantic context which is true whenever none of the contained contexts -// is false. -// -function AND(a, b) { - SemanticContext.call(this); - var operands = new Set(); - if (a instanceof AND) { - a.opnds.map(function(o) { - operands.add(o); - }); - } else { - operands.add(a); } - if (b instanceof AND) { - b.opnds.map(function(o) { - operands.add(o); - }); - } else { - operands.add(b); + + compareTo(other) { + return this.precedence - other.precedence; } - var precedencePredicates = PrecedencePredicate.filterPrecedencePredicates(operands); - if (precedencePredicates.length > 0) { - // interested in the transition with the lowest precedence - var reduced = null; - precedencePredicates.map( function(p) { - if(reduced===null || p.precedence=prec}?"; + } + + static filterPrecedencePredicates(set) { + const result = []; + set.values().map( function(context) { + if (context instanceof PrecedencePredicate) { + result.push(context); } }); - operands.add(reduced); + return result; } - this.opnds = operands.values(); - return this; } -AND.prototype = Object.create(SemanticContext.prototype); -AND.prototype.constructor = AND; - -AND.prototype.equals = function(other) { - if (this === other) { - return true; - } else if (!(other instanceof AND)) { - return false; - } else { - return this.opnds === other.opnds; - } -}; - -AND.prototype.updateHashCode = function(hash) { - hash.update(this.opnds, "AND"); -}; -// -// {@inheritDoc} -// -//

-// The evaluation of predicates by this context is short-circuiting, but -// unordered.

-// -AND.prototype.evaluate = function(parser, outerContext) { - for (var i = 0; i < this.opnds.length; i++) { - if (!this.opnds[i].evaluate(parser, outerContext)) { - return false; +class AND extends SemanticContext { + /** + * A semantic context which is true whenever none of the contained contexts + * is false + */ + constructor(a, b) { + super(); + const operands = new Set(); + if (a instanceof AND) { + a.opnds.map(function(o) { + operands.add(o); + }); + } else { + operands.add(a); } - } - return true; -}; - -AND.prototype.evalPrecedence = function(parser, outerContext) { - var differs = false; - var operands = []; - for (var i = 0; i < this.opnds.length; i++) { - var context = this.opnds[i]; - var evaluated = context.evalPrecedence(parser, outerContext); - differs |= (evaluated !== context); - if (evaluated === null) { - // The AND context is false if any element is false - return null; - } else if (evaluated !== SemanticContext.NONE) { - // Reduce the result by skipping true elements - operands.push(evaluated); + if (b instanceof AND) { + b.opnds.map(function(o) { + operands.add(o); + }); + } else { + operands.add(b); } - } - if (!differs) { + const precedencePredicates = PrecedencePredicate.filterPrecedencePredicates(operands); + if (precedencePredicates.length > 0) { + // interested in the transition with the lowest precedence + let reduced = null; + precedencePredicates.map( function(p) { + if(reduced===null || p.precedence 3 ? s.slice(3) : s; -}; - -// -// A semantic context which is true whenever at least one of the contained -// contexts is true. -// -function OR(a, b) { - SemanticContext.call(this); - var operands = new Set(); - if (a instanceof OR) { - a.opnds.map(function(o) { - operands.add(o); - }); - } else { - operands.add(a); - } - if (b instanceof OR) { - b.opnds.map(function(o) { - operands.add(o); - }); - } else { - operands.add(b); - } - - var precedencePredicates = PrecedencePredicate.filterPrecedencePredicates(operands); - if (precedencePredicates.length > 0) { - // interested in the transition with the highest precedence - var s = precedencePredicates.sort(function(a, b) { - return a.compareTo(b); - }); - var reduced = s[s.length-1]; - operands.add(reduced); - } - this.opnds = operands.values(); - return this; -} - -OR.prototype = Object.create(SemanticContext.prototype); -OR.prototype.constructor = OR; - -OR.prototype.constructor = function(other) { - if (this === other) { - return true; - } else if (!(other instanceof OR)) { - return false; - } else { - return this.opnds === other.opnds; - } -}; - -OR.prototype.updateHashCode = function(hash) { - hash.update(this.opnds, "OR"); -}; - -//

-// The evaluation of predicates by this context is short-circuiting, but -// unordered.

-// -OR.prototype.evaluate = function(parser, outerContext) { - for (var i = 0; i < this.opnds.length; i++) { - if (this.opnds[i].evaluate(parser, outerContext)) { + equals(other) { + if (this === other) { return true; + } else if (!(other instanceof AND)) { + return false; + } else { + return this.opnds === other.opnds; } } - return false; -}; -OR.prototype.evalPrecedence = function(parser, outerContext) { - var differs = false; - var operands = []; - for (var i = 0; i < this.opnds.length; i++) { - var context = this.opnds[i]; - var evaluated = context.evalPrecedence(parser, outerContext); - differs |= (evaluated !== context); - if (evaluated === SemanticContext.NONE) { - // The OR context is true if any element is true - return SemanticContext.NONE; - } else if (evaluated !== null) { - // Reduce the result by skipping false elements - operands.push(evaluated); - } + updateHashCode(hash) { + hash.update(this.opnds, "AND"); } - if (!differs) { + + /** + * {@inheritDoc} + * + *

+ * The evaluation of predicates by this context is short-circuiting, but + * unordered.

+ */ + evaluate(parser, outerContext) { + for (let i = 0; i < this.opnds.length; i++) { + if (!this.opnds[i].evaluate(parser, outerContext)) { + return false; + } + } + return true; + } + + evalPrecedence(parser, outerContext) { + let differs = false; + const operands = []; + for (let i = 0; i < this.opnds.length; i++) { + const context = this.opnds[i]; + const evaluated = context.evalPrecedence(parser, outerContext); + differs |= (evaluated !== context); + if (evaluated === null) { + // The AND context is false if any element is false + return null; + } else if (evaluated !== SemanticContext.NONE) { + // Reduce the result by skipping true elements + operands.push(evaluated); + } + } + if (!differs) { + return this; + } + if (operands.length === 0) { + // all elements were true, so the AND context is true + return SemanticContext.NONE; + } + let result = null; + operands.map(function(o) { + result = result === null ? o : SemanticContext.andContext(result, o); + }); + return result; + } + + toString() { + let s = ""; + this.opnds.map(function(o) { + s += "&& " + o.toString(); + }); + return s.length > 3 ? s.slice(3) : s; + } +} + + +class OR extends SemanticContext { + /** + * A semantic context which is true whenever at least one of the contained + * contexts is true + */ + constructor(a, b) { + super(); + const operands = new Set(); + if (a instanceof OR) { + a.opnds.map(function(o) { + operands.add(o); + }); + } else { + operands.add(a); + } + if (b instanceof OR) { + b.opnds.map(function(o) { + operands.add(o); + }); + } else { + operands.add(b); + } + + const precedencePredicates = PrecedencePredicate.filterPrecedencePredicates(operands); + if (precedencePredicates.length > 0) { + // interested in the transition with the highest precedence + const s = precedencePredicates.sort(function(a, b) { + return a.compareTo(b); + }); + const reduced = s[s.length-1]; + operands.add(reduced); + } + this.opnds = operands.values(); return this; } - if (operands.length === 0) { - // all elements were false, so the OR context is false - return null; + + equals(other) { + if (this === other) { + return true; + } else if (!(other instanceof OR)) { + return false; + } else { + return this.opnds === other.opnds; + } } - var result = null; - operands.map(function(o) { - return result === null ? o : SemanticContext.orContext(result, o); - }); - return result; -}; -OR.prototype.toString = function() { - var s = ""; - this.opnds.map(function(o) { - s += "|| " + o.toString(); - }); - return s.length > 3 ? s.slice(3) : s; -}; + updateHashCode(hash) { + hash.update(this.opnds, "OR"); + } -exports.SemanticContext = SemanticContext; -exports.PrecedencePredicate = PrecedencePredicate; -exports.Predicate = Predicate; + /** + *

+ * The evaluation of predicates by this context is short-circuiting, but + * unordered.

+ */ + evaluate(parser, outerContext) { + for (let i = 0; i < this.opnds.length; i++) { + if (this.opnds[i].evaluate(parser, outerContext)) { + return true; + } + } + return false; + } + + evalPrecedence(parser, outerContext) { + let differs = false; + const operands = []; + for (let i = 0; i < this.opnds.length; i++) { + const context = this.opnds[i]; + const evaluated = context.evalPrecedence(parser, outerContext); + differs |= (evaluated !== context); + if (evaluated === SemanticContext.NONE) { + // The OR context is true if any element is true + return SemanticContext.NONE; + } else if (evaluated !== null) { + // Reduce the result by skipping false elements + operands.push(evaluated); + } + } + if (!differs) { + return this; + } + if (operands.length === 0) { + // all elements were false, so the OR context is false + return null; + } + const result = null; + operands.map(function(o) { + return result === null ? o : SemanticContext.orContext(result, o); + }); + return result; + } + + toString() { + let s = ""; + this.opnds.map(function(o) { + s += "|| " + o.toString(); + }); + return s.length > 3 ? s.slice(3) : s; + } +} + +module.exports = { + SemanticContext, + PrecedencePredicate, + Predicate +}