chevrotain
Version:
Chevrotain is a high performance fault tolerant javascript parsing DSL for building recursive decent parsers
1,252 lines • 101 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var cache = require("./cache");
var cache_1 = require("./cache");
var exceptions_public_1 = require("./exceptions_public");
var lang_extensions_1 = require("../lang/lang_extensions");
var checks_1 = require("./grammar/checks");
var utils_1 = require("../utils/utils");
var follow_1 = require("./grammar/follow");
var tokens_public_1 = require("../scan/tokens_public");
var lookahead_1 = require("./grammar/lookahead");
var gast_builder_1 = require("./gast_builder");
var interpreter_1 = require("./grammar/interpreter");
var constants_1 = require("./constants");
var gast_1 = require("./grammar/gast/gast");
var tokens_1 = require("../scan/tokens");
var cst_1 = require("./cst/cst");
var keys_1 = require("./grammar/keys");
var cst_visitor_1 = require("./cst/cst_visitor");
var errors_public_1 = require("./errors_public");
var gast_public_1 = require("./grammar/gast/gast_public");
var gast_resolver_public_1 = require("./grammar/gast/gast_resolver_public");
var ParserDefinitionErrorType;
(function (ParserDefinitionErrorType) {
ParserDefinitionErrorType[ParserDefinitionErrorType["INVALID_RULE_NAME"] = 0] = "INVALID_RULE_NAME";
ParserDefinitionErrorType[ParserDefinitionErrorType["DUPLICATE_RULE_NAME"] = 1] = "DUPLICATE_RULE_NAME";
ParserDefinitionErrorType[ParserDefinitionErrorType["INVALID_RULE_OVERRIDE"] = 2] = "INVALID_RULE_OVERRIDE";
ParserDefinitionErrorType[ParserDefinitionErrorType["DUPLICATE_PRODUCTIONS"] = 3] = "DUPLICATE_PRODUCTIONS";
ParserDefinitionErrorType[ParserDefinitionErrorType["UNRESOLVED_SUBRULE_REF"] = 4] = "UNRESOLVED_SUBRULE_REF";
ParserDefinitionErrorType[ParserDefinitionErrorType["LEFT_RECURSION"] = 5] = "LEFT_RECURSION";
ParserDefinitionErrorType[ParserDefinitionErrorType["NONE_LAST_EMPTY_ALT"] = 6] = "NONE_LAST_EMPTY_ALT";
ParserDefinitionErrorType[ParserDefinitionErrorType["AMBIGUOUS_ALTS"] = 7] = "AMBIGUOUS_ALTS";
ParserDefinitionErrorType[ParserDefinitionErrorType["CONFLICT_TOKENS_RULES_NAMESPACE"] = 8] = "CONFLICT_TOKENS_RULES_NAMESPACE";
ParserDefinitionErrorType[ParserDefinitionErrorType["INVALID_TOKEN_NAME"] = 9] = "INVALID_TOKEN_NAME";
ParserDefinitionErrorType[ParserDefinitionErrorType["INVALID_NESTED_RULE_NAME"] = 10] = "INVALID_NESTED_RULE_NAME";
ParserDefinitionErrorType[ParserDefinitionErrorType["DUPLICATE_NESTED_NAME"] = 11] = "DUPLICATE_NESTED_NAME";
ParserDefinitionErrorType[ParserDefinitionErrorType["NO_NON_EMPTY_LOOKAHEAD"] = 12] = "NO_NON_EMPTY_LOOKAHEAD";
ParserDefinitionErrorType[ParserDefinitionErrorType["AMBIGUOUS_PREFIX_ALTS"] = 13] = "AMBIGUOUS_PREFIX_ALTS";
ParserDefinitionErrorType[ParserDefinitionErrorType["TOO_MANY_ALTS"] = 14] = "TOO_MANY_ALTS";
})(ParserDefinitionErrorType = exports.ParserDefinitionErrorType || (exports.ParserDefinitionErrorType = {}));
var IN_RULE_RECOVERY_EXCEPTION = "InRuleRecoveryException";
exports.END_OF_FILE = tokens_public_1.createTokenInstance(tokens_public_1.EOF, "", NaN, NaN, NaN, NaN, NaN, NaN);
Object.freeze(exports.END_OF_FILE);
var DEFAULT_PARSER_CONFIG = Object.freeze({
recoveryEnabled: false,
maxLookahead: 4,
ignoredIssues: {},
dynamicTokensEnabled: false,
// TODO: Document this breaking change, can it be mitigated?
// TODO: change to true
outputCst: false,
errorMessageProvider: errors_public_1.defaultParserErrorProvider
});
var DEFAULT_RULE_CONFIG = Object.freeze({
recoveryValueFunc: function () { return undefined; },
resyncEnabled: true
});
/**
* Convenience used to express an empty alternative in an OR (alternation).
* can be used to more clearly describe the intent in a case of empty alternation.
*
* For example:
*
* 1. without using EMPTY_ALT:
*
* this.OR([
* {ALT: () => {
* this.CONSUME1(OneTok)
* return "1"
* }},
* {ALT: () => {
* this.CONSUME1(TwoTok)
* return "2"
* }},
* {ALT: () => { // implicitly empty because there are no invoked grammar rules (OR/MANY/CONSUME...) inside this alternative.
* return "666"
* }},
* ])
*
*
* 2. using EMPTY_ALT:
*
* this.OR([
* {ALT: () => {
* this.CONSUME1(OneTok)
* return "1"
* }},
* {ALT: () => {
* this.CONSUME1(TwoTok)
* return "2"
* }},
* {ALT: EMPTY_ALT("666")}, // explicitly empty, clearer intent
* ])
*
*/
function EMPTY_ALT(value) {
if (value === void 0) { value = undefined; }
return function () {
return value;
};
}
exports.EMPTY_ALT = EMPTY_ALT;
var EOF_FOLLOW_KEY = {};
/**
* A Recognizer capable of self analysis to determine it's grammar structure
* This is used for more advanced features requiring such information.
* For example: Error Recovery, Automatic lookahead calculation.
*/
var Parser = /** @class */ (function () {
function Parser(input, tokenVocabulary, config) {
if (config === void 0) { config = DEFAULT_PARSER_CONFIG; }
this._errors = [];
this.isBackTrackingStack = [];
this.RULE_STACK = [];
this.RULE_OCCURRENCE_STACK = [];
this.CST_STACK = [];
this.tokensMap = undefined;
this.definedRulesNames = [];
this.shortRuleNameToFull = new lang_extensions_1.HashTable();
this.fullRuleNameToShort = new lang_extensions_1.HashTable();
// The shortName Index must be coded "after" the first 8bits to enable building unique lookahead keys
this.ruleShortNameIdx = 256;
this.LAST_EXPLICIT_RULE_STACK = [];
this.selfAnalysisDone = false;
this.currIdx = -1;
/**
* Only used internally for storing productions as they are built for the first time.
* The final productions should be accessed from the static cache.
*/
this._productions = new lang_extensions_1.HashTable();
this.input = input;
// configuration
this.recoveryEnabled = utils_1.has(config, "recoveryEnabled")
? config.recoveryEnabled
: DEFAULT_PARSER_CONFIG.recoveryEnabled;
// performance optimization, NOOP will be inlined which
// effectively means that this optional feature does not exist
// when not used.
if (!this.recoveryEnabled) {
this.attemptInRepetitionRecovery = utils_1.NOOP;
}
this.dynamicTokensEnabled = utils_1.has(config, "dynamicTokensEnabled")
? config.dynamicTokensEnabled
: DEFAULT_PARSER_CONFIG.dynamicTokensEnabled;
this.maxLookahead = utils_1.has(config, "maxLookahead")
? config.maxLookahead
: DEFAULT_PARSER_CONFIG.maxLookahead;
this.ignoredIssues = utils_1.has(config, "ignoredIssues")
? config.ignoredIssues
: DEFAULT_PARSER_CONFIG.ignoredIssues;
this.outputCst = utils_1.has(config, "outputCst")
? config.outputCst
: DEFAULT_PARSER_CONFIG.outputCst;
this.errorMessageProvider = utils_1.defaults(config.errorMessageProvider, DEFAULT_PARSER_CONFIG.errorMessageProvider);
if (!this.outputCst) {
this.cstInvocationStateUpdate = utils_1.NOOP;
this.cstFinallyStateUpdate = utils_1.NOOP;
this.cstPostTerminal = utils_1.NOOP;
this.cstPostNonTerminal = utils_1.NOOP;
this.getLastExplicitRuleShortName = this.getLastExplicitRuleShortNameNoCst;
this.getPreviousExplicitRuleShortName = this.getPreviousExplicitRuleShortNameNoCst;
this.getPreviousExplicitRuleOccurenceIndex = this.getPreviousExplicitRuleOccurenceIndexNoCst;
this.manyInternal = this.manyInternalNoCst;
this.orInternal = this.orInternalNoCst;
this.optionInternal = this.optionInternalNoCst;
this.atLeastOneInternal = this.atLeastOneInternalNoCst;
this.manySepFirstInternal = this.manySepFirstInternalNoCst;
this.atLeastOneSepFirstInternal = this.atLeastOneSepFirstInternalNoCst;
}
this.className = lang_extensions_1.classNameFromInstance(this);
this.firstAfterRepMap = cache.getFirstAfterRepForClass(this.className);
this.classLAFuncs = cache.getLookaheadFuncsForClass(this.className);
this.cstDictDefForRule = cache.getCstDictDefPerRuleForClass(this.className);
if (!cache.CLASS_TO_DEFINITION_ERRORS.containsKey(this.className)) {
this.definitionErrors = [];
cache.CLASS_TO_DEFINITION_ERRORS.put(this.className, this.definitionErrors);
}
else {
this.definitionErrors = cache.CLASS_TO_DEFINITION_ERRORS.get(this.className);
}
if (utils_1.isArray(tokenVocabulary)) {
this.tokensMap = utils_1.reduce(tokenVocabulary, function (acc, tokenClazz) {
acc[tokens_public_1.tokenName(tokenClazz)] = tokenClazz;
return acc;
}, {});
}
else if (utils_1.has(tokenVocabulary, "modes") &&
utils_1.every(utils_1.flatten(utils_1.values(tokenVocabulary.modes)), tokens_1.isTokenType)) {
var allTokenTypes = utils_1.flatten(utils_1.values(tokenVocabulary.modes));
var uniqueTokens = utils_1.uniq(allTokenTypes);
this.tokensMap = utils_1.reduce(uniqueTokens, function (acc, tokenClazz) {
acc[tokens_public_1.tokenName(tokenClazz)] = tokenClazz;
return acc;
}, {});
}
else if (utils_1.isObject(tokenVocabulary)) {
this.tokensMap = utils_1.cloneObj(tokenVocabulary);
}
else {
throw new Error("<tokensDictionary> argument must be An Array of Token constructors" +
" A dictionary of Token constructors or an IMultiModeLexerDefinition");
}
var noTokenCategoriesUsed = utils_1.every(utils_1.values(tokenVocabulary), function (tokenConstructor) { return utils_1.isEmpty(tokenConstructor.categoryMatches); });
this.tokenMatcher = noTokenCategoriesUsed
? tokens_1.tokenStructuredMatcherNoCategories
: tokens_1.tokenStructuredMatcher;
// always add EOF to the tokenNames -> constructors map. it is useful to assure all the input has been
// parsed with a clear error message ("expecting EOF but found ...")
/* tslint:disable */
this.tokensMap["EOF"] = tokens_public_1.EOF;
/* tslint:enable */
// Because ES2015+ syntax should be supported for creating Token classes
// We cannot assume that the Token classes were created using the "extendToken" utilities
// Therefore we must augment the Token classes both on Lexer initialization and on Parser initialization
tokens_1.augmentTokenTypes(utils_1.values(this.tokensMap));
}
Parser.performSelfAnalysis = function (parserInstance) {
var definitionErrors = [];
var defErrorsMsgs;
parserInstance.selfAnalysisDone = true;
var className = lang_extensions_1.classNameFromInstance(parserInstance);
// can't test this with nyc tool, instrumentation causes the class name to be not empty.
/* istanbul ignore if */
if (className === "") {
// just a simple "throw Error" without any fancy "definition error" because the logic below relies on a unique parser name to
// save/access those definition errors...
/* istanbul ignore next */
throw Error("A Parser's constructor may not be an anonymous Function, it must be a named function\n" +
"The constructor's name is used at runtime for performance (caching) purposes.");
}
// this information should only be computed once
if (!cache.CLASS_TO_SELF_ANALYSIS_DONE.containsKey(className)) {
cache.CLASS_TO_SELF_ANALYSIS_DONE.put(className, true);
var orgProductions_1 = parserInstance._productions;
var clonedProductions_1 = new lang_extensions_1.HashTable();
// clone the grammar productions to support grammar inheritance. requirements:
// 1. We want to avoid rebuilding the grammar every time so a cache for the productions is used.
// 2. We need to collect the production from multiple grammars in an inheritance scenario during constructor invocation
// so the myGast variable is used.
// 3. If a Production has been overridden references to it in the GAST must also be updated.
utils_1.forEach(orgProductions_1.keys(), function (key) {
var value = orgProductions_1.get(key);
clonedProductions_1.put(key, gast_1.cloneProduction(value));
});
cache.getProductionsForClass(className).putAll(clonedProductions_1);
// assumes this cache has been initialized (in the relevant parser's constructor)
// TODO: consider making the self analysis a member method to resolve this.
// that way it won't be callable before the constructor has been invoked...
definitionErrors = cache.CLASS_TO_DEFINITION_ERRORS.get(className);
var resolverErrors = gast_resolver_public_1.resolveGrammar({
rules: clonedProductions_1.values()
});
definitionErrors.push.apply(definitionErrors, resolverErrors); // mutability for the win?
// only perform additional grammar validations IFF no resolving errors have occurred.
// as unresolved grammar may lead to unhandled runtime exceptions in the follow up validations.
if (utils_1.isEmpty(resolverErrors)) {
var validationErrors = gast_resolver_public_1.validateGrammar({
rules: clonedProductions_1.values(),
maxLookahead: parserInstance.maxLookahead,
tokenTypes: utils_1.values(parserInstance.tokensMap),
ignoredIssues: parserInstance.ignoredIssues,
errMsgProvider: errors_public_1.defaultGrammarValidatorErrorProvider,
grammarName: className
});
definitionErrors.push.apply(definitionErrors, validationErrors); // mutability for the win?
}
if (!utils_1.isEmpty(definitionErrors) &&
!Parser.DEFER_DEFINITION_ERRORS_HANDLING) {
defErrorsMsgs = utils_1.map(definitionErrors, function (defError) { return defError.message; });
throw new Error("Parser Definition Errors detected:\n " + defErrorsMsgs.join("\n-------------------------------\n"));
}
if (utils_1.isEmpty(definitionErrors)) {
// this analysis may fail if the grammar is not perfectly valid
var allFollows = follow_1.computeAllProdsFollows(clonedProductions_1.values());
cache.setResyncFollowsForClass(className, allFollows);
}
var cstAnalysisResult = cst_1.analyzeCst(clonedProductions_1.values(), parserInstance.fullRuleNameToShort);
cache
.getCstDictDefPerRuleForClass(className)
.putAll(cstAnalysisResult.dictDef);
cache.CLASS_TO_ALL_RULE_NAMES.put(className, cstAnalysisResult.allRuleNames);
}
// reThrow the validation errors each time an erroneous parser is instantiated
if (!utils_1.isEmpty(cache.CLASS_TO_DEFINITION_ERRORS.get(className)) &&
!Parser.DEFER_DEFINITION_ERRORS_HANDLING) {
defErrorsMsgs = utils_1.map(cache.CLASS_TO_DEFINITION_ERRORS.get(className), function (defError) { return defError.message; });
throw new Error("Parser Definition Errors detected:\n " + defErrorsMsgs.join("\n-------------------------------\n"));
}
};
Object.defineProperty(Parser.prototype, "errors", {
get: function () {
return utils_1.cloneArr(this._errors);
},
set: function (newErrors) {
this._errors = newErrors;
},
enumerable: true,
configurable: true
});
/**
* Resets the parser state, should be overridden for custom parsers which "carry" additional state.
* When overriding, remember to also invoke the super implementation!
*/
Parser.prototype.reset = function () {
this.resetLexerState();
this.isBackTrackingStack = [];
this.errors = [];
this.RULE_STACK = [];
this.LAST_EXPLICIT_RULE_STACK = [];
this.CST_STACK = [];
this.RULE_OCCURRENCE_STACK = [];
};
Parser.prototype.isAtEndOfInput = function () {
return this.tokenMatcher(this.LA(1), tokens_public_1.EOF);
};
Parser.prototype.getBaseCstVisitorConstructor = function () {
var cachedConstructor = cache_1.CLASS_TO_BASE_CST_VISITOR.get(this.className);
if (utils_1.isUndefined(cachedConstructor)) {
var allRuleNames = cache_1.CLASS_TO_ALL_RULE_NAMES.get(this.className);
cachedConstructor = cst_visitor_1.createBaseSemanticVisitorConstructor(this.className, allRuleNames);
cache_1.CLASS_TO_BASE_CST_VISITOR.put(this.className, cachedConstructor);
}
return cachedConstructor;
};
Parser.prototype.getBaseCstVisitorConstructorWithDefaults = function () {
var cachedConstructor = cache_1.CLASS_TO_BASE_CST_VISITOR_WITH_DEFAULTS.get(this.className);
if (utils_1.isUndefined(cachedConstructor)) {
var allRuleNames = cache_1.CLASS_TO_ALL_RULE_NAMES.get(this.className);
var baseConstructor = this.getBaseCstVisitorConstructor();
cachedConstructor = cst_visitor_1.createBaseVisitorConstructorWithDefaults(this.className, allRuleNames, baseConstructor);
cache_1.CLASS_TO_BASE_CST_VISITOR_WITH_DEFAULTS.put(this.className, cachedConstructor);
}
return cachedConstructor;
};
Parser.prototype.getGAstProductions = function () {
return cache.getProductionsForClass(this.className);
};
// This is more than a convenience method.
// It is mostly used to draw the diagrams and having this method present on the parser instance
// can avoid certain situations in which the serialization logic would fail due to multiple versions of chevrotain
// bundled (due to multiple prototype chains and "instanceof" usage).
Parser.prototype.getSerializedGastProductions = function () {
return gast_public_1.serializeGrammar(cache.getProductionsForClass(this.className).values());
};
/**
* @param startRuleName {string}
* @param precedingInput {IToken[]} - The token vector up to (not including) the content assist point
* @returns {ISyntacticContentAssistPath[]}
*/
Parser.prototype.computeContentAssist = function (startRuleName, precedingInput) {
var startRuleGast = cache
.getProductionsForClass(this.className)
.get(startRuleName);
if (utils_1.isUndefined(startRuleGast)) {
throw Error("Rule ->" + startRuleName + "<- does not exist in this grammar.");
}
return interpreter_1.nextPossibleTokensAfter([startRuleGast], precedingInput, this.tokenMatcher, this.maxLookahead);
};
Parser.prototype.isBackTracking = function () {
return !utils_1.isEmpty(this.isBackTrackingStack);
};
Parser.prototype.getCurrRuleFullName = function () {
var shortName = this.getLastExplicitRuleShortName();
return this.shortRuleNameToFull.get(shortName);
};
Parser.prototype.shortRuleNameToFullName = function (shortName) {
return this.shortRuleNameToFull.get(shortName);
};
Parser.prototype.getHumanReadableRuleStack = function () {
var _this = this;
if (!utils_1.isEmpty(this.LAST_EXPLICIT_RULE_STACK)) {
return utils_1.map(this.LAST_EXPLICIT_RULE_STACK, function (currIdx) {
return _this.shortRuleNameToFullName(_this.RULE_STACK[currIdx]);
});
}
else {
return utils_1.map(this.RULE_STACK, function (currShortName) {
return _this.shortRuleNameToFullName(currShortName);
});
}
};
Parser.prototype.SAVE_ERROR = function (error) {
if (exceptions_public_1.isRecognitionException(error)) {
error.context = {
ruleStack: this.getHumanReadableRuleStack(),
ruleOccurrenceStack: utils_1.cloneArr(this.RULE_OCCURRENCE_STACK)
};
this._errors.push(error);
return error;
}
else {
throw Error("Trying to save an Error which is not a RecognitionException");
}
};
/**
* @param grammarRule - The rule to try and parse in backtracking mode.
* @param args - argumens to be passed to the grammar rule execution
*
* @return {TokenType():boolean} a lookahead function that will try to parse the given grammarRule and will return true if succeed.
*/
Parser.prototype.BACKTRACK = function (grammarRule, args) {
return function () {
// save org state
this.isBackTrackingStack.push(1);
var orgState = this.saveRecogState();
try {
grammarRule.apply(this, args);
// if no exception was thrown we have succeed parsing the rule.
return true;
}
catch (e) {
if (exceptions_public_1.isRecognitionException(e)) {
return false;
}
else {
throw e;
}
}
finally {
this.reloadRecogState(orgState);
this.isBackTrackingStack.pop();
}
};
};
// Parsing DSL
/**
* Convenience method equivalent to CONSUME1.
* @see CONSUME1
*/
Parser.prototype.CONSUME = function (tokType, options) {
return this.consumeInternal(tokType, 0, options);
};
/**
*
* A Parsing DSL method use to consume a single terminal Token.
* a Token will be consumed, IFF the next token in the token vector matches <tokType>.
* otherwise the parser will attempt to perform error recovery.
*
* The index in the method name indicates the unique occurrence of a terminal consumption
* inside a the top level rule. What this means is that if a terminal appears
* more than once in a single rule, each appearance must have a difference index.
*
* for example:
*
* function parseQualifiedName() {
* this.CONSUME1(Identifier);
* this.MANY(()=> {
* this.CONSUME1(Dot);
* this.CONSUME2(Identifier); // <-- here we use CONSUME2 because the terminal
* }); // 'Identifier' has already appeared previously in the
* // the rule 'parseQualifiedName'
* }
*
* @param {TokenType} tokType - The Type of the token to be consumed.
* @param options - optional properties to modify the behavior of CONSUME.
*/
Parser.prototype.CONSUME1 = function (tokType, options) {
return this.consumeInternal(tokType, 1, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME2 = function (tokType, options) {
return this.consumeInternal(tokType, 2, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME3 = function (tokType, options) {
return this.consumeInternal(tokType, 3, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME4 = function (tokType, options) {
return this.consumeInternal(tokType, 4, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME5 = function (tokType, options) {
return this.consumeInternal(tokType, 5, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME6 = function (tokType, options) {
return this.consumeInternal(tokType, 6, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME7 = function (tokType, options) {
return this.consumeInternal(tokType, 7, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME8 = function (tokType, options) {
return this.consumeInternal(tokType, 8, options);
};
/**
* @see CONSUME1
*/
Parser.prototype.CONSUME9 = function (tokType, options) {
return this.consumeInternal(tokType, 9, options);
};
/**
* Convenience method equivalent to SUBRULE1
* @see SUBRULE1
*/
Parser.prototype.SUBRULE = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 0, args);
};
/**
* The Parsing DSL Method is used by one rule to call another.
*
* This may seem redundant as it does not actually do much.
* However using it is mandatory for all sub rule invocations.
* calling another rule without wrapping in SUBRULE(...)
* will cause errors/mistakes in the Recognizer's self analysis,
* which will lead to errors in error recovery/automatic lookahead calculation
* and any other functionality relying on the Recognizer's self analysis
* output.
*
* As in CONSUME the index in the method name indicates the occurrence
* of the sub rule invocation in its rule.
*
* @param {TokenType} ruleToCall - The rule to invoke.
* @param {*[]} args - The arguments to pass to the invoked subrule.
* @returns {*} - The result of invoking ruleToCall.
*/
Parser.prototype.SUBRULE1 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 1, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE2 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 2, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE3 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 3, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE4 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 4, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE5 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 5, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE6 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 6, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE7 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 7, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE8 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 8, args);
};
/**
* @see SUBRULE1
*/
Parser.prototype.SUBRULE9 = function (ruleToCall, args) {
if (args === void 0) { args = undefined; }
return this.subruleInternal(ruleToCall, 9, args);
};
/**
* Convenience method equivalent to OPTION1.
* @see OPTION1
*/
Parser.prototype.OPTION = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 0);
};
/**
* Parsing DSL Method that Indicates an Optional production
* in EBNF notation: [...].
*
* Note that there are two syntax forms:
* - Passing the grammar action directly:
* this.OPTION(()=> {
* this.CONSUME(Digit)}
* );
*
* - using an "options" object:
* this.OPTION({
* GATE:predicateFunc,
* DEF: ()=>{
* this.CONSUME(Digit)
* }});
*
* The optional 'GATE' property in "options" object form can be used to add constraints
* to invoking the grammar action.
*
* As in CONSUME the index in the method name indicates the occurrence
* of the optional production in it's top rule.
*
* @param actionORMethodDef - The grammar action to optionally invoke once
* or an "OPTIONS" object describing the grammar action and optional properties.
*
* @returns {OUT}
*/
Parser.prototype.OPTION1 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 1);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION2 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 2);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION3 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 3);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION4 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 4);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION5 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 5);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION6 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 6);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION7 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 7);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION8 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 8);
};
/**
* @see OPTION1
*/
Parser.prototype.OPTION9 = function (actionORMethodDef) {
return this.optionInternal(actionORMethodDef, 9);
};
/**
* Convenience method equivalent to OR1.
* @see OR1
*/
Parser.prototype.OR = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 0);
};
/**
* Parsing DSL method that indicates a choice between a set of alternatives must be made.
* This is equivalent to EBNF alternation (A | B | C | D ...)
*
* There are a couple of syntax forms for the inner alternatives array.
*
* Passing alternatives array directly:
* this.OR([
* {ALT:()=>{this.CONSUME(One)}},
* {ALT:()=>{this.CONSUME(Two)}},
* {ALT:()=>{this.CONSUME(Three)}}
* ])
*
* Passing alternative array directly with predicates (GATE).
* this.OR([
* {GATE: predicateFunc1, ALT:()=>{this.CONSUME(One)}},
* {GATE: predicateFuncX, ALT:()=>{this.CONSUME(Two)}},
* {GATE: predicateFuncX, ALT:()=>{this.CONSUME(Three)}}
* ])
*
* These syntax forms can also be mixed:
* this.OR([
* {GATE: predicateFunc1, ALT:()=>{this.CONSUME(One)}},
* {ALT:()=>{this.CONSUME(Two)}},
* {ALT:()=>{this.CONSUME(Three)}}
* ])
*
* Additionally an "options" object may be used:
* this.OR({
* DEF:[
* {ALT:()=>{this.CONSUME(One)}},
* {ALT:()=>{this.CONSUME(Two)}},
* {ALT:()=>{this.CONSUME(Three)}}
* ],
* // OPTIONAL property
* ERR_MSG: "A Number"
* })
*
* The 'predicateFuncX' in the long form can be used to add constraints to choosing the alternative.
*
* As in CONSUME the index in the method name indicates the occurrence
* of the alternation production in it's top rule.
*
* @param altsOrOpts - A set of alternatives or an "OPTIONS" object describing the alternatives and optional properties.
*
* @returns {*} - The result of invoking the chosen alternative.
*/
Parser.prototype.OR1 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 1);
};
/**
* @see OR1
*/
Parser.prototype.OR2 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 2);
};
/**
* @see OR1
*/
Parser.prototype.OR3 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 3);
};
/**
* @see OR1
*/
Parser.prototype.OR4 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 4);
};
/**
* @see OR1
*/
Parser.prototype.OR5 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 5);
};
/**
* @see OR1
*/
Parser.prototype.OR6 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 6);
};
/**
* @see OR1
*/
Parser.prototype.OR7 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 7);
};
/**
* @see OR1
*/
Parser.prototype.OR8 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 8);
};
/**
* @see OR1
*/
Parser.prototype.OR9 = function (altsOrOpts) {
return this.orInternal(altsOrOpts, 9);
};
/**
* Convenience method equivalent to MANY1.
* @see MANY1
*/
Parser.prototype.MANY = function (actionORMethodDef) {
return this.manyInternal(0, actionORMethodDef, []);
};
/**
* Parsing DSL method, that indicates a repetition of zero or more.
* This is equivalent to EBNF repetition {...}.
*
* Note that there are two syntax forms:
* - Passing the grammar action directly:
* this.MANY(()=>{
* this.CONSUME(Comma)
* this.CONSUME(Digit)
* })
*
* - using an "options" object:
* this.MANY({
* GATE: predicateFunc,
* DEF: () => {
* this.CONSUME(Comma)
* this.CONSUME(Digit)
* }
* });
*
* The optional 'GATE' property in "options" object form can be used to add constraints
* to invoking the grammar action.
*
* As in CONSUME the index in the method name indicates the occurrence
* of the repetition production in it's top rule.
*
* @param {TokenType} actionORMethodDef - The grammar action to optionally invoke multiple times
* or an "OPTIONS" object describing the grammar action and optional properties.
*
* @returns {OUT[]}
*/
Parser.prototype.MANY1 = function (actionORMethodDef) {
return this.manyInternal(1, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY2 = function (actionORMethodDef) {
return this.manyInternal(2, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY3 = function (actionORMethodDef) {
return this.manyInternal(3, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY4 = function (actionORMethodDef) {
return this.manyInternal(4, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY5 = function (actionORMethodDef) {
return this.manyInternal(5, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY6 = function (actionORMethodDef) {
return this.manyInternal(6, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY7 = function (actionORMethodDef) {
return this.manyInternal(7, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY8 = function (actionORMethodDef) {
return this.manyInternal(8, actionORMethodDef, []);
};
/**
* @see MANY1
*/
Parser.prototype.MANY9 = function (actionORMethodDef) {
return this.manyInternal(9, actionORMethodDef, []);
};
/**
* Convenience method equivalent to MANY_SEP1.
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP = function (options) {
return this.manySepFirstInternal(0, options, {
values: [],
separators: []
});
};
/**
* Parsing DSL method, that indicates a repetition of zero or more with a separator
* Token between the repetitions.
*
* Example:
*
* this.MANY_SEP({
* SEP:Comma,
* DEF: () => {
* this.CONSUME(Number};
* ...
* );
* })
*
* Note that because this DSL method always requires more than one argument the options object is always required
* and it is not possible to use a shorter form like in the MANY DSL method.
*
* Note that for the purposes of deciding on whether or not another iteration exists
* Only a single Token is examined (The separator). Therefore if the grammar being implemented is
* so "crazy" to require multiple tokens to identify an item separator please use the more basic DSL methods
* to implement it.
*
* As in CONSUME the index in the method name indicates the occurrence
* of the repetition production in it's top rule.
*
* Note that due to current limitations in the implementation the "SEP" property must appear BEFORE the "DEF" property.
*
* @param options - An object defining the grammar of each iteration and the separator between iterations
*
* @return {ISeparatedIterationResult<OUT>}
*/
Parser.prototype.MANY_SEP1 = function (options) {
return this.manySepFirstInternal(1, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP2 = function (options) {
return this.manySepFirstInternal(2, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP3 = function (options) {
return this.manySepFirstInternal(3, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP4 = function (options) {
return this.manySepFirstInternal(4, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP5 = function (options) {
return this.manySepFirstInternal(5, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP6 = function (options) {
return this.manySepFirstInternal(6, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP7 = function (options) {
return this.manySepFirstInternal(7, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP8 = function (options) {
return this.manySepFirstInternal(8, options, {
values: [],
separators: []
});
};
/**
* @see MANY_SEP1
*/
Parser.prototype.MANY_SEP9 = function (options) {
return this.manySepFirstInternal(9, options, {
values: [],
separators: []
});
};
/**
* Convenience method equivalent to AT_LEAST_ONE1.
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE = function (actionORMethodDef) {
return this.atLeastOneInternal(0, actionORMethodDef, []);
};
/**
* Convenience method, same as MANY but the repetition is of one or more.
* failing to match at least one repetition will result in a parsing error and
* cause a parsing error.
*
* @see MANY1
*
* @param actionORMethodDef - The grammar action to optionally invoke multiple times
* or an "OPTIONS" object describing the grammar action and optional properties.
*
* @return {OUT[]}
*/
Parser.prototype.AT_LEAST_ONE1 = function (actionORMethodDef) {
return this.atLeastOneInternal(1, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE2 = function (actionORMethodDef) {
return this.atLeastOneInternal(2, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE3 = function (actionORMethodDef) {
return this.atLeastOneInternal(3, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE4 = function (actionORMethodDef) {
return this.atLeastOneInternal(4, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE5 = function (actionORMethodDef) {
return this.atLeastOneInternal(5, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE6 = function (actionORMethodDef) {
return this.atLeastOneInternal(6, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE7 = function (actionORMethodDef) {
return this.atLeastOneInternal(7, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE8 = function (actionORMethodDef) {
return this.atLeastOneInternal(8, actionORMethodDef, []);
};
/**
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE9 = function (actionORMethodDef) {
return this.atLeastOneInternal(9, actionORMethodDef, []);
};
/**
* Convenience method equivalent to AT_LEAST_ONE_SEP1.
* @see AT_LEAST_ONE1
*/
Parser.prototype.AT_LEAST_ONE_SEP = function (options) {
return this.atLeastOneSepFirstInternal(0, options, {
values: [],
separators: []
});
};
/**
* Convenience method, same as MANY_SEP but the repetition is of one or more.
* failing to match at least one repetition will result in a parsing error and
* cause the parser to attempt error recovery.
*
* Note that an additional optional property ERR_MSG can be used to provide custom error messages.
*
* @see MANY_SEP1
*
* @param options - An object defining the grammar of each iteration and the separator between iterations
*
* @return {ISeparatedIterationResult<OUT>}
*/
Parser.prototype.AT_LEAST_ONE_SEP1 = function (options) {
return this.atLeastOneSepFirstInternal(1, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP2 = function (options) {
return this.atLeastOneSepFirstInternal(2, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP3 = function (options) {
return this.atLeastOneSepFirstInternal(3, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP4 = function (options) {
return this.atLeastOneSepFirstInternal(4, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP5 = function (options) {
return this.atLeastOneSepFirstInternal(5, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP6 = function (options) {
return this.atLeastOneSepFirstInternal(6, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP7 = function (options) {
return this.atLeastOneSepFirstInternal(7, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP8 = function (options) {
return this.atLeastOneSepFirstInternal(8, options, {
values: [],
separators: []
});
};
/**
* @see AT_LEAST_ONE_SEP1
*/
Parser.prototype.AT_LEAST_ONE_SEP9 = function (options) {
return this.atLeastOneSepFirstInternal(9, options, {
values: [],
separators: []
});
};
/**
*
* @param {string} name - The name of the rule.
* @param {TokenType} implementation - The implementation of the rule.
* @param {IRuleConfig} [config] - The rule's optional configuration.
*
* @returns {TokenType} - The parsing rule which is the production implementation wrapped with the parsing logic that handles
* Parser state / error recovery&reporting/ ...
*/
Parser.prototype.RULE = function (name, implementation,
// TODO: how to describe the optional return type of CSTNode? T|CstNode is not good because it is not backward
// compatible, T|any is very general...
config) {
// TODO: how to describe the optional return type of CSTNode? T|CstNode is not good because it is not backward
// compatible, T|any is very general...
if (config === void 0) { config = DEFAULT_RULE_CONFIG; }
if (utils_1.contains(this.definedRulesNames, name)) {
var errMsg = errors_public_1.defaultGrammarValidatorErrorProvider.buildDuplicateRuleNameError({
topLevelRule: name,
grammarName: this.className
});
var error = {
message: errMsg,
type: ParserDefinitionErrorType.DUPLICATE_RULE_NAME,
ruleName: name
};
this.definitionErrors.push(error);
}
this.definedRulesNames.push(name);
// only build the gast representation once.
if (!this._productions.containsKey(name)) {
var gastProduction = gast_builder_1.buildTopProduction(implementation.toString(), name, this.tokensMap);
this._productions.put(name, gastProduction);
}
else {
var parserClassProductions = cache.getProductionsForClass(this.className);
var cachedProduction = parserClassProductions.get(name);
// in case of duplicate rules the cache will not be filled at this point.
if (!utils_1.isUndefined(cachedProduction)) {
// filling up the _productions is always needed to inheriting grammars can access it (as an instance member)
// otherwise they will be unaware of productions defined in super grammars.
this._productions.put(name, cachedProduction);
}
}
var ruleImplementation = this.defineRule(name, implementation, config);
this[name] = ruleImplementation;
return ruleImplementation;
};
/**
* @See RULE
* Same as RULE, but should only be used in "extending" grammars to override rules/productions
* from the super grammar.
*/
Parser.prototype.OVERRIDE_RULE = function (name, impl, config) {
if (config === void 0) { config = DEFAULT_RULE_CONFIG; }
var ruleErrors = [];
ruleErrors = ruleErrors.concat(checks_1.validateRuleIsOverridden(name, this.definedRulesNames, this.className));
this.definitionErrors.push.apply(this.definitionErrors, ruleErrors); // mutability for the win
var alreadyOverridden = cache.getProductionOverriddenForClass(this.className);
// only build the GAST of an overridden rule once.
if (!alreadyOverridden.containsKey(name)) {
alreadyOverridden.put(name, true);
var gastProduction = gast_builder_1.buildTopProduction(impl.toString(), name, this.tokensMap);
this._productions.put(name, gastProduction);
}
else {
var parserClassProductions = cache.getProductionsForClass(this.className);
// filling up the _productions is always needed to inheriting grammars can access it (as an instance member)
// otherwise they will be unaware of productions defined in super grammars.
this._productions.put(name, parserClassProductions.get(name));
}
return this.defineRule(name, impl, config);
};
Parser.prototype.ruleInvocationStateUpdate = function (shortName, fullName, idxInCallingRule) {
this.RULE_OCCURRENCE_STACK.push(idxInCallingRule);
this.RULE_STACK.push(shortName);
// NOOP when cst is disabled
this.cstInvocationStateUpdate(fullName, shortName);
};
Parser.prototype.ruleFinallyStateUpdate = function () {
this.RULE_STACK.pop();
this.RULE_OCCURRENCE_STACK.pop();
// NOOP when cst is disabled
this.cstFinallyStateUpdate();
if (this.RULE_STACK.length === 0 && !this.isAtEndOfInput()) {
var firstRedundantTok = this.LA(1);
var errMsg = this.errorMessageProvider.buildNotAllInputParsedMessage({
firstRedundant: firstRedundantTok,
ruleName: this.ge