import some from "lodash/some" import every from "lodash/every" import has from "lodash/has" import includes from "lodash/includes" import { AbstractProduction, Alternation, Alternative, NonTerminal, Option, Repetition, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Rule, Terminal } from "./model" import { GAstVisitor } from "./visitor" import { IProduction, IProductionWithOccurrence } from "@chevrotain/types" export function isSequenceProd( prod: IProduction ): prod is { definition: IProduction[] } & IProduction { return ( prod instanceof Alternative || prod instanceof Option || prod instanceof Repetition || prod instanceof RepetitionMandatory || prod instanceof RepetitionMandatoryWithSeparator || prod instanceof RepetitionWithSeparator || prod instanceof Terminal || prod instanceof Rule ) } export function isOptionalProd( prod: IProduction, alreadyVisited: NonTerminal[] = [] ): boolean { const isDirectlyOptional = prod instanceof Option || prod instanceof Repetition || prod instanceof 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 Alternation) { // for OR its enough for just one of the alternatives to be optional return some((prod).definition, (subProd: IProduction) => { return isOptionalProd(subProd, alreadyVisited) }) } else if (prod instanceof NonTerminal && includes(alreadyVisited, prod)) { // avoiding stack overflow due to infinite recursion return false } else if (prod instanceof AbstractProduction) { if (prod instanceof NonTerminal) { alreadyVisited.push(prod) } return every( (prod).definition, (subProd: IProduction) => { return isOptionalProd(subProd, alreadyVisited) } ) } else { return false } } export function isBranchingProd( prod: IProduction ): prod is { definition: IProduction[] } & IProduction { return prod instanceof Alternation } export function getProductionDslName(prod: IProductionWithOccurrence): string { /* istanbul ignore else */ if (prod instanceof NonTerminal) { return "SUBRULE" } else if (prod instanceof Option) { return "OPTION" } else if (prod instanceof Alternation) { return "OR" } else if (prod instanceof RepetitionMandatory) { return "AT_LEAST_ONE" } else if (prod instanceof RepetitionMandatoryWithSeparator) { return "AT_LEAST_ONE_SEP" } else if (prod instanceof RepetitionWithSeparator) { return "MANY_SEP" } else if (prod instanceof Repetition) { return "MANY" } else if (prod instanceof Terminal) { return "CONSUME" } else { throw Error("non exhaustive match") } }