// Copyright 2017-2022 The MathJax Consortium
// SPDX-License-Identifier: Apache-2.0

// Package tex is a source-shaped Go port of MathJax 3.2.2's TeX input jax. // It compiles the fixed package set used by D2 (base, AMS, mathtools, AMS-CD, // braket, cancel, cases, color, gensymb, mhchem, and physics) into the shared // internal MathML tree.
package tex import ( ) const maxMacros = 1000 // Compiler implements pipeline.Compiler. Compiler has no mutable parse state; // every Compile call receives fresh macro and environment tables, as does the // MathJax TeX input jax after ParseOptions.clear(). type Compiler struct { // augmentedPackages is used only by the pinned source-handler oracle, // whose provenance explicitly loads the official empheq and newcommand // components in addition to D2's package list. Public compilers keep the // exact fixed D2 registrations. augmentedPackages bool } // NewCompiler constructs the fixed MathJax 3.2.2 compiler used by D2. func () *Compiler { return &Compiler{} } var _ pipeline.Compiler = (*Compiler)(nil) // Compile parses one TeX expression and wraps the result in MathJax's math // node. Display mode is represented by the explicit display="block" // attribute, matching TeX.compile in ts/input/tex.ts. func ( *Compiler) ( string, bool) (*mml.Node, error) { := newParseState() .augmentedPackages = .augmentedPackages := &parser{source: , state: , display: } , , := .parseRow(0, false) if != nil { var *Error if !errors.As(, &) { return nil, } return mathError(.Message, ), nil } if != "" { return nil, texError("ExtraCloseMissingOpen", "Extra close brace or missing open brace") } , = .amsTagFinalize() if != nil { var *Error if !errors.As(, &) { return nil, } return mathError(.Message, ), nil } // MmlMath has an inferred-mrow child even when the TeX stack reduces to a // single node. Keep that wrapper explicit in the shared Go tree so layout // sees the same structure as the JavaScript MML factory. := node("math", ...) if { .Attributes.Set("display", "block") } // cleanSubSup runs after successful parsing and before inheritance. // A later script can repair a popped view, or an ignored owner discard it. fixPrescripts() , = cleanPoppedScripts(, .poppedScripts) if != nil { return nil, } .Walk(func( *mml.Node) bool { .RemoveProperty(poppedScriptOrigin) .RemoveProperty(resolvedFontScope) .RemoveProperty(ambientFontSource) .RemoveProperty(vectorFactoryToken) .RemoveProperty(vectorFactoryDone) .RemoveProperty(limitsScriptOrigin) return true }) := stretchyCleanupOperators(.operators) setMathMLInheritance(, ) if := filterNonscript(.nonscriptSpaces); != nil { return nil, } = moveMathLimits() cleanStretchy(, ) cleanMathMLAttributes() .operators = combineRelations(, .operators) return , nil } func mathError( string, bool) *mml.Node { := setAttributes(node("merror", node("mtext", mml.NewText())), map[string]any{"data-mjx-error": }) := node("math", ) if { .Attributes.Set("display", "block") } setMathMLInheritance(, ) cleanMathMLAttributes() return }