'use strict';

var model = require('./model.js');
var some = require('../../../../../../lodash-es@4.17.21/node_modules/lodash-es/some.js');
var includes = require('../../../../../../lodash-es@4.17.21/node_modules/lodash-es/includes.js');
var every = require('../../../../../../lodash-es@4.17.21/node_modules/lodash-es/every.js');

function isSequenceProd(prod) {
    return (prod instanceof model.Alternative ||
        prod instanceof model.Option ||
        prod instanceof model.Repetition ||
        prod instanceof model.RepetitionMandatory ||
        prod instanceof model.RepetitionMandatoryWithSeparator ||
        prod instanceof model.RepetitionWithSeparator ||
        prod instanceof model.Terminal ||
        prod instanceof model.Rule);
}
function isOptionalProd(prod, alreadyVisited = []) {
    const isDirectlyOptional = prod instanceof model.Option ||
        prod instanceof model.Repetition ||
        prod instanceof model.RepetitionWithSeparator;
    if (isDirectlyOptional) {
        return true;
    }
    // note that this can cause infinite loop if one optional empty TOP production has a cyclic dependency with another
    // empty optional top rule
    // may be indirectly optional ((A?B?C?) | (D?E?F?))
    if (prod instanceof model.Alternation) {
        // for OR its enough for just one of the alternatives to be optional
        return some.default(prod.definition, (subProd) => {
            return isOptionalProd(subProd, alreadyVisited);
        });
    }
    else if (prod instanceof model.NonTerminal && includes.default(alreadyVisited, prod)) {
        // avoiding stack overflow due to infinite recursion
        return false;
    }
    else if (prod instanceof model.AbstractProduction) {
        if (prod instanceof model.NonTerminal) {
            alreadyVisited.push(prod);
        }
        return every.default(prod.definition, (subProd) => {
            return isOptionalProd(subProd, alreadyVisited);
        });
    }
    else {
        return false;
    }
}
function isBranchingProd(prod) {
    return prod instanceof model.Alternation;
}
function getProductionDslName(prod) {
    /* istanbul ignore else */
    if (prod instanceof model.NonTerminal) {
        return "SUBRULE";
    }
    else if (prod instanceof model.Option) {
        return "OPTION";
    }
    else if (prod instanceof model.Alternation) {
        return "OR";
    }
    else if (prod instanceof model.RepetitionMandatory) {
        return "AT_LEAST_ONE";
    }
    else if (prod instanceof model.RepetitionMandatoryWithSeparator) {
        return "AT_LEAST_ONE_SEP";
    }
    else if (prod instanceof model.RepetitionWithSeparator) {
        return "MANY_SEP";
    }
    else if (prod instanceof model.Repetition) {
        return "MANY";
    }
    else if (prod instanceof model.Terminal) {
        return "CONSUME";
        /* c8 ignore next 3 */
    }
    else {
        throw Error("non exhaustive match");
    }
}

exports.getProductionDslName = getProductionDslName;
exports.isBranchingProd = isBranchingProd;
exports.isOptionalProd = isOptionalProd;
exports.isSequenceProd = isSequenceProd;
