refactored ATN to be an es6 class
This commit is contained in:
parent
225249fdae
commit
e7b935e7e2
|
@ -6,91 +6,117 @@
|
|||
var LL1Analyzer = require('./../LL1Analyzer').LL1Analyzer;
|
||||
var IntervalSet = require('./../IntervalSet').IntervalSet;
|
||||
|
||||
function ATN(grammarType , maxTokenType) {
|
||||
class ATN {
|
||||
constructor(grammarType , maxTokenType) {
|
||||
|
||||
// Used for runtime deserialization of ATNs from strings///
|
||||
// The type of the ATN.
|
||||
this.grammarType = grammarType;
|
||||
// The maximum value for any symbol recognized by a transition in the ATN.
|
||||
this.maxTokenType = maxTokenType;
|
||||
this.states = [];
|
||||
// Each subrule/rule is a decision point and we must track them so we
|
||||
// can go back later and build DFA predictors for them. This includes
|
||||
// all the rules, subrules, optional blocks, ()+, ()* etc...
|
||||
this.decisionToState = [];
|
||||
// Maps from rule index to starting state number.
|
||||
this.ruleToStartState = [];
|
||||
// Maps from rule index to stop state number.
|
||||
this.ruleToStopState = null;
|
||||
this.modeNameToStartState = {};
|
||||
// For lexer ATNs, this maps the rule index to the resulting token type.
|
||||
// For parser ATNs, this maps the rule index to the generated bypass token
|
||||
// type if the
|
||||
// {@link ATNDeserializationOptions//isGenerateRuleBypassTransitions}
|
||||
// deserialization option was specified; otherwise, this is {@code null}.
|
||||
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;
|
||||
}
|
||||
// Used for runtime deserialization of ATNs from strings///
|
||||
// The type of the ATN.
|
||||
this.grammarType = grammarType;
|
||||
// The maximum value for any symbol recognized by a transition in the ATN.
|
||||
this.maxTokenType = maxTokenType;
|
||||
this.states = [];
|
||||
// Each subrule/rule is a decision point and we must track them so we
|
||||
// can go back later and build DFA predictors for them. This includes
|
||||
// all the rules, subrules, optional blocks, ()+, ()* etc...
|
||||
this.decisionToState = [];
|
||||
// Maps from rule index to starting state number.
|
||||
this.ruleToStartState = [];
|
||||
// Maps from rule index to stop state number.
|
||||
this.ruleToStopState = null;
|
||||
this.modeNameToStartState = {};
|
||||
// For lexer ATNs, this maps the rule index to the resulting token type.
|
||||
// For parser ATNs, this maps the rule index to the generated bypass token
|
||||
// type if the
|
||||
// {@link ATNDeserializationOptions//isGenerateRuleBypassTransitions}
|
||||
// deserialization option was specified; otherwise, this is {@code null}.
|
||||
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 = [];
|
||||
}
|
||||
|
||||
// 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.
|
||||
ATN.prototype.nextTokensInContext = function(s, ctx) {
|
||||
var anal = new LL1Analyzer(this);
|
||||
return anal.LOOK(s, null, ctx);
|
||||
};
|
||||
nextTokensInContext(s, ctx) {
|
||||
var anal = new LL1Analyzer(this);
|
||||
return anal.LOOK(s, null, ctx);
|
||||
}
|
||||
|
||||
// Compute the set of valid tokens that can occur starting in {@code s} and
|
||||
// staying in same rule. {@link Token//EPSILON} is in set if we reach end of
|
||||
// rule.
|
||||
ATN.prototype.nextTokensNoContext = function(s) {
|
||||
if (s.nextTokenWithinRule !== null ) {
|
||||
nextTokensNoContext(s) {
|
||||
if (s.nextTokenWithinRule !== null ) {
|
||||
return s.nextTokenWithinRule;
|
||||
}
|
||||
s.nextTokenWithinRule = this.nextTokensInContext(s, null);
|
||||
s.nextTokenWithinRule.readOnly = true;
|
||||
return s.nextTokenWithinRule;
|
||||
}
|
||||
s.nextTokenWithinRule = this.nextTokensInContext(s, null);
|
||||
s.nextTokenWithinRule.readOnly = true;
|
||||
return s.nextTokenWithinRule;
|
||||
};
|
||||
|
||||
ATN.prototype.nextTokens = function(s, ctx) {
|
||||
if ( ctx===undefined ) {
|
||||
return this.nextTokensNoContext(s);
|
||||
} else {
|
||||
return this.nextTokensInContext(s, ctx);
|
||||
nextTokens(s, ctx) {
|
||||
if ( ctx===undefined ) {
|
||||
return this.nextTokensNoContext(s);
|
||||
} else {
|
||||
return this.nextTokensInContext(s, ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ATN.prototype.addState = function( state) {
|
||||
if ( state !== null ) {
|
||||
state.atn = this;
|
||||
state.stateNumber = this.states.length;
|
||||
addState(state) {
|
||||
if ( state !== null ) {
|
||||
state.atn = this;
|
||||
state.stateNumber = this.states.length;
|
||||
}
|
||||
this.states.push(state);
|
||||
}
|
||||
this.states.push(state);
|
||||
};
|
||||
|
||||
ATN.prototype.removeState = function( state) {
|
||||
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];
|
||||
removeState(state) {
|
||||
this.states[state.stateNumber] = null; // just free mem, don't shift states in list
|
||||
}
|
||||
};
|
||||
|
||||
defineDecisionState(s) {
|
||||
this.decisionToState.push(s);
|
||||
s.decision = this.decisionToState.length-1;
|
||||
return s.decision;
|
||||
}
|
||||
|
||||
getDecisionState(decision) {
|
||||
if (this.decisionToState.length===0) {
|
||||
return null;
|
||||
} else {
|
||||
return this.decisionToState[decision];
|
||||
}
|
||||
}
|
||||
|
||||
getExpectedTokens(stateNumber, ctx ) {
|
||||
if ( stateNumber < 0 || stateNumber >= this.states.length ) {
|
||||
throw("Invalid state number.");
|
||||
}
|
||||
var s = this.states[stateNumber];
|
||||
var following = this.nextTokens(s);
|
||||
if (!following.contains(Token.EPSILON)) {
|
||||
return following;
|
||||
}
|
||||
var expected = new IntervalSet();
|
||||
expected.addSet(following);
|
||||
expected.removeOne(Token.EPSILON);
|
||||
while (ctx !== null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
|
||||
var invokingState = this.states[ctx.invokingState];
|
||||
var 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the set of input symbols which could follow ATN state number
|
||||
// {@code stateNumber} in the specified full {@code context}. This method
|
||||
|
@ -111,32 +137,6 @@ ATN.prototype.getDecisionState = function( decision) {
|
|||
// number {@code stateNumber}
|
||||
var Token = require('./../Token').Token;
|
||||
|
||||
ATN.prototype.getExpectedTokens = function( stateNumber, ctx ) {
|
||||
if ( stateNumber < 0 || stateNumber >= this.states.length ) {
|
||||
throw("Invalid state number.");
|
||||
}
|
||||
var s = this.states[stateNumber];
|
||||
var following = this.nextTokens(s);
|
||||
if (!following.contains(Token.EPSILON)) {
|
||||
return following;
|
||||
}
|
||||
var expected = new IntervalSet();
|
||||
expected.addSet(following);
|
||||
expected.removeOne(Token.EPSILON);
|
||||
while (ctx !== null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
|
||||
var invokingState = this.states[ctx.invokingState];
|
||||
var 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;
|
||||
};
|
||||
|
||||
ATN.INVALID_ALT_NUMBER = 0;
|
||||
|
||||
module.exports = ATN;
|
||||
|
|
Loading…
Reference in New Issue