UNPKG

@flowscripter/mpeg-sdl-parser

Version:

ISO/IEC 14496-34 Syntactic Description Language (MPEG SDL) parser implemented in TypeScript

341 lines (284 loc) 8.82 kB
import { AstPath, type Doc, doc } from "prettier"; import { addCommaSeparatorsToDoc, getDocWithTrivia } from "./print_utils"; import type { BitModifier } from "../ast/node/BitModifier"; import type { AbstractNode } from "../ast/node/AbstractNode"; import type { ClassDeclaration } from "../ast/node/ClassDeclaration"; import type { ExtendedClassIdRange } from "../ast/node/ExtendedClassIdRange"; import type { AbstractClassId } from "../ast/node/AbstractClassId"; import type { ClassDefinition } from "../ast/node/ClassDefinition"; import type { ClassIdRange } from "../ast/node/ClassIdRange"; import { ClassIdKind } from "../ast/node/enum/class_id_kind"; import type { ExpandableModifier } from "../ast/node/ExpandableModifier"; import type { ExtendsModifier } from "../ast/node/ExtendsModifier"; import type { Parameter } from "../ast/node/Parameter"; import type { ParameterList } from "../ast/node/ParameterList"; import type { ParameterValueList } from "../ast/node/ParameterValueList"; import type { ClassId } from "../ast/node/ClassId"; const { hardline, indent, join } = doc.builders; export function printBitModifier( path: AstPath<BitModifier>, print: (path: AstPath<AbstractNode>) => Doc, ): Doc { const bitModifier = path.node; const elements = []; elements.push(getDocWithTrivia(bitModifier.colonPunctuator)); const subElements = []; subElements.push(getDocWithTrivia(bitModifier.bitKeyword)); subElements.push( getDocWithTrivia(bitModifier.openParenthesisPunctuator), ); subElements.push(path.call(print, "length")); subElements.push( getDocWithTrivia(bitModifier.closeParenthesisPunctuator), ); elements.push(subElements); if (bitModifier.identifier !== undefined) { elements.push( path.call( print, "identifier" as keyof BitModifier["identifier"], ), ); } if (bitModifier.assignmentOperator !== undefined) { elements.push(getDocWithTrivia(bitModifier.assignmentOperator!)); } elements.push( path.call( print, "classId", ), ); return join(" ", elements); } export function printClassDeclaration( path: AstPath<ClassDeclaration>, print: (path: AstPath<AbstractNode>) => Doc, ): Doc { const classDeclaration = path.node; const elements = []; if (classDeclaration.alignedModifier !== undefined) { elements.push( path.call( print, "alignedModifier" as keyof ClassDeclaration["alignedModifier"], ), ); } if (classDeclaration.expandableModifier !== undefined) { elements.push( path.call( print, "expandableModifier" as keyof ClassDeclaration["expandableModifier"], ), ); } if (classDeclaration.isAbstract) { elements.push(getDocWithTrivia(classDeclaration.abstractKeyword!)); } elements.push(getDocWithTrivia(classDeclaration.classKeyword)); const identifierElements = [ path.call(print, "identifier"), ]; if (classDeclaration.parameterList !== undefined) { identifierElements.push( path.call( print, "parameterList" as keyof ClassDeclaration["parameterList"], ), ); } elements.push(identifierElements); if (classDeclaration.extendsModifier !== undefined) { elements.push( path.call( print, "extendsModifier" as keyof ClassDeclaration["extendsModifier"], ), ); } if (classDeclaration.bitModifier !== undefined) { elements.push( path.call(print, "bitModifier" as keyof ClassDeclaration["bitModifier"]), ); } elements.push(getDocWithTrivia(classDeclaration.openBracePunctuator)); const parts = []; parts.push(join(" ", elements)); if (classDeclaration.statements.length > 0) { parts.push(indent([ hardline, join(hardline, path.map(print, "statements")), ])); } parts.push( getDocWithTrivia(classDeclaration.closeBracePunctuator, true), ); return parts; } export function printClassDefinition( path: AstPath<ClassDefinition>, print: (path: AstPath<AbstractNode>) => Doc, ): Doc { const classDefinition = path.node; const elements = []; if (classDefinition.isLegacy) { elements.push(getDocWithTrivia(classDefinition.legacyKeyword!)); } elements.push(path.call(print, "classIdentifier")); const identifierElements = [ path.call(print, "identifier"), ]; if (classDefinition.parameterValueList !== undefined) { identifierElements.push([ path.call( print, "parameterValueList" as keyof ClassDefinition["parameterValueList"], ), ]); } elements.push(identifierElements); return [ join(" ", elements), getDocWithTrivia(classDefinition.semicolonPunctuator), ]; } export function printClassId( path: AstPath<AbstractClassId>, print: (path: AstPath<AbstractNode>) => Doc, ): Doc { const { classIdKind } = path.node; switch (classIdKind) { case ClassIdKind.SINGLE: return (path as AstPath<ClassId>).call(print, "value"); case ClassIdKind.RANGE: { const classIdRange = path.node as ClassIdRange; return [ (path as AstPath<ClassIdRange>).call(print, "startClassId"), getDocWithTrivia(classIdRange.rangeOperator), (path as AstPath<ClassIdRange>).call(print, "endClassId"), ]; } case ClassIdKind.EXTENDED_RANGE: { const extendedClassIdRange = path.node as ExtendedClassIdRange; const elements = []; const outputValuesDoc = (path as AstPath<ExtendedClassIdRange>).map( print, "classIds", ); elements.push( ...addCommaSeparatorsToDoc( outputValuesDoc, extendedClassIdRange.commaPunctuators, ), ); return elements; } default: { const exhaustiveCheck: never = classIdKind; throw new Error( "Unreachable code reached, classIdKind == " + exhaustiveCheck, ); } } } export function printExpandableModifier( path: AstPath<ExpandableModifier>, print: (path: AstPath<AbstractNode>) => Doc, ): Doc { const expandableModifier = path.node; const elements = []; elements.push(getDocWithTrivia(expandableModifier.expandableKeyword)); if (expandableModifier.maxClassSize !== undefined) { elements.push( getDocWithTrivia(expandableModifier.openParenthesisPunctuator!), ); elements.push( path.call( print, "maxClassSize" as keyof ExpandableModifier["maxClassSize"], ), ), elements.push( getDocWithTrivia(expandableModifier.closeParenthesisPunctuator!), ); } return elements; } export function printExtendsModifier( path: AstPath<ExtendsModifier>, print: (path: AstPath<AbstractNode>) => Doc, ): Doc { const mapEntryList = path.node; const elements = [ path.call(print, "identifier"), ]; if (mapEntryList.parameterValueList !== undefined) { elements.push( path.call( print, "parameterValueList" as keyof ExtendsModifier["parameterValueList"], ), ); } return join(" ", [ getDocWithTrivia(mapEntryList.extendsKeyword), elements, ]); } export function printParameter( path: AstPath<Parameter>, print: (path: AstPath<AbstractNode>) => Doc, ): doc.builders.Doc { const parameter = path.node; const elements = []; if (parameter.classIdentifier !== undefined) { elements.push( path.call( print, "classIdentifier" as keyof Parameter["classIdentifier"], ), ); } else if (parameter.elementaryType !== undefined) { elements.push( path.call( print, "elementaryType" as keyof Parameter["elementaryType"], ), ); } elements.push(path.call(print, "identifier")); return join(" ", elements); } export function printParameterList( path: AstPath<ParameterList>, print: (path: AstPath<AbstractNode>) => Doc, ): doc.builders.Doc { const parameterList = path.node; const outputValuesDoc = path.map(print, "parameters"); const elements = addCommaSeparatorsToDoc( outputValuesDoc, parameterList.commaPunctuators, ); return [ getDocWithTrivia(parameterList.openParenthesisPunctuator), join(" ", elements), getDocWithTrivia(parameterList.closeParenthesisPunctuator), ]; } export function printParameterValueList( path: AstPath<ParameterValueList>, print: (path: AstPath<AbstractNode>) => Doc, ): doc.builders.Doc { const parameterValueList = path.node; const outputValuesDoc = path.map(print, "values"); const elements = addCommaSeparatorsToDoc( outputValuesDoc, parameterValueList.commaPunctuators, ); return [ getDocWithTrivia(parameterValueList.openParenthesisPunctuator), join(" ", elements), getDocWithTrivia(parameterValueList.closeParenthesisPunctuator), ]; }