Merge pull request #2771 from carocad/atn-es6
Javascript: migrate prototypical ATN objects to ES6
This commit is contained in:
commit
1284814c21
|
@ -7,8 +7,8 @@ var Token = require('./Token').Token;
|
||||||
var ParseTreeListener = require('./tree/Tree').ParseTreeListener;
|
var ParseTreeListener = require('./tree/Tree').ParseTreeListener;
|
||||||
var Recognizer = require('./Recognizer').Recognizer;
|
var Recognizer = require('./Recognizer').Recognizer;
|
||||||
var DefaultErrorStrategy = require('./error/ErrorStrategy').DefaultErrorStrategy;
|
var DefaultErrorStrategy = require('./error/ErrorStrategy').DefaultErrorStrategy;
|
||||||
var ATNDeserializer = require('./atn/ATNDeserializer').ATNDeserializer;
|
var ATNDeserializer = require('./atn/ATNDeserializer');
|
||||||
var ATNDeserializationOptions = require('./atn/ATNDeserializationOptions').ATNDeserializationOptions;
|
var ATNDeserializationOptions = require('./atn/ATNDeserializationOptions');
|
||||||
var TerminalNode = require('./tree/Tree').TerminalNode;
|
var TerminalNode = require('./tree/Tree').TerminalNode;
|
||||||
var ErrorNode = require('./tree/Tree').ErrorNode;
|
var ErrorNode = require('./tree/Tree').ErrorNode;
|
||||||
|
|
||||||
|
@ -671,4 +671,4 @@ Parser.prototype.setTrace = function(trace) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Parser = Parser;
|
exports.Parser = Parser;
|
||||||
|
|
|
@ -3,139 +3,153 @@
|
||||||
* can be found in the LICENSE.txt file in the project root.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var LL1Analyzer = require('./../LL1Analyzer').LL1Analyzer;
|
const {LL1Analyzer} = require('./../LL1Analyzer');
|
||||||
var IntervalSet = require('./../IntervalSet').IntervalSet;
|
const {IntervalSet} = require('./../IntervalSet');
|
||||||
|
const {Token} = require('./../Token');
|
||||||
|
|
||||||
function ATN(grammarType , maxTokenType) {
|
class ATN {
|
||||||
|
constructor(grammarType , maxTokenType) {
|
||||||
|
|
||||||
// Used for runtime deserialization of ATNs from strings///
|
/**
|
||||||
// The type of the ATN.
|
* Used for runtime deserialization of ATNs from strings
|
||||||
this.grammarType = grammarType;
|
* The type of the ATN.
|
||||||
// The maximum value for any symbol recognized by a transition in the ATN.
|
*/
|
||||||
this.maxTokenType = maxTokenType;
|
this.grammarType = grammarType;
|
||||||
this.states = [];
|
// The maximum value for any symbol recognized by a transition in the ATN.
|
||||||
// Each subrule/rule is a decision point and we must track them so we
|
this.maxTokenType = maxTokenType;
|
||||||
// can go back later and build DFA predictors for them. This includes
|
this.states = [];
|
||||||
// all the rules, subrules, optional blocks, ()+, ()* etc...
|
/**
|
||||||
this.decisionToState = [];
|
* Each subrule/rule is a decision point and we must track them so we
|
||||||
// Maps from rule index to starting state number.
|
* can go back later and build DFA predictors for them. This includes
|
||||||
this.ruleToStartState = [];
|
* all the rules, subrules, optional blocks, ()+, ()* etc...
|
||||||
// Maps from rule index to stop state number.
|
*/
|
||||||
this.ruleToStopState = null;
|
this.decisionToState = [];
|
||||||
this.modeNameToStartState = {};
|
// Maps from rule index to starting state number.
|
||||||
// For lexer ATNs, this maps the rule index to the resulting token type.
|
this.ruleToStartState = [];
|
||||||
// For parser ATNs, this maps the rule index to the generated bypass token
|
// Maps from rule index to stop state number.
|
||||||
// type if the
|
this.ruleToStopState = null;
|
||||||
// {@link ATNDeserializationOptions//isGenerateRuleBypassTransitions}
|
this.modeNameToStartState = {};
|
||||||
// deserialization option was specified; otherwise, this is {@code null}.
|
/**
|
||||||
this.ruleToTokenType = null;
|
* For lexer ATNs, this maps the rule index to the resulting token type.
|
||||||
// For lexer ATNs, this is an array of {@link LexerAction} objects which may
|
* For parser ATNs, this maps the rule index to the generated bypass token
|
||||||
// be referenced by action transitions in the ATN.
|
* type if the {@link ATNDeserializationOptions//isGenerateRuleBypassTransitions}
|
||||||
this.lexerActions = null;
|
* deserialization option was specified; otherwise, this is {@code null}
|
||||||
this.modeToStartState = [];
|
*/
|
||||||
|
this.ruleToTokenType = null;
|
||||||
|
/**
|
||||||
|
* For lexer ATNs, this is an array of {@link LexerAction} objects which may
|
||||||
|
* be referenced by action transitions in the ATN
|
||||||
|
*/
|
||||||
|
this.lexerActions = null;
|
||||||
|
this.modeToStartState = [];
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
}
|
* Compute the set of valid tokens that can occur starting in state {@code s}.
|
||||||
|
* If {@code ctx} is null, the set of tokens will not include what can follow
|
||||||
|
* the rule surrounding {@code s}. In other words, the set will be
|
||||||
|
* restricted to tokens reachable staying within {@code s}'s rule
|
||||||
|
*/
|
||||||
|
nextTokensInContext(s, ctx) {
|
||||||
|
const anal = new LL1Analyzer(this);
|
||||||
|
return anal.LOOK(s, null, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the set of valid tokens that can occur starting in state {@code s}.
|
/**
|
||||||
// If {@code ctx} is null, the set of tokens will not include what can follow
|
* Compute the set of valid tokens that can occur starting in {@code s} and
|
||||||
// the rule surrounding {@code s}. In other words, the set will be
|
* staying in same rule. {@link Token//EPSILON} is in set if we reach end of
|
||||||
// restricted to tokens reachable staying within {@code s}'s rule.
|
* rule
|
||||||
ATN.prototype.nextTokensInContext = function(s, ctx) {
|
*/
|
||||||
var anal = new LL1Analyzer(this);
|
nextTokensNoContext(s) {
|
||||||
return anal.LOOK(s, null, ctx);
|
if (s.nextTokenWithinRule !== null ) {
|
||||||
};
|
return s.nextTokenWithinRule;
|
||||||
|
}
|
||||||
// Compute the set of valid tokens that can occur starting in {@code s} and
|
s.nextTokenWithinRule = this.nextTokensInContext(s, null);
|
||||||
// staying in same rule. {@link Token//EPSILON} is in set if we reach end of
|
s.nextTokenWithinRule.readOnly = true;
|
||||||
// rule.
|
|
||||||
ATN.prototype.nextTokensNoContext = function(s) {
|
|
||||||
if (s.nextTokenWithinRule !== null ) {
|
|
||||||
return s.nextTokenWithinRule;
|
return s.nextTokenWithinRule;
|
||||||
}
|
}
|
||||||
s.nextTokenWithinRule = this.nextTokensInContext(s, null);
|
|
||||||
s.nextTokenWithinRule.readOnly = true;
|
|
||||||
return s.nextTokenWithinRule;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATN.prototype.nextTokens = function(s, ctx) {
|
nextTokens(s, ctx) {
|
||||||
if ( ctx===undefined ) {
|
if ( ctx===undefined ) {
|
||||||
return this.nextTokensNoContext(s);
|
return this.nextTokensNoContext(s);
|
||||||
} else {
|
} else {
|
||||||
return this.nextTokensInContext(s, ctx);
|
return this.nextTokensInContext(s, ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ATN.prototype.addState = function( state) {
|
addState(state) {
|
||||||
if ( state !== null ) {
|
if ( state !== null ) {
|
||||||
state.atn = this;
|
state.atn = this;
|
||||||
state.stateNumber = this.states.length;
|
state.stateNumber = this.states.length;
|
||||||
|
}
|
||||||
|
this.states.push(state);
|
||||||
}
|
}
|
||||||
this.states.push(state);
|
|
||||||
};
|
|
||||||
|
|
||||||
ATN.prototype.removeState = function( state) {
|
removeState(state) {
|
||||||
this.states[state.stateNumber] = null; // just free mem, don't shift states in list
|
this.states[state.stateNumber] = null; // just free mem, don't shift states in list
|
||||||
};
|
|
||||||
|
|
||||||
ATN.prototype.defineDecisionState = function( s) {
|
|
||||||
this.decisionToState.push(s);
|
|
||||||
s.decision = this.decisionToState.length-1;
|
|
||||||
return s.decision;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATN.prototype.getDecisionState = function( decision) {
|
|
||||||
if (this.decisionToState.length===0) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return this.decisionToState[decision];
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Computes the set of input symbols which could follow ATN state number
|
defineDecisionState(s) {
|
||||||
// {@code stateNumber} in the specified full {@code context}. This method
|
this.decisionToState.push(s);
|
||||||
// considers the complete parser context, but does not evaluate semantic
|
s.decision = this.decisionToState.length-1;
|
||||||
// predicates (i.e. all predicates encountered during the calculation are
|
return s.decision;
|
||||||
// assumed true). If a path in the ATN exists from the starting state to the
|
}
|
||||||
// {@link RuleStopState} of the outermost context without matching any
|
|
||||||
// symbols, {@link Token//EOF} is added to the returned set.
|
|
||||||
//
|
|
||||||
// <p>If {@code context} is {@code null}, it is treated as
|
|
||||||
// {@link ParserRuleContext//EMPTY}.</p>
|
|
||||||
//
|
|
||||||
// @param stateNumber the ATN state number
|
|
||||||
// @param context the full parse context
|
|
||||||
// @return The set of potentially valid input symbols which could follow the
|
|
||||||
// specified state in the specified context.
|
|
||||||
// @throws IllegalArgumentException if the ATN does not contain a state with
|
|
||||||
// number {@code stateNumber}
|
|
||||||
var Token = require('./../Token').Token;
|
|
||||||
|
|
||||||
ATN.prototype.getExpectedTokens = function( stateNumber, ctx ) {
|
getDecisionState(decision) {
|
||||||
if ( stateNumber < 0 || stateNumber >= this.states.length ) {
|
if (this.decisionToState.length===0) {
|
||||||
throw("Invalid state number.");
|
return null;
|
||||||
|
} else {
|
||||||
|
return this.decisionToState[decision];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var s = this.states[stateNumber];
|
|
||||||
var following = this.nextTokens(s);
|
/**
|
||||||
if (!following.contains(Token.EPSILON)) {
|
* Computes the set of input symbols which could follow ATN state number
|
||||||
return following;
|
* {@code stateNumber} in the specified full {@code context}. This method
|
||||||
}
|
* considers the complete parser context, but does not evaluate semantic
|
||||||
var expected = new IntervalSet();
|
* predicates (i.e. all predicates encountered during the calculation are
|
||||||
expected.addSet(following);
|
* assumed true). If a path in the ATN exists from the starting state to the
|
||||||
expected.removeOne(Token.EPSILON);
|
* {@link RuleStopState} of the outermost context without matching any
|
||||||
while (ctx !== null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
|
* symbols, {@link Token//EOF} is added to the returned set.
|
||||||
var invokingState = this.states[ctx.invokingState];
|
*
|
||||||
var rt = invokingState.transitions[0];
|
* <p>If {@code context} is {@code null}, it is treated as
|
||||||
following = this.nextTokens(rt.followState);
|
* {@link ParserRuleContext//EMPTY}.</p>
|
||||||
|
*
|
||||||
|
* @param stateNumber the ATN state number
|
||||||
|
* @param ctx the full parse context
|
||||||
|
*
|
||||||
|
* @return {IntervalSet} The set of potentially valid input symbols which could follow the
|
||||||
|
* specified state in the specified context.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the ATN does not contain a state with
|
||||||
|
* number {@code stateNumber}
|
||||||
|
*/
|
||||||
|
getExpectedTokens(stateNumber, ctx ) {
|
||||||
|
if ( stateNumber < 0 || stateNumber >= this.states.length ) {
|
||||||
|
throw("Invalid state number.");
|
||||||
|
}
|
||||||
|
const s = this.states[stateNumber];
|
||||||
|
let following = this.nextTokens(s);
|
||||||
|
if (!following.contains(Token.EPSILON)) {
|
||||||
|
return following;
|
||||||
|
}
|
||||||
|
const expected = new IntervalSet();
|
||||||
expected.addSet(following);
|
expected.addSet(following);
|
||||||
expected.removeOne(Token.EPSILON);
|
expected.removeOne(Token.EPSILON);
|
||||||
ctx = ctx.parentCtx;
|
while (ctx !== null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
|
||||||
|
const invokingState = this.states[ctx.invokingState];
|
||||||
|
const rt = invokingState.transitions[0];
|
||||||
|
following = this.nextTokens(rt.followState);
|
||||||
|
expected.addSet(following);
|
||||||
|
expected.removeOne(Token.EPSILON);
|
||||||
|
ctx = ctx.parentCtx;
|
||||||
|
}
|
||||||
|
if (following.contains(Token.EPSILON)) {
|
||||||
|
expected.addOne(Token.EOF);
|
||||||
|
}
|
||||||
|
return expected;
|
||||||
}
|
}
|
||||||
if (following.contains(Token.EPSILON)) {
|
}
|
||||||
expected.addOne(Token.EOF);
|
|
||||||
}
|
|
||||||
return expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATN.INVALID_ALT_NUMBER = 0;
|
ATN.INVALID_ALT_NUMBER = 0;
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,22 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
///
|
|
||||||
|
|
||||||
// A tuple: (ATN state, predicted alt, syntactic, semantic context).
|
const {DecisionState} = require('./ATNState');
|
||||||
// The syntactic context is a graph-structured stack node whose
|
const {SemanticContext} = require('./SemanticContext');
|
||||||
// path(s) to the root is the rule invocation(s)
|
const {Hash} = require("../Utils");
|
||||||
// chain used to arrive at the state. The semantic context is
|
|
||||||
// the tree of semantic predicates encountered before reaching
|
|
||||||
// an ATN state.
|
|
||||||
///
|
|
||||||
|
|
||||||
var DecisionState = require('./ATNState').DecisionState;
|
|
||||||
var SemanticContext = require('./SemanticContext').SemanticContext;
|
|
||||||
var Hash = require("../Utils").Hash;
|
|
||||||
|
|
||||||
|
|
||||||
function checkParams(params, isCfg) {
|
function checkParams(params, isCfg) {
|
||||||
if(params===null) {
|
if(params===null) {
|
||||||
var result = { state:null, alt:null, context:null, semanticContext:null };
|
const result = { state:null, alt:null, context:null, semanticContext:null };
|
||||||
if(isCfg) {
|
if(isCfg) {
|
||||||
result.reachesIntoOuterContext = 0;
|
result.reachesIntoOuterContext = 0;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
var props = {};
|
const props = {};
|
||||||
props.state = params.state || null;
|
props.state = params.state || null;
|
||||||
props.alt = (params.alt === undefined) ? null : params.alt;
|
props.alt = (params.alt === undefined) ? null : params.alt;
|
||||||
props.context = params.context || null;
|
props.context = params.context || null;
|
||||||
|
@ -39,138 +29,144 @@ function checkParams(params, isCfg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ATNConfig(params, config) {
|
class ATNConfig {
|
||||||
this.checkContext(params, config);
|
/**
|
||||||
params = checkParams(params);
|
* @param {Object} params A tuple: (ATN state, predicted alt, syntactic, semantic context).
|
||||||
config = checkParams(config, true);
|
* The syntactic context is a graph-structured stack node whose
|
||||||
// The ATN state associated with this configuration///
|
* path(s) to the root is the rule invocation(s)
|
||||||
this.state = params.state!==null ? params.state : config.state;
|
* chain used to arrive at the state. The semantic context is
|
||||||
// What alt (or lexer rule) is predicted by this configuration///
|
* the tree of semantic predicates encountered before reaching
|
||||||
this.alt = params.alt!==null ? params.alt : config.alt;
|
* an ATN state
|
||||||
// The stack of invoking states leading to the rule/states associated
|
*/
|
||||||
// with this config. We track only those contexts pushed during
|
constructor(params, config) {
|
||||||
// execution of the ATN simulator.
|
this.checkContext(params, config);
|
||||||
this.context = params.context!==null ? params.context : config.context;
|
params = checkParams(params);
|
||||||
this.semanticContext = params.semanticContext!==null ? params.semanticContext :
|
config = checkParams(config, true);
|
||||||
(config.semanticContext!==null ? config.semanticContext : SemanticContext.NONE);
|
// The ATN state associated with this configuration///
|
||||||
// We cannot execute predicates dependent upon local context unless
|
this.state = params.state!==null ? params.state : config.state;
|
||||||
// we know for sure we are in the correct context. Because there is
|
// What alt (or lexer rule) is predicted by this configuration///
|
||||||
// no way to do this efficiently, we simply cannot evaluate
|
this.alt = params.alt!==null ? params.alt : config.alt;
|
||||||
// dependent predicates unless we are in the rule that initially
|
/**
|
||||||
// invokes the ATN simulator.
|
* The stack of invoking states leading to the rule/states associated
|
||||||
//
|
* with this config. We track only those contexts pushed during
|
||||||
// closure() tracks the depth of how far we dip into the
|
* execution of the ATN simulator
|
||||||
// outer context: depth > 0. Note that it may not be totally
|
*/
|
||||||
// accurate depth since I don't ever decrement. TODO: make it a boolean then
|
this.context = params.context!==null ? params.context : config.context;
|
||||||
this.reachesIntoOuterContext = config.reachesIntoOuterContext;
|
this.semanticContext = params.semanticContext!==null ? params.semanticContext :
|
||||||
this.precedenceFilterSuppressed = config.precedenceFilterSuppressed;
|
(config.semanticContext!==null ? config.semanticContext : SemanticContext.NONE);
|
||||||
return this;
|
// TODO: make it a boolean then
|
||||||
|
/**
|
||||||
|
* We cannot execute predicates dependent upon local context unless
|
||||||
|
* we know for sure we are in the correct context. Because there is
|
||||||
|
* no way to do this efficiently, we simply cannot evaluate
|
||||||
|
* dependent predicates unless we are in the rule that initially
|
||||||
|
* invokes the ATN simulator.
|
||||||
|
* closure() tracks the depth of how far we dip into the
|
||||||
|
* outer context: depth > 0. Note that it may not be totally
|
||||||
|
* accurate depth since I don't ever decrement
|
||||||
|
*/
|
||||||
|
this.reachesIntoOuterContext = config.reachesIntoOuterContext;
|
||||||
|
this.precedenceFilterSuppressed = config.precedenceFilterSuppressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkContext(params, config) {
|
||||||
|
if((params.context===null || params.context===undefined) &&
|
||||||
|
(config===null || config.context===null || config.context===undefined)) {
|
||||||
|
this.context = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashCode() {
|
||||||
|
const hash = new Hash();
|
||||||
|
this.updateHashCode(hash);
|
||||||
|
return hash.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHashCode(hash) {
|
||||||
|
hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ATN configuration is equal to another if both have
|
||||||
|
* the same state, they predict the same alternative, and
|
||||||
|
* syntactic/semantic contexts are the same
|
||||||
|
*/
|
||||||
|
equals(other) {
|
||||||
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (! (other instanceof ATNConfig)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.state.stateNumber===other.state.stateNumber &&
|
||||||
|
this.alt===other.alt &&
|
||||||
|
(this.context===null ? other.context===null : this.context.equals(other.context)) &&
|
||||||
|
this.semanticContext.equals(other.semanticContext) &&
|
||||||
|
this.precedenceFilterSuppressed===other.precedenceFilterSuppressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashCodeForConfigSet() {
|
||||||
|
const hash = new Hash();
|
||||||
|
hash.update(this.state.stateNumber, this.alt, this.semanticContext);
|
||||||
|
return hash.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
equalsForConfigSet(other) {
|
||||||
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (! (other instanceof ATNConfig)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.state.stateNumber===other.state.stateNumber &&
|
||||||
|
this.alt===other.alt &&
|
||||||
|
this.semanticContext.equals(other.semanticContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return "(" + this.state + "," + this.alt +
|
||||||
|
(this.context!==null ? ",[" + this.context.toString() + "]" : "") +
|
||||||
|
(this.semanticContext !== SemanticContext.NONE ?
|
||||||
|
("," + this.semanticContext.toString())
|
||||||
|
: "") +
|
||||||
|
(this.reachesIntoOuterContext>0 ?
|
||||||
|
(",up=" + this.reachesIntoOuterContext)
|
||||||
|
: "") + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ATNConfig.prototype.checkContext = function(params, config) {
|
|
||||||
if((params.context===null || params.context===undefined) &&
|
|
||||||
(config===null || config.context===null || config.context===undefined)) {
|
|
||||||
this.context = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
class LexerATNConfig extends ATNConfig {
|
||||||
|
constructor(params, config) {
|
||||||
|
super(params, config);
|
||||||
|
|
||||||
ATNConfig.prototype.hashCode = function() {
|
// This is the backing field for {@link //getLexerActionExecutor}.
|
||||||
var hash = new Hash();
|
const lexerActionExecutor = params.lexerActionExecutor || null;
|
||||||
this.updateHashCode(hash);
|
this.lexerActionExecutor = lexerActionExecutor || (config!==null ? config.lexerActionExecutor : null);
|
||||||
return hash.finish();
|
this.passedThroughNonGreedyDecision = config!==null ? this.checkNonGreedyDecision(config, this.state) : false;
|
||||||
};
|
this.hashCodeForConfigSet = LexerATNConfig.prototype.hashCode;
|
||||||
|
this.equalsForConfigSet = LexerATNConfig.prototype.equals;
|
||||||
|
return this;
|
||||||
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
|
|
||||||
// the same state, they predict the same alternative, and
|
|
||||||
// syntactic/semantic contexts are the same.
|
|
||||||
|
|
||||||
ATNConfig.prototype.equals = function(other) {
|
|
||||||
if (this === other) {
|
|
||||||
return true;
|
|
||||||
} else if (! (other instanceof ATNConfig)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.state.stateNumber===other.state.stateNumber &&
|
|
||||||
this.alt===other.alt &&
|
|
||||||
(this.context===null ? other.context===null : this.context.equals(other.context)) &&
|
|
||||||
this.semanticContext.equals(other.semanticContext) &&
|
|
||||||
this.precedenceFilterSuppressed===other.precedenceFilterSuppressed;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
updateHashCode(hash) {
|
||||||
ATNConfig.prototype.hashCodeForConfigSet = function() {
|
hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext, this.passedThroughNonGreedyDecision, this.lexerActionExecutor);
|
||||||
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;
|
|
||||||
} else if (! (other instanceof ATNConfig)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.state.stateNumber===other.state.stateNumber &&
|
|
||||||
this.alt===other.alt &&
|
|
||||||
this.semanticContext.equals(other.semanticContext);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
return this === other ||
|
||||||
|
(other instanceof LexerATNConfig &&
|
||||||
|
this.passedThroughNonGreedyDecision == other.passedThroughNonGreedyDecision &&
|
||||||
|
(this.lexerActionExecutor ? this.lexerActionExecutor.equals(other.lexerActionExecutor) : !other.lexerActionExecutor) &&
|
||||||
|
super.equals(other));
|
||||||
|
}
|
||||||
|
|
||||||
ATNConfig.prototype.toString = function() {
|
checkNonGreedyDecision(source, target) {
|
||||||
return "(" + this.state + "," + this.alt +
|
return source.passedThroughNonGreedyDecision ||
|
||||||
(this.context!==null ? ",[" + this.context.toString() + "]" : "") +
|
(target instanceof DecisionState) && target.nonGreedy;
|
||||||
(this.semanticContext !== SemanticContext.NONE ?
|
}
|
||||||
("," + this.semanticContext.toString())
|
|
||||||
: "") +
|
|
||||||
(this.reachesIntoOuterContext>0 ?
|
|
||||||
(",up=" + this.reachesIntoOuterContext)
|
|
||||||
: "") + ")";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function LexerATNConfig(params, config) {
|
|
||||||
ATNConfig.call(this, params, config);
|
|
||||||
|
|
||||||
// This is the backing field for {@link //getLexerActionExecutor}.
|
|
||||||
var lexerActionExecutor = params.lexerActionExecutor || null;
|
|
||||||
this.lexerActionExecutor = lexerActionExecutor || (config!==null ? config.lexerActionExecutor : null);
|
|
||||||
this.passedThroughNonGreedyDecision = config!==null ? this.checkNonGreedyDecision(config, this.state) : false;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerATNConfig.prototype = Object.create(ATNConfig.prototype);
|
|
||||||
LexerATNConfig.prototype.constructor = LexerATNConfig;
|
|
||||||
|
|
||||||
LexerATNConfig.prototype.updateHashCode = function(hash) {
|
module.exports.ATNConfig = ATNConfig;
|
||||||
hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext, this.passedThroughNonGreedyDecision, this.lexerActionExecutor);
|
module.exports.LexerATNConfig = LexerATNConfig;
|
||||||
};
|
|
||||||
|
|
||||||
LexerATNConfig.prototype.equals = function(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.hashCodeForConfigSet = LexerATNConfig.prototype.hashCode;
|
|
||||||
|
|
||||||
LexerATNConfig.prototype.equalsForConfigSet = LexerATNConfig.prototype.equals;
|
|
||||||
|
|
||||||
|
|
||||||
LexerATNConfig.prototype.checkNonGreedyDecision = function(source, target) {
|
|
||||||
return source.passedThroughNonGreedyDecision ||
|
|
||||||
(target instanceof DecisionState) && target.nonGreedy;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.ATNConfig = ATNConfig;
|
|
||||||
exports.LexerATNConfig = LexerATNConfig;
|
|
||||||
|
|
|
@ -1,21 +1,12 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
const ATN = require('./ATN');
|
||||||
// Specialized {@link Set}{@code <}{@link ATNConfig}{@code >} that can track
|
const Utils = require('./../Utils');
|
||||||
// info about the set, with support for combining similar configurations using a
|
const {SemanticContext} = require('./SemanticContext');
|
||||||
// graph-structured stack.
|
const {merge} = require('./../PredictionContext');
|
||||||
///
|
|
||||||
|
|
||||||
var ATN = require('./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) {
|
function hashATNConfig(c) {
|
||||||
return c.hashCodeForConfigSet();
|
return c.hashCodeForConfigSet();
|
||||||
|
@ -30,224 +21,233 @@ function equalATNConfigs(a, b) {
|
||||||
return a.equalsForConfigSet(b);
|
return a.equalsForConfigSet(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized {@link Set}{@code <}{@link ATNConfig}{@code >} that can track
|
||||||
|
* info about the set, with support for combining similar configurations using a
|
||||||
|
* graph-structured stack
|
||||||
|
*/
|
||||||
|
class ATNConfigSet {
|
||||||
|
constructor(fullCtx) {
|
||||||
|
/**
|
||||||
|
* The reason that we need this is because we don't want the hash map to use
|
||||||
|
* the standard hash code and equals. We need all configurations with the
|
||||||
|
* same
|
||||||
|
* {@code (s,i,_,semctx)} to be equal. Unfortunately, this key effectively
|
||||||
|
* doubles
|
||||||
|
* the number of objects associated with ATNConfigs. The other solution is
|
||||||
|
* to
|
||||||
|
* use a hash table that lets us specify the equals/hashcode operation.
|
||||||
|
* All configs but hashed by (s, i, _, pi) not including context. Wiped out
|
||||||
|
* when we go readonly as this set becomes a DFA state
|
||||||
|
*/
|
||||||
|
this.configLookup = new Utils.Set(hashATNConfig, equalATNConfigs);
|
||||||
|
/**
|
||||||
|
* Indicates that this configuration set is part of a full context
|
||||||
|
* LL prediction. It will be used to determine how to merge $. With SLL
|
||||||
|
* it's a wildcard whereas it is not for LL context merge
|
||||||
|
*/
|
||||||
|
this.fullCtx = fullCtx === undefined ? true : fullCtx;
|
||||||
|
/**
|
||||||
|
* Indicates that the set of configurations is read-only. Do not
|
||||||
|
* allow any code to manipulate the set; DFA states will point at
|
||||||
|
* the sets and they must not change. This does not protect the other
|
||||||
|
* fields; in particular, conflictingAlts is set after
|
||||||
|
* we've made this readonly
|
||||||
|
*/
|
||||||
|
this.readOnly = false;
|
||||||
|
// Track the elements as they are added to the set; supports get(i)///
|
||||||
|
this.configs = [];
|
||||||
|
|
||||||
function ATNConfigSet(fullCtx) {
|
// TODO: these fields make me pretty uncomfortable but nice to pack up info
|
||||||
//
|
// together, saves recomputation
|
||||||
// The reason that we need this is because we don't want the hash map to use
|
// TODO: can we track conflicts as they are added to save scanning configs
|
||||||
// the standard hash code and equals. We need all configurations with the
|
// later?
|
||||||
// same
|
this.uniqueAlt = 0;
|
||||||
// {@code (s,i,_,semctx)} to be equal. Unfortunately, this key effectively
|
this.conflictingAlts = null;
|
||||||
// doubles
|
|
||||||
// the number of objects associated with ATNConfigs. The other solution is
|
|
||||||
// to
|
|
||||||
// use a hash table that lets us specify the equals/hashcode operation.
|
|
||||||
// All configs but hashed by (s, i, _, pi) not including context. Wiped out
|
|
||||||
// when we go readonly as this set becomes a DFA state.
|
|
||||||
this.configLookup = new Set(hashATNConfig, equalATNConfigs);
|
|
||||||
// Indicates that this configuration set is part of a full context
|
|
||||||
// LL prediction. It will be used to determine how to merge $. With SLL
|
|
||||||
// it's a wildcard whereas it is not for LL context merge.
|
|
||||||
this.fullCtx = fullCtx === undefined ? true : fullCtx;
|
|
||||||
// Indicates that the set of configurations is read-only. Do not
|
|
||||||
// allow any code to manipulate the set; DFA states will point at
|
|
||||||
// the sets and they must not change. This does not protect the other
|
|
||||||
// fields; in particular, conflictingAlts is set after
|
|
||||||
// we've made this readonly.
|
|
||||||
this.readOnly = false;
|
|
||||||
// Track the elements as they are added to the set; supports get(i)///
|
|
||||||
this.configs = [];
|
|
||||||
|
|
||||||
// TODO: these fields make me pretty uncomfortable but nice to pack up info
|
/**
|
||||||
// together, saves recomputation
|
* Used in parser and lexer. In lexer, it indicates we hit a pred
|
||||||
// TODO: can we track conflicts as they are added to save scanning configs
|
* while computing a closure operation. Don't make a DFA state from this
|
||||||
// later?
|
*/
|
||||||
this.uniqueAlt = 0;
|
this.hasSemanticContext = false;
|
||||||
this.conflictingAlts = null;
|
this.dipsIntoOuterContext = false;
|
||||||
|
|
||||||
// Used in parser and lexer. In lexer, it indicates we hit a pred
|
|
||||||
// while computing a closure operation. Don't make a DFA state from this.
|
|
||||||
this.hasSemanticContext = false;
|
|
||||||
this.dipsIntoOuterContext = false;
|
|
||||||
|
|
||||||
this.cachedHashCode = -1;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adding a new config means merging contexts with existing configs for
|
|
||||||
// {@code (s, i, pi, _)}, where {@code s} is the
|
|
||||||
// {@link ATNConfig//state}, {@code i} is the {@link ATNConfig//alt}, and
|
|
||||||
// {@code pi} is the {@link ATNConfig//semanticContext}. We use
|
|
||||||
// {@code (s,i,pi)} as key.
|
|
||||||
//
|
|
||||||
// <p>This method updates {@link //dipsIntoOuterContext} and
|
|
||||||
// {@link //hasSemanticContext} when necessary.</p>
|
|
||||||
// /
|
|
||||||
ATNConfigSet.prototype.add = function(config, mergeCache) {
|
|
||||||
if (mergeCache === undefined) {
|
|
||||||
mergeCache = null;
|
|
||||||
}
|
|
||||||
if (this.readOnly) {
|
|
||||||
throw "This set is readonly";
|
|
||||||
}
|
|
||||||
if (config.semanticContext !== SemanticContext.NONE) {
|
|
||||||
this.hasSemanticContext = true;
|
|
||||||
}
|
|
||||||
if (config.reachesIntoOuterContext > 0) {
|
|
||||||
this.dipsIntoOuterContext = true;
|
|
||||||
}
|
|
||||||
var existing = this.configLookup.add(config);
|
|
||||||
if (existing === config) {
|
|
||||||
this.cachedHashCode = -1;
|
this.cachedHashCode = -1;
|
||||||
this.configs.push(config); // track order here
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adding a new config means merging contexts with existing configs for
|
||||||
|
* {@code (s, i, pi, _)}, where {@code s} is the
|
||||||
|
* {@link ATNConfig//state}, {@code i} is the {@link ATNConfig//alt}, and
|
||||||
|
* {@code pi} is the {@link ATNConfig//semanticContext}. We use
|
||||||
|
* {@code (s,i,pi)} as key.
|
||||||
|
*
|
||||||
|
* <p>This method updates {@link //dipsIntoOuterContext} and
|
||||||
|
* {@link //hasSemanticContext} when necessary.</p>
|
||||||
|
*/
|
||||||
|
add(config, mergeCache) {
|
||||||
|
if (mergeCache === undefined) {
|
||||||
|
mergeCache = null;
|
||||||
|
}
|
||||||
|
if (this.readOnly) {
|
||||||
|
throw "This set is readonly";
|
||||||
|
}
|
||||||
|
if (config.semanticContext !== SemanticContext.NONE) {
|
||||||
|
this.hasSemanticContext = true;
|
||||||
|
}
|
||||||
|
if (config.reachesIntoOuterContext > 0) {
|
||||||
|
this.dipsIntoOuterContext = true;
|
||||||
|
}
|
||||||
|
const existing = this.configLookup.add(config);
|
||||||
|
if (existing === config) {
|
||||||
|
this.cachedHashCode = -1;
|
||||||
|
this.configs.push(config); // track order here
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// a previous (s,i,pi,_), merge with it and save result
|
||||||
|
const rootIsWildcard = !this.fullCtx;
|
||||||
|
const merged = merge(existing.context, config.context, rootIsWildcard, mergeCache);
|
||||||
|
/**
|
||||||
|
* no need to check for existing.context, config.context in cache
|
||||||
|
* since only way to create new graphs is "call rule" and here. We
|
||||||
|
* cache at both places
|
||||||
|
*/
|
||||||
|
existing.reachesIntoOuterContext = Math.max( existing.reachesIntoOuterContext, config.reachesIntoOuterContext);
|
||||||
|
// make sure to preserve the precedence filter suppression during the merge
|
||||||
|
if (config.precedenceFilterSuppressed) {
|
||||||
|
existing.precedenceFilterSuppressed = true;
|
||||||
|
}
|
||||||
|
existing.context = merged; // replace context; no need to alt mapping
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// a previous (s,i,pi,_), merge with it and save result
|
|
||||||
var rootIsWildcard = !this.fullCtx;
|
|
||||||
var merged = merge(existing.context, config.context, rootIsWildcard, mergeCache);
|
|
||||||
// no need to check for existing.context, config.context in cache
|
|
||||||
// since only way to create new graphs is "call rule" and here. We
|
|
||||||
// cache at both places.
|
|
||||||
existing.reachesIntoOuterContext = Math.max( existing.reachesIntoOuterContext, config.reachesIntoOuterContext);
|
|
||||||
// make sure to preserve the precedence filter suppression during the merge
|
|
||||||
if (config.precedenceFilterSuppressed) {
|
|
||||||
existing.precedenceFilterSuppressed = true;
|
|
||||||
}
|
|
||||||
existing.context = merged; // replace context; no need to alt mapping
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.getStates = function() {
|
getStates() {
|
||||||
var states = new Set();
|
const states = new Utils.Set();
|
||||||
for (var i = 0; i < this.configs.length; i++) {
|
for (let i = 0; i < this.configs.length; i++) {
|
||||||
states.add(this.configs[i].state);
|
states.add(this.configs[i].state);
|
||||||
|
}
|
||||||
|
return states;
|
||||||
}
|
}
|
||||||
return states;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.getPredicates = function() {
|
getPredicates() {
|
||||||
var preds = [];
|
const preds = [];
|
||||||
for (var i = 0; i < this.configs.length; i++) {
|
for (let i = 0; i < this.configs.length; i++) {
|
||||||
var c = this.configs[i].semanticContext;
|
const c = this.configs[i].semanticContext;
|
||||||
if (c !== SemanticContext.NONE) {
|
if (c !== SemanticContext.NONE) {
|
||||||
preds.push(c.semanticContext);
|
preds.push(c.semanticContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preds;
|
||||||
|
}
|
||||||
|
|
||||||
|
optimizeConfigs(interpreter) {
|
||||||
|
if (this.readOnly) {
|
||||||
|
throw "This set is readonly";
|
||||||
|
}
|
||||||
|
if (this.configLookup.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.configs.length; i++) {
|
||||||
|
const config = this.configs[i];
|
||||||
|
config.context = interpreter.getCachedContext(config.context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return preds;
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperty(ATNConfigSet.prototype, "items", {
|
addAll(coll) {
|
||||||
get : function() {
|
for (let i = 0; i < coll.length; i++) {
|
||||||
|
this.add(coll[i]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashCode() {
|
||||||
|
const hash = new Utils.Hash();
|
||||||
|
hash.update(this.configs);
|
||||||
|
return hash.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHashCode(hash) {
|
||||||
|
if (this.readOnly) {
|
||||||
|
if (this.cachedHashCode === -1) {
|
||||||
|
this.cachedHashCode = this.hashCode();
|
||||||
|
}
|
||||||
|
hash.update(this.cachedHashCode);
|
||||||
|
} else {
|
||||||
|
hash.update(this.hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
return this.configs.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
contains(item) {
|
||||||
|
if (this.configLookup === null) {
|
||||||
|
throw "This method is not implemented for readonly sets.";
|
||||||
|
}
|
||||||
|
return this.configLookup.contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
containsFast(item) {
|
||||||
|
if (this.configLookup === null) {
|
||||||
|
throw "This method is not implemented for readonly sets.";
|
||||||
|
}
|
||||||
|
return this.configLookup.containsFast(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
if (this.readOnly) {
|
||||||
|
throw "This set is readonly";
|
||||||
|
}
|
||||||
|
this.configs = [];
|
||||||
|
this.cachedHashCode = -1;
|
||||||
|
this.configLookup = new Utils.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
setReadonly(readOnly) {
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
if (readOnly) {
|
||||||
|
this.configLookup = null; // can't mod, no need for lookup cache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return Utils.arrayToString(this.configs) +
|
||||||
|
(this.hasSemanticContext ? ",hasSemanticContext=" + this.hasSemanticContext : "") +
|
||||||
|
(this.uniqueAlt !== ATN.INVALID_ALT_NUMBER ? ",uniqueAlt=" + this.uniqueAlt : "") +
|
||||||
|
(this.conflictingAlts !== null ? ",conflictingAlts=" + this.conflictingAlts : "") +
|
||||||
|
(this.dipsIntoOuterContext ? ",dipsIntoOuterContext" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
get items(){
|
||||||
return this.configs;
|
return this.configs;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.optimizeConfigs = function(interpreter) {
|
get length(){
|
||||||
if (this.readOnly) {
|
|
||||||
throw "This set is readonly";
|
|
||||||
}
|
|
||||||
if (this.configLookup.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < this.configs.length; i++) {
|
|
||||||
var config = this.configs[i];
|
|
||||||
config.context = interpreter.getCachedContext(config.context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.addAll = function(coll) {
|
|
||||||
for (var i = 0; i < coll.length; i++) {
|
|
||||||
this.add(coll[i]);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.equals = function(other) {
|
|
||||||
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.hashCode = function() {
|
|
||||||
var hash = new Hash();
|
|
||||||
hash.update(this.configs);
|
|
||||||
return hash.finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.updateHashCode = function(hash) {
|
|
||||||
if (this.readOnly) {
|
|
||||||
if (this.cachedHashCode === -1) {
|
|
||||||
this.cachedHashCode = this.hashCode();
|
|
||||||
}
|
|
||||||
hash.update(this.cachedHashCode);
|
|
||||||
} else {
|
|
||||||
hash.update(this.hashCode());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Object.defineProperty(ATNConfigSet.prototype, "length", {
|
|
||||||
get : function() {
|
|
||||||
return this.configs.length;
|
return this.configs.length;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.isEmpty = function() {
|
|
||||||
return this.configs.length === 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.contains = function(item) {
|
|
||||||
if (this.configLookup === null) {
|
|
||||||
throw "This method is not implemented for readonly sets.";
|
|
||||||
}
|
|
||||||
return this.configLookup.contains(item);
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.containsFast = function(item) {
|
|
||||||
if (this.configLookup === null) {
|
|
||||||
throw "This method is not implemented for readonly sets.";
|
|
||||||
}
|
|
||||||
return this.configLookup.containsFast(item);
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.clear = function() {
|
|
||||||
if (this.readOnly) {
|
|
||||||
throw "This set is readonly";
|
|
||||||
}
|
|
||||||
this.configs = [];
|
|
||||||
this.cachedHashCode = -1;
|
|
||||||
this.configLookup = new Set();
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.setReadonly = function(readOnly) {
|
|
||||||
this.readOnly = readOnly;
|
|
||||||
if (readOnly) {
|
|
||||||
this.configLookup = null; // can't mod, no need for lookup cache
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNConfigSet.prototype.toString = function() {
|
|
||||||
return Utils.arrayToString(this.configs) +
|
|
||||||
(this.hasSemanticContext ? ",hasSemanticContext=" + this.hasSemanticContext : "") +
|
|
||||||
(this.uniqueAlt !== ATN.INVALID_ALT_NUMBER ? ",uniqueAlt=" + this.uniqueAlt : "") +
|
|
||||||
(this.conflictingAlts !== null ? ",conflictingAlts=" + this.conflictingAlts : "") +
|
|
||||||
(this.dipsIntoOuterContext ? ",dipsIntoOuterContext" : "");
|
|
||||||
};
|
|
||||||
|
|
||||||
function OrderedATNConfigSet() {
|
|
||||||
ATNConfigSet.call(this);
|
|
||||||
this.configLookup = new Set();
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderedATNConfigSet.prototype = Object.create(ATNConfigSet.prototype);
|
|
||||||
OrderedATNConfigSet.prototype.constructor = OrderedATNConfigSet;
|
|
||||||
|
|
||||||
exports.ATNConfigSet = ATNConfigSet;
|
class OrderedATNConfigSet extends ATNConfigSet {
|
||||||
exports.OrderedATNConfigSet = OrderedATNConfigSet;
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.configLookup = new Utils.Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ATNConfigSet,
|
||||||
|
OrderedATNConfigSet
|
||||||
|
}
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
* can be found in the LICENSE.txt file in the project root.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ATNDeserializationOptions(copyFrom) {
|
class ATNDeserializationOptions {
|
||||||
if(copyFrom===undefined) {
|
constructor(copyFrom) {
|
||||||
copyFrom = null;
|
if(copyFrom===undefined) {
|
||||||
|
copyFrom = null;
|
||||||
|
}
|
||||||
|
this.readOnly = false;
|
||||||
|
this.verifyATN = copyFrom===null ? true : copyFrom.verifyATN;
|
||||||
|
this.generateRuleBypassTransitions = copyFrom===null ? false : copyFrom.generateRuleBypassTransitions;
|
||||||
}
|
}
|
||||||
this.readOnly = false;
|
|
||||||
this.verifyATN = copyFrom===null ? true : copyFrom.verifyATN;
|
|
||||||
this.generateRuleBypassTransitions = copyFrom===null ? false : copyFrom.generateRuleBypassTransitions;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ATNDeserializationOptions.defaultOptions = new ATNDeserializationOptions();
|
ATNDeserializationOptions.defaultOptions = new ATNDeserializationOptions();
|
||||||
|
@ -22,4 +22,4 @@ ATNDeserializationOptions.defaultOptions.readOnly = true;
|
||||||
// raise Exception("The object is read only.")
|
// raise Exception("The object is read only.")
|
||||||
// super(type(self), self).__setattr__(key,value)
|
// super(type(self), self).__setattr__(key,value)
|
||||||
|
|
||||||
exports.ATNDeserializationOptions = ATNDeserializationOptions;
|
module.exports = ATNDeserializationOptions
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,52 +1,52 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
///
|
|
||||||
|
|
||||||
var DFAState = require('./../dfa/DFAState').DFAState;
|
const {DFAState} = require('./../dfa/DFAState');
|
||||||
var ATNConfigSet = require('./ATNConfigSet').ATNConfigSet;
|
const {ATNConfigSet} = require('./ATNConfigSet');
|
||||||
var getCachedPredictionContext = require('./../PredictionContext').getCachedPredictionContext;
|
const {getCachedPredictionContext} = require('./../PredictionContext');
|
||||||
var Map = require('./../Utils').Map;
|
const {Map} = require('./../Utils');
|
||||||
|
|
||||||
function ATNSimulator(atn, sharedContextCache) {
|
class ATNSimulator {
|
||||||
|
constructor(atn, sharedContextCache) {
|
||||||
|
/**
|
||||||
|
* The context cache maps all PredictionContext objects that are ==
|
||||||
|
* to a single cached copy. This cache is shared across all contexts
|
||||||
|
* in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet
|
||||||
|
* to use only cached nodes/graphs in addDFAState(). We don't want to
|
||||||
|
* fill this during closure() since there are lots of contexts that
|
||||||
|
* pop up but are not used ever again. It also greatly slows down closure().
|
||||||
|
*
|
||||||
|
* <p>This cache makes a huge difference in memory and a little bit in speed.
|
||||||
|
* For the Java grammar on java.*, it dropped the memory requirements
|
||||||
|
* at the end from 25M to 16M. We don't store any of the full context
|
||||||
|
* graphs in the DFA because they are limited to local context only,
|
||||||
|
* but apparently there's a lot of repetition there as well. We optimize
|
||||||
|
* the config contexts before storing the config set in the DFA states
|
||||||
|
* by literally rebuilding them with cached subgraphs only.</p>
|
||||||
|
*
|
||||||
|
* <p>I tried a cache for use during closure operations, that was
|
||||||
|
* whacked after each adaptivePredict(). It cost a little bit
|
||||||
|
* more time I think and doesn't save on the overall footprint
|
||||||
|
* so it's not worth the complexity.</p>
|
||||||
|
*/
|
||||||
|
this.atn = atn;
|
||||||
|
this.sharedContextCache = sharedContextCache;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// The context cache maps all PredictionContext objects that are ==
|
getCachedContext(context) {
|
||||||
// to a single cached copy. This cache is shared across all contexts
|
if (this.sharedContextCache ===null) {
|
||||||
// in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet
|
return context;
|
||||||
// to use only cached nodes/graphs in addDFAState(). We don't want to
|
}
|
||||||
// fill this during closure() since there are lots of contexts that
|
const visited = new Map();
|
||||||
// pop up but are not used ever again. It also greatly slows down closure().
|
return getCachedPredictionContext(context, this.sharedContextCache, visited);
|
||||||
//
|
}
|
||||||
// <p>This cache makes a huge difference in memory and a little bit in speed.
|
|
||||||
// For the Java grammar on java.*, it dropped the memory requirements
|
|
||||||
// at the end from 25M to 16M. We don't store any of the full context
|
|
||||||
// graphs in the DFA because they are limited to local context only,
|
|
||||||
// but apparently there's a lot of repetition there as well. We optimize
|
|
||||||
// the config contexts before storing the config set in the DFA states
|
|
||||||
// by literally rebuilding them with cached subgraphs only.</p>
|
|
||||||
//
|
|
||||||
// <p>I tried a cache for use during closure operations, that was
|
|
||||||
// whacked after each adaptivePredict(). It cost a little bit
|
|
||||||
// more time I think and doesn't save on the overall footprint
|
|
||||||
// so it's not worth the complexity.</p>
|
|
||||||
///
|
|
||||||
this.atn = atn;
|
|
||||||
this.sharedContextCache = sharedContextCache;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must distinguish between missing edge and edge we know leads nowhere///
|
// Must distinguish between missing edge and edge we know leads nowhere///
|
||||||
ATNSimulator.ERROR = new DFAState(0x7FFFFFFF, new ATNConfigSet());
|
ATNSimulator.ERROR = new DFAState(0x7FFFFFFF, new ATNConfigSet());
|
||||||
|
|
||||||
|
|
||||||
ATNSimulator.prototype.getCachedContext = function(context) {
|
module.exports = ATNSimulator;
|
||||||
if (this.sharedContextCache ===null) {
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
var visited = new Map();
|
|
||||||
return getCachedPredictionContext(context, this.sharedContextCache, visited);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.ATNSimulator = ATNSimulator;
|
|
||||||
|
|
|
@ -1,84 +1,115 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
//
|
|
||||||
|
|
||||||
// The following images show the relation of states and
|
const INITIAL_NUM_TRANSITIONS = 4;
|
||||||
// {@link ATNState//transitions} for various grammar constructs.
|
|
||||||
//
|
|
||||||
// <ul>
|
|
||||||
//
|
|
||||||
// <li>Solid edges marked with an &//0949; indicate a required
|
|
||||||
// {@link EpsilonTransition}.</li>
|
|
||||||
//
|
|
||||||
// <li>Dashed edges indicate locations where any transition derived from
|
|
||||||
// {@link Transition} might appear.</li>
|
|
||||||
//
|
|
||||||
// <li>Dashed nodes are place holders for either a sequence of linked
|
|
||||||
// {@link BasicState} states or the inclusion of a block representing a nested
|
|
||||||
// construct in one of the forms below.</li>
|
|
||||||
//
|
|
||||||
// <li>Nodes showing multiple outgoing alternatives with a {@code ...} support
|
|
||||||
// any number of alternatives (one or more). Nodes without the {@code ...} only
|
|
||||||
// support the exact number of alternatives shown in the diagram.</li>
|
|
||||||
//
|
|
||||||
// </ul>
|
|
||||||
//
|
|
||||||
// <h2>Basic Blocks</h2>
|
|
||||||
//
|
|
||||||
// <h3>Rule</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/Rule.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h3>Block of 1 or more alternatives</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/Block.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h2>Greedy Loops</h2>
|
|
||||||
//
|
|
||||||
// <h3>Greedy Closure: {@code (...)*}</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/ClosureGreedy.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h3>Greedy Positive Closure: {@code (...)+}</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/PositiveClosureGreedy.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h3>Greedy Optional: {@code (...)?}</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/OptionalGreedy.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h2>Non-Greedy Loops</h2>
|
|
||||||
//
|
|
||||||
// <h3>Non-Greedy Closure: {@code (...)*?}</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/ClosureNonGreedy.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h3>Non-Greedy Positive Closure: {@code (...)+?}</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/PositiveClosureNonGreedy.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
// <h3>Non-Greedy Optional: {@code (...)??}</h3>
|
|
||||||
//
|
|
||||||
// <embed src="images/OptionalNonGreedy.svg" type="image/svg+xml"/>
|
|
||||||
//
|
|
||||||
|
|
||||||
var INITIAL_NUM_TRANSITIONS = 4;
|
/**
|
||||||
|
* The following images show the relation of states and
|
||||||
|
* {@link ATNState//transitions} for various grammar constructs.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
*
|
||||||
|
* <li>Solid edges marked with an &//0949; indicate a required
|
||||||
|
* {@link EpsilonTransition}.</li>
|
||||||
|
*
|
||||||
|
* <li>Dashed edges indicate locations where any transition derived from
|
||||||
|
* {@link Transition} might appear.</li>
|
||||||
|
*
|
||||||
|
* <li>Dashed nodes are place holders for either a sequence of linked
|
||||||
|
* {@link BasicState} states or the inclusion of a block representing a nested
|
||||||
|
* construct in one of the forms below.</li>
|
||||||
|
*
|
||||||
|
* <li>Nodes showing multiple outgoing alternatives with a {@code ...} support
|
||||||
|
* any number of alternatives (one or more). Nodes without the {@code ...} only
|
||||||
|
* support the exact number of alternatives shown in the diagram.</li>
|
||||||
|
*
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Basic Blocks</h2>
|
||||||
|
*
|
||||||
|
* <h3>Rule</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/Rule.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h3>Block of 1 or more alternatives</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/Block.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h2>Greedy Loops</h2>
|
||||||
|
*
|
||||||
|
* <h3>Greedy Closure: {@code (...)*}</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/ClosureGreedy.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h3>Greedy Positive Closure: {@code (...)+}</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/PositiveClosureGreedy.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h3>Greedy Optional: {@code (...)?}</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/OptionalGreedy.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h2>Non-Greedy Loops</h2>
|
||||||
|
*
|
||||||
|
* <h3>Non-Greedy Closure: {@code (...)*?}</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/ClosureNonGreedy.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h3>Non-Greedy Positive Closure: {@code (...)+?}</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/PositiveClosureNonGreedy.svg" type="image/svg+xml"/>
|
||||||
|
*
|
||||||
|
* <h3>Non-Greedy Optional: {@code (...)??}</h3>
|
||||||
|
*
|
||||||
|
* <embed src="images/OptionalNonGreedy.svg" type="image/svg+xml"/>
|
||||||
|
*/
|
||||||
|
class ATNState {
|
||||||
|
constructor() {
|
||||||
|
// Which ATN are we in?
|
||||||
|
this.atn = null;
|
||||||
|
this.stateNumber = ATNState.INVALID_STATE_NUMBER;
|
||||||
|
this.stateType = null;
|
||||||
|
this.ruleIndex = 0; // at runtime, we don't have Rule objects
|
||||||
|
this.epsilonOnlyTransitions = false;
|
||||||
|
// Track the transitions emanating from this ATN state.
|
||||||
|
this.transitions = [];
|
||||||
|
// Used to cache lookahead during parsing, not used during construction
|
||||||
|
this.nextTokenWithinRule = null;
|
||||||
|
}
|
||||||
|
|
||||||
function ATNState() {
|
toString() {
|
||||||
// Which ATN are we in?
|
return this.stateNumber;
|
||||||
this.atn = null;
|
}
|
||||||
this.stateNumber = ATNState.INVALID_STATE_NUMBER;
|
|
||||||
this.stateType = null;
|
equals(other) {
|
||||||
this.ruleIndex = 0; // at runtime, we don't have Rule objects
|
if (other instanceof ATNState) {
|
||||||
this.epsilonOnlyTransitions = false;
|
return this.stateNumber===other.stateNumber;
|
||||||
// Track the transitions emanating from this ATN state.
|
} else {
|
||||||
this.transitions = [];
|
return false;
|
||||||
// Used to cache lookahead during parsing, not used during construction
|
}
|
||||||
this.nextTokenWithinRule = null;
|
}
|
||||||
return this;
|
|
||||||
|
isNonGreedyExitState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTransition(trans, index) {
|
||||||
|
if(index===undefined) {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
if (this.transitions.length===0) {
|
||||||
|
this.epsilonOnlyTransitions = trans.isEpsilon;
|
||||||
|
} else if(this.epsilonOnlyTransitions !== trans.isEpsilon) {
|
||||||
|
this.epsilonOnlyTransitions = false;
|
||||||
|
}
|
||||||
|
if (index===-1) {
|
||||||
|
this.transitions.push(trans);
|
||||||
|
} else {
|
||||||
|
this.transitions.splice(index, 1, trans);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// constants for serialization
|
// constants for serialization
|
||||||
|
@ -113,214 +144,172 @@ ATNState.serializationNames = [
|
||||||
|
|
||||||
ATNState.INVALID_STATE_NUMBER = -1;
|
ATNState.INVALID_STATE_NUMBER = -1;
|
||||||
|
|
||||||
ATNState.prototype.toString = function() {
|
|
||||||
return this.stateNumber;
|
|
||||||
};
|
|
||||||
|
|
||||||
ATNState.prototype.equals = function(other) {
|
class BasicState extends ATNState {
|
||||||
if (other instanceof ATNState) {
|
constructor() {
|
||||||
return this.stateNumber===other.stateNumber;
|
super();
|
||||||
} else {
|
this.stateType = ATNState.BASIC;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
ATNState.prototype.isNonGreedyExitState = function() {
|
class DecisionState extends ATNState {
|
||||||
return false;
|
constructor() {
|
||||||
};
|
super();
|
||||||
|
this.decision = -1;
|
||||||
|
this.nonGreedy = false;
|
||||||
ATNState.prototype.addTransition = function(trans, index) {
|
return this;
|
||||||
if(index===undefined) {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
if (this.transitions.length===0) {
|
|
||||||
this.epsilonOnlyTransitions = trans.isEpsilon;
|
|
||||||
} else if(this.epsilonOnlyTransitions !== trans.isEpsilon) {
|
|
||||||
this.epsilonOnlyTransitions = false;
|
|
||||||
}
|
}
|
||||||
if (index===-1) {
|
}
|
||||||
this.transitions.push(trans);
|
|
||||||
} else {
|
/**
|
||||||
this.transitions.splice(index, 1, trans);
|
* The start of a regular {@code (...)} block
|
||||||
|
*/
|
||||||
|
class BlockStartState extends DecisionState {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.endState = null;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function BasicState() {
|
|
||||||
ATNState.call(this);
|
|
||||||
this.stateType = ATNState.BASIC;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicState.prototype = Object.create(ATNState.prototype);
|
class BasicBlockStartState extends BlockStartState {
|
||||||
BasicState.prototype.constructor = BasicState;
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.stateType = ATNState.BLOCK_START;
|
||||||
function DecisionState() {
|
return this;
|
||||||
ATNState.call(this);
|
}
|
||||||
this.decision = -1;
|
|
||||||
this.nonGreedy = false;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DecisionState.prototype = Object.create(ATNState.prototype);
|
/**
|
||||||
DecisionState.prototype.constructor = DecisionState;
|
* Terminal node of a simple {@code (a|b|c)} block
|
||||||
|
*/
|
||||||
|
class BlockEndState extends ATNState {
|
||||||
// The start of a regular {@code (...)} block.
|
constructor() {
|
||||||
function BlockStartState() {
|
super();
|
||||||
DecisionState.call(this);
|
this.stateType = ATNState.BLOCK_END;
|
||||||
this.endState = null;
|
this.startState = null;
|
||||||
return this;
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockStartState.prototype = Object.create(DecisionState.prototype);
|
/**
|
||||||
BlockStartState.prototype.constructor = BlockStartState;
|
* The last node in the ATN for a rule, unless that rule is the start symbol.
|
||||||
|
* In that case, there is one transition to EOF. Later, we might encode
|
||||||
|
* references to all calls to this rule to compute FOLLOW sets for
|
||||||
function BasicBlockStartState() {
|
* error handling
|
||||||
BlockStartState.call(this);
|
*/
|
||||||
this.stateType = ATNState.BLOCK_START;
|
class RuleStopState extends ATNState {
|
||||||
return this;
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.stateType = ATNState.RULE_STOP;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlockStartState.prototype = Object.create(BlockStartState.prototype);
|
class RuleStartState extends ATNState {
|
||||||
BasicBlockStartState.prototype.constructor = BasicBlockStartState;
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.stateType = ATNState.RULE_START;
|
||||||
// Terminal node of a simple {@code (a|b|c)} block.
|
this.stopState = null;
|
||||||
function BlockEndState() {
|
this.isPrecedenceRule = false;
|
||||||
ATNState.call(this);
|
return this;
|
||||||
this.stateType = ATNState.BLOCK_END;
|
}
|
||||||
this.startState = null;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockEndState.prototype = Object.create(ATNState.prototype);
|
/**
|
||||||
BlockEndState.prototype.constructor = BlockEndState;
|
* Decision state for {@code A+} and {@code (A|B)+}. It has two transitions:
|
||||||
|
* one to the loop back to start of the block and one to exit.
|
||||||
|
*/
|
||||||
// The last node in the ATN for a rule, unless that rule is the start symbol.
|
class PlusLoopbackState extends DecisionState {
|
||||||
// In that case, there is one transition to EOF. Later, we might encode
|
constructor() {
|
||||||
// references to all calls to this rule to compute FOLLOW sets for
|
super();
|
||||||
// error handling.
|
this.stateType = ATNState.PLUS_LOOP_BACK;
|
||||||
//
|
return this;
|
||||||
function RuleStopState() {
|
}
|
||||||
ATNState.call(this);
|
|
||||||
this.stateType = ATNState.RULE_STOP;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RuleStopState.prototype = Object.create(ATNState.prototype);
|
/**
|
||||||
RuleStopState.prototype.constructor = RuleStopState;
|
* Start of {@code (A|B|...)+} loop. Technically a decision state, but
|
||||||
|
* we don't use for code generation; somebody might need it, so I'm defining
|
||||||
function RuleStartState() {
|
* it for completeness. In reality, the {@link PlusLoopbackState} node is the
|
||||||
ATNState.call(this);
|
* real decision-making note for {@code A+}
|
||||||
this.stateType = ATNState.RULE_START;
|
*/
|
||||||
this.stopState = null;
|
class PlusBlockStartState extends BlockStartState {
|
||||||
this.isPrecedenceRule = false;
|
constructor() {
|
||||||
return this;
|
super();
|
||||||
|
this.stateType = ATNState.PLUS_BLOCK_START;
|
||||||
|
this.loopBackState = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RuleStartState.prototype = Object.create(ATNState.prototype);
|
/**
|
||||||
RuleStartState.prototype.constructor = RuleStartState;
|
* The block that begins a closure loop
|
||||||
|
*/
|
||||||
// Decision state for {@code A+} and {@code (A|B)+}. It has two transitions:
|
class StarBlockStartState extends BlockStartState {
|
||||||
// one to the loop back to start of the block and one to exit.
|
constructor() {
|
||||||
//
|
super();
|
||||||
function PlusLoopbackState() {
|
this.stateType = ATNState.STAR_BLOCK_START;
|
||||||
DecisionState.call(this);
|
return this;
|
||||||
this.stateType = ATNState.PLUS_LOOP_BACK;
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlusLoopbackState.prototype = Object.create(DecisionState.prototype);
|
class StarLoopbackState extends ATNState {
|
||||||
PlusLoopbackState.prototype.constructor = PlusLoopbackState;
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.stateType = ATNState.STAR_LOOP_BACK;
|
||||||
// Start of {@code (A|B|...)+} loop. Technically a decision state, but
|
return this;
|
||||||
// we don't use for code generation; somebody might need it, so I'm defining
|
}
|
||||||
// it for completeness. In reality, the {@link PlusLoopbackState} node is the
|
|
||||||
// real decision-making note for {@code A+}.
|
|
||||||
//
|
|
||||||
function PlusBlockStartState() {
|
|
||||||
BlockStartState.call(this);
|
|
||||||
this.stateType = ATNState.PLUS_BLOCK_START;
|
|
||||||
this.loopBackState = null;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlusBlockStartState.prototype = Object.create(BlockStartState.prototype);
|
class StarLoopEntryState extends DecisionState {
|
||||||
PlusBlockStartState.prototype.constructor = PlusBlockStartState;
|
constructor() {
|
||||||
|
super();
|
||||||
// The block that begins a closure loop.
|
this.stateType = ATNState.STAR_LOOP_ENTRY;
|
||||||
function StarBlockStartState() {
|
this.loopBackState = null;
|
||||||
BlockStartState.call(this);
|
// Indicates whether this state can benefit from a precedence DFA during SLL decision making.
|
||||||
this.stateType = ATNState.STAR_BLOCK_START;
|
this.isPrecedenceDecision = null;
|
||||||
return this;
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StarBlockStartState.prototype = Object.create(BlockStartState.prototype);
|
/**
|
||||||
StarBlockStartState.prototype.constructor = StarBlockStartState;
|
* Mark the end of a * or + loop
|
||||||
|
*/
|
||||||
|
class LoopEndState extends ATNState {
|
||||||
function StarLoopbackState() {
|
constructor() {
|
||||||
ATNState.call(this);
|
super();
|
||||||
this.stateType = ATNState.STAR_LOOP_BACK;
|
this.stateType = ATNState.LOOP_END;
|
||||||
return this;
|
this.loopBackState = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StarLoopbackState.prototype = Object.create(ATNState.prototype);
|
/**
|
||||||
StarLoopbackState.prototype.constructor = StarLoopbackState;
|
* The Tokens rule start state linking to each lexer rule start state
|
||||||
|
*/
|
||||||
|
class TokensStartState extends DecisionState {
|
||||||
function StarLoopEntryState() {
|
constructor() {
|
||||||
DecisionState.call(this);
|
super();
|
||||||
this.stateType = ATNState.STAR_LOOP_ENTRY;
|
this.stateType = ATNState.TOKEN_START;
|
||||||
this.loopBackState = null;
|
return this;
|
||||||
// Indicates whether this state can benefit from a precedence DFA during SLL decision making.
|
}
|
||||||
this.isPrecedenceDecision = null;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StarLoopEntryState.prototype = Object.create(DecisionState.prototype);
|
module.exports = {
|
||||||
StarLoopEntryState.prototype.constructor = StarLoopEntryState;
|
ATNState,
|
||||||
|
BasicState,
|
||||||
|
DecisionState,
|
||||||
// Mark the end of a * or + loop.
|
BlockStartState,
|
||||||
function LoopEndState() {
|
BlockEndState,
|
||||||
ATNState.call(this);
|
LoopEndState,
|
||||||
this.stateType = ATNState.LOOP_END;
|
RuleStartState,
|
||||||
this.loopBackState = null;
|
RuleStopState,
|
||||||
return this;
|
TokensStartState,
|
||||||
|
PlusLoopbackState,
|
||||||
|
StarLoopbackState,
|
||||||
|
StarLoopEntryState,
|
||||||
|
PlusBlockStartState,
|
||||||
|
StarBlockStartState,
|
||||||
|
BasicBlockStartState
|
||||||
}
|
}
|
||||||
|
|
||||||
LoopEndState.prototype = Object.create(ATNState.prototype);
|
|
||||||
LoopEndState.prototype.constructor = LoopEndState;
|
|
||||||
|
|
||||||
|
|
||||||
// The Tokens rule start state linking to each lexer rule start state */
|
|
||||||
function TokensStartState() {
|
|
||||||
DecisionState.call(this);
|
|
||||||
this.stateType = ATNState.TOKEN_START;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
TokensStartState.prototype = Object.create(DecisionState.prototype);
|
|
||||||
TokensStartState.prototype.constructor = TokensStartState;
|
|
||||||
|
|
||||||
exports.ATNState = ATNState;
|
|
||||||
exports.BasicState = BasicState;
|
|
||||||
exports.DecisionState = DecisionState;
|
|
||||||
exports.BlockStartState = BlockStartState;
|
|
||||||
exports.BlockEndState = BlockEndState;
|
|
||||||
exports.LoopEndState = LoopEndState;
|
|
||||||
exports.RuleStartState = RuleStartState;
|
|
||||||
exports.RuleStopState = RuleStopState;
|
|
||||||
exports.TokensStartState = TokensStartState;
|
|
||||||
exports.PlusLoopbackState = PlusLoopbackState;
|
|
||||||
exports.StarLoopbackState = StarLoopbackState;
|
|
||||||
exports.StarLoopEntryState = StarLoopEntryState;
|
|
||||||
exports.PlusBlockStartState = PlusBlockStartState;
|
|
||||||
exports.StarBlockStartState = StarBlockStartState;
|
|
||||||
exports.BasicBlockStartState = BasicBlockStartState;
|
|
||||||
|
|
|
@ -2,16 +2,12 @@
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
///
|
|
||||||
|
|
||||||
// Represents the type of recognizer an ATN applies to.
|
/**
|
||||||
|
* Represents the type of recognizer an ATN applies to
|
||||||
function ATNType() {
|
*/
|
||||||
|
module.exports = {
|
||||||
}
|
LEXER: 0,
|
||||||
|
PARSER: 1
|
||||||
ATNType.LEXER = 0;
|
};
|
||||||
ATNType.PARSER = 1;
|
|
||||||
|
|
||||||
exports.ATNType = ATNType;
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,366 +1,384 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
//
|
|
||||||
|
|
||||||
function LexerActionType() {
|
const LexerActionType = {
|
||||||
|
// The type of a {@link LexerChannelAction} action.
|
||||||
|
CHANNEL: 0,
|
||||||
|
// The type of a {@link LexerCustomAction} action
|
||||||
|
CUSTOM: 1,
|
||||||
|
// The type of a {@link LexerModeAction} action.
|
||||||
|
MODE: 2,
|
||||||
|
//The type of a {@link LexerMoreAction} action.
|
||||||
|
MORE: 3,
|
||||||
|
//The type of a {@link LexerPopModeAction} action.
|
||||||
|
POP_MODE: 4,
|
||||||
|
//The type of a {@link LexerPushModeAction} action.
|
||||||
|
PUSH_MODE: 5,
|
||||||
|
//The type of a {@link LexerSkipAction} action.
|
||||||
|
SKIP: 6,
|
||||||
|
//The type of a {@link LexerTypeAction} action.
|
||||||
|
TYPE: 7
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerActionType.CHANNEL = 0; //The type of a {@link LexerChannelAction} action.
|
class LexerAction {
|
||||||
LexerActionType.CUSTOM = 1; //The type of a {@link LexerCustomAction} action.
|
constructor(action) {
|
||||||
LexerActionType.MODE = 2; //The type of a {@link LexerModeAction} action.
|
this.actionType = action;
|
||||||
LexerActionType.MORE = 3; //The type of a {@link LexerMoreAction} action.
|
this.isPositionDependent = false;
|
||||||
LexerActionType.POP_MODE = 4; //The type of a {@link LexerPopModeAction} action.
|
}
|
||||||
LexerActionType.PUSH_MODE = 5; //The type of a {@link LexerPushModeAction} action.
|
|
||||||
LexerActionType.SKIP = 6; //The type of a {@link LexerSkipAction} action.
|
|
||||||
LexerActionType.TYPE = 7; //The type of a {@link LexerTypeAction} action.
|
|
||||||
|
|
||||||
function LexerAction(action) {
|
hashCode() {
|
||||||
this.actionType = action;
|
const hash = new Hash();
|
||||||
this.isPositionDependent = false;
|
this.updateHashCode(hash);
|
||||||
return this;
|
return hash.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHashCode(hash) {
|
||||||
|
hash.update(this.actionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
return this === other;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerAction.prototype.hashCode = function() {
|
|
||||||
var hash = new Hash();
|
|
||||||
this.updateHashCode(hash);
|
|
||||||
return hash.finish()
|
|
||||||
};
|
|
||||||
|
|
||||||
LexerAction.prototype.updateHashCode = function(hash) {
|
/**
|
||||||
hash.update(this.actionType);
|
* Implements the {@code skip} lexer action by calling {@link Lexer//skip}.
|
||||||
};
|
*
|
||||||
|
* <p>The {@code skip} command does not have any parameters, so this action is
|
||||||
|
* implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
|
||||||
|
*/
|
||||||
|
class LexerSkipAction extends LexerAction {
|
||||||
|
constructor() {
|
||||||
|
super(LexerActionType.SKIP);
|
||||||
|
}
|
||||||
|
|
||||||
LexerAction.prototype.equals = function(other) {
|
execute(lexer) {
|
||||||
return this === other;
|
lexer.skip();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return "skip";
|
||||||
//
|
}
|
||||||
// Implements the {@code skip} lexer action by calling {@link Lexer//skip}.
|
|
||||||
//
|
|
||||||
// <p>The {@code skip} command does not have any parameters, so this action is
|
|
||||||
// implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
|
|
||||||
function LexerSkipAction() {
|
|
||||||
LexerAction.call(this, LexerActionType.SKIP);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerSkipAction.prototype = Object.create(LexerAction.prototype);
|
|
||||||
LexerSkipAction.prototype.constructor = LexerSkipAction;
|
|
||||||
|
|
||||||
// Provides a singleton instance of this parameterless lexer action.
|
// Provides a singleton instance of this parameterless lexer action.
|
||||||
LexerSkipAction.INSTANCE = new LexerSkipAction();
|
LexerSkipAction.INSTANCE = new LexerSkipAction();
|
||||||
|
|
||||||
LexerSkipAction.prototype.execute = function(lexer) {
|
/**
|
||||||
lexer.skip();
|
* Implements the {@code type} lexer action by calling {@link Lexer//setType}
|
||||||
};
|
* with the assigned type
|
||||||
|
*/
|
||||||
LexerSkipAction.prototype.toString = function() {
|
class LexerTypeAction extends LexerAction {
|
||||||
return "skip";
|
constructor(type) {
|
||||||
};
|
super(LexerActionType.TYPE);
|
||||||
|
this.type = type;
|
||||||
// Implements the {@code type} lexer action by calling {@link Lexer//setType}
|
|
||||||
// with the assigned type.
|
|
||||||
function LexerTypeAction(type) {
|
|
||||||
LexerAction.call(this, LexerActionType.TYPE);
|
|
||||||
this.type = type;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
LexerTypeAction.prototype = Object.create(LexerAction.prototype);
|
|
||||||
LexerTypeAction.prototype.constructor = LexerTypeAction;
|
|
||||||
|
|
||||||
LexerTypeAction.prototype.execute = function(lexer) {
|
|
||||||
lexer.type = this.type;
|
|
||||||
};
|
|
||||||
|
|
||||||
LexerTypeAction.prototype.updateHashCode = function(hash) {
|
|
||||||
hash.update(this.actionType, this.type);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
LexerTypeAction.prototype.equals = function(other) {
|
|
||||||
if(this === other) {
|
|
||||||
return true;
|
|
||||||
} else if (! (other instanceof LexerTypeAction)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.type === other.type;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LexerTypeAction.prototype.toString = function() {
|
execute(lexer) {
|
||||||
return "type(" + this.type + ")";
|
lexer.type = this.type;
|
||||||
};
|
|
||||||
|
|
||||||
// Implements the {@code pushMode} lexer action by calling
|
|
||||||
// {@link Lexer//pushMode} with the assigned mode.
|
|
||||||
function LexerPushModeAction(mode) {
|
|
||||||
LexerAction.call(this, LexerActionType.PUSH_MODE);
|
|
||||||
this.mode = mode;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
LexerPushModeAction.prototype = Object.create(LexerAction.prototype);
|
|
||||||
LexerPushModeAction.prototype.constructor = LexerPushModeAction;
|
|
||||||
|
|
||||||
// <p>This action is implemented by calling {@link Lexer//pushMode} with the
|
|
||||||
// value provided by {@link //getMode}.</p>
|
|
||||||
LexerPushModeAction.prototype.execute = function(lexer) {
|
|
||||||
lexer.pushMode(this.mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
LexerPushModeAction.prototype.updateHashCode = function(hash) {
|
|
||||||
hash.update(this.actionType, this.mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
LexerPushModeAction.prototype.equals = function(other) {
|
|
||||||
if (this === other) {
|
|
||||||
return true;
|
|
||||||
} else if (! (other instanceof LexerPushModeAction)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.mode === other.mode;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LexerPushModeAction.prototype.toString = function() {
|
updateHashCode(hash) {
|
||||||
return "pushMode(" + this.mode + ")";
|
hash.update(this.actionType, this.type);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
if(this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (! (other instanceof LexerTypeAction)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.type === other.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Implements the {@code popMode} lexer action by calling {@link Lexer//popMode}.
|
toString() {
|
||||||
//
|
return "type(" + this.type + ")";
|
||||||
// <p>The {@code popMode} command does not have any parameters, so this action is
|
}
|
||||||
// implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
|
|
||||||
function LexerPopModeAction() {
|
|
||||||
LexerAction.call(this,LexerActionType.POP_MODE);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerPopModeAction.prototype = Object.create(LexerAction.prototype);
|
|
||||||
LexerPopModeAction.prototype.constructor = LexerPopModeAction;
|
/**
|
||||||
|
* Implements the {@code pushMode} lexer action by calling
|
||||||
|
* {@link Lexer//pushMode} with the assigned mode
|
||||||
|
*/
|
||||||
|
class LexerPushModeAction extends LexerAction {
|
||||||
|
constructor(mode) {
|
||||||
|
super(LexerActionType.PUSH_MODE);
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This action is implemented by calling {@link Lexer//pushMode} with the
|
||||||
|
* value provided by {@link //getMode}.</p>
|
||||||
|
*/
|
||||||
|
execute(lexer) {
|
||||||
|
lexer.pushMode(this.mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHashCode(hash) {
|
||||||
|
hash.update(this.actionType, this.mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (! (other instanceof LexerPushModeAction)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.mode === other.mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return "pushMode(" + this.mode + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the {@code popMode} lexer action by calling {@link Lexer//popMode}.
|
||||||
|
*
|
||||||
|
* <p>The {@code popMode} command does not have any parameters, so this action is
|
||||||
|
* implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
|
||||||
|
*/
|
||||||
|
class LexerPopModeAction extends LexerAction {
|
||||||
|
constructor() {
|
||||||
|
super(LexerActionType.POP_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This action is implemented by calling {@link Lexer//popMode}.</p>
|
||||||
|
*/
|
||||||
|
execute(lexer) {
|
||||||
|
lexer.popMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return "popMode";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LexerPopModeAction.INSTANCE = new LexerPopModeAction();
|
LexerPopModeAction.INSTANCE = new LexerPopModeAction();
|
||||||
|
|
||||||
// <p>This action is implemented by calling {@link Lexer//popMode}.</p>
|
/**
|
||||||
LexerPopModeAction.prototype.execute = function(lexer) {
|
* Implements the {@code more} lexer action by calling {@link Lexer//more}.
|
||||||
lexer.popMode();
|
*
|
||||||
};
|
* <p>The {@code more} command does not have any parameters, so this action is
|
||||||
|
* implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
|
||||||
|
*/
|
||||||
|
class LexerMoreAction extends LexerAction {
|
||||||
|
constructor() {
|
||||||
|
super(LexerActionType.MORE);
|
||||||
|
}
|
||||||
|
|
||||||
LexerPopModeAction.prototype.toString = function() {
|
/**
|
||||||
return "popMode";
|
* <p>This action is implemented by calling {@link Lexer//popMode}.</p>
|
||||||
};
|
*/
|
||||||
|
execute(lexer) {
|
||||||
|
lexer.more();
|
||||||
|
}
|
||||||
|
|
||||||
// Implements the {@code more} lexer action by calling {@link Lexer//more}.
|
toString() {
|
||||||
//
|
return "more";
|
||||||
// <p>The {@code more} command does not have any parameters, so this action is
|
}
|
||||||
// implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
|
|
||||||
function LexerMoreAction() {
|
|
||||||
LexerAction.call(this, LexerActionType.MORE);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerMoreAction.prototype = Object.create(LexerAction.prototype);
|
|
||||||
LexerMoreAction.prototype.constructor = LexerMoreAction;
|
|
||||||
|
|
||||||
LexerMoreAction.INSTANCE = new LexerMoreAction();
|
LexerMoreAction.INSTANCE = new LexerMoreAction();
|
||||||
|
|
||||||
// <p>This action is implemented by calling {@link Lexer//popMode}.</p>
|
|
||||||
LexerMoreAction.prototype.execute = function(lexer) {
|
|
||||||
lexer.more();
|
|
||||||
};
|
|
||||||
|
|
||||||
LexerMoreAction.prototype.toString = function() {
|
/**
|
||||||
return "more";
|
* Implements the {@code mode} lexer action by calling {@link Lexer//mode} with
|
||||||
};
|
* the assigned mode
|
||||||
|
*/
|
||||||
|
class LexerModeAction extends LexerAction {
|
||||||
|
constructor(mode) {
|
||||||
|
super(LexerActionType.MODE);
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This action is implemented by calling {@link Lexer//mode} with the
|
||||||
|
* value provided by {@link //getMode}.</p>
|
||||||
|
*/
|
||||||
|
execute(lexer) {
|
||||||
|
lexer.mode(this.mode);
|
||||||
|
}
|
||||||
|
|
||||||
// Implements the {@code mode} lexer action by calling {@link Lexer//mode} with
|
updateHashCode(hash) {
|
||||||
// the assigned mode.
|
hash.update(this.actionType, this.mode);
|
||||||
function LexerModeAction(mode) {
|
}
|
||||||
LexerAction.call(this, LexerActionType.MODE);
|
|
||||||
this.mode = mode;
|
equals(other) {
|
||||||
return this;
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (! (other instanceof LexerModeAction)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.mode === other.mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return "mode(" + this.mode + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerModeAction.prototype = Object.create(LexerAction.prototype);
|
/**
|
||||||
LexerModeAction.prototype.constructor = LexerModeAction;
|
* Executes a custom lexer action by calling {@link Recognizer//action} with the
|
||||||
|
* rule and action indexes assigned to the custom action. The implementation of
|
||||||
// <p>This action is implemented by calling {@link Lexer//mode} with the
|
* a custom action is added to the generated code for the lexer in an override
|
||||||
// value provided by {@link //getMode}.</p>
|
* of {@link Recognizer//action} when the grammar is compiled.
|
||||||
LexerModeAction.prototype.execute = function(lexer) {
|
*
|
||||||
lexer.mode(this.mode);
|
* <p>This class may represent embedded actions created with the <code>{...}</code>
|
||||||
};
|
* syntax in ANTLR 4, as well as actions created for lexer commands where the
|
||||||
|
* command argument could not be evaluated when the grammar was compiled.</p>
|
||||||
LexerModeAction.prototype.updateHashCode = function(hash) {
|
*/
|
||||||
hash.update(this.actionType, this.mode);
|
class LexerCustomAction extends LexerAction {
|
||||||
};
|
/**
|
||||||
|
* Constructs a custom lexer action with the specified rule and action
|
||||||
LexerModeAction.prototype.equals = function(other) {
|
* indexes.
|
||||||
if (this === other) {
|
*
|
||||||
return true;
|
* @param ruleIndex The rule index to use for calls to
|
||||||
} else if (! (other instanceof LexerModeAction)) {
|
* {@link Recognizer//action}.
|
||||||
return false;
|
* @param actionIndex The action index to use for calls to
|
||||||
} else {
|
* {@link Recognizer//action}.
|
||||||
return this.mode === other.mode;
|
*/
|
||||||
|
constructor(ruleIndex, actionIndex) {
|
||||||
|
super(LexerActionType.CUSTOM);
|
||||||
|
this.ruleIndex = ruleIndex;
|
||||||
|
this.actionIndex = actionIndex;
|
||||||
|
this.isPositionDependent = true;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LexerModeAction.prototype.toString = function() {
|
/**
|
||||||
return "mode(" + this.mode + ")";
|
* <p>Custom actions are implemented by calling {@link Lexer//action} with the
|
||||||
};
|
* appropriate rule and action indexes.</p>
|
||||||
|
*/
|
||||||
|
execute(lexer) {
|
||||||
|
lexer.action(null, this.ruleIndex, this.actionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
// Executes a custom lexer action by calling {@link Recognizer//action} with the
|
updateHashCode(hash) {
|
||||||
// rule and action indexes assigned to the custom action. The implementation of
|
hash.update(this.actionType, this.ruleIndex, this.actionIndex);
|
||||||
// a custom action is added to the generated code for the lexer in an override
|
}
|
||||||
// of {@link Recognizer//action} when the grammar is compiled.
|
|
||||||
//
|
|
||||||
// <p>This class may represent embedded actions created with the <code>{...}</code>
|
|
||||||
// syntax in ANTLR 4, as well as actions created for lexer commands where the
|
|
||||||
// command argument could not be evaluated when the grammar was compiled.</p>
|
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
// Constructs a custom lexer action with the specified rule and action
|
if (this === other) {
|
||||||
// indexes.
|
return true;
|
||||||
//
|
} else if (! (other instanceof LexerCustomAction)) {
|
||||||
// @param ruleIndex The rule index to use for calls to
|
return false;
|
||||||
// {@link Recognizer//action}.
|
} else {
|
||||||
// @param actionIndex The action index to use for calls to
|
return this.ruleIndex === other.ruleIndex && this.actionIndex === other.actionIndex;
|
||||||
// {@link Recognizer//action}.
|
}
|
||||||
|
}
|
||||||
function LexerCustomAction(ruleIndex, actionIndex) {
|
|
||||||
LexerAction.call(this, LexerActionType.CUSTOM);
|
|
||||||
this.ruleIndex = ruleIndex;
|
|
||||||
this.actionIndex = actionIndex;
|
|
||||||
this.isPositionDependent = true;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerCustomAction.prototype = Object.create(LexerAction.prototype);
|
/**
|
||||||
LexerCustomAction.prototype.constructor = LexerCustomAction;
|
* Implements the {@code channel} lexer action by calling
|
||||||
|
* {@link Lexer//setChannel} with the assigned channel.
|
||||||
// <p>Custom actions are implemented by calling {@link Lexer//action} with the
|
* Constructs a new {@code channel} action with the specified channel value.
|
||||||
// appropriate rule and action indexes.</p>
|
* @param channel The channel value to pass to {@link Lexer//setChannel}
|
||||||
LexerCustomAction.prototype.execute = function(lexer) {
|
*/
|
||||||
lexer.action(null, this.ruleIndex, this.actionIndex);
|
class LexerChannelAction extends LexerAction {
|
||||||
};
|
constructor(channel) {
|
||||||
|
super(LexerActionType.CHANNEL);
|
||||||
LexerCustomAction.prototype.updateHashCode = function(hash) {
|
this.channel = channel;
|
||||||
hash.update(this.actionType, this.ruleIndex, this.actionIndex);
|
|
||||||
};
|
|
||||||
|
|
||||||
LexerCustomAction.prototype.equals = function(other) {
|
|
||||||
if (this === other) {
|
|
||||||
return true;
|
|
||||||
} else if (! (other instanceof LexerCustomAction)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.ruleIndex === other.ruleIndex && this.actionIndex === other.actionIndex;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Implements the {@code channel} lexer action by calling
|
/**
|
||||||
// {@link Lexer//setChannel} with the assigned channel.
|
* <p>This action is implemented by calling {@link Lexer//setChannel} with the
|
||||||
// Constructs a new {@code channel} action with the specified channel value.
|
* value provided by {@link //getChannel}.</p>
|
||||||
// @param channel The channel value to pass to {@link Lexer//setChannel}.
|
*/
|
||||||
function LexerChannelAction(channel) {
|
execute(lexer) {
|
||||||
LexerAction.call(this, LexerActionType.CHANNEL);
|
lexer._channel = this.channel;
|
||||||
this.channel = channel;
|
}
|
||||||
return this;
|
|
||||||
|
updateHashCode(hash) {
|
||||||
|
hash.update(this.actionType, this.channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (! (other instanceof LexerChannelAction)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.channel === other.channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return "channel(" + this.channel + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerChannelAction.prototype = Object.create(LexerAction.prototype);
|
|
||||||
LexerChannelAction.prototype.constructor = LexerChannelAction;
|
|
||||||
|
|
||||||
// <p>This action is implemented by calling {@link Lexer//setChannel} with the
|
/**
|
||||||
// value provided by {@link //getChannel}.</p>
|
* This implementation of {@link LexerAction} is used for tracking input offsets
|
||||||
LexerChannelAction.prototype.execute = function(lexer) {
|
* for position-dependent actions within a {@link LexerActionExecutor}.
|
||||||
lexer._channel = this.channel;
|
*
|
||||||
};
|
* <p>This action is not serialized as part of the ATN, and is only required for
|
||||||
|
* position-dependent lexer actions which appear at a location other than the
|
||||||
LexerChannelAction.prototype.updateHashCode = function(hash) {
|
* end of a rule. For more information about DFA optimizations employed for
|
||||||
hash.update(this.actionType, this.channel);
|
* lexer actions, see {@link LexerActionExecutor//append} and
|
||||||
};
|
* {@link LexerActionExecutor//fixOffsetBeforeMatch}.</p>
|
||||||
|
*
|
||||||
LexerChannelAction.prototype.equals = function(other) {
|
* Constructs a new indexed custom action by associating a character offset
|
||||||
if (this === other) {
|
* with a {@link LexerAction}.
|
||||||
return true;
|
*
|
||||||
} else if (! (other instanceof LexerChannelAction)) {
|
* <p>Note: This class is only required for lexer actions for which
|
||||||
return false;
|
* {@link LexerAction//isPositionDependent} returns {@code true}.</p>
|
||||||
} else {
|
*
|
||||||
return this.channel === other.channel;
|
* @param offset The offset into the input {@link CharStream}, relative to
|
||||||
|
* the token start index, at which the specified lexer action should be
|
||||||
|
* executed.
|
||||||
|
* @param action The lexer action to execute at a particular offset in the
|
||||||
|
* input {@link CharStream}.
|
||||||
|
*/
|
||||||
|
class LexerIndexedCustomAction extends LexerAction {
|
||||||
|
constructor(offset, action) {
|
||||||
|
super(action.actionType);
|
||||||
|
this.offset = offset;
|
||||||
|
this.action = action;
|
||||||
|
this.isPositionDependent = true;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LexerChannelAction.prototype.toString = function() {
|
/**
|
||||||
return "channel(" + this.channel + ")";
|
* <p>This method calls {@link //execute} on the result of {@link //getAction}
|
||||||
};
|
* using the provided {@code lexer}.</p>
|
||||||
|
*/
|
||||||
|
execute(lexer) {
|
||||||
|
// assume the input stream position was properly set by the calling code
|
||||||
|
this.action.execute(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
// This implementation of {@link LexerAction} is used for tracking input offsets
|
updateHashCode(hash) {
|
||||||
// for position-dependent actions within a {@link LexerActionExecutor}.
|
hash.update(this.actionType, this.offset, this.action);
|
||||||
//
|
}
|
||||||
// <p>This action is not serialized as part of the ATN, and is only required for
|
|
||||||
// position-dependent lexer actions which appear at a location other than the
|
|
||||||
// end of a rule. For more information about DFA optimizations employed for
|
|
||||||
// lexer actions, see {@link LexerActionExecutor//append} and
|
|
||||||
// {@link LexerActionExecutor//fixOffsetBeforeMatch}.</p>
|
|
||||||
|
|
||||||
// Constructs a new indexed custom action by associating a character offset
|
equals(other) {
|
||||||
// with a {@link LexerAction}.
|
if (this === other) {
|
||||||
//
|
return true;
|
||||||
// <p>Note: This class is only required for lexer actions for which
|
} else if (! (other instanceof LexerIndexedCustomAction)) {
|
||||||
// {@link LexerAction//isPositionDependent} returns {@code true}.</p>
|
return false;
|
||||||
//
|
} else {
|
||||||
// @param offset The offset into the input {@link CharStream}, relative to
|
return this.offset === other.offset && this.action === other.action;
|
||||||
// the token start index, at which the specified lexer action should be
|
}
|
||||||
// executed.
|
}
|
||||||
// @param action The lexer action to execute at a particular offset in the
|
|
||||||
// input {@link CharStream}.
|
|
||||||
function LexerIndexedCustomAction(offset, action) {
|
|
||||||
LexerAction.call(this, action.actionType);
|
|
||||||
this.offset = offset;
|
|
||||||
this.action = action;
|
|
||||||
this.isPositionDependent = true;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LexerIndexedCustomAction.prototype = Object.create(LexerAction.prototype);
|
module.exports = {
|
||||||
LexerIndexedCustomAction.prototype.constructor = LexerIndexedCustomAction;
|
LexerActionType,
|
||||||
|
LexerSkipAction,
|
||||||
// <p>This method calls {@link //execute} on the result of {@link //getAction}
|
LexerChannelAction,
|
||||||
// using the provided {@code lexer}.</p>
|
LexerCustomAction,
|
||||||
LexerIndexedCustomAction.prototype.execute = function(lexer) {
|
LexerIndexedCustomAction,
|
||||||
// assume the input stream position was properly set by the calling code
|
LexerMoreAction,
|
||||||
this.action.execute(lexer);
|
LexerTypeAction,
|
||||||
};
|
LexerPushModeAction,
|
||||||
|
LexerPopModeAction,
|
||||||
LexerIndexedCustomAction.prototype.updateHashCode = function(hash) {
|
LexerModeAction
|
||||||
hash.update(this.actionType, this.offset, this.action);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LexerIndexedCustomAction.prototype.equals = function(other) {
|
|
||||||
if (this === other) {
|
|
||||||
return true;
|
|
||||||
} else if (! (other instanceof LexerIndexedCustomAction)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.offset === other.offset && this.action === other.action;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
exports.LexerActionType = LexerActionType;
|
|
||||||
exports.LexerSkipAction = LexerSkipAction;
|
|
||||||
exports.LexerChannelAction = LexerChannelAction;
|
|
||||||
exports.LexerCustomAction = LexerCustomAction;
|
|
||||||
exports.LexerIndexedCustomAction = LexerIndexedCustomAction;
|
|
||||||
exports.LexerMoreAction = LexerMoreAction;
|
|
||||||
exports.LexerTypeAction = LexerTypeAction;
|
|
||||||
exports.LexerPushModeAction = LexerPushModeAction;
|
|
||||||
exports.LexerPopModeAction = LexerPopModeAction;
|
|
||||||
exports.LexerModeAction = LexerModeAction;
|
|
||||||
|
|
|
@ -1,166 +1,173 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
///
|
|
||||||
|
|
||||||
// Represents an executor for a sequence of lexer actions which traversed during
|
const {hashStuff} = require("../Utils");
|
||||||
// the matching operation of a lexer rule (token).
|
const {LexerIndexedCustomAction} = require('./LexerAction');
|
||||||
//
|
|
||||||
// <p>The executor tracks position information for position-dependent lexer actions
|
|
||||||
// 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;
|
class LexerActionExecutor {
|
||||||
var LexerIndexedCustomAction = require('./LexerAction').LexerIndexedCustomAction;
|
/**
|
||||||
|
* Represents an executor for a sequence of lexer actions which traversed during
|
||||||
|
* the matching operation of a lexer rule (token).
|
||||||
|
*
|
||||||
|
* <p>The executor tracks position information for position-dependent lexer actions
|
||||||
|
* 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>
|
||||||
|
*/
|
||||||
|
constructor(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.cachedHashCode = hashStuff(lexerActions); // "".join([str(la) for la in
|
||||||
|
// lexerActions]))
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
function LexerActionExecutor(lexerActions) {
|
/**
|
||||||
this.lexerActions = lexerActions === null ? [] : lexerActions;
|
* Creates a {@link LexerActionExecutor} which encodes the current offset
|
||||||
// Caches the result of {@link //hashCode} since the hash code is an element
|
* for position-dependent lexer actions.
|
||||||
// of the performance-critical {@link LexerATNConfig//hashCode} operation.
|
*
|
||||||
this.cachedHashCode = hashStuff(lexerActions); // "".join([str(la) for la in
|
* <p>Normally, when the executor encounters lexer actions where
|
||||||
// lexerActions]))
|
* {@link LexerAction//isPositionDependent} returns {@code true}, it calls
|
||||||
return this;
|
* {@link IntStream//seek} on the input {@link CharStream} to set the input
|
||||||
|
* position to the <em>end</em> of the current token. This behavior provides
|
||||||
|
* for efficient DFA representation of lexer actions which appear at the end
|
||||||
|
* of a lexer rule, even when the lexer rule matches a variable number of
|
||||||
|
* characters.</p>
|
||||||
|
*
|
||||||
|
* <p>Prior to traversing a match transition in the ATN, the current offset
|
||||||
|
* from the token start index is assigned to all position-dependent lexer
|
||||||
|
* actions which have not already been assigned a fixed offset. By storing
|
||||||
|
* the offsets relative to the token start index, the DFA representation of
|
||||||
|
* lexer actions which appear in the middle of tokens remains efficient due
|
||||||
|
* to sharing among tokens of the same length, regardless of their absolute
|
||||||
|
* position in the input stream.</p>
|
||||||
|
*
|
||||||
|
* <p>If the current executor already has offsets assigned to all
|
||||||
|
* position-dependent lexer actions, the method returns {@code this}.</p>
|
||||||
|
*
|
||||||
|
* @param offset The current offset to assign to all position-dependent
|
||||||
|
* lexer actions which do not already have offsets assigned.
|
||||||
|
*
|
||||||
|
* @return {LexerActionExecutor} A {@link LexerActionExecutor} which stores input stream offsets
|
||||||
|
* for all position-dependent lexer actions.
|
||||||
|
*/
|
||||||
|
fixOffsetBeforeMatch(offset) {
|
||||||
|
let updatedLexerActions = null;
|
||||||
|
for (let i = 0; i < this.lexerActions.length; i++) {
|
||||||
|
if (this.lexerActions[i].isPositionDependent &&
|
||||||
|
!(this.lexerActions[i] instanceof LexerIndexedCustomAction)) {
|
||||||
|
if (updatedLexerActions === null) {
|
||||||
|
updatedLexerActions = this.lexerActions.concat([]);
|
||||||
|
}
|
||||||
|
updatedLexerActions[i] = new LexerIndexedCustomAction(offset,
|
||||||
|
this.lexerActions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (updatedLexerActions === null) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
return new LexerActionExecutor(updatedLexerActions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the actions encapsulated by this executor within the context of a
|
||||||
|
* particular {@link Lexer}.
|
||||||
|
*
|
||||||
|
* <p>This method calls {@link IntStream//seek} to set the position of the
|
||||||
|
* {@code input} {@link CharStream} prior to calling
|
||||||
|
* {@link LexerAction//execute} on a position-dependent action. Before the
|
||||||
|
* method returns, the input position will be restored to the same position
|
||||||
|
* it was in when the method was invoked.</p>
|
||||||
|
*
|
||||||
|
* @param lexer The lexer instance.
|
||||||
|
* @param input The input stream which is the source for the current token.
|
||||||
|
* When this method is called, the current {@link IntStream//index} for
|
||||||
|
* {@code input} should be the start of the following token, i.e. 1
|
||||||
|
* character past the end of the current token.
|
||||||
|
* @param startIndex The token start index. This value may be passed to
|
||||||
|
* {@link IntStream//seek} to set the {@code input} position to the beginning
|
||||||
|
* of the token.
|
||||||
|
*/
|
||||||
|
execute(lexer, input, startIndex) {
|
||||||
|
let requiresSeek = false;
|
||||||
|
const stopIndex = input.index;
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < this.lexerActions.length; i++) {
|
||||||
|
let lexerAction = this.lexerActions[i];
|
||||||
|
if (lexerAction instanceof LexerIndexedCustomAction) {
|
||||||
|
const offset = lexerAction.offset;
|
||||||
|
input.seek(startIndex + offset);
|
||||||
|
lexerAction = lexerAction.action;
|
||||||
|
requiresSeek = (startIndex + offset) !== stopIndex;
|
||||||
|
} else if (lexerAction.isPositionDependent) {
|
||||||
|
input.seek(stopIndex);
|
||||||
|
requiresSeek = false;
|
||||||
|
}
|
||||||
|
lexerAction.execute(lexer);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (requiresSeek) {
|
||||||
|
input.seek(stopIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashCode() {
|
||||||
|
return this.cachedHashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHashCode(hash) {
|
||||||
|
hash.update(this.cachedHashCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (!(other instanceof LexerActionExecutor)) {
|
||||||
|
return false;
|
||||||
|
} else if (this.cachedHashCode != other.cachedHashCode) {
|
||||||
|
return false;
|
||||||
|
} else if (this.lexerActions.length != other.lexerActions.length) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
const numActions = this.lexerActions.length
|
||||||
|
for (let idx = 0; idx < numActions; ++idx) {
|
||||||
|
if (!this.lexerActions[idx].equals(other.lexerActions[idx])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link LexerActionExecutor} which executes the actions for
|
||||||
|
* the input {@code lexerActionExecutor} followed by a specified
|
||||||
|
* {@code lexerAction}.
|
||||||
|
*
|
||||||
|
* @param lexerActionExecutor The executor for actions already traversed by
|
||||||
|
* the lexer while matching a token within a particular
|
||||||
|
* {@link LexerATNConfig}. If this is {@code null}, the method behaves as
|
||||||
|
* though it were an empty executor.
|
||||||
|
* @param lexerAction The lexer action to execute after the actions
|
||||||
|
* specified in {@code lexerActionExecutor}.
|
||||||
|
*
|
||||||
|
* @return {LexerActionExecutor} A {@link LexerActionExecutor} for executing the combine actions
|
||||||
|
* of {@code lexerActionExecutor} and {@code lexerAction}.
|
||||||
|
*/
|
||||||
|
static append(lexerActionExecutor, lexerAction) {
|
||||||
|
if (lexerActionExecutor === null) {
|
||||||
|
return new LexerActionExecutor([ lexerAction ]);
|
||||||
|
}
|
||||||
|
const lexerActions = lexerActionExecutor.lexerActions.concat([ lexerAction ]);
|
||||||
|
return new LexerActionExecutor(lexerActions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a {@link LexerActionExecutor} which executes the actions for
|
|
||||||
// the input {@code lexerActionExecutor} followed by a specified
|
|
||||||
// {@code lexerAction}.
|
|
||||||
//
|
|
||||||
// @param lexerActionExecutor The executor for actions already traversed by
|
|
||||||
// the lexer while matching a token within a particular
|
|
||||||
// {@link LexerATNConfig}. If this is {@code null}, the method behaves as
|
|
||||||
// though it were an empty executor.
|
|
||||||
// @param lexerAction The lexer action to execute after the actions
|
|
||||||
// specified in {@code lexerActionExecutor}.
|
|
||||||
//
|
|
||||||
// @return A {@link LexerActionExecutor} for executing the combine actions
|
|
||||||
// of {@code lexerActionExecutor} and {@code lexerAction}.
|
|
||||||
LexerActionExecutor.append = function(lexerActionExecutor, lexerAction) {
|
|
||||||
if (lexerActionExecutor === null) {
|
|
||||||
return new LexerActionExecutor([ lexerAction ]);
|
|
||||||
}
|
|
||||||
var lexerActions = lexerActionExecutor.lexerActions.concat([ lexerAction ]);
|
|
||||||
return new LexerActionExecutor(lexerActions);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Creates a {@link LexerActionExecutor} which encodes the current offset
|
module.exports = LexerActionExecutor;
|
||||||
// for position-dependent lexer actions.
|
|
||||||
//
|
|
||||||
// <p>Normally, when the executor encounters lexer actions where
|
|
||||||
// {@link LexerAction//isPositionDependent} returns {@code true}, it calls
|
|
||||||
// {@link IntStream//seek} on the input {@link CharStream} to set the input
|
|
||||||
// position to the <em>end</em> of the current token. This behavior provides
|
|
||||||
// for efficient DFA representation of lexer actions which appear at the end
|
|
||||||
// of a lexer rule, even when the lexer rule matches a variable number of
|
|
||||||
// characters.</p>
|
|
||||||
//
|
|
||||||
// <p>Prior to traversing a match transition in the ATN, the current offset
|
|
||||||
// from the token start index is assigned to all position-dependent lexer
|
|
||||||
// actions which have not already been assigned a fixed offset. By storing
|
|
||||||
// the offsets relative to the token start index, the DFA representation of
|
|
||||||
// lexer actions which appear in the middle of tokens remains efficient due
|
|
||||||
// to sharing among tokens of the same length, regardless of their absolute
|
|
||||||
// position in the input stream.</p>
|
|
||||||
//
|
|
||||||
// <p>If the current executor already has offsets assigned to all
|
|
||||||
// position-dependent lexer actions, the method returns {@code this}.</p>
|
|
||||||
//
|
|
||||||
// @param offset The current offset to assign to all position-dependent
|
|
||||||
// lexer actions which do not already have offsets assigned.
|
|
||||||
//
|
|
||||||
// @return A {@link LexerActionExecutor} which stores input stream offsets
|
|
||||||
// for all position-dependent lexer actions.
|
|
||||||
// /
|
|
||||||
LexerActionExecutor.prototype.fixOffsetBeforeMatch = function(offset) {
|
|
||||||
var updatedLexerActions = null;
|
|
||||||
for (var i = 0; i < this.lexerActions.length; i++) {
|
|
||||||
if (this.lexerActions[i].isPositionDependent &&
|
|
||||||
!(this.lexerActions[i] instanceof LexerIndexedCustomAction)) {
|
|
||||||
if (updatedLexerActions === null) {
|
|
||||||
updatedLexerActions = this.lexerActions.concat([]);
|
|
||||||
}
|
|
||||||
updatedLexerActions[i] = new LexerIndexedCustomAction(offset,
|
|
||||||
this.lexerActions[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (updatedLexerActions === null) {
|
|
||||||
return this;
|
|
||||||
} else {
|
|
||||||
return new LexerActionExecutor(updatedLexerActions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute the actions encapsulated by this executor within the context of a
|
|
||||||
// particular {@link Lexer}.
|
|
||||||
//
|
|
||||||
// <p>This method calls {@link IntStream//seek} to set the position of the
|
|
||||||
// {@code input} {@link CharStream} prior to calling
|
|
||||||
// {@link LexerAction//execute} on a position-dependent action. Before the
|
|
||||||
// method returns, the input position will be restored to the same position
|
|
||||||
// it was in when the method was invoked.</p>
|
|
||||||
//
|
|
||||||
// @param lexer The lexer instance.
|
|
||||||
// @param input The input stream which is the source for the current token.
|
|
||||||
// When this method is called, the current {@link IntStream//index} for
|
|
||||||
// {@code input} should be the start of the following token, i.e. 1
|
|
||||||
// character past the end of the current token.
|
|
||||||
// @param startIndex The token start index. This value may be passed to
|
|
||||||
// {@link IntStream//seek} to set the {@code input} position to the beginning
|
|
||||||
// of the token.
|
|
||||||
// /
|
|
||||||
LexerActionExecutor.prototype.execute = function(lexer, input, startIndex) {
|
|
||||||
var requiresSeek = false;
|
|
||||||
var stopIndex = input.index;
|
|
||||||
try {
|
|
||||||
for (var i = 0; i < this.lexerActions.length; i++) {
|
|
||||||
var lexerAction = this.lexerActions[i];
|
|
||||||
if (lexerAction instanceof LexerIndexedCustomAction) {
|
|
||||||
var offset = lexerAction.offset;
|
|
||||||
input.seek(startIndex + offset);
|
|
||||||
lexerAction = lexerAction.action;
|
|
||||||
requiresSeek = (startIndex + offset) !== stopIndex;
|
|
||||||
} else if (lexerAction.isPositionDependent) {
|
|
||||||
input.seek(stopIndex);
|
|
||||||
requiresSeek = false;
|
|
||||||
}
|
|
||||||
lexerAction.execute(lexer);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (requiresSeek) {
|
|
||||||
input.seek(stopIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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.cachedHashCode != other.cachedHashCode) {
|
|
||||||
return false;
|
|
||||||
} else if (this.lexerActions.length != other.lexerActions.length) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
var numActions = this.lexerActions.length
|
|
||||||
for (var idx = 0; idx < numActions; ++idx) {
|
|
||||||
if (!this.lexerActions[idx].equals(other.lexerActions[idx])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.LexerActionExecutor = LexerActionExecutor;
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,404 +1,397 @@
|
||||||
//
|
|
||||||
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
//
|
|
||||||
|
|
||||||
// A tree structure used to record the semantic context in which
|
const {Set, Hash} = require('./../Utils');
|
||||||
// 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>
|
|
||||||
//
|
|
||||||
|
|
||||||
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
|
class Predicate extends SemanticContext {
|
||||||
// context (i.e., null context). That way, we can evaluate them without
|
constructor(ruleIndex, predIndex, isCtxDependent) {
|
||||||
// having to create proper rule-specific context during prediction (as
|
super();
|
||||||
// opposed to the parser, which creates them naturally). In a practical
|
this.ruleIndex = ruleIndex === undefined ? -1 : ruleIndex;
|
||||||
// sense, this avoids a cast exception from RuleContext to myruleContext.
|
this.predIndex = predIndex === undefined ? -1 : predIndex;
|
||||||
//
|
this.isCtxDependent = isCtxDependent === undefined ? false : isCtxDependent; // e.g., $i ref in pred
|
||||||
// <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) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
evaluate(parser, outerContext) {
|
||||||
// Evaluate the precedence predicates for the context and reduce the result.
|
const localctx = this.isCtxDependent ? outerContext : null;
|
||||||
//
|
return parser.sempred(localctx, this.ruleIndex, this.predIndex);
|
||||||
// @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;
|
|
||||||
};
|
|
||||||
|
|
||||||
SemanticContext.andContext = function(a, b) {
|
updateHashCode(hash) {
|
||||||
if (a === null || a === SemanticContext.NONE) {
|
hash.update(this.ruleIndex, this.predIndex, this.isCtxDependent);
|
||||||
return b;
|
|
||||||
}
|
}
|
||||||
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) {
|
equals(other) {
|
||||||
if (a === null) {
|
if (this === other) {
|
||||||
return b;
|
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) {
|
toString() {
|
||||||
SemanticContext.call(this);
|
return "{" + this.ruleIndex + ":" + this.predIndex + "}?";
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
SemanticContext.NONE = new Predicate();
|
||||||
|
|
||||||
|
|
||||||
Predicate.prototype.evaluate = function(parser, outerContext) {
|
class PrecedencePredicate extends SemanticContext {
|
||||||
var localctx = this.isCtxDependent ? outerContext : null;
|
constructor(precedence) {
|
||||||
return parser.sempred(localctx, this.ruleIndex, this.predIndex);
|
super();
|
||||||
};
|
this.precedence = precedence === undefined ? 0 : precedence;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
Predicate.prototype.toString = function() {
|
evaluate(parser, outerContext) {
|
||||||
return "{" + this.ruleIndex + ":" + this.predIndex + "}?";
|
return parser.precpred(outerContext, this.precedence);
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
PrecedencePredicate.prototype.compareTo = function(other) {
|
evalPrecedence(parser, outerContext) {
|
||||||
return this.precedence - other.precedence;
|
if (parser.precpred(outerContext, this.precedence)) {
|
||||||
};
|
return SemanticContext.NONE;
|
||||||
|
} else {
|
||||||
PrecedencePredicate.prototype.updateHashCode = function(hash) {
|
return null;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
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) {
|
compareTo(other) {
|
||||||
operands.add(o);
|
return this.precedence - other.precedence;
|
||||||
});
|
|
||||||
} else {
|
|
||||||
operands.add(b);
|
|
||||||
}
|
}
|
||||||
var precedencePredicates = PrecedencePredicate.filterPrecedencePredicates(operands);
|
|
||||||
if (precedencePredicates.length > 0) {
|
updateHashCode(hash) {
|
||||||
// interested in the transition with the lowest precedence
|
hash.update(31);
|
||||||
var reduced = null;
|
}
|
||||||
precedencePredicates.map( function(p) {
|
|
||||||
if(reduced===null || p.precedence<reduced.precedence) {
|
equals(other) {
|
||||||
reduced = p;
|
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);
|
class AND extends SemanticContext {
|
||||||
AND.prototype.constructor = AND;
|
/**
|
||||||
|
* A semantic context which is true whenever none of the contained contexts
|
||||||
AND.prototype.equals = function(other) {
|
* is false
|
||||||
if (this === other) {
|
*/
|
||||||
return true;
|
constructor(a, b) {
|
||||||
} else if (!(other instanceof AND)) {
|
super();
|
||||||
return false;
|
const operands = new Set();
|
||||||
} else {
|
if (a instanceof AND) {
|
||||||
return this.opnds === other.opnds;
|
a.opnds.map(function(o) {
|
||||||
}
|
operands.add(o);
|
||||||
};
|
});
|
||||||
|
} else {
|
||||||
AND.prototype.updateHashCode = function(hash) {
|
operands.add(a);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
if (b instanceof AND) {
|
||||||
return true;
|
b.opnds.map(function(o) {
|
||||||
};
|
operands.add(o);
|
||||||
|
});
|
||||||
AND.prototype.evalPrecedence = function(parser, outerContext) {
|
} else {
|
||||||
var differs = false;
|
operands.add(b);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
const precedencePredicates = PrecedencePredicate.filterPrecedencePredicates(operands);
|
||||||
if (!differs) {
|
if (precedencePredicates.length > 0) {
|
||||||
return this;
|
// interested in the transition with the lowest precedence
|
||||||
}
|
let reduced = null;
|
||||||
if (operands.length === 0) {
|
precedencePredicates.map( function(p) {
|
||||||
// all elements were true, so the AND context is true
|
if(reduced===null || p.precedence<reduced.precedence) {
|
||||||
return SemanticContext.NONE;
|
reduced = p;
|
||||||
}
|
}
|
||||||
var result = null;
|
});
|
||||||
operands.map(function(o) {
|
operands.add(reduced);
|
||||||
result = result === null ? o : SemanticContext.andContext(result, o);
|
}
|
||||||
});
|
this.opnds = operands.values();
|
||||||
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);
|
equals(other) {
|
||||||
if (precedencePredicates.length > 0) {
|
if (this === other) {
|
||||||
// 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)) {
|
|
||||||
return true;
|
return true;
|
||||||
|
} else if (!(other instanceof AND)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.opnds === other.opnds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
OR.prototype.evalPrecedence = function(parser, outerContext) {
|
updateHashCode(hash) {
|
||||||
var differs = false;
|
hash.update(this.opnds, "AND");
|
||||||
var operands = [];
|
}
|
||||||
for (var i = 0; i < this.opnds.length; i++) {
|
|
||||||
var context = this.opnds[i];
|
/**
|
||||||
var evaluated = context.evalPrecedence(parser, outerContext);
|
* {@inheritDoc}
|
||||||
differs |= (evaluated !== context);
|
*
|
||||||
if (evaluated === SemanticContext.NONE) {
|
* <p>
|
||||||
// The OR context is true if any element is true
|
* 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;
|
return SemanticContext.NONE;
|
||||||
} else if (evaluated !== null) {
|
}
|
||||||
// Reduce the result by skipping false elements
|
let result = null;
|
||||||
operands.push(evaluated);
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other) {
|
||||||
|
if (this === other) {
|
||||||
|
return true;
|
||||||
|
} else if (!(other instanceof OR)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.opnds === other.opnds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!differs) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
if (operands.length === 0) {
|
|
||||||
// all elements were false, so the OR context is false
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var result = null;
|
|
||||||
operands.map(function(o) {
|
|
||||||
return result === null ? o : SemanticContext.orContext(result, o);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
OR.prototype.toString = function() {
|
updateHashCode(hash) {
|
||||||
var s = "";
|
hash.update(this.opnds, "OR");
|
||||||
this.opnds.map(function(o) {
|
}
|
||||||
s += "|| " + o.toString();
|
|
||||||
});
|
|
||||||
return s.length > 3 ? s.slice(3) : s;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.SemanticContext = SemanticContext;
|
/**
|
||||||
exports.PrecedencePredicate = PrecedencePredicate;
|
* <p>
|
||||||
exports.Predicate = Predicate;
|
* 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
|
||||||
|
}
|
||||||
|
|
|
@ -2,45 +2,48 @@
|
||||||
* Use of this file is governed by the BSD 3-clause license that
|
* 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.
|
* can be found in the LICENSE.txt file in the project root.
|
||||||
*/
|
*/
|
||||||
//
|
|
||||||
|
|
||||||
// An ATN transition between any two ATN states. Subclasses define
|
const {Token} = require('./../Token');
|
||||||
// atom, set, epsilon, action, predicate, rule transitions.
|
const {IntervalSet} = require('./../IntervalSet');
|
||||||
//
|
const {Predicate, PrecedencePredicate} = require('./SemanticContext');
|
||||||
// <p>This is a one way link. It emanates from a state (usually via a list of
|
|
||||||
// transitions) and has a target state.</p>
|
|
||||||
//
|
|
||||||
// <p>Since we never have to change the ATN transitions once we construct it,
|
|
||||||
// we can fix these transitions as specific classes. The DFA transitions
|
|
||||||
// on the other hand need to update the labels as it adds transitions to
|
|
||||||
// the states. We'll use the term Edge for the DFA to distinguish them from
|
|
||||||
// ATN transitions.</p>
|
|
||||||
|
|
||||||
var Token = require('./../Token').Token;
|
/**
|
||||||
var Interval = require('./../IntervalSet').Interval;
|
* An ATN transition between any two ATN states. Subclasses define
|
||||||
var IntervalSet = require('./../IntervalSet').IntervalSet;
|
* atom, set, epsilon, action, predicate, rule transitions.
|
||||||
var Predicate = require('./SemanticContext').Predicate;
|
*
|
||||||
var PrecedencePredicate = require('./SemanticContext').PrecedencePredicate;
|
* <p>This is a one way link. It emanates from a state (usually via a list of
|
||||||
|
* transitions) and has a target state.</p>
|
||||||
function Transition (target) {
|
*
|
||||||
// The target of this transition.
|
* <p>Since we never have to change the ATN transitions once we construct it,
|
||||||
if (target===undefined || target===null) {
|
* we can fix these transitions as specific classes. The DFA transitions
|
||||||
throw "target cannot be null.";
|
* on the other hand need to update the labels as it adds transitions to
|
||||||
|
* the states. We'll use the term Edge for the DFA to distinguish them from
|
||||||
|
* ATN transitions.</p>
|
||||||
|
*/
|
||||||
|
class Transition {
|
||||||
|
constructor(target) {
|
||||||
|
// The target of this transition.
|
||||||
|
if (target===undefined || target===null) {
|
||||||
|
throw "target cannot be null.";
|
||||||
|
}
|
||||||
|
this.target = target;
|
||||||
|
// Are we epsilon, action, sempred?
|
||||||
|
this.isEpsilon = false;
|
||||||
|
this.label = null;
|
||||||
}
|
}
|
||||||
this.target = target;
|
|
||||||
// Are we epsilon, action, sempred?
|
|
||||||
this.isEpsilon = false;
|
|
||||||
this.label = null;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
// constants for serialization
|
|
||||||
|
// constants for serialization
|
||||||
|
|
||||||
Transition.EPSILON = 1;
|
Transition.EPSILON = 1;
|
||||||
Transition.RANGE = 2;
|
Transition.RANGE = 2;
|
||||||
Transition.RULE = 3;
|
Transition.RULE = 3;
|
||||||
Transition.PREDICATE = 4; // e.g., {isType(input.LT(1))}?
|
// e.g., {isType(input.LT(1))}?
|
||||||
|
Transition.PREDICATE = 4;
|
||||||
Transition.ATOM = 5;
|
Transition.ATOM = 5;
|
||||||
Transition.ACTION = 6;
|
Transition.ACTION = 6;
|
||||||
Transition.SET = 7; // ~(A|B) or ~atom, wildcard, which convert to next 2
|
// ~(A|B) or ~atom, wildcard, which convert to next 2
|
||||||
|
Transition.SET = 7;
|
||||||
Transition.NOT_SET = 8;
|
Transition.NOT_SET = 8;
|
||||||
Transition.WILDCARD = 9;
|
Transition.WILDCARD = 9;
|
||||||
Transition.PRECEDENCE = 10;
|
Transition.PRECEDENCE = 10;
|
||||||
|
@ -74,243 +77,227 @@ Transition.serializationTypes = {
|
||||||
|
|
||||||
|
|
||||||
// TODO: make all transitions sets? no, should remove set edges
|
// TODO: make all transitions sets? no, should remove set edges
|
||||||
function AtomTransition(target, label) {
|
|
||||||
Transition.call(this, target);
|
class AtomTransition extends Transition {
|
||||||
this.label_ = label; // The token type or character value; or, signifies special label.
|
constructor(target, label) {
|
||||||
this.label = this.makeLabel();
|
super(target);
|
||||||
this.serializationType = Transition.ATOM;
|
// The token type or character value; or, signifies special label.
|
||||||
return this;
|
this.label_ = label;
|
||||||
|
this.label = this.makeLabel();
|
||||||
|
this.serializationType = Transition.ATOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeLabel() {
|
||||||
|
const s = new IntervalSet();
|
||||||
|
s.addOne(this.label_);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
|
return this.label_ === symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.label_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomTransition.prototype = Object.create(Transition.prototype);
|
|
||||||
AtomTransition.prototype.constructor = AtomTransition;
|
|
||||||
|
|
||||||
AtomTransition.prototype.makeLabel = function() {
|
class RuleTransition extends Transition {
|
||||||
var s = new IntervalSet();
|
constructor(ruleStart, ruleIndex, precedence, followState) {
|
||||||
s.addOne(this.label_);
|
super(ruleStart);
|
||||||
return s;
|
// ptr to the rule definition object for this rule ref
|
||||||
};
|
this.ruleIndex = ruleIndex;
|
||||||
|
this.precedence = precedence;
|
||||||
|
// what node to begin computations following ref to rule
|
||||||
|
this.followState = followState;
|
||||||
|
this.serializationType = Transition.RULE;
|
||||||
|
this.isEpsilon = true;
|
||||||
|
}
|
||||||
|
|
||||||
AtomTransition.prototype.matches = function( symbol, minVocabSymbol, maxVocabSymbol) {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
return this.label_ === symbol;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
AtomTransition.prototype.toString = function() {
|
|
||||||
return this.label_;
|
|
||||||
};
|
|
||||||
|
|
||||||
function RuleTransition(ruleStart, ruleIndex, precedence, followState) {
|
|
||||||
Transition.call(this, ruleStart);
|
|
||||||
this.ruleIndex = ruleIndex; // ptr to the rule definition object for this rule ref
|
|
||||||
this.precedence = precedence;
|
|
||||||
this.followState = followState; // what node to begin computations following ref to rule
|
|
||||||
this.serializationType = Transition.RULE;
|
|
||||||
this.isEpsilon = true;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RuleTransition.prototype = Object.create(Transition.prototype);
|
class EpsilonTransition extends Transition {
|
||||||
RuleTransition.prototype.constructor = RuleTransition;
|
constructor(target, outermostPrecedenceReturn) {
|
||||||
|
super(target);
|
||||||
|
this.serializationType = Transition.EPSILON;
|
||||||
|
this.isEpsilon = true;
|
||||||
|
this.outermostPrecedenceReturn = outermostPrecedenceReturn;
|
||||||
|
}
|
||||||
|
|
||||||
RuleTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
function EpsilonTransition(target, outermostPrecedenceReturn) {
|
return "epsilon";
|
||||||
Transition.call(this, target);
|
}
|
||||||
this.serializationType = Transition.EPSILON;
|
|
||||||
this.isEpsilon = true;
|
|
||||||
this.outermostPrecedenceReturn = outermostPrecedenceReturn;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EpsilonTransition.prototype = Object.create(Transition.prototype);
|
|
||||||
EpsilonTransition.prototype.constructor = EpsilonTransition;
|
|
||||||
|
|
||||||
EpsilonTransition.prototype.matches = function( symbol, minVocabSymbol, maxVocabSymbol) {
|
class RangeTransition extends Transition {
|
||||||
return false;
|
constructor(target, start, stop) {
|
||||||
};
|
super(target);
|
||||||
|
this.serializationType = Transition.RANGE;
|
||||||
|
this.start = start;
|
||||||
|
this.stop = stop;
|
||||||
|
this.label = this.makeLabel();
|
||||||
|
}
|
||||||
|
|
||||||
EpsilonTransition.prototype.toString = function() {
|
makeLabel() {
|
||||||
return "epsilon";
|
const s = new IntervalSet();
|
||||||
};
|
s.addRange(this.start, this.stop);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
function RangeTransition(target, start, stop) {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
Transition.call(this, target);
|
return symbol >= this.start && symbol <= this.stop;
|
||||||
this.serializationType = Transition.RANGE;
|
}
|
||||||
this.start = start;
|
|
||||||
this.stop = stop;
|
toString() {
|
||||||
this.label = this.makeLabel();
|
return "'" + String.fromCharCode(this.start) + "'..'" + String.fromCharCode(this.stop) + "'";
|
||||||
return this;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RangeTransition.prototype = Object.create(Transition.prototype);
|
|
||||||
RangeTransition.prototype.constructor = RangeTransition;
|
|
||||||
|
|
||||||
RangeTransition.prototype.makeLabel = function() {
|
class AbstractPredicateTransition extends Transition {
|
||||||
var s = new IntervalSet();
|
constructor(target) {
|
||||||
s.addRange(this.start, this.stop);
|
super(target);
|
||||||
return s;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
RangeTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
|
||||||
return symbol >= this.start && symbol <= this.stop;
|
|
||||||
};
|
|
||||||
|
|
||||||
RangeTransition.prototype.toString = function() {
|
|
||||||
return "'" + String.fromCharCode(this.start) + "'..'" + String.fromCharCode(this.stop) + "'";
|
|
||||||
};
|
|
||||||
|
|
||||||
function AbstractPredicateTransition(target) {
|
|
||||||
Transition.call(this, target);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractPredicateTransition.prototype = Object.create(Transition.prototype);
|
class PredicateTransition extends AbstractPredicateTransition {
|
||||||
AbstractPredicateTransition.prototype.constructor = AbstractPredicateTransition;
|
constructor(target, ruleIndex, predIndex, isCtxDependent) {
|
||||||
|
super(target);
|
||||||
|
this.serializationType = Transition.PREDICATE;
|
||||||
|
this.ruleIndex = ruleIndex;
|
||||||
|
this.predIndex = predIndex;
|
||||||
|
this.isCtxDependent = isCtxDependent; // e.g., $i ref in pred
|
||||||
|
this.isEpsilon = true;
|
||||||
|
}
|
||||||
|
|
||||||
function PredicateTransition(target, ruleIndex, predIndex, isCtxDependent) {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
AbstractPredicateTransition.call(this, target);
|
return false;
|
||||||
this.serializationType = Transition.PREDICATE;
|
}
|
||||||
this.ruleIndex = ruleIndex;
|
|
||||||
this.predIndex = predIndex;
|
getPredicate() {
|
||||||
this.isCtxDependent = isCtxDependent; // e.g., $i ref in pred
|
return new Predicate(this.ruleIndex, this.predIndex, this.isCtxDependent);
|
||||||
this.isEpsilon = true;
|
}
|
||||||
return this;
|
|
||||||
|
toString() {
|
||||||
|
return "pred_" + this.ruleIndex + ":" + this.predIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PredicateTransition.prototype = Object.create(AbstractPredicateTransition.prototype);
|
|
||||||
PredicateTransition.prototype.constructor = PredicateTransition;
|
|
||||||
|
|
||||||
PredicateTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
class ActionTransition extends Transition {
|
||||||
return false;
|
constructor(target, ruleIndex, actionIndex, isCtxDependent) {
|
||||||
};
|
super(target);
|
||||||
|
this.serializationType = Transition.ACTION;
|
||||||
|
this.ruleIndex = ruleIndex;
|
||||||
|
this.actionIndex = actionIndex===undefined ? -1 : actionIndex;
|
||||||
|
this.isCtxDependent = isCtxDependent===undefined ? false : isCtxDependent; // e.g., $i ref in pred
|
||||||
|
this.isEpsilon = true;
|
||||||
|
}
|
||||||
|
|
||||||
PredicateTransition.prototype.getPredicate = function() {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
return new Predicate(this.ruleIndex, this.predIndex, this.isCtxDependent);
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
PredicateTransition.prototype.toString = function() {
|
toString() {
|
||||||
return "pred_" + this.ruleIndex + ":" + this.predIndex;
|
return "action_" + this.ruleIndex + ":" + this.actionIndex;
|
||||||
};
|
}
|
||||||
|
|
||||||
function ActionTransition(target, ruleIndex, actionIndex, isCtxDependent) {
|
|
||||||
Transition.call(this, target);
|
|
||||||
this.serializationType = Transition.ACTION;
|
|
||||||
this.ruleIndex = ruleIndex;
|
|
||||||
this.actionIndex = actionIndex===undefined ? -1 : actionIndex;
|
|
||||||
this.isCtxDependent = isCtxDependent===undefined ? false : isCtxDependent; // e.g., $i ref in pred
|
|
||||||
this.isEpsilon = true;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionTransition.prototype = Object.create(Transition.prototype);
|
|
||||||
ActionTransition.prototype.constructor = ActionTransition;
|
|
||||||
|
|
||||||
|
|
||||||
ActionTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionTransition.prototype.toString = function() {
|
|
||||||
return "action_" + this.ruleIndex + ":" + this.actionIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// A transition containing a set of values.
|
// A transition containing a set of values.
|
||||||
function SetTransition(target, set) {
|
class SetTransition extends Transition {
|
||||||
Transition.call(this, target);
|
constructor(target, set) {
|
||||||
this.serializationType = Transition.SET;
|
super(target);
|
||||||
if (set !==undefined && set !==null) {
|
this.serializationType = Transition.SET;
|
||||||
this.label = set;
|
if (set !==undefined && set !==null) {
|
||||||
} else {
|
this.label = set;
|
||||||
this.label = new IntervalSet();
|
} else {
|
||||||
this.label.addOne(Token.INVALID_TYPE);
|
this.label = new IntervalSet();
|
||||||
|
this.label.addOne(Token.INVALID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
|
return this.label.contains(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.label.toString();
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetTransition.prototype = Object.create(Transition.prototype);
|
class NotSetTransition extends SetTransition {
|
||||||
SetTransition.prototype.constructor = SetTransition;
|
constructor(target, set) {
|
||||||
|
super(target, set);
|
||||||
|
this.serializationType = Transition.NOT_SET;
|
||||||
|
}
|
||||||
|
|
||||||
SetTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
return this.label.contains(symbol);
|
return symbol >= minVocabSymbol && symbol <= maxVocabSymbol &&
|
||||||
};
|
!super.matches(symbol, minVocabSymbol, maxVocabSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
SetTransition.prototype.toString = function() {
|
return '~' + super.toString();
|
||||||
return this.label.toString();
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function NotSetTransition(target, set) {
|
|
||||||
SetTransition.call(this, target, set);
|
|
||||||
this.serializationType = Transition.NOT_SET;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NotSetTransition.prototype = Object.create(SetTransition.prototype);
|
class WildcardTransition extends Transition {
|
||||||
NotSetTransition.prototype.constructor = NotSetTransition;
|
constructor(target) {
|
||||||
|
super(target);
|
||||||
|
this.serializationType = Transition.WILDCARD;
|
||||||
|
}
|
||||||
|
|
||||||
NotSetTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
return symbol >= minVocabSymbol && symbol <= maxVocabSymbol &&
|
return symbol >= minVocabSymbol && symbol <= maxVocabSymbol;
|
||||||
!SetTransition.prototype.matches.call(this, symbol, minVocabSymbol, maxVocabSymbol);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
NotSetTransition.prototype.toString = function() {
|
toString() {
|
||||||
return '~' + SetTransition.prototype.toString.call(this);
|
return ".";
|
||||||
};
|
}
|
||||||
|
|
||||||
function WildcardTransition(target) {
|
|
||||||
Transition.call(this, target);
|
|
||||||
this.serializationType = Transition.WILDCARD;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WildcardTransition.prototype = Object.create(Transition.prototype);
|
class PrecedencePredicateTransition extends AbstractPredicateTransition {
|
||||||
WildcardTransition.prototype.constructor = WildcardTransition;
|
constructor(target, precedence) {
|
||||||
|
super(target);
|
||||||
|
this.serializationType = Transition.PRECEDENCE;
|
||||||
|
this.precedence = precedence;
|
||||||
|
this.isEpsilon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(symbol, minVocabSymbol, maxVocabSymbol) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
WildcardTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
getPredicate() {
|
||||||
return symbol >= minVocabSymbol && symbol <= maxVocabSymbol;
|
return new PrecedencePredicate(this.precedence);
|
||||||
};
|
}
|
||||||
|
|
||||||
WildcardTransition.prototype.toString = function() {
|
toString() {
|
||||||
return ".";
|
return this.precedence + " >= _p";
|
||||||
};
|
}
|
||||||
|
|
||||||
function PrecedencePredicateTransition(target, precedence) {
|
|
||||||
AbstractPredicateTransition.call(this, target);
|
|
||||||
this.serializationType = Transition.PRECEDENCE;
|
|
||||||
this.precedence = precedence;
|
|
||||||
this.isEpsilon = true;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrecedencePredicateTransition.prototype = Object.create(AbstractPredicateTransition.prototype);
|
module.exports = {
|
||||||
PrecedencePredicateTransition.prototype.constructor = PrecedencePredicateTransition;
|
Transition,
|
||||||
|
AtomTransition,
|
||||||
PrecedencePredicateTransition.prototype.matches = function(symbol, minVocabSymbol, maxVocabSymbol) {
|
SetTransition,
|
||||||
return false;
|
NotSetTransition,
|
||||||
};
|
RuleTransition,
|
||||||
|
ActionTransition,
|
||||||
PrecedencePredicateTransition.prototype.getPredicate = function() {
|
EpsilonTransition,
|
||||||
return new PrecedencePredicate(this.precedence);
|
RangeTransition,
|
||||||
};
|
WildcardTransition,
|
||||||
|
PredicateTransition,
|
||||||
PrecedencePredicateTransition.prototype.toString = function() {
|
PrecedencePredicateTransition,
|
||||||
return this.precedence + " >= _p";
|
AbstractPredicateTransition
|
||||||
};
|
}
|
||||||
|
|
||||||
exports.Transition = Transition;
|
|
||||||
exports.AtomTransition = AtomTransition;
|
|
||||||
exports.SetTransition = SetTransition;
|
|
||||||
exports.NotSetTransition = NotSetTransition;
|
|
||||||
exports.RuleTransition = RuleTransition;
|
|
||||||
exports.ActionTransition = ActionTransition;
|
|
||||||
exports.EpsilonTransition = EpsilonTransition;
|
|
||||||
exports.RangeTransition = RangeTransition;
|
|
||||||
exports.WildcardTransition = WildcardTransition;
|
|
||||||
exports.PredicateTransition = PredicateTransition;
|
|
||||||
exports.PrecedencePredicateTransition = PrecedencePredicateTransition;
|
|
||||||
exports.AbstractPredicateTransition = AbstractPredicateTransition;
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.ATN = require('./ATN');
|
exports.ATN = require('./ATN');
|
||||||
exports.ATNDeserializer = require('./ATNDeserializer').ATNDeserializer;
|
exports.ATNDeserializer = require('./ATNDeserializer');
|
||||||
exports.LexerATNSimulator = require('./LexerATNSimulator').LexerATNSimulator;
|
exports.LexerATNSimulator = require('./LexerATNSimulator');
|
||||||
exports.ParserATNSimulator = require('./ParserATNSimulator').ParserATNSimulator;
|
exports.ParserATNSimulator = require('./ParserATNSimulator');
|
||||||
exports.PredictionMode = require('./PredictionMode').PredictionMode;
|
exports.PredictionMode = require('./PredictionMode');
|
||||||
|
|
Loading…
Reference in New Issue