"use strict";
var cache = require("./cache");
var exceptions_public_1 = require("./exceptions_public");
var lang_extensions_1 = require("../lang/lang_extensions");
var resolver_1 = require("./grammar/resolver");
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_public_1 = require("./grammar/gast_public");
var gast_1 = require("./grammar/gast");
var tokens_1 = require("../scan/tokens");
var serializeGrammar = gast_public_1.gast.serializeGrammar;
(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";
})(exports.ParserDefinitionErrorType || (exports.ParserDefinitionErrorType = {}));
var ParserDefinitionErrorType = exports.ParserDefinitionErrorType;
var IN_RULE_RECOVERY_EXCEPTION = "InRuleRecoveryException";
var END_OF_FILE = new tokens_public_1.EOF();
END_OF_FILE.tokenType = tokens_public_1.EOF.tokenType;
Object.freeze(END_OF_FILE);
// Lookahead keys are 32Bit integers in the form
// ZZZZZZZZZZZZZZZZZZZZZZZZ-YYYY-XXXX
// XXXX -> Occurrence Index bitmap.
// YYYY -> DSL Method Name bitmap.
// ZZZZZZZZZZZZZZZZZZZZZZZZ -> Rule short Index bitmap.
var BITS_FOR_METHOD_IDX = 4;
var BITS_FOR_OCCURRENCE_IDX = 4;
// short string used as part of mapping keys.
// being short improves the performance when composing KEYS for maps out of these
// The 4 - 7 bits (16 possible values, are reserved for the DSL method indices)
/* tslint:disable */
var OR_IDX = 1 << BITS_FOR_METHOD_IDX;
var OPTION_IDX = 2 << BITS_FOR_METHOD_IDX;
var MANY_IDX = 3 << BITS_FOR_METHOD_IDX;
var AT_LEAST_ONE_IDX = 4 << BITS_FOR_METHOD_IDX;
var MANY_SEP_IDX = 5 << BITS_FOR_METHOD_IDX;
var AT_LEAST_ONE_SEP_IDX = 6 << BITS_FOR_METHOD_IDX;
var DEFAULT_PARSER_CONFIG = Object.freeze({
    recoveryEnabled: false,
    maxLookahead: 5,
    ignoredIssues: {},
    dynamicTokensEnabled: false
});
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 = (function () {
    function Parser(input, tokensMapOrArr, config) {
        if (config === void 0) { config = DEFAULT_PARSER_CONFIG; }
        this._errors = [];
        this._input = [];
        this.inputIdx = -1;
        this.savedTokenIdx = -1;
        this.isBackTrackingStack = [];
        this.RULE_STACK = [];
        this.RULE_OCCURRENCE_STACK = [];
        this.tokensMap = undefined;
        this.definedRulesNames = [];
        this.shortRuleNameToFull = new lang_extensions_1.HashTable();
        this.ruleShortNameIdx = 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.className = lang_extensions_1.classNameFromInstance(this);
        this.firstAfterRepMap = cache.getFirstAfterRepForClass(this.className);
        this.classLAFuncs = cache.getLookaheadFuncsForClass(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(tokensMapOrArr)) {
            this.tokensMap = utils_1.reduce(tokensMapOrArr, function (acc, tokenClazz) {
                acc[tokens_public_1.tokenName(tokenClazz)] = tokenClazz;
                return acc;
            }, {});
        }
        else if (utils_1.isObject(tokensMapOrArr)) {
            this.tokensMap = utils_1.cloneObj(tokensMapOrArr);
        }
        else {
            throw new Error("'tokensMapOrArr' argument must be An Array of Token constructors or a Dictionary of Tokens.");
        }
        var allTokens = utils_1.values(this.tokensMap);
        var areAllStructuredTokens = utils_1.every(allTokens, function (currTokType) {
            return tokens_1.isSimpleTokenType(currTokType);
        });
        if (areAllStructuredTokens) {
            this.tokenMatcher = tokens_1.tokenStructuredMatcher;
            this.tokenClassIdentityFunc = tokens_1.tokenStructuredIdentity;
            // same IdentityFunc used in structured Mode
            this.tokenInstanceIdentityFunc = tokens_1.tokenStructuredIdentity;
        }
        else {
            this.tokenMatcher = tokens_1.tokenInstanceofMatcher;
            this.tokenClassIdentityFunc = tokens_1.tokenClassIdentity;
            this.tokenInstanceIdentityFunc = tokens_1.tokenInstanceIdentity;
        }
        // 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.augmentTokenClasses(utils_1.values(this.tokensMap));
    }
    Parser.performSelfAnalysis = function (parserInstance) {
        var definitionErrors = [];
        var defErrorsMsgs;
        var className = lang_extensions_1.classNameFromInstance(parserInstance);
        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...
            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 = resolver_1.resolveGrammar(clonedProductions_1);
            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 = checks_1.validateGrammar(clonedProductions_1.values(), parserInstance.maxLookahead, parserInstance.ignoredIssues);
                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)) {
                var allFollows = follow_1.computeAllProdsFollows(clonedProductions_1.values());
                cache.setResyncFollowsForClass(className, allFollows);
            }
        }
        // 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
    });
    Object.defineProperty(Parser.prototype, "input", {
        get: function () {
            return utils_1.cloneArr(this._input);
        },
        set: function (newInput) {
            this.reset();
            this._input = newInput;
        },
        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._input = [];
        this.RULE_STACK = [];
        this.RULE_OCCURRENCE_STACK = [];
    };
    Parser.prototype.isAtEndOfInput = function () {
        return this.tokenMatcher(this.LA(1), tokens_public_1.EOF);
    };
    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 serializeGrammar(cache.getProductionsForClass(this.className).values());
    };
    /**
     * @param startRuleName {string}
     * @param precedingInput {ISimpleTokenOrIToken[]} - 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 = utils_1.last(this.RULE_STACK);
        return this.shortRuleNameToFull.get(shortName);
    };
    Parser.prototype.shortRuleNameToFullName = function (shortName) {
        return this.shortRuleNameToFull.get(shortName);
    };
    Parser.prototype.getHumanReadableRuleStack = function () {
        var _this = this;
        return utils_1.map(this.RULE_STACK, function (currShortName) { return _this.shortRuleNameToFullName(currShortName); });
    };
    Parser.prototype.SAVE_ERROR = function (error) {
        if (exceptions_public_1.exceptions.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 isValid - A predicate that given the result of the parse attempt will "decide" if the parse was successfully or not.
     *
     * @return {Function():boolean} a lookahead function that will try to parse the given grammarRule and will return true if succeed.
     */
    Parser.prototype.BACKTRACK = function (grammarRule, isValid) {
        return function () {
            // save org state
            this.isBackTrackingStack.push(1);
            var orgState = this.saveRecogState();
            try {
                var ruleResult = grammarRule.call(this);
                return isValid(ruleResult);
            }
            catch (e) {
                if (exceptions_public_1.exceptions.isRecognitionException(e)) {
                    return false;
                }
                else {
                    throw e;
                }
            }
            finally {
                this.reloadRecogState(orgState);
                this.isBackTrackingStack.pop();
            }
        };
    };
    // skips a token and returns the next token
    Parser.prototype.SKIP_TOKEN = function () {
        // example: assume 45 tokens in the input, if input index is 44 it means that NEXT_TOKEN will return
        // input[45] which is the 46th item and no longer exists,
        // so in this case the largest valid input index is 43 (input.length - 2 )
        if (this.inputIdx <= this._input.length - 2) {
            this.consumeToken();
            return this.LA(1);
        }
        else {
            return END_OF_FILE;
        }
    };
    // Parsing DSL
    /**
     * Convenience method equivalent to CONSUME1.
     * @see CONSUME1
     */
    Parser.prototype.CONSUME = function (tokClass) {
        return this.CONSUME1(tokClass);
    };
    /**
     *
     * A Parsing DSL method use to consume a single terminal Token.
     * a Token will be consumed, IFF the next token in the token vector is an instanceof tokClass.
     * 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 {Function} tokClass - A constructor function specifying the type of token to be consumed.
     *
     * @returns {Token} - The consumed token.
     */
    // TODO: what is the returned type? ISimpleTokenOrIToken or IToken? or || ?
    Parser.prototype.CONSUME1 = function (tokClass) {
        return this.consumeInternal(tokClass, 1);
    };
    /**
     * @see CONSUME1
     */
    Parser.prototype.CONSUME2 = function (tokClass) {
        return this.consumeInternal(tokClass, 2);
    };
    /**
     * @see CONSUME1
     */
    Parser.prototype.CONSUME3 = function (tokClass) {
        return this.consumeInternal(tokClass, 3);
    };
    /**
     * @see CONSUME1
     */
    Parser.prototype.CONSUME4 = function (tokClass) {
        return this.consumeInternal(tokClass, 4);
    };
    /**
     * @see CONSUME1
     */
    Parser.prototype.CONSUME5 = function (tokClass) {
        return this.consumeInternal(tokClass, 5);
    };
    /**
     * Convenience method equivalent to SUBRULE1
     * @see SUBRULE1
     */
    Parser.prototype.SUBRULE = function (ruleToCall, args) {
        if (args === void 0) { args = []; }
        return this.SUBRULE1(ruleToCall, 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 {Function} 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 = []; }
        return ruleToCall.call(this, 1, args);
    };
    /**
     * @see SUBRULE1
     */
    Parser.prototype.SUBRULE2 = function (ruleToCall, args) {
        if (args === void 0) { args = []; }
        return ruleToCall.call(this, 2, args);
    };
    /**
     * @see SUBRULE1
     */
    Parser.prototype.SUBRULE3 = function (ruleToCall, args) {
        if (args === void 0) { args = []; }
        return ruleToCall.call(this, 3, args);
    };
    /**
     * @see SUBRULE1
     */
    Parser.prototype.SUBRULE4 = function (ruleToCall, args) {
        if (args === void 0) { args = []; }
        return ruleToCall.call(this, 4, args);
    };
    /**
     * @see SUBRULE1
     */
    Parser.prototype.SUBRULE5 = function (ruleToCall, args) {
        if (args === void 0) { args = []; }
        return ruleToCall.call(this, 5, args);
    };
    /**
     * Convenience method equivalent to OPTION1.
     * @see OPTION1
     */
    Parser.prototype.OPTION = function (predicateOrAction, action) {
        return this.OPTION1.call(this, predicateOrAction, action);
    };
    /**
     * Parsing DSL Method that Indicates an Optional production
     * in EBNF notation: [...].
     *
     * Note that the 'action' param is optional. so both of the following forms are valid:
     *
     * - short: this.OPTION(()=>{ this.CONSUME(Digit});
     * - long: this.OPTION(predicateFunc, ()=>{ this.CONSUME(Digit});
     *
     * The 'predicateFunc' in the long form can be used to add constraints (none grammar related)
     * to optionally 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 {Function} predicateOrAction - The predicate / gate function that implements the constraint on the grammar
     *                                       or the grammar action to optionally invoke once.
     * @param {Function} [action] - The action to optionally invoke.
     *
     * @returns {boolean} - True iff the OPTION's action has been invoked
     */
    Parser.prototype.OPTION1 = function (predicateOrAction, action) {
        return this.optionInternal(predicateOrAction, action, 1);
    };
    /**
     * @see OPTION1
     */
    Parser.prototype.OPTION2 = function (predicateOrAction, action) {
        return this.optionInternal(predicateOrAction, action, 2);
    };
    /**
     * @see OPTION1
     */
    Parser.prototype.OPTION3 = function (predicateOrAction, action) {
        return this.optionInternal(predicateOrAction, action, 3);
    };
    /**
     * @see OPTION1
     */
    Parser.prototype.OPTION4 = function (predicateOrAction, action) {
        return this.optionInternal(predicateOrAction, action, 4);
    };
    /**
     * @see OPTION1
     */
    Parser.prototype.OPTION5 = function (predicateOrAction, action) {
        return this.optionInternal(predicateOrAction, action, 5);
    };
    /**
     * Convenience method equivalent to OR1.
     * @see OR1
     */
    Parser.prototype.OR = function (alts, errMsgTypes) {
        return this.OR1(alts, errMsgTypes);
    };
    /**
     * 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 two forms:
     *
     * - short: this.OR([
     *           {ALT:()=>{this.CONSUME(One)}},
     *           {ALT:()=>{this.CONSUME(Two)}},
     *           {ALT:()=>{this.CONSUME(Three)}},
     *        ], "a number")
     *
     * - long: this.OR([
     *           {GATE: predicateFunc1, ALT:()=>{this.CONSUME(One)}},
     *           {GATE: predicateFuncX, ALT:()=>{this.CONSUME(Two)}},
     *           {GATE: predicateFuncX, ALT:()=>{this.CONSUME(Three)}},
     *        ], "a number")
     *
     * They can also be mixed:
     * mixed: this.OR([
     *           {GATE: predicateFunc1, ALT:()=>{this.CONSUME(One)}},
     *           {ALT:()=>{this.CONSUME(Two)}},
     *           {ALT:()=>{this.CONSUME(Three)}}
     *        ], "a number")
     *
     * The 'predicateFuncX' in the long form can be used to add constraints (none grammar related) 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 {{ALT:Function}[] | {GATE:Function, ALT:Function}[]} alts - An array of alternatives.
     *
     * @param {string} [errMsgTypes] - A description for the alternatives used in error messages
     *                                 If none is provided, the error message will include the names of the expected
     *                                 Tokens sequences which may start each alternative.
     *
     * @returns {*} - The result of invoking the chosen alternative.
     */
    Parser.prototype.OR1 = function (alts, errMsgTypes) {
        return this.orInternal(alts, errMsgTypes, 1);
    };
    /**
     * @see OR1
     */
    Parser.prototype.OR2 = function (alts, errMsgTypes) {
        return this.orInternal(alts, errMsgTypes, 2);
    };
    /**
     * @see OR1
     */
    Parser.prototype.OR3 = function (alts, errMsgTypes) {
        return this.orInternal(alts, errMsgTypes, 3);
    };
    /**
     * @see OR1
     */
    Parser.prototype.OR4 = function (alts, errMsgTypes) {
        return this.orInternal(alts, errMsgTypes, 4);
    };
    /**
     * @see OR1
     */
    Parser.prototype.OR5 = function (alts, errMsgTypes) {
        return this.orInternal(alts, errMsgTypes, 5);
    };
    /**
     * Convenience method equivalent to MANY1.
     * @see MANY1
     */
    Parser.prototype.MANY = function (predicateOrAction, action) {
        return this.MANY1.call(this, predicateOrAction, action);
    };
    /**
     * Parsing DSL method, that indicates a repetition of zero or more.
     * This is equivalent to EBNF repetition {...}.
     *
     * Note that the 'action' param is optional. so both of the following forms are valid:
     *
     * short: this.MANY(()=>{
     *                       this.CONSUME(Comma};
     *                       this.CONSUME(Digit});
     *
     * long: this.MANY(predicateFunc, () => {
     *                       this.CONSUME(Comma};
     *                       this.CONSUME(Digit});
     *
     * The 'predicateFunc' in the long form can be used to add constraints (none grammar related) taking another iteration.
     *
     * As in CONSUME the index in the method name indicates the occurrence
     * of the repetition production in it's top rule.
     *
     * @param {Function} predicateOrAction - The predicate / gate function that implements the constraint on the grammar
     *                                   or the grammar action to optionally invoke multiple times.
     * @param {Function} [action] - The action to optionally invoke multiple times.
     */
    Parser.prototype.MANY1 = function (predicateOrAction, action) {
        this.manyInternal(this.MANY1, 1, predicateOrAction, action);
    };
    /**
     * @see MANY1
     */
    Parser.prototype.MANY2 = function (predicateOrAction, action) {
        this.manyInternal(this.MANY2, 2, predicateOrAction, action);
    };
    /**
     * @see MANY1
     */
    Parser.prototype.MANY3 = function (predicateOrAction, action) {
        this.manyInternal(this.MANY3, 3, predicateOrAction, action);
    };
    /**
     * @see MANY1
     */
    Parser.prototype.MANY4 = function (predicateOrAction, action) {
        this.manyInternal(this.MANY4, 4, predicateOrAction, action);
    };
    /**
     * @see MANY1
     */
    Parser.prototype.MANY5 = function (predicateOrAction, action) {
        this.manyInternal(this.MANY5, 5, predicateOrAction, action);
    };
    /**
     * Convenience method equivalent to MANY_SEP1.
     * @see MANY_SEP1
     */
    Parser.prototype.MANY_SEP = function (separator, action) {
        return this.MANY_SEP1.call(this, separator, action);
    };
    /**
     * Parsing DSL method, that indicates a repetition of zero or more with a separator
     * Token between the repetitions.
     *
     * Example:
     *
     * this.MANY_SEP(Comma, () => {
     *                     this.CONSUME(Number};
     *                     ...
     *                   );
     *
     * 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 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.
     *
     * @param {TokenConstructor} separator - The Token class which will be used as a separator between repetitions.
     * @param {Function} [action] - The action to optionally invoke.
     *
     * @return {Token[]} - The consumed separator Tokens.
     */
    Parser.prototype.MANY_SEP1 = function (separator, action) {
        return this.manySepFirstInternal(this.MANY_SEP1, 1, separator, action);
    };
    /**
     * @see MANY_SEP1
     */
    Parser.prototype.MANY_SEP2 = function (separator, action) {
        return this.manySepFirstInternal(this.MANY_SEP2, 2, separator, action);
    };
    /**
     * @see MANY_SEP1
     */
    Parser.prototype.MANY_SEP3 = function (separator, action) {
        return this.manySepFirstInternal(this.MANY_SEP3, 3, separator, action);
    };
    /**
     * @see MANY_SEP1
     */
    Parser.prototype.MANY_SEP4 = function (separator, action) {
        return this.manySepFirstInternal(this.MANY_SEP4, 4, separator, action);
    };
    /**
     * @see MANY_SEP1
     */
    Parser.prototype.MANY_SEP5 = function (separator, action) {
        return this.manySepFirstInternal(this.MANY_SEP5, 5, separator, action);
    };
    /**
     * Convenience method equivalent to AT_LEAST_ONE1.
     * @see AT_LEAST_ONE1
     */
    Parser.prototype.AT_LEAST_ONE = function (predicateOrAction, action, errMsg) {
        return this.AT_LEAST_ONE1.call(this, predicateOrAction, action, errMsg);
    };
    /**
     * 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 the parser to attempt error recovery.
     *
     * @see MANY1
     *
     * @param {Function} predicateOrAction  - The predicate / gate function that implements the constraint on the grammar
     *                                        or the grammar action to invoke at least once.
     * @param {Function} [action] - The action to optionally invoke.
     * @param {string} [errMsg] - Short title/classification to what is being matched.
     */
    Parser.prototype.AT_LEAST_ONE1 = function (predicateOrAction, action, errMsg) {
        this.atLeastOneInternal(this.AT_LEAST_ONE1, 1, predicateOrAction, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE1
     */
    Parser.prototype.AT_LEAST_ONE2 = function (predicateOrAction, action, errMsg) {
        this.atLeastOneInternal(this.AT_LEAST_ONE2, 2, predicateOrAction, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE1
     */
    Parser.prototype.AT_LEAST_ONE3 = function (predicateOrAction, action, errMsg) {
        this.atLeastOneInternal(this.AT_LEAST_ONE3, 3, predicateOrAction, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE1
     */
    Parser.prototype.AT_LEAST_ONE4 = function (predicateOrAction, action, errMsg) {
        this.atLeastOneInternal(this.AT_LEAST_ONE4, 4, predicateOrAction, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE1
     */
    Parser.prototype.AT_LEAST_ONE5 = function (predicateOrAction, action, errMsg) {
        this.atLeastOneInternal(this.AT_LEAST_ONE5, 5, predicateOrAction, action, errMsg);
    };
    /**
     * Convenience method equivalent to AT_LEAST_ONE_SEP1.
     * @see AT_LEAST_ONE1
     */
    Parser.prototype.AT_LEAST_ONE_SEP = function (separator, action, errMsg) {
        return this.AT_LEAST_ONE_SEP1.call(this, separator, action, errMsg);
    };
    /**
     *
     * 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.
     *
     * @see MANY_SEP1
     *
     * @param {TokenConstructor} separator - The Token class which will be used as a separator between repetitions.
     * @param {Function} [action] - The action to optionally invoke.
     * @param {string} [errMsg] - Short title/classification to what is being matched.
     */
    Parser.prototype.AT_LEAST_ONE_SEP1 = function (separator, action, errMsg) {
        return this.atLeastOneSepFirstInternal(this.atLeastOneSepFirstInternal, 1, separator, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE_SEP1
     */
    Parser.prototype.AT_LEAST_ONE_SEP2 = function (separator, action, errMsg) {
        return this.atLeastOneSepFirstInternal(this.atLeastOneSepFirstInternal, 2, separator, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE_SEP1
     */
    Parser.prototype.AT_LEAST_ONE_SEP3 = function (separator, action, errMsg) {
        return this.atLeastOneSepFirstInternal(this.atLeastOneSepFirstInternal, 3, separator, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE_SEP1
     */
    Parser.prototype.AT_LEAST_ONE_SEP4 = function (separator, action, errMsg) {
        return this.atLeastOneSepFirstInternal(this.atLeastOneSepFirstInternal, 4, separator, action, errMsg);
    };
    /**
     * @see AT_LEAST_ONE_SEP1
     */
    Parser.prototype.AT_LEAST_ONE_SEP5 = function (separator, action, errMsg) {
        return this.atLeastOneSepFirstInternal(this.atLeastOneSepFirstInternal, 5, separator, action, errMsg);
    };
    /**
     *
     * @param {string} name - The name of the rule.
     * @param {Function} implementation - The implementation of the rule.
     * @param {IRuleConfig} [config] - The rule's optional configuration.
     *
     * @returns {Function} - 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, config) {
        if (config === void 0) { config = DEFAULT_RULE_CONFIG; }
        var ruleErrors = checks_1.validateRuleName(name, this.className);
        ruleErrors = ruleErrors.concat(checks_1.validateRuleDoesNotAlreadyExist(name, this.definedRulesNames, this.className));
        this.definedRulesNames.push(name);
        this.definitionErrors.push.apply(this.definitionErrors, ruleErrors); // mutability for the win
        // 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);
            }
        }
        return this.defineRule(name, implementation, config);
    };
    /**
     * @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 = checks_1.validateRuleName(name, this.className);
        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, idxInCallingRule) {
        this.RULE_OCCURRENCE_STACK.push(idxInCallingRule);
        this.RULE_STACK.push(shortName);
    };
    Parser.prototype.ruleFinallyStateUpdate = function () {
        this.RULE_STACK.pop();
        this.RULE_OCCURRENCE_STACK.pop();
        if ((this.RULE_STACK.length === 0) && !this.isAtEndOfInput()) {
            var firstRedundantTok = this.LA(1);
            this.SAVE_ERROR(new exceptions_public_1.exceptions.NotAllInputParsedException("Redundant input, expecting EOF but found: " + tokens_public_1.getImage(firstRedundantTok), firstRedundantTok));
        }
    };
    /**
     * Returns an "imaginary" Token to insert when Single Token Insertion is done
     * Override this if you require special behavior in your grammar.
     * For example if an IntegerToken is required provide one with the image '0' so it would be valid syntactically.
     */
    Parser.prototype.getTokenToInsert = function (tokClass) {
        var tokToInsert;
        if (tokens_public_1.LazyToken.prototype.isPrototypeOf(tokClass.prototype)) {
            tokToInsert = new tokClass(NaN, NaN, {
                orgText: "",
                lineToOffset: []
            });
        }
        else if (tokens_public_1.SimpleLazyToken.prototype.isPrototypeOf(tokClass.prototype)) {
            tokToInsert = {
                startOffset: NaN,
                endOffset: NaN,
                cacheData: {
                    orgText: "",
                    lineToOffset: []
                }
            };
        }/* istanbul ignore else */ 
        else if (tokens_public_1.Token.prototype.isPrototypeOf(tokClass.prototype)) {
            tokToInsert = new tokClass("", NaN, NaN, NaN, NaN, NaN);
        }
        else {
            /* istanbul ignore next */ throw Error("non exhaustive match");
        }
        tokToInsert.isInsertedInRecovery = true;
        return tokToInsert;
    };
    /**
     * By default all tokens type may be inserted. This behavior may be overridden in inheriting Recognizers
     * for example: One may decide that only punctuation tokens may be inserted automatically as they have no additional
     * semantic value. (A mandatory semicolon has no additional semantic meaning, but an Integer may have additional meaning
     * depending on its int value and context (Inserting an integer 0 in cardinality: "[1..]" will cause semantic issues
     * as the max of the cardinality will be greater than the min value (and this is a false error!).
     */
    Parser.prototype.canTokenTypeBeInsertedInRecovery = function (tokClass) {
        return true;
    };
    /**
     * @param {Token} actualToken - The actual unexpected (mismatched) Token instance encountered.
     * @param {Function} expectedTokType - The Class of the expected Token.
     * @returns {string} - The error message saved as part of a MismatchedTokenException.
     */
    Parser.prototype.getMisMatchTokenErrorMessage = function (expectedTokType, actualToken) {
        var hasLabel = tokens_public_1.hasTokenLabel(expectedTokType);
        var expectedMsg = hasLabel ?
            "--> " + tokens_public_1.tokenLabel(expectedTokType) + " <--" :
            "token of type --> " + tokens_public_1.tokenName(expectedTokType) + " <--";
        var msg = "Expecting " + expectedMsg + " but found --> '" + tokens_public_1.getImage(actualToken) + "' <--";
        return msg;
    };
    Parser.prototype.getCurrentGrammarPath = function (tokClass, tokIdxInRule) {
        var pathRuleStack = this.getHumanReadableRuleStack();
        var pathOccurrenceStack = utils_1.cloneArr(this.RULE_OCCURRENCE_STACK);
        var grammarPath = {
            ruleStack: pathRuleStack,
            occurrenceStack: pathOccurrenceStack,
            lastTok: tokClass,
            lastTokOccurrence: tokIdxInRule
        };
        return grammarPath;
    };
    // TODO: should this be a member method or a utility? it does not have any state or usage of 'this'...
    // TODO: should this be more explicitly part of the public API?
    Parser.prototype.getNextPossibleTokenTypes = function (grammarPath) {
        var topRuleName = utils_1.first(grammarPath.ruleStack);
        var gastProductions = this.getGAstProductions();
        var topProduction = gastProductions.get(topRuleName);
        var nextPossibleTokenTypes = new interpreter_1.NextAfterTokenWalker(topProduction, grammarPath).startWalking();
        return nextPossibleTokenTypes;
    };
    /**
     * @param tokClass - The Type of Token we wish to consume (Reference to its constructor function).
     * @param idx - Occurrence index of consumed token in the invoking parser rule text
     *         for example:
     *         IDENT (DOT IDENT)*
     *         the first ident will have idx 1 and the second one idx 2
     *         * note that for the second ident the idx is always 2 even if its invoked 30 times in the same rule
     *           the idx is about the position in grammar (source code) and has nothing to do with a specific invocation
     *           details.
     *
     * @returns {Token} - The consumed Token.
     */
    Parser.prototype.consumeInternal = function (tokClass, idx) {
        // TODO: this is an hack to avoid try catch block in V8, should be removed once V8 supports try/catch optimizations.
        // as the IF/ELSE itself has some overhead.
        if (!this.recoveryEnabled) {
            return this.consumeInternalOptimized(tokClass);
        }
        else {
            return this.consumeInternalWithTryCatch(tokClass, idx);
        }
    };
    Parser.prototype.consumeInternalWithTryCatch = function (tokClass, idx) {
        try {
            return this.consumeInternalOptimized(tokClass);
        }
        catch (eFromConsumption) {
            // no recovery allowed during backtracking, otherwise backtracking may recover invalid syntax and accept it
            // but the original syntax could have been parsed successfully without any backtracking + recovery
            if (this.recoveryEnabled &&
                // TODO: more robust checking of the exception type. Perhaps Typescript extending expressions?
                eFromConsumption.name === "MismatchedTokenException" && !this.isBackTracking()) {
                var follows = this.getFollowsForInRuleRecovery(tokClass, idx);
                try {
                    return this.tryInRuleRecovery(tokClass, follows);
                }
                catch (eFromInRuleRecovery) {
                    if (eFromInRuleRecovery.name === IN_RULE_RECOVERY_EXCEPTION) {
                        // failed in RuleRecovery.
                        // throw the original error in order to trigger reSync error recovery
                        throw eFromConsumption;
                    }
                    else {
                        throw eFromInRuleRecovery;
                    }
                }
            }
            else {
                throw eFromConsumption;
            }
        }
    };
    /**
     * Convenience method equivalent to LA(1)
     * It is no longer used directly in chevrotain due to
     * performance considerations (avoid the need for inlining optimizations).
     *
     * But it is maintained for backward compatibility reasons.
     *
     * @deprecated
     */
    Parser.prototype.NEXT_TOKEN = function () {
        return this.LA(1);
    };
    // Lexer (accessing Token vector) related methods which can be overridden to implement lazy lexers
    // or lexers dependent on parser context.
    Parser.prototype.LA = function (howMuch) {
        if (this._input.length <= this.inputIdx + howMuch) {
            return END_OF_FILE;
        }
        else {
            return this._input[this.inputIdx + howMuch];
        }
    };
    Parser.prototype.consumeToken = function () {
        this.inputIdx++;
    };
    Parser.prototype.saveLexerState = function () {
        this.savedTokenIdx = this.inputIdx;
    };
    Parser.prototype.restoreLexerState = function () {
        this.inputIdx = this.savedTokenIdx;
    };
    Parser.prototype.resetLexerState = function () {
        this.inputIdx = -1;
    };
    Parser.prototype.moveLexerStateToEnd = function () {
        this.inputIdx = this.input.length - 1;
    };
    // other functionality
    Parser.prototype.saveRecogState = function () {
        // errors is a getter which will clone the errors array
        var savedErrors = this.errors;
        var savedRuleStack = utils_1.cloneArr(this.RULE_STACK);
        return {
            errors: savedErrors,
            lexerState: this.inputIdx,
            RULE_STACK: savedRuleStack
        };
    };
    Parser.prototype.reloadRecogState = function (newState) {
        this.errors = newState.errors;
        this.inputIdx = newState.lexerState;
        this.RULE_STACK = newState.RULE_STACK;
    };
    Parser.prototype.defineRule = function (ruleName, impl, config) {
        var resyncEnabled = utils_1.has(config, "resyncEnabled") ?
            config.resyncEnabled :
            DEFAULT_RULE_CONFIG.resyncEnabled;
        var recoveryValueFunc = utils_1.has(config, "recoveryValueFunc") ?
            config.recoveryValueFunc :
            DEFAULT_RULE_CONFIG.recoveryValueFunc;
        // performance optimization: Use small integers as keys for the longer human readable "full" rule names.
        // this greatly improves Map access time (as much as 8% for some performance benchmarks).
        /* tslint:disable */
        var shortName = this.ruleShortNameIdx << (BITS_FOR_METHOD_IDX + BITS_FOR_OCCURRENCE_IDX);
        /* tslint:enable */
        this.ruleShortNameIdx++;
        this.shortRuleNameToFull.put(shortName, ruleName);
        function invokeRuleNoTry(args) {
            var result = impl.apply(this, args);
            this.ruleFinallyStateUpdate();
            return result;
        }
        function invokeRuleWithTry(args, isFirstRule) {
            try {
                // actual parsing happens here
                return impl.apply(this, args);
            }
            catch (e) {
                // TODO: this is part of a Performance hack for V8 due to lack of support
                // of try/catch optimizations. Should be removed once V8 supports that.
                // This is needed because in case of an error during a nested subRule
                // there will be no "finally" block to perform the "ruleFinallyStateUpdate"
                // So this block properly rewinds the parser's state in the case error recovery is disabled.
                if (isFirstRule) {
                    for (var i = this.RULE_STACK.length; i > 1; i--) {
                        this.ruleFinallyStateUpdate();
                    }
                }
                var isFirstInvokedRule = (this.RULE_STACK.length === 1);
                // note the reSync is always enabled for the first rule invocation, because we must always be able to
                // reSync with EOF and just output some INVALID ParseTree
                // during backtracking reSync recovery is disabled, otherwise we can't be certain the backtracking
                // path is really the most valid one
                var reSyncEnabled = resyncEnabled && !this.isBackTracking() && this.recoveryEnabled;
                if (exceptions_public_1.exceptions.isRecognitionException(e)) {
                    if (reSyncEnabled) {
                        var reSyncTokType = this.findReSyncTokenType();
                        if (this.isInCurrentRuleReSyncSet(reSyncTokType)) {
                            e.resyncedTokens = this.reSyncTo(reSyncTokType);
                            return recoveryValueFunc();
                        }
                        else {
                            // to be handled farther up the call stack
                            throw e;
                        }
                    }
                    else if (isFirstInvokedRule) {
                        // otherwise a Redundant input error will be created as well and we cannot guarantee that this is indeed the case
                        this.moveLexerStateToEnd();
                        // the parser should never throw one of its own errors outside its flow.
                        // even if error recovery is disabled
                        return recoveryValueFunc();
                    }
                    else {
                        // to be handled farther up the call stack
                        throw e;
                    }
                }
                else {
                    // some other Error type which we don't know how to handle (for example a built in JavaScript Error)
                    throw e;
                }
            }
            finally {
                this.ruleFinallyStateUpdate();
            }
        }
        var wrappedGrammarRule = function (idxInCallingRule, args) {
            if (idxInCallingRule === void 0) { idxInCallingRule = 1; }
            this.ruleInvocationStateUpdate(shortName, idxInCallingRule);
            // TODO: performance hack due to V8 lack of try/catch optimizations.
            // should be removed once V8 support those.
            var isFirstRule = this.RULE_STACK.length === 1;
            if (!this.recoveryEnabled && !isFirstRule) {
                return invokeRuleNoTry.call(this, args);
            }
            else {
                return invokeRuleWithTry.call(this, args, isFirstRule);
            }
        };
        var ruleNamePropName = "ruleName";
        wrappedGrammarRule[ruleNamePropName] = ruleName;
        return wrappedGrammarRule;
    };
    Parser.prototype.tryInRepetitionRecovery = function (grammarRule, grammarRuleArgs, lookAheadFunc, expectedTokType) {
        var _this = this;
        // TODO: can the resyncTokenType be cached?
        var reSyncTokType = this.findReSyncTokenType();
        this.saveLexerState();
        var resyncedTokens = [];
        var passedResyncPoint = false;
        var nextTokenWithoutResync = this.LA(1);
        var currToken = this.LA(1);
        var generateErrorMessage = function () {
            // we are preemptively re-syncing before an error has been detected, therefor we must reproduce
            // the error that would have been thrown
            var msg = _this.getMisMatchTokenErrorMessage(expectedTokType, nextTokenWithoutResync);
            var error = new exceptions_public_1.exceptions.MismatchedTokenException(msg, nextTokenWithoutResync);
            // the first token here will be the original cause of the error, this is not part of the resyncedTokens property.
            error.resyncedTokens = utils_1.dropRight(resyncedTokens);
            _this.SAVE_ERROR(error);
        };
        while (!passedResyncPoint) {
            // re-synced to a point where we can safely exit the repetition/
            if (this.tokenMatcher(currToken, expectedTokType)) {
                generateErrorMessage();
                return; // must return here to avoid reverting the inputIdx
            }
            else if (lookAheadFunc.call(this)) {
                generateErrorMessage();
                // recursive invocation in other to support multiple re-syncs in the same top level repetition grammar rule
                grammarRule.apply(this, grammarRuleArgs);
                return; // must return here to avoid reverting the inputIdx
            }
            else if (this.tokenMatcher(currToken, reSyncTokType)) {
                passedResyncPoint = true;
            }
            else {
                currToken = this.SKIP_TOKEN();
                this.addToResyncTokens(currToken, resyncedTokens);
            }
        }
        // we were unable to find a CLOSER point to resync inside the Repetition, reset the state.
        // The parsing exception we were trying to prevent will happen in the NEXT parsing step. it may be handled by
        // "between rules" resync recovery later in the flow.
        this.restoreLexerState();
    };
    Parser.prototype.shouldInRepetitionRecoveryBeTried = function (expectTokAfterLastMatch, nextTokIdx) {
        // arguments to try and perform resync into the next iteration of the many are missing
        if (expectTokAfterLastMatch === undefined || nextTokIdx === undefined) {
            return false;
        }
        // no need to recover, next token is what we expect...
        if (this.tokenMatcher(this.LA(1), expectTokAfterLastMatch)) {
            return false;
        }
        // error recovery is disabled during backtracking as it can make the parser ignore a valid grammar path
        // and prefer some backtracking path that includes recovered errors.
        if (this.isBackTracking()) {
            return false;
        }
        // if we can perform inRule recovery (single token insertion or deletion) we always prefer that recovery algorithm
        // because if it works, it makes the least amount of changes to the input stream (greedy algorithm)
        //noinspection RedundantIfStatementJS
        if (this.canPerformInRuleRecovery(expectTokAfterLastMatch, this.getFollowsForInRuleRecovery(expectTokAfterLastMatch, nextTokIdx))) {
            return false;
        }
        return true;
    };
    // Error Recovery functionality
    Parser.prototype.getFollowsForInRuleRecovery = function (tokClass, tokIdxInRule) {
        var grammarPath = this.getCurrentGrammarPath(tokClass, tokIdxInRule);
        var follows = this.getNextPossibleTokenTypes(grammarPath);
        return follows;
    };
    Parser.prototype.tryInRuleRecovery = function (expectedTokType, follows) {
        if (this.canRecoverWithSingleTokenInsertion(expectedTokType, follows)) {
            var tokToInsert = this.getTokenToInsert(expectedTokType);
            return tokToInsert;
        }
        if (this.canRecoverWithSingleTokenDeletion(expectedTokType)) {
            var nextTok = this.SKIP_TOKEN();
            this.consumeToken();
            return nextTok;
        }
        throw new InRuleRecoveryException("sad sad panda");
    };
    Parser.prototype.canPerformInRuleRecovery = function (expectedToken, follows) {
        return this.canRecoverWithSingleTokenInsertion(expectedToken, follows) ||
            this.canRecoverWithSingleTokenDeletion(expectedToken);
    };
    Parser.prototype.canRecoverWithSingleTokenInsertion = function (expectedTokType, follows) {
        var _this = this;
        if (!this.canTokenTypeBeInsertedInRecovery(expectedTokType)) {
            return false;
        }
        // must know the possible following tokens to perform single token insertion
        if (utils_1.isEmpty(follows)) {
            return false;
        }
        var mismatchedTok = this.LA(1);
        var isMisMatchedTokInFollows = utils_1.find(follows, function (possibleFollowsTokType) {
            return _this.tokenMatcher(mismatchedTok, possibleFollowsTokType);
        }) !== undefined;
        return isMisMatchedTokInFollows;
    };
    Parser.prototype.canRecoverWithSingleTokenDeletion = function (expectedTokType) {
        var isNextTokenWhatIsExpected = this.tokenMatcher(this.LA(2), expectedTokType);
        return isNextTokenWhatIsExpected;
    };
    Parser.prototype.isInCurrentRuleReSyncSet = function (tokenType) {
        var followKey = this.getCurrFollowKey();
        var currentRuleReSyncSet = this.getFollowSetFromFollowKey(followKey);
        return utils_1.contains(currentRuleReSyncSet, tokenType);
    };
    Parser.prototype.findReSyncTokenType = function () {
        var allPossibleReSyncTokTypes = this.flattenFollowSet();
        // this loop will always terminate as EOF is always in the follow stack and also always (virtually) in the input
        var nextToken = this.LA(1);
        var k = 2;
        while (true) {
            var nextTokenType = tokens_public_1.getTokenConstructor(nextToken);
            if (utils_1.contains(allPossibleReSyncTokTypes, nextTokenType)) {
                return nextTokenType;
            }
            nextToken = this.LA(k);
            k++;
        }
    };
    Parser.prototype.getCurrFollowKey = function () {
        // the length is at least one as we always add the ruleName to the stack before invoking the rule.
        if (this.RULE_STACK.length === 1) {
            return EOF_FOLLOW_KEY;
        }
        var currRuleIdx = this.RULE_STACK.length - 1;
        var currRuleOccIdx = currRuleIdx;
        var prevRuleIdx = currRuleIdx - 1;
        return {
            ruleName: this.shortRuleNameToFullName(this.RULE_STACK[currRuleIdx]),
            idxInCallingRule: this.RULE_OCCURRENCE_STACK[currRuleOccIdx],
            inRule: this.shortRuleNameToFullName(this.RULE_STACK[prevRuleIdx])
        };
    };
    Parser.prototype.buildFullFollowKeyStack = function () {
        var _this = this;
        return utils_1.map(this.RULE_STACK, function (ruleName, idx) {
            if (idx === 0) {
                return EOF_FOLLOW_KEY;
            }
            return {
                ruleName: _this.shortRuleNameToFullName(ruleName),
                idxInCallingRule: _this.RULE_OCCURRENCE_STACK[idx],
                inRule: _this.shortRuleNameToFullName(_this.RULE_STACK[idx - 1])
            };
        });
    };
    Parser.prototype.flattenFollowSet = function () {
        var _this = this;
        var followStack = utils_1.map(this.buildFullFollowKeyStack(), function (currKey) {
            return _this.getFollowSetFromFollowKey(currKey);
        });
        return utils_1.flatten(followStack);
    };
    Parser.prototype.getFollowSetFromFollowKey = function (followKey) {
        if (followKey === EOF_FOLLOW_KEY) {
            return [tokens_public_1.EOF];
        }
        var followName = followKey.ruleName + followKey.idxInCallingRule + constants_1.IN + followKey.inRule;
        return cache.getResyncFollowsForClass(this.className).get(followName);
    };
    // It does not make any sense to include a virtual EOF token in the list of resynced tokens
    // as EOF does not really exist and thus does not contain any useful information (line/column numbers)
    Parser.prototype.addToResyncTokens = function (token, resyncTokens) {
        if (!this.tokenMatcher(token, tokens_public_1.EOF)) {
            resyncTokens.push(token);
        }
        return resyncTokens;
    };
    Parser.prototype.reSyncTo = function (tokClass) {
        var resyncedTokens = [];
        var nextTok = this.LA(1);
        while ((this.tokenMatcher(nextTok, tokClass)) === false) {
            nextTok = this.SKIP_TOKEN();
            this.addToResyncTokens(nextTok, resyncedTokens);
        }
        // the last token is not part of the error.
        return utils_1.dropRight(resyncedTokens);
    };
    Parser.prototype.attemptInRepetitionRecovery = function (prodFunc, args, lookaheadFunc, dslMethodIdx, prodOccurrence, nextToksWalker) {
        var key = this.getKeyForAutomaticLookahead(dslMethodIdx, prodOccurrence);
        var firstAfterRepInfo = this.firstAfterRepMap.get(key);
        if (firstAfterRepInfo === undefined) {
            var currRuleName = this.getCurrRuleFullName();
            var ruleGrammar = this.getGAstProductions().get(currRuleName);
            var walker = new nextToksWalker(ruleGrammar, prodOccurrence);
            firstAfterRepInfo = walker.startWalking();
            this.firstAfterRepMap.put(key, firstAfterRepInfo);
        }
        var expectTokAfterLastMatch = firstAfterRepInfo.token;
        var nextTokIdx = firstAfterRepInfo.occurrence;
        var isEndOfRule = firstAfterRepInfo.isEndOfRule;
        // special edge case of a TOP most repetition after which the input should END.
        // this will force an attempt for inRule recovery in that scenario.
        if (this.RULE_STACK.length === 1 &&
            isEndOfRule &&
            expectTokAfterLastMatch === undefined) {
            expectTokAfterLastMatch = tokens_public_1.EOF;
            nextTokIdx = 1;
        }
        if (this.shouldInRepetitionRecoveryBeTried(expectTokAfterLastMatch, nextTokIdx)) {
            // TODO: performance optimization: instead of passing the original args here, we modify
            // the args param (or create a new one) and make sure the lookahead func is explicitly provided
            // to avoid searching the cache for it once more.
            this.tryInRepetitionRecovery(prodFunc, args, lookaheadFunc, expectTokAfterLastMatch);
        }
    };
    // Implementation of parsing DSL
    Parser.prototype.optionInternal = function (predicateOrAction, action, occurrence) {
        var lookAheadFunc = this.getLookaheadFuncForOption(occurrence);
        if (action === undefined) {
            action = predicateOrAction;
        } // predicate present
        else if (!predicateOrAction.call(this)) {
            return false;
        }
        if ((lookAheadFunc).call(this)) {
            action.call(this);
            return true;
        }
        return false;
    };
    Parser.prototype.atLeastOneInternal = function (prodFunc, prodOccurrence, predicate, action, userDefinedErrMsg) {
        var _this = this;
        var lookAheadFunc = this.getLookaheadFuncForAtLeastOne(prodOccurrence);
        if (!utils_1.isFunction(action)) {
            userDefinedErrMsg = action;
            action = predicate;
        }
        else {
            var orgLookAheadFunc_1 = lookAheadFunc;
            lookAheadFunc = function () {
                return predicate.call(_this) &&
                    orgLookAheadFunc_1.call(_this);
            };
        }
        if (lookAheadFunc.call(this)) {
            action.call(this);
            while (lookAheadFunc.call(this)) {
                action.call(this);
            }
        }
        else {
            throw this.raiseEarlyExitException(prodOccurrence, lookahead_1.PROD_TYPE.REPETITION_MANDATORY, userDefinedErrMsg);
        }
        // note that while it may seem that this can cause an error because by using a recursive call to
        // AT_LEAST_ONE we change the grammar to AT_LEAST_TWO, AT_LEAST_THREE ... , the possible recursive call
        // from the tryInRepetitionRecovery(...) will only happen IFF there really are TWO/THREE/.... items.
        // Performance optimization: "attemptInRepetitionRecovery" will be defined as NOOP unless recovery is enabled
        this.attemptInRepetitionRecovery(prodFunc, [lookAheadFunc, action, userDefinedErrMsg], lookAheadFunc, AT_LEAST_ONE_IDX, prodOccurrence, interpreter_1.NextTerminalAfterAtLeastOneWalker);
    };
    Parser.prototype.atLeastOneSepFirstInternal = function (prodFunc, prodOccurrence, separator, action, userDefinedErrMsg) {
        var _this = this;
        var separatorsResult = [];
        var firstIterationLookaheadFunc = this.getLookaheadFuncForAtLeastOneSep(prodOccurrence);
        // 1st iteration
        if (firstIterationLookaheadFunc.call(this)) {
            action.call(this);
            var separatorLookAheadFunc = function () { return _this.tokenMatcher(_this.LA(1), separator); };
            // 2nd..nth iterations
            while (separatorLookAheadFunc()) {
                // note that this CONSUME will never enter recovery because
                // the separatorLookAheadFunc checks that the separator really does exist.
                separatorsResult.push(this.CONSUME(separator));
                action.call(this);
            }
            // Performance optimization: "attemptInRepetitionRecovery" will be defined as NOOP unless recovery is enabled
            this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal, [prodOccurrence, separator, separatorLookAheadFunc,
                action, separatorsResult, interpreter_1.NextTerminalAfterAtLeastOneSepWalker], separatorLookAheadFunc, AT_LEAST_ONE_SEP_IDX, prodOccurrence, interpreter_1.NextTerminalAfterAtLeastOneSepWalker);
        }
        else {
            throw this.raiseEarlyExitException(prodOccurrence, lookahead_1.PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR, userDefinedErrMsg);
        }
        return separatorsResult;
    };
    Parser.prototype.manyInternal = function (prodFunc, prodOccurrence, predicate, action) {
        var _this = this;
        var lookaheadFunction = this.getLookaheadFuncForMany(prodOccurrence);
        if (action === undefined) {
            action = predicate;
        }
        else {
            var orgLookaheadFunction_1 = lookaheadFunction;
            lookaheadFunction = function () {
                return predicate.call(_this) &&
                    orgLookaheadFunction_1.call(_this);
            };
        }
        while (lookaheadFunction.call(this)) {
            action.call(this);
        }
        // Performance optimization: "attemptInRepetitionRecovery" will be defined as NOOP unless recovery is enabled
        this.attemptInRepetitionRecovery(prodFunc, [lookaheadFunction, action], lookaheadFunction, MANY_IDX, prodOccurrence, interpreter_1.NextTerminalAfterManyWalker);
    };
    Parser.prototype.manySepFirstInternal = function (prodFunc, prodOccurrence, separator, action) {
        var _this = this;
        var separatorsResult = [];
        var firstIterationLaFunc = this.getLookaheadFuncForManySep(prodOccurrence);
        // 1st iteration
        if (firstIterationLaFunc.call(this)) {
            action.call(this);
            var separatorLookAheadFunc = function () { return _this.tokenMatcher(_this.LA(1), separator); };
            // 2nd..nth iterations
            while (separatorLookAheadFunc()) {
                // note that this CONSUME will never enter recovery because
                // the separatorLookAheadFunc checks that the separator really does exist.
                separatorsResult.push(this.CONSUME(separator));
                action.call(this);
            }
            // Performance optimization: "attemptInRepetitionRecovery" will be defined as NOOP unless recovery is enabled
            this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal, [prodOccurrence, separator, separatorLookAheadFunc, action, separatorsResult, interpreter_1.NextTerminalAfterManySepWalker], separatorLookAheadFunc, MANY_SEP_IDX, prodOccurrence, interpreter_1.NextTerminalAfterManySepWalker);
        }
        return separatorsResult;
    };
    Parser.prototype.repetitionSepSecondInternal = function (prodOccurrence, separator, separatorLookAheadFunc, action, separatorsResult, nextTerminalAfterWalker) {
        while (separatorLookAheadFunc()) {
            // note that this CONSUME will never enter recovery because
            // the separatorLookAheadFunc checks that the separator really does exist.
            separatorsResult.push(this.CONSUME(separator));
            action.call(this);
        }
        // we can only arrive to this function after an error
        // has occurred (hence the name 'second') so the following
        // IF will always be entered, its possible to remove it...
        // however it is kept to avoid confusion and be consistent.
        // Performance optimization: "attemptInRepetitionRecovery" will be defined as NOOP unless recovery is enabled
        /* istanbul ignore else */
        this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal, [prodOccurrence, separator, separatorLookAheadFunc,
            action, separatorsResult, nextTerminalAfterWalker], separatorLookAheadFunc, AT_LEAST_ONE_SEP_IDX, prodOccurrence, nextTerminalAfterWalker);
    };
    Parser.prototype.orInternal = function (alts, errMsgTypes, occurrence) {
        var laFunc = this.getLookaheadFuncForOr(occurrence, alts);
        var altToTake = laFunc.call(this, alts);
        if (altToTake !== undefined) {
            var chosenAlternative = alts[altToTake];
            return chosenAlternative.ALT.call(this);
        }
        this.raiseNoAltException(occurrence, errMsgTypes);
    };
    // to enable optimizations this logic has been extract to a method as its invoker contains try/catch
    Parser.prototype.consumeInternalOptimized = function (expectedTokClass) {
        var nextToken = this.LA(1);
        if (this.tokenMatcher(nextToken, expectedTokClass)) {
            this.consumeToken();
            return nextToken;
        }
        else {
            var msg = this.getMisMatchTokenErrorMessage(expectedTokClass, nextToken);
            throw this.SAVE_ERROR(new exceptions_public_1.exceptions.MismatchedTokenException(msg, nextToken));
        }
    };
    // this actually returns a number, but it is always used as a string (object prop key)
    Parser.prototype.getKeyForAutomaticLookahead = function (dslMethodIdx, occurrence) {
        var ruleStack = this.RULE_STACK;
        var currRuleShortName = ruleStack[ruleStack.length - 1];
        /* tslint:disable */
        return occurrence | dslMethodIdx | currRuleShortName;
        /* tslint:enable */
    };
    Parser.prototype.getLookaheadFuncForOr = function (occurrence, alts) {
        var key = this.getKeyForAutomaticLookahead(OR_IDX, occurrence);
        var laFunc = this.classLAFuncs.get(key);
        if (laFunc === undefined) {
            var ruleName = this.getCurrRuleFullName();
            var ruleGrammar = this.getGAstProductions().get(ruleName);
            // note that hasPredicates is only computed once.
            var hasPredicates = utils_1.some(alts, function (currAlt) { return utils_1.isFunction(currAlt.GATE); });
            laFunc = lookahead_1.buildLookaheadFuncForOr(occurrence, ruleGrammar, this.maxLookahead, hasPredicates, this.tokenMatcher, this.tokenClassIdentityFunc, this.tokenInstanceIdentityFunc, this.dynamicTokensEnabled);
            this.classLAFuncs.put(key, laFunc);
            return laFunc;
        }
        else {
            return laFunc;
        }
    };
    // Automatic lookahead calculation
    Parser.prototype.getLookaheadFuncForOption = function (occurrence) {
        var key = this.getKeyForAutomaticLookahead(OPTION_IDX, occurrence);
        return this.getLookaheadFuncFor(key, occurrence, lookahead_1.buildLookaheadForOption, this.maxLookahead);
    };
    Parser.prototype.getLookaheadFuncForMany = function (occurrence) {
        var key = this.getKeyForAutomaticLookahead(MANY_IDX, occurrence);
        return this.getLookaheadFuncFor(key, occurrence, lookahead_1.buildLookaheadForMany, this.maxLookahead);
    };
    Parser.prototype.getLookaheadFuncForManySep = function (occurrence) {
        var key = this.getKeyForAutomaticLookahead(MANY_SEP_IDX, occurrence);
        return this.getLookaheadFuncFor(key, occurrence, lookahead_1.buildLookaheadForManySep, this.maxLookahead);
    };
    Parser.prototype.getLookaheadFuncForAtLeastOne = function (occurrence) {
        var key = this.getKeyForAutomaticLookahead(AT_LEAST_ONE_IDX, occurrence);
        return this.getLookaheadFuncFor(key, occurrence, lookahead_1.buildLookaheadForAtLeastOne, this.maxLookahead);
    };
    Parser.prototype.getLookaheadFuncForAtLeastOneSep = function (occurrence) {
        var key = this.getKeyForAutomaticLookahead(AT_LEAST_ONE_SEP_IDX, occurrence);
        return this.getLookaheadFuncFor(key, occurrence, lookahead_1.buildLookaheadForAtLeastOneSep, this.maxLookahead);
    };
    // TODO: consider caching the error message computed information
    Parser.prototype.raiseNoAltException = function (occurrence, errMsgTypes) {
        var errSuffix = " but found: '" + tokens_public_1.getImage(this.LA(1)) + "'";
        if (errMsgTypes === undefined) {
            var ruleName = this.getCurrRuleFullName();
            var ruleGrammar = this.getGAstProductions().get(ruleName);
            // TODO: getLookaheadPathsForOr can be slow for large enough maxLookahead and certain grammars, consider caching ?
            var lookAheadPathsPerAlternative = lookahead_1.getLookaheadPathsForOr(occurrence, ruleGrammar, this.maxLookahead);
            var allLookAheadPaths = utils_1.reduce(lookAheadPathsPerAlternative, function (result, currAltPaths) { return result.concat(currAltPaths); }, []);
            var nextValidTokenSequences = utils_1.map(allLookAheadPaths, function (currPath) {
                return ("[" + utils_1.map(currPath, function (currTokenClass) { return tokens_public_1.tokenLabel(currTokenClass); }).join(",") + "]");
            });
            errMsgTypes = "one of these possible Token sequences:\n  <" + nextValidTokenSequences.join(" ,") + ">";
        }
        throw this.SAVE_ERROR(new exceptions_public_1.exceptions.NoViableAltException("Expecting: " + errMsgTypes + " " + errSuffix, this.LA(1)));
    };
    Parser.prototype.getLookaheadFuncFor = function (key, occurrence, laFuncBuilder, maxLookahead) {
        var laFunc = this.classLAFuncs.get(key);
        if (laFunc === undefined) {
            var ruleName = this.getCurrRuleFullName();
            var ruleGrammar = this.getGAstProductions().get(ruleName);
            laFunc = laFuncBuilder.apply(null, 
            //TODO: change
            [occurrence, ruleGrammar, maxLookahead, this.tokenMatcher,
                this.tokenClassIdentityFunc, this.tokenInstanceIdentityFunc, this.dynamicTokensEnabled]);
            this.classLAFuncs.put(key, laFunc);
            return laFunc;
        }
        else {
            return laFunc;
        }
    };
    // TODO: consider caching the error message computed information
    Parser.prototype.raiseEarlyExitException = function (occurrence, prodType, userDefinedErrMsg) {
        var errSuffix = " but found: '" + tokens_public_1.getImage(this.LA(1)) + "'";
        if (userDefinedErrMsg === undefined) {
            var ruleName = this.getCurrRuleFullName();
            var ruleGrammar = this.getGAstProductions().get(ruleName);
            var lookAheadPathsPerAlternative = lookahead_1.getLookaheadPathsForOptionalProd(occurrence, ruleGrammar, prodType, this.maxLookahead);
            var insideProdPaths = lookAheadPathsPerAlternative[0];
            var nextValidTokenSequences = utils_1.map(insideProdPaths, function (currPath) {
                return ("[" + utils_1.map(currPath, function (currTokenClass) { return tokens_public_1.tokenLabel(currTokenClass); }).join(",") + "]");
            });
            userDefinedErrMsg = "expecting at least one iteration which starts with one of these possible Token sequences::\n  " +
                ("<" + nextValidTokenSequences.join(" ,") + ">");
        }
        else {
            userDefinedErrMsg = "Expecting at least one " + userDefinedErrMsg;
        }
        throw this.SAVE_ERROR(new exceptions_public_1.exceptions.EarlyExitException(userDefinedErrMsg + errSuffix, this.LA(1)));
    };
    Parser.NO_RESYNC = false;
    // Set this flag to true if you don't want the Parser to throw error when problems in it's definition are detected.
    // (normally during the parser's constructor).
    // This is a design time flag, it will not affect the runtime error handling of the parser, just design time errors,
    // for example: duplicate rule names, referencing an unresolved subrule, ect...
    // This flag should not be enabled during normal usage, it is used in special situations, for example when
    // needing to display the parser definition errors in some GUI(online playground).
    Parser.DEFER_DEFINITION_ERRORS_HANDLING = false;
    return Parser;
}());
exports.Parser = Parser;
function InRuleRecoveryException(message) {
    this.name = IN_RULE_RECOVERY_EXCEPTION;
    this.message = message;
}
InRuleRecoveryException.prototype = Error.prototype;
