TreasureTrails/node_modules/@chevrotain/gast/src/helpers.ts
2026-03-18 09:02:21 -05:00

101 lines
2.9 KiB
TypeScript

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((<Alternation>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(
(<AbstractProduction>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")
}
}