Erster Docker-Stand

This commit is contained in:
Ali
2026-02-20 16:06:40 +09:00
commit f31e2e8ed3
8818 changed files with 1605323 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
export {
Rule,
Terminal,
NonTerminal,
Option,
Repetition,
RepetitionMandatory,
RepetitionMandatoryWithSeparator,
RepetitionWithSeparator,
Alternation,
Alternative,
serializeGrammar,
serializeProduction
} from "./model"
export { GAstVisitor } from "./visitor"
export {
getProductionDslName,
isOptionalProd,
isBranchingProd,
isSequenceProd
} from "./helpers"

View File

@@ -0,0 +1,101 @@
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")
}
}

View File

@@ -0,0 +1,420 @@
import map from "lodash/map"
import forEach from "lodash/forEach"
import isString from "lodash/isString"
import isRegExp from "lodash/isRegExp"
import pickBy from "lodash/pickBy"
import assign from "lodash/assign"
import {
IGASTVisitor,
IProduction,
IProductionWithOccurrence,
ISerializedGast,
TokenType
} from "@chevrotain/types"
// TODO: duplicated code to avoid extracting another sub-package -- how to avoid?
function tokenLabel(tokType: TokenType): string {
if (hasTokenLabel(tokType)) {
return tokType.LABEL
} else {
return tokType.name
}
}
// TODO: duplicated code to avoid extracting another sub-package -- how to avoid?
function hasTokenLabel(
obj: TokenType
): obj is TokenType & Pick<Required<TokenType>, "LABEL"> {
return isString(obj.LABEL) && obj.LABEL !== ""
}
export abstract class AbstractProduction<T extends IProduction = IProduction>
implements IProduction
{
public get definition(): T[] {
return this._definition
}
public set definition(value: T[]) {
this._definition = value
}
constructor(protected _definition: T[]) {}
accept(visitor: IGASTVisitor): void {
visitor.visit(this)
forEach(this.definition, (prod) => {
prod.accept(visitor)
})
}
}
export class NonTerminal
extends AbstractProduction
implements IProductionWithOccurrence
{
public nonTerminalName!: string
public label?: string
public referencedRule!: Rule
public idx: number = 1
constructor(options: {
nonTerminalName: string
label?: string
referencedRule?: Rule
idx?: number
}) {
super([])
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
set definition(definition: IProduction[]) {
// immutable
}
get definition(): IProduction[] {
if (this.referencedRule !== undefined) {
return this.referencedRule.definition
}
return []
}
accept(visitor: IGASTVisitor): void {
visitor.visit(this)
// don't visit children of a reference, we will get cyclic infinite loops if we do so
}
}
export class Rule extends AbstractProduction {
public name!: string
public orgText: string = ""
constructor(options: {
name: string
definition: IProduction[]
orgText?: string
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class Alternative extends AbstractProduction {
public ignoreAmbiguities: boolean = false
constructor(options: {
definition: IProduction[]
ignoreAmbiguities?: boolean
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class Option
extends AbstractProduction
implements IProductionWithOccurrence
{
public idx: number = 1
public maxLookahead?: number
constructor(options: {
definition: IProduction[]
idx?: number
maxLookahead?: number
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class RepetitionMandatory
extends AbstractProduction
implements IProductionWithOccurrence
{
public idx: number = 1
public maxLookahead?: number
constructor(options: {
definition: IProduction[]
idx?: number
maxLookahead?: number
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class RepetitionMandatoryWithSeparator
extends AbstractProduction
implements IProductionWithOccurrence
{
public separator!: TokenType
public idx: number = 1
public maxLookahead?: number
constructor(options: {
definition: IProduction[]
separator: TokenType
idx?: number
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class Repetition
extends AbstractProduction
implements IProductionWithOccurrence
{
public separator!: TokenType
public idx: number = 1
public maxLookahead?: number
constructor(options: {
definition: IProduction[]
idx?: number
maxLookahead?: number
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class RepetitionWithSeparator
extends AbstractProduction
implements IProductionWithOccurrence
{
public separator!: TokenType
public idx: number = 1
public maxLookahead?: number
constructor(options: {
definition: IProduction[]
separator: TokenType
idx?: number
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class Alternation
extends AbstractProduction<Alternative>
implements IProductionWithOccurrence
{
public idx: number = 1
public ignoreAmbiguities: boolean = false
public hasPredicates: boolean = false
public maxLookahead?: number
public get definition(): Alternative[] {
return this._definition
}
public set definition(value: Alternative[]) {
this._definition = value
}
constructor(options: {
definition: Alternative[]
idx?: number
ignoreAmbiguities?: boolean
hasPredicates?: boolean
maxLookahead?: number
}) {
super(options.definition)
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
}
export class Terminal implements IProductionWithOccurrence {
public terminalType!: TokenType
public label?: string
public idx: number = 1
constructor(options: {
terminalType: TokenType
label?: string
idx?: number
}) {
assign(
this,
pickBy(options, (v) => v !== undefined)
)
}
accept(visitor: IGASTVisitor): void {
visitor.visit(this)
}
}
export interface ISerializedBasic extends ISerializedGast {
type:
| "Alternative"
| "Option"
| "RepetitionMandatory"
| "Repetition"
| "Alternation"
idx?: number
}
export interface ISerializedGastRule extends ISerializedGast {
type: "Rule"
name: string
orgText: string
}
export interface ISerializedNonTerminal extends ISerializedGast {
type: "NonTerminal"
name: string
label?: string
idx: number
}
export interface ISerializedTerminal extends ISerializedGast {
type: "Terminal"
name: string
terminalLabel?: string
label?: string
pattern?: string
idx: number
}
export interface ISerializedTerminalWithSeparator extends ISerializedGast {
type: "RepetitionMandatoryWithSeparator" | "RepetitionWithSeparator"
idx: number
separator: ISerializedTerminal
}
export type ISerializedGastAny =
| ISerializedBasic
| ISerializedGastRule
| ISerializedNonTerminal
| ISerializedTerminal
| ISerializedTerminalWithSeparator
export function serializeGrammar(topRules: Rule[]): ISerializedGast[] {
return map(topRules, serializeProduction)
}
export function serializeProduction(node: IProduction): ISerializedGast {
function convertDefinition(definition: IProduction[]): ISerializedGast[] {
return map(definition, serializeProduction)
}
/* istanbul ignore else */
if (node instanceof NonTerminal) {
const serializedNonTerminal: ISerializedNonTerminal = {
type: "NonTerminal",
name: node.nonTerminalName,
idx: node.idx
}
if (isString(node.label)) {
serializedNonTerminal.label = node.label
}
return serializedNonTerminal
} else if (node instanceof Alternative) {
return <ISerializedBasic>{
type: "Alternative",
definition: convertDefinition(node.definition)
}
} else if (node instanceof Option) {
return <ISerializedBasic>{
type: "Option",
idx: node.idx,
definition: convertDefinition(node.definition)
}
} else if (node instanceof RepetitionMandatory) {
return <ISerializedBasic>{
type: "RepetitionMandatory",
idx: node.idx,
definition: convertDefinition(node.definition)
}
} else if (node instanceof RepetitionMandatoryWithSeparator) {
return <ISerializedTerminalWithSeparator>{
type: "RepetitionMandatoryWithSeparator",
idx: node.idx,
separator: <ISerializedTerminal>(
serializeProduction(new Terminal({ terminalType: node.separator }))
),
definition: convertDefinition(node.definition)
}
} else if (node instanceof RepetitionWithSeparator) {
return <ISerializedTerminalWithSeparator>{
type: "RepetitionWithSeparator",
idx: node.idx,
separator: <ISerializedTerminal>(
serializeProduction(new Terminal({ terminalType: node.separator }))
),
definition: convertDefinition(node.definition)
}
} else if (node instanceof Repetition) {
return <ISerializedBasic>{
type: "Repetition",
idx: node.idx,
definition: convertDefinition(node.definition)
}
} else if (node instanceof Alternation) {
return <ISerializedBasic>{
type: "Alternation",
idx: node.idx,
definition: convertDefinition(node.definition)
}
} else if (node instanceof Terminal) {
const serializedTerminal = <ISerializedTerminal>{
type: "Terminal",
name: node.terminalType.name,
label: tokenLabel(node.terminalType),
idx: node.idx
}
if (isString(node.label)) {
serializedTerminal.terminalLabel = node.label
}
const pattern = node.terminalType.PATTERN
if (node.terminalType.PATTERN) {
serializedTerminal.pattern = isRegExp(pattern)
? (<any>pattern).source
: pattern
}
return serializedTerminal
} else if (node instanceof Rule) {
return <ISerializedGastRule>{
type: "Rule",
name: node.name,
orgText: node.orgText,
definition: convertDefinition(node.definition)
}
} else {
throw Error("non exhaustive match")
}
}

View File

@@ -0,0 +1,76 @@
import {
Alternation,
Alternative,
NonTerminal,
Option,
Repetition,
RepetitionMandatory,
RepetitionMandatoryWithSeparator,
RepetitionWithSeparator,
Rule,
Terminal
} from "./model"
import { IProduction } from "@chevrotain/types"
export abstract class GAstVisitor {
public visit(node: IProduction): any {
const nodeAny: any = node
switch (nodeAny.constructor) {
case NonTerminal:
return this.visitNonTerminal(nodeAny)
case Alternative:
return this.visitAlternative(nodeAny)
case Option:
return this.visitOption(nodeAny)
case RepetitionMandatory:
return this.visitRepetitionMandatory(nodeAny)
case RepetitionMandatoryWithSeparator:
return this.visitRepetitionMandatoryWithSeparator(nodeAny)
case RepetitionWithSeparator:
return this.visitRepetitionWithSeparator(nodeAny)
case Repetition:
return this.visitRepetition(nodeAny)
case Alternation:
return this.visitAlternation(nodeAny)
case Terminal:
return this.visitTerminal(nodeAny)
case Rule:
return this.visitRule(nodeAny)
/* istanbul ignore next */
default:
throw Error("non exhaustive match")
}
}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitNonTerminal(node: NonTerminal): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitAlternative(node: Alternative): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitOption(node: Option): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitRepetition(node: Repetition): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitRepetitionMandatory(node: RepetitionMandatory): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitRepetitionMandatoryWithSeparator(
node: RepetitionMandatoryWithSeparator
): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitRepetitionWithSeparator(node: RepetitionWithSeparator): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitAlternation(node: Alternation): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitTerminal(node: Terminal): any {}
/* istanbul ignore next - testing the fact a NOOP function exists is non-trivial */
public visitRule(node: Rule): any {}
}