refactored SemanticContext.js.js to use es6 classes
use const/let for better scoping use object destructuring use jsdoc
This commit is contained in:
parent
21538ebb59
commit
6ebe0d1317
|
@ -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}.
|
||||
//
|
||||
// <p>I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of
|
||||
// {@link SemanticContext} within the scope of this outer class.</p>
|
||||
//
|
||||
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}.
|
||||
*
|
||||
* <p>I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of
|
||||
* {@link SemanticContext} within the scope of this outer class.</p>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*/
|
||||
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.
|
||||
* <ul>
|
||||
* <li>{@link //NONE}: if the predicate simplifies to {@code true} after
|
||||
* precedence predicates are evaluated.</li>
|
||||
* <li>{@code null}: if the predicate simplifies to {@code false} after
|
||||
* precedence predicates are evaluated.</li>
|
||||
* <li>{@code this}: if the semantic context is not changed as a result of
|
||||
* precedence predicate evaluation.</li>
|
||||
* <li>A non-{@code null} {@link SemanticContext}: the new simplified
|
||||
* semantic context after precedence predicates are evaluated.</li>
|
||||
* </ul>
|
||||
*/
|
||||
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.
|
||||
//
|
||||
// <p>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.</p>
|
||||
//
|
||||
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.
|
||||
// <ul>
|
||||
// <li>{@link //NONE}: if the predicate simplifies to {@code true} after
|
||||
// precedence predicates are evaluated.</li>
|
||||
// <li>{@code null}: if the predicate simplifies to {@code false} after
|
||||
// precedence predicates are evaluated.</li>
|
||||
// <li>{@code this}: if the semantic context is not changed as a result of
|
||||
// precedence predicate evaluation.</li>
|
||||
// <li>A non-{@code null} {@link SemanticContext}: the new simplified
|
||||
// semantic context after precedence predicates are evaluated.</li>
|
||||
// </ul>
|
||||
//
|
||||
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<reduced.precedence) {
|
||||
reduced = p;
|
||||
|
||||
updateHashCode(hash) {
|
||||
hash.update(31);
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
if (this === other) {
|
||||
return true;
|
||||
} else if (!(other instanceof PrecedencePredicate)) {
|
||||
return false;
|
||||
} else {
|
||||
return this.precedence === other.precedence;
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
return "{"+this.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}
|
||||
//
|
||||
// <p>
|
||||
// The evaluation of predicates by this context is short-circuiting, but
|
||||
// unordered.</p>
|
||||
//
|
||||
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<reduced.precedence) {
|
||||
reduced = p;
|
||||
}
|
||||
});
|
||||
operands.add(reduced);
|
||||
}
|
||||
this.opnds = operands.values();
|
||||
return this;
|
||||
}
|
||||
if (operands.length === 0) {
|
||||
// all elements were true, so the AND context is true
|
||||
return SemanticContext.NONE;
|
||||
}
|
||||
var result = null;
|
||||
operands.map(function(o) {
|
||||
result = result === null ? o : SemanticContext.andContext(result, o);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
AND.prototype.toString = function() {
|
||||
var s = "";
|
||||
this.opnds.map(function(o) {
|
||||
s += "&& " + o.toString();
|
||||
});
|
||||
return s.length > 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");
|
||||
};
|
||||
|
||||
// <p>
|
||||
// The evaluation of predicates by this context is short-circuiting, but
|
||||
// unordered.</p>
|
||||
//
|
||||
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}
|
||||
*
|
||||
* <p>
|
||||
* The evaluation of predicates by this context is short-circuiting, but
|
||||
* unordered.</p>
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* <p>
|
||||
* The evaluation of predicates by this context is short-circuiting, but
|
||||
* unordered.</p>
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue