// Copyright (c) 2009-2022 The MathJax Consortium
// Copyright (c) 2018-2022 Omar Al-Ithawi and The MathJax Consortium
// SPDX-License-Identifier: Apache-2.0
//
// This file is a Go translation and modification of MathJax 3.2.2.
// Sources: ts/input/tex/ParseUtil.ts,
// base/{BaseItems,BaseMappings,BaseMethods}.ts,
// ams/{AmsMappings,AmsMethods}.ts, braket/{BraketItems,BraketMappings,
// BraketMethods}.ts, cancel/CancelConfiguration.ts,
// color/{ColorConfiguration,ColorMethods}.ts,
// enclose/EncloseConfiguration.ts, gensymb/GensymbConfiguration.ts,
// mathtools/{MathtoolsMappings,MathtoolsMethods,MathtoolsUtil}.ts,
// mhchem/MhchemConfiguration.ts,
// newcommand/{NewcommandMappings,NewcommandMethods}.ts, and
// physics/{PhysicsItems,PhysicsMappings,PhysicsMethods}.ts.

package tex

import (
	
	
	
	

	
	
	
	texcancel 
	texcolor 
	
	
)

func ( *parser) ( string,  **derivativeAutoOpen) ([]*mml.Node, error) {
	// Mathtools' dynamic paired-delimiter map has priority -5, ahead of
	// the builtin and user macro maps (including AMS operators at -1).
	// Registration order does not change that precedence.
	,  := .state.pairedDelimiters[]
	if ,  := .state.macros[];  && ! {
		if .builtinNot {
			.commandNot = true
			return nil, nil
		}
		return .invokeMacro(, )
	}
	if ! {
		if , ,  := .amsTagCommand();  {
			return , 
		}
	}
	if , ,  := .mathtoolsCommand();  {
		return , 
	}
	if .state.augmentedPackages {
		if , ,  := .empheqCommand();  {
			return , 
		}
	}
	if , ,  := .physicsCommand(, );  {
		return , 
	}
	if , ,  := .amscdCommand();  {
		return , 
	}
	if , ,  := .baseAMSCommand();  {
		return , 
	}
	if isHFill() {
		return nil, unsupportedHFill()
	}
	if  == "\n" {
		return []*mml.Node{setAttributes(node("mspace"), map[string]any{"linebreak": "newline"})}, nil
	}
	if .state.augmentedPackages {
		switch  {
		case "newcommand", "renewcommand", "providecommand":
			return nil, .defineCommand()
		case "newenvironment", "renewenvironment":
			return nil, .defineEnvironment()
		case "def", "gdef", "edef", "xdef":
			return nil, .macroDef()
		case "let":
			return nil, .letCommand()
		}
	}
	if ,  := .state.pairedDelimiters[];  {
		return .invokePairedDelimiter(, )
	}
	if isHLine() {
		return nil, misplacedHLine()
	}
	// Dynamic maps precede Base's closing CellItem handlers, which in turn
	// precede the symbol fallback (notably the backslash delimiter glyph).
	if  == "\\" ||  == "newline" ||  == "cr" {
		return nil, .crCommand()
	}
	// Braket's command map precedes the delimiter symbol fallback.
	if  == "|" {
		return .braketBar(), nil
	}
	if ,  := .lookupExtensionSymbol();  {
		return []*mml.Node{}, nil
	}
	if ,  := .lookupMJSourceSymbol();  {
		return []*mml.Node{}, nil
	}
	if ,  := identifierSymbols[];  {
		 := token("mi", .char)
		if .attrs == nil {
			.Attributes.Set("mathvariant", "normal")
		} else {
			setAttributes(, .attrs)
		}
		return []*mml.Node{}, nil
	}
	if ,  := operatorSymbols[];  {
		 := .operator(.char, .class, .attrs)
		if .attrs != nil {
			if ,  := .attrs["movesupsub"];  {
				.SetProperty("movesupsub", )
			}
		}
		return []*mml.Node{}, nil
	}
	if ,  := functionNames[];  {
		if  == "injlim" ||  == "projlim" {
			 := map[string]string{"injlim": "inj\u2006lim", "projlim": "proj\u2006lim"}[]
			return []*mml.Node{.namedOperator()}, nil
		}
		if  == "gcd" ||  == "lim" ||  == "liminf" ||  == "limsup" ||  == "max" ||  == "min" ||  == "sup" ||  == "inf" {
			return []*mml.Node{.namedOperator()}, nil
		}
		 := token("mi", )
		.TeXClass = mml.TeXClassOp
		.SetProperty("texClass", mml.TeXClassOp)
		.commandNamedFunction = true
		return []*mml.Node{}, nil
	}

	if ,  := mathVariants[];  {
		return .mathFont()
	}

	switch  {
	case "not":
		.commandNot = true
		return nil, nil
	case "nonscript":
		.commandNonscript = true
		return nil, nil
	case "dots":
		.commandDots = .startDots()
		return nil, nil
	case "mmlToken":
		return .mmlToken()
	case ",":
		return []*mml.Node{spacer("0.167em")}, nil
	case ":":
		return []*mml.Node{spacer("0.222em")}, nil
	case ";":
		return []*mml.Node{spacer("0.278em")}, nil
	case "!":
		return []*mml.Node{spacer("-0.167em")}, nil
	case ">":
		return []*mml.Node{spacer("0.222em")}, nil
	case "quad":
		return []*mml.Node{spacer("1em")}, nil
	case "qquad":
		return []*mml.Node{spacer("2em")}, nil
	case "enspace":
		return []*mml.Node{spacer("0.5em")}, nil
	case "thinspace":
		return []*mml.Node{spacer("0.167em")}, nil
	case "negthinspace":
		return []*mml.Node{spacer("-0.167em")}, nil
	case "enskip":
		return []*mml.Node{spacer("0.5em")}, nil
	case "space", "\u00a0":
		return []*mml.Node{token("mtext", "\u00a0")}, nil
	case "{", "}", "$", "%", "#", "&", "_":
		return []*mml.Node{.token("mo", )}, nil
	case "backslash":
		return []*mml.Node{.token("mo", "∖")}, nil
	case "Vert":
		return []*mml.Node{.operator("‖", mml.TeXClassOrd, map[string]any{"fence": false, "stretchy": false})}, nil
	case "vert":
		return []*mml.Node{.operator("|", mml.TeXClassOrd, map[string]any{"fence": false, "stretchy": false})}, nil
	case "frac":
		return .fraction(, "")
	case "dfrac":
		return .fraction(, "D")
	case "tfrac":
		return .fraction(, "T")
	case "binom":
		return .binomial(, "")
	case "dbinom":
		return .binomial(, "D")
	case "tbinom":
		return .binomial(, "T")
	case "genfrac":
		return .generalizedFraction()
	case "cfrac":
		return .continuedFraction()
	case "sqrt":
		return .sqrt()
	case "root":
		return .root()
	case "uproot", "leftroot":
		return nil, .moveRoot()
	case "mathchoice":
		return .mathChoice()

	case "left":
		return .leftRight()
	case "middle":
		// Single-token consumers (such as a pending script) cannot own
		// this closing item. Read the delimiter before reporting the error.
		if ,  := .readDelimiter(, false);  != nil {
			return nil, 
		}
		return nil, texError("ExtraMiddle", "Extra \\middle")
	case "big", "Big", "bigg", "Bigg", "bigl", "Bigl", "biggl", "Biggl", "bigr", "Bigr", "biggr", "Biggr", "bigm", "Bigm", "biggm", "Biggm":
		return .bigDelimiter()

	case "overline", "underline", "overbrace", "underbrace", "overparen", "underparen", "overrightarrow", "overleftarrow", "underrightarrow", "underleftarrow", "overleftrightarrow", "underleftrightarrow":
		return .underOver()
	case "bar", "hat", "widehat", "tilde", "widetilde", "vec", "dot", "ddot", "dddot", "ddddot", "acute", "grave", "breve", "check", "mathring":
		return .accent()
	case "overset", "stackrel":
		return .overSet()
	case "buildrel":
		return .buildRelation()
	case "underset":
		return .underSet()
	case "overunderset":
		return .overUnderSet()
	case "xrightarrow", "xleftarrow", "xleftrightarrow", "xLeftarrow", "xRightarrow", "xLeftrightarrow", "xhookleftarrow", "xhookrightarrow", "xmapsto", "xrightharpoondown", "xleftharpoondown", "xrightleftharpoons", "xrightharpoonup", "xleftharpoonup", "xleftrightharpoons":
		return .xArrow()

	case "text", "textnormal":
		return .hboxCommand(, "", false)
	case "textrm", "textup":
		return .hboxCommand(, "normal", false)
	case "mbox", "hbox":
		return .hboxCommand(, "", true)
	case "textbf":
		return .hboxCommand(, "bold", false)
	case "textit":
		return .hboxCommand(, "italic", false)
	case "texttt":
		return .hboxCommand(, "monospace", false)
	case "textsf":
		return .hboxCommand(, "sans-serif", false)
	case "operatorname":
		return .operatorName()
	case "DeclareMathOperator":
		return nil, .declareMathOperator()
	case "mathop", "mathrel", "mathbin", "mathord", "mathopen", "mathclose", "mathpunct", "mathinner":
		return .mathClass()
	case "injlim", "projlim":
		 := map[string]string{"injlim": "inj\u2006lim", "projlim": "proj\u2006lim"}[]
		 := .operator(, mml.TeXClassOp, map[string]any{"movablelimits": true})
		.SetProperty("movesupsub", true)
		return []*mml.Node{}, nil

	case "kern", "mkern", "hskip", "mskip", "hspace", "mspace":
		return .horizontalSpace()
	case "hspace*":
		return .horizontalSpace()
	case "strut":
		// BaseMethods.Strut uses an explicit empty row and fixed point sizes.
		 := node("mpadded", node("mrow"))
		.Attributes.Set("height", "8.6pt")
		.Attributes.Set("depth", "3pt")
		.Attributes.Set("width", 0)
		return []*mml.Node{}, nil
	case "phantom", "hphantom", "vphantom":
		return .phantom()
	case "smash":
		return .smash()
	case "llap", "rlap", "clap", "mathllap", "mathrlap", "mathclap", "crampedllap", "crampedrlap", "crampedclap":
		return .lap()
	case "cramped":
		return .cramped()
	case "mathmbox":
		return .mathMBox()
	case "mathmakebox":
		return .mathMakeBox()
	case "raise", "lower":
		return .raiseLower()
	case "moveleft", "moveright":
		return .moveLeftRight()
	case "rule":
		return .rule()
	case "Rule", "Space":
		return .rule3D()
	case "vcenter":
		,  := .parseArgument()
		if  != nil {
			return nil, 
		}
		return []*mml.Node{texAtom(, mml.TeXClassVCenter)}, nil
	case "fbox":
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		,  := .internalMath(, "", false)
		if  != nil {
			return nil, 
		}
		return []*mml.Node{setAttributes(node("menclose", ...), map[string]any{"notation": "box"})}, nil
	case "framebox":
		return .frameBox()

	case "begin":
		return .beginEnvironment()
	case "end":
		return .endEnvironment()
	case "matrix", "array", "pmatrix", "cases", "eqalign", "eqalignno", "leqalignno", "displaylines":
		return .matrixCommand()

	case "DeclarePairedDelimiter", "DeclarePairedDelimiters", "DeclarePairedDelimiterX", "DeclarePairedDelimitersX", "DeclarePairedDelimiterXPP", "DeclarePairedDelimitersXPP":
		return nil, .declarePairedDelimiter()

	case "textcolor":
		return .textColor()
	case "definecolor":
		return nil, .defineColor()
	case "colorbox":
		return .colorBox(, false)
	case "fcolorbox":
		return .colorBox(, true)
	case "enclose":
		return .enclose()
	case "cancel", "bcancel", "xcancel":
		return .cancel()
	case "cancelto":
		return .cancelTo()
	case "ce", "pu":
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		 := mhchem.ModeCE
		if  == "pu" {
			 = mhchem.ModePU
		}
		,  := mhchem.ToTeX(, )
		if  != nil {
			return nil, texError("MhchemParse", "%s", )
		}
		.source = .source[:.pos] +  + .source[.pos:]
		return nil, nil

	case "bra", "ket", "braket", "innerproduct", "ip", "outerproduct", "dyad", "ketbra", "op", "expectationvalue", "expval", "ev", "matrixelement", "matrixel", "mel":
		return .physicsBraket()
	case "Braket", "Set", "set":
		return .braket()
	case "dd", "differential", "variation", "var", "dv", "derivative", "pdv", "pderivative", "partialderivative", "fdv", "fderivative", "functionalderivative":
		return .derivative(, )
	case "diffd":
		return []*mml.Node{physicsDifferential("d")}, nil
	case "commutator", "comm", "anticommutator", "acomm", "poissonbracket", "pb":
		return .commutator()
	case "vectorbold", "vb":
		return .vectorBold()
	case "vectorarrow", "va", "vectorunit", "vu":
		return .vectorAccent()
	case "vnabla":
		return []*mml.Node{.physicsNabla()}, nil
	case "qqtext", "qq", "qcc", "qif", "qthen", "qelse", "qotherwise", "qunless", "qgiven", "qusing", "qassume", "qsince", "qlet", "qfor", "qall", "qeven", "qodd", "qinteger", "qand", "qor", "qas", "qin":
		return .quickQuadText()
	case "mqty", "matrixquantity", "smqty", "smallmatrixquantity":
		return .matrixQuantity()
	case "prescript":
		return .prescript()
	case "nobreakspace":
		return []*mml.Node{token("mtext", "\u00a0")}, nil
	case "negmedspace":
		return []*mml.Node{spacer("-0.222em")}, nil
	case "negthickspace":
		return []*mml.Node{spacer("-0.278em")}, nil

	case "color":
		// parseRow handles the declaration form so that it can wrap the rest of
		// the current group. Reaching this path only happens in a one-token
		// context (e.g. a script), where an empty style is the source behavior.
		,  := .readColor()
		if  != nil {
			return nil, 
		}
		return []*mml.Node{setAttributes(node("mstyle", forcedRow(nil, true)), map[string]any{"mathcolor": })}, nil
	case "noalign", "notag", "nonumber", "nolimits", "limits", "displaystyle", "textstyle", "scriptstyle", "scriptscriptstyle":
		return nil, nil
	}
	return nil, texError("UndefinedControlSequence", "Undefined control sequence \\%s", )
}

func namedOperator( string) *mml.Node {
	 := token("mo", )
	.Attributes.Set("movablelimits", true)
	.SetProperty("movablelimits", true)
	.SetProperty("movesupsub", true)
	.Attributes.Set("form", "prefix")
	.TeXClass = mml.TeXClassOp
	.SetProperty("texClass", mml.TeXClassOp)
	return 
}

func lookupExtensionSymbol( string) (*mml.Node, bool) {
	for ,  := range gensymb.Configuration.Symbols {
		if .Name !=  {
			continue
		}
		 := token(.TokenKind, .Character)
		for ,  := range .Attributes {
			.Attributes.Set(.Name, .Value)
		}
		return , true
	}
	return nil, false
}

func space( string) *mml.Node {
	 := setAttributes(node("mspace"), map[string]any{"width": })
	.Flags.Spacelike = true
	return 
}

// BaseMethods.Spacer fixes scriptlevel at zero around explicit TeX spacing.
// That is observable under declarations such as \Huge and in scripts: the
// mspace inherits mathsize but does not shrink with the surrounding level.
func spacer( string) *mml.Node {
	return setAttributes(node("mstyle", space()), map[string]any{"scriptlevel": 0})
}

func ( *parser) (,  string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := node("mfrac", , )
	if  != "" {
		 = setAttributes(node("mstyle", ), styleAttributes())
	}
	return []*mml.Node{}, nil
}

func ( *parser) (,  string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := setAttributes(node("mfrac", , ), map[string]any{"linethickness": "0"})
	// AMS Genfrac uses string zero, fixedFence, then an optional style
	// around the entire fenced expression (including its MathChoice fences).
	.SetProperty("withDelims", true)
	 := forcedRow([]*mml.Node{
		.amsFixedFencePalette("(", mml.TeXClassOpen),
		,
		.amsFixedFencePalette(")", mml.TeXClassClose),
	}, false)
	.SetProperty("open", "(")
	.SetProperty("close", ")")
	.SetProperty("texClass", mml.TeXClassOrd)
	.TeXClass = mml.TeXClassOrd
	if  != "" {
		 = setAttributes(node("mstyle", ), styleAttributes())
	}
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := node("mfrac", , )
	if  != "" {
		.Attributes.Set("linethickness", )
	}
	 := 
	if  != "" {
		 = setAttributes(node("mstyle", ), styleAttributes())
	}
	,  := .convertDelimiterArgument()
	if  != nil {
		return nil, 
	}
	,  := .convertDelimiterArgument()
	if  != nil {
		return nil, 
	}
	if  != "" ||  != "" {
		 = .fenced(, , , true)
	}
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := func( *mml.Node) *mml.Node {
		 := setAttributes(node("mpadded", node("mrow")), map[string]any{
			"width": "0", "height": "8.6pt", "depth": "3pt",
		})
		 := setAttributes(node("mstyle", texAtom(, mml.TeXClassOrd)), map[string]any{"displaystyle": false, "scriptlevel": 0})
		return node("mrow", , )
	}
	 := node("mfrac", (), ())
	if  == "l" ||  == "r" {
		 := map[string]string{"l": "left", "r": "right"}[]
		.Attributes.Set("numalign", )
		.Attributes.Set("denomalign", )
	}
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	// BaseMethods.Sqrt collects an immediately following \\frac's two
	// arguments before creating the child parser for the radicand.
	if  == `\frac` {
		for  := 0;  < 2; ++ {
			, ,  := .readArgument(, false)
			if  != nil {
				return nil, 
			}
			 += "{" +  + "}"
		}
	}
	,  := .parseArgumentString()
	if  != nil {
		return nil, 
	}
	if  == "" {
		return []*mml.Node{node("msqrt", )}, nil
	}
	,  := .parseRootIndex()
	if  != nil {
		return nil, 
	}
	return []*mml.Node{node("mroot", , )}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .pos
	 := 0
	for .pos < len(.source) {
		if  == 0 && strings.HasPrefix(.source[.pos:], "\\of") {
			 := .source[:.pos]
			.pos += len("\\of")
			,  := .parseArgument()
			if  != nil {
				return nil, 
			}
			,  := .parseRootIndex()
			if  != nil {
				return nil, 
			}
			return []*mml.Node{node("mroot", , )}, nil
		}
		switch .source[.pos] {
		case '{':
			++
		case '}':
			if  > 0 {
				--
			}
		}
		.consumeRune()
	}
	return nil, texError("TokenNotFoundForCommand", "Could not find \\of for \\root")
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := make([]*mml.Node, 4)
	for  := range  {
		,  := .parseArgument()
		if  != nil {
			return nil, 
		}
		[] = 
	}
	return []*mml.Node{node("MathChoice", ...)}, nil
}

func styleAttributes( string) map[string]any {
	switch strings.TrimSpace() {
	case "0", "D", "D'":
		return map[string]any{"displaystyle": true, "scriptlevel": 0}
	case "1", "T", "T'":
		return map[string]any{"displaystyle": false, "scriptlevel": 0}
	case "2", "S", "S'":
		return map[string]any{"displaystyle": false, "scriptlevel": 1}
	case "3", "SS", "SS'":
		return map[string]any{"displaystyle": false, "scriptlevel": 2}
	}
	return nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .readDelimiter(, true)
	if  != nil {
		return nil, 
	}
	 := map[string]string{"big": "1.2em", "Big": "1.623em", "bigg": "2.047em", "Bigg": "2.470em"}
	 := strings.TrimRight(, "lrm")
	 := mml.TeXClassOrd
	if strings.HasSuffix(, "l") {
		 = mml.TeXClassOpen
	} else if strings.HasSuffix(, "r") {
		 = mml.TeXClassClose
	} else if strings.HasSuffix(, "m") {
		 = mml.TeXClassRel
	}
	 := .token("mo", )
	.Attributes.Set("minsize", [])
	.Attributes.Set("maxsize", [])
	.Attributes.Set("fence", true)
	.Attributes.Set("stretchy", true)
	.Attributes.Set("symmetric", true)
	return []*mml.Node{texAtom(, )}, nil
}

var accentCharacters = map[string]string{
	"bar": "¯", "hat": "^", "widehat": "^", "tilde": "~", "widetilde": "~", "vec": "→",
	"dot": "˙", "ddot": "¨", "dddot": "⃛", "ddddot": "⃜",
	"acute": "´", "grave": "`", "breve": "˘", "check": "ˇ", "mathring": "˚",
}

func ( *parser) ( string) ([]*mml.Node, error) {
	if  == "vec" ||  == "hat" {
		// StarMacro now continues in the caller. Keep its genuine accent
		// ParseArg child independent without changing the caller's later input.
		,  := .vectorAlias, .starMacroChildren
		.vectorAlias, .starMacroChildren = true, true
		defer func() { .vectorAlias, .starMacroChildren = ,  }()
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := strings.HasPrefix(, "wide")
	 := .operator(accentCharacters[], mml.TeXClassOrd, map[string]any{"accent": true, "stretchy": })
	ambientFontToken()
	// BaseMethods.Accent passes mathaccent through NodeUtil's property layer.
	// SVGmo uses that internal marker to zero the accent width and translate
	// the source glyph around its origin before the mover centers it.
	.SetProperty("mathaccent", true)
	// BaseMethods.Accent disables movable limits on its embellished core,
	// or on a nonembellished base carrying its own movablelimits property.
	 := 
	if .Flags.Embellished {
		 = limitsCore()
	}
	if  != nil {
		,  := .Property("movablelimits")
		if .Kind == "mo" || limitsTruthy() {
			applySourceObject(, mjSourceObject{{Name: "movablelimits", Value: false}})
		}
	}
	// BaseMethods.Accent leaves the parent implicit; its accent value is
	// inherited from the operator during MathML inheritance.
	 := node("mover", , )
	return []*mml.Node{texAtom(, mml.TeXClassOrd)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := strings.HasPrefix(, "under")
	 := "¯"
	 := true
	switch  {
	case "bar":
		 = false
	case "overline", "underline":
		 = "―"
	case "overbrace", "underbrace":
		 = map[bool]string{true: "⏟", false: "⏞"}[]
	case "overparen":
		 = "⏜"
	case "underparen":
		 = "⏝"
	case "overleftrightarrow", "underleftrightarrow":
		 = "↔"
	case "overrightarrow", "underrightarrow":
		 = "→"
	case "overleftarrow", "underleftarrow":
		 = "←"
	}
	 := .operator(, mml.TeXClassOrd, map[string]any{"stretchy": })
	if  == "overbrace" ||  == "underbrace" {
		// The parser represents inline movable limits as side scripts. Restore
		// their under/over form for ParseUtil.underOver's brace normalization;
		// the renderer still chooses inline placement from movablelimits.
		if ,  := .Property("movesupsub");  == true && .Flags.Embellished {
			 := map[string]string{"msub": "munder", "msup": "mover", "msubsup": "munderover"}[.Kind]
			if  != "" {
				 := node(, .Children...)
				.Attributes.SetList(.Attributes.Explicit())
				.Properties = .Properties.Clone()
				 = 
			}
		}
		// Preserve ParseUtil.underOver's operator normalization: a brace must
		// not become a movable limit of a bare sum in inline math, and an
		// embellished under/over base needs its own unembellished row.
		,  := .Property("movablelimits")
		,  := .Attributes.Get("movablelimits")
		 := propertyBool()
		if .Kind == "mo" {
			 =  || propertyBool()
			 := operatorForms()
			if ,  := .Attributes.GetExplicit("form");  {
				 = append([]string{propertyString()}, ...)
			}
			if ,  := lookupOperatorDefinition(textContent(), );  {
				for ,  := range .Properties {
					if .Name == "movablelimits" && propertyBool(.Value) {
						 = true
					}
				}
			}
		}
		if  {
			applySourceObject(, mjSourceObject{{Name: "movablelimits", Value: false}})
		}
		if (.Kind == "munder" || .Kind == "mover" || .Kind == "munderover") && .Flags.Embellished {
			// Stop at the operator: its text child is not the spacing target.
			 := 
			for .Kind != "mo" && .Flags.Embellished {
				 := .Core()
				if  == nil ||  ==  {
					break
				}
				 = 
			}
			if .Kind == "mo" {
				.Attributes.Set("lspace", 0)
				.Attributes.Set("rspace", 0)
			}
			 := .noteMO(node("mo"))
			.Attributes.Set("rspace", 0)
			 = node("mrow", , )
		}
		// MathJax's UnderOver(..., stack=true) keeps the brace inside an OP
		// atom. A following script labels the whole brace instead of replacing
		// its accent or being rejected as a duplicate exponent/subscript.
		.Attributes.Set("accent", true)
		,  := "mover", "accent"
		if  {
			,  = "munder", "accentunder"
		}
		 := texAtom(setAttributes(node(, , ), map[string]any{: true}), mml.TeXClassOp)
		.SetProperty("movesupsub", true)
		.SetProperty("subsupOK", true)
		return []*mml.Node{}, nil
	}
	checkMovableLimits()
	 = .normalizeDecorationBase()
	if  {
		 := setAttributes(node("munder", , ), map[string]any{"accentunder": true})
		.SetProperty("subsupOK", true)
		return []*mml.Node{}, nil
	}
	 := setAttributes(node("mover", , ), map[string]any{"accent": true})
	.SetProperty("subsupOK", true)
	return []*mml.Node{}, nil
}

// normalizeDecorationBase preserves ParseUtil.underOver's embellished-base
// row. Side-script families and grouped bases are deliberately excluded.
func normalizeDecorationBase( *mml.Node) *mml.Node {
	return normalizeDecorationBaseWithMO(, func() *mml.Node { return node("mo") })
}

func normalizeDecorationBaseWithMO( *mml.Node,  func() *mml.Node) *mml.Node {
	if (.Kind != "munder" && .Kind != "mover" && .Kind != "munderover") || !.Flags.Embellished {
		return 
	}
	applySourceObject(limitsCore(), mjSourceObject{{Name: "lspace", Value: 0}, {Name: "rspace", Value: 0}})
	 := ()
	.Attributes.Set("rspace", 0)
	return node("mrow", , )
}

// normalizeStackBase restores the primary scripted-base representation before
// the direct Overset/Underset handlers apply the shared movable-limit policy.
func normalizeStackBase( *mml.Node) *mml.Node {
	// Inline movable-limit scripts use a side-script representation in this
	// parser. The primary parser retains their under/over kind before the
	// Overset/Underset handler disables the base's movable limits.
	if ,  := .Property("movesupsub");  == true && .Flags.Embellished {
		 := map[string]string{"msub": "munder", "msup": "mover", "msubsup": "munderover"}[.Kind]
		if  != "" {
			 := node(, .Children...)
			.Attributes.SetList(.Attributes.Explicit())
			.Properties = .Properties.Clone()
			 = 
		}
	}

	checkMovableLimits()
	return 
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	if  == "overset" {
		 = normalizeStackBase()
		if .Kind == "mo" {
			.Attributes.Set("accent", false)
		}
	}
	return []*mml.Node{node("mover", , )}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 = normalizeStackBase()
	if .Kind == "mo" {
		.Attributes.Set("accent", false)
	}
	return []*mml.Node{setAttributes(node("munder", , ), map[string]any{"accentunder": false})}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	checkMovableLimits()
	if .Kind == "mo" {
		.Attributes.Set("accent", false)
	}
	if .Kind == "mo" {
		.Attributes.Set("accent", false)
	}
	return []*mml.Node{setAttributes(node("munderover", , , ), map[string]any{"accent": false, "accentunder": false})}, nil
}

// checkMovableLimits ports ParseUtil.checkMovableLimits. Only the direct base's
// property and, for an mo, its contextual dictionary entry participate. A
// grouped or scripted descendant must retain its own movable-limit policy.
func checkMovableLimits( *mml.Node) {
	,  := .Property("movablelimits")
	 :=  != nil
	switch value := .(type) {
	case bool:
		 = 
	case string:
		 =  != ""
	case int:
		 =  != 0
	case int64:
		 =  != 0
	case float64:
		 =  != 0 &&  ==  // JavaScript NaN is falsy.
	}
	if .Kind == "mo" {
		// NodeUtil.getForm uses getForms directly, without an explicit-form
		// override or a recursive core-operator traversal.
		if ,  := lookupOperatorDefinition(textContent(), operatorForms());  {
			for ,  := range .Properties {
				if .Name == "movablelimits" && propertyBool(.Value) {
					 = true
				}
			}
		}
	}
	if  {
		applySourceObject(, mjSourceObject{{Name: "movablelimits", Value: false}})
	}
}

var arrowCharacters = map[string]string{
	"xrightarrow": "→", "xleftarrow": "←", "xleftrightarrow": "↔",
	"xLeftarrow": "⇐", "xRightarrow": "⇒", "xLeftrightarrow": "⇔",
	"xhookleftarrow": "↩", "xhookrightarrow": "↪", "xmapsto": "↦",
	"xrightharpoondown": "⇁", "xleftharpoondown": "↽",
	"xrightleftharpoons": "⇌", "xrightharpoonup": "⇀",
	"xleftharpoonup": "↼", "xleftrightharpoons": "⇋",
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := .operator(arrowCharacters[], mml.TeXClassRel, map[string]any{"stretchy": true})
	if  {
		,  := .parseArgumentString()
		if  != nil {
			return nil, 
		}
		return []*mml.Node{node("munderover", , , )}, nil
	}
	return []*mml.Node{node("mover", , )}, nil
}

func ( *parser) (,  string) ([]*mml.Node, error) {
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	 := textRow()
	if  != "normal" {
		applyMathVariant(, )
		.Walk(func( *mml.Node) bool {
			if .Kind == "mtext" {
				.Attributes.Set("mathvariant", )
			}
			return true
		})
	}
	return []*mml.Node{}, nil
}

func textRow( string) *mml.Node {
	// ParseUtil.internalText creates a node, bypassing the token factory.
	return node("mtext", mml.NewText(strings.ReplaceAll(, "~", "\u00a0")))
}

var mathVariants = func() map[string]string {
	 := baseFontMappings("MathFont")
	// Preserve the pre-existing Go-only extension separately from source aliases.
	["boldsymbol"] = "bold-italic"
	return 
}()

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	// The Go-only boldsymbol extension predates this ambient-font policy.
	// Keep its existing whole-token scope; the pinned package omits it.
	,  := .parseMathFontString(, mathVariants[],  != "boldsymbol")
	if  != nil {
		return nil, 
	}
	return []*mml.Node{texAtom(, mml.TeXClassOrd)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .readStar()
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	 := .operator(strings.TrimSpace(), mml.TeXClassOp, map[string]any{"mathvariant": "normal", "movablelimits": })
	.SetProperty("movesupsub", )
	return []*mml.Node{}, nil
}

func ( *parser) ( string) error {
	 := .readStar()
	,  := .readCSNameArgument()
	if  != nil {
		return 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return 
	}
	 := "\\operatorname"
	if  {
		 += "*"
	}
	.state.macros[] = macroDefinition{body:  + "{" +  + "}"}
	return nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := map[string]mml.TeXClass{
		"mathop": mml.TeXClassOp, "mathrel": mml.TeXClassRel, "mathbin": mml.TeXClassBin,
		"mathord": mml.TeXClassOrd, "mathopen": mml.TeXClassOpen, "mathclose": mml.TeXClassClose,
		"mathpunct": mml.TeXClassPunct, "mathinner": mml.TeXClassInner,
	}
	 := texAtom(, [])
	if  == "mathop" {
		.SetProperty("movablelimits", true)
		.SetProperty("movesupsub", true)
		.commandNamedFunction = true
	}
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .readDimension()
	if  != nil {
		return nil, 
	}
	return []*mml.Node{space()}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := node("mphantom", )
	if  == "hphantom" {
		return []*mml.Node{texAtom(setAttributes(node("mpadded", ), map[string]any{"height": 0, "depth": 0}), mml.TeXClassOrd)}, nil
	}
	if  == "vphantom" {
		return []*mml.Node{texAtom(setAttributes(node("mpadded", ), map[string]any{"width": 0}), mml.TeXClassOrd)}, nil
	}
	return []*mml.Node{texAtom(, mml.TeXClassOrd)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := map[string]any{}
	if  == "" ||  == "t" {
		["height"] = 0
	}
	if  == "" ||  == "b" {
		["depth"] = 0
	}
	return []*mml.Node{texAtom(setAttributes(node("mpadded", ), ), mml.TeXClassOrd)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	if strings.HasPrefix(, "math") || strings.HasPrefix(, "cramped") {
		return .mathLap()
	}
	if  == "clap" ||  == "textclap" ||  == "textllap" ||  == "textrlap" {
		return .textLap()
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := "left"
	if strings.Contains(, "llap") ||  == "llap" {
		 = "right"
	} else if strings.Contains(, "clap") ||  == "clap" {
		 = "center"
	}
	 := node("mpadded", )
	.Attributes.Set("width", 0)
	if  == "right" {
		.Attributes.Set("lspace", "-1width")
	} else if  == "center" {
		.Attributes.Set("lspace", "-.5width")
	}
	return []*mml.Node{texAtom(, mml.TeXClassOrd)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := node("mstyle", )
	.Attributes.Set("data-cramped", true)
	setMathtoolsDisplayLevel(, )
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := []*mml.Node{}
	if .Kind == "mrow" && .Flags.Inferred {
		 = .Children
	}
	return []*mml.Node{node("mrow", ...)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	 := "c"
	, ,  := .readBrackets(&)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	 := node("mpadded", )
	if  &&  != "" {
		.Attributes.Set("width", )
	}
	if  == "c" {
		.Attributes.Set("data-align", "center")
	} else if  == "r" {
		.Attributes.Set("data-align", "right")
	}
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .readDimension()
	if  != nil {
		return nil, 
	}
	 :=  == "lower"
	if strings.HasPrefix(, "-") {
		 = [1:]
		 = !
	}
	,  := "+"+, "-"+
	if  {
		,  = , 
	}
	.commandPosition = &positionItem{name: , height: , depth: }
	return nil, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .readDimension()
	if  != nil {
		return nil, 
	}
	 := "-" + 
	if strings.HasPrefix(, "-") {
		 = [1:]
	}
	if  == "moveleft" {
		,  = , 
	}
	.commandPosition = &positionItem{
		name:  ,
		left:  setAttributes(node("mspace"), map[string]any{"width": }),
		right: setAttributes(node("mspace"), map[string]any{"width": }),
	}
	return nil, nil
}

func negateDimension( string) string {
	if strings.HasPrefix(, "-") {
		return strings.TrimPrefix(, "-")
	}
	return "-" + strings.TrimPrefix(, "+")
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		var  *Error
		if errors.As(, &) && .ID == "MissingCloseBracket" {
			return nil, texError(.ID, "Could not find closing ']' for argument to %s", "\\"+)
		}
		return nil, 
	}
	,  := .readDimension()
	if  != nil {
		return nil, 
	}
	,  := .readDimension()
	if  != nil {
		return nil, 
	}
	 := .activeColor
	if  == "" {
		 = "black"
	}
	 := setAttributes(node("mspace"), map[string]any{"width": , "height": , "mathbackground": })
	if  != "" {
		 := setAttributes(node("mpadded", ), map[string]any{"voffset": })
		if strings.HasPrefix(, "-") {
			.Attributes.Set("height", )
			.Attributes.Set("depth", "+"+[1:])
		} else {
			.Attributes.Set("height", "+"+)
		}
		return []*mml.Node{}, nil
	}
	return []*mml.Node{}, nil
}

func ( *parser) () bool {
	// TexParser.GetStar calls GetNext, which skips JavaScript whitespace.
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	if .pos < len(.source) && .source[.pos] == '*' {
		.pos++
		return true
	}
	return false
}

func ( *parser) ( string) (string, error) {
	 = strings.TrimSpace()
	if  == "" ||  == "." {
		return "", nil
	}
	if ,  := lookupDelimiter();  {
		return , nil
	}
	return "", texError("MissingOrUnrecognizedDelim", "Missing or unrecognized delimiter")
}

func ( *parser) ( string) error {
	,  := .readCSNameArgument()
	if  != nil {
		return 
	}
	 := 1
	 := "#1"
	if strings.Contains(, "X") {
		, ,  := .readBrackets(nil)
		if  != nil {
			return 
		}
		if  != "" {
			,  = parseInteger(, "IllegalMacroParam")
			if  != nil {
				return 
			}
		}
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return 
	}
	if strings.Contains(, "X") {
		, _,  = .readArgument(, false)
		if  != nil {
			return 
		}
	}
	.state.pairedDelimiters[] = pairedDelimiter{open: , close: , body: , arguments: }
	return nil
}

func ( *parser) ( string,  pairedDelimiter) ([]*mml.Node, error) {
	 := .readStar()
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	 := make([]string, .arguments)
	for  := range  {
		[], _,  = .readArgument(, false)
		if  != nil {
			return nil, 
		}
	}
	,  := substituteArguments(.body, )
	if  != nil {
		return nil, 
	}
	,  := .parseString()
	if  != nil {
		return nil, 
	}
	,  := .convertDelimiterArgument(.open)
	if  != nil {
		return nil, 
	}
	,  := .convertDelimiterArgument(.close)
	if  != nil {
		return nil, 
	}
	 := 
	if  &&  != "" {
		 = true
	}
	return []*mml.Node{.fenced(, , , )}, nil
}

func ( *parser) ( string) (string, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return "", 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return "", 
	}
	,  := .state.colorModel.GetColor(, )
	return , translateColorError()
}

func translateColorError( error) error {
	if  == nil {
		return nil
	}
	var  *texcolor.Error
	if errors.As(, &) {
		return &Error{ID: .ID, Message: .Message}
	}
	return 
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .readColor()
	if  != nil {
		return nil, 
	}
	 := .activeColor
	.activeColor = 
	defer func() { .activeColor =  }()
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	return []*mml.Node{setAttributes(node("mstyle", ), map[string]any{"mathcolor": })}, nil
}

func ( *parser) ( string) error {
	, ,  := .readArgument(, false)
	if  != nil {
		return 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return 
	}
	return translateColorError(.state.colorModel.DefineColor(, , ))
}

func ( *parser) ( string,  bool) ([]*mml.Node, error) {
	 := ""
	var  error
	if  {
		, _,  = .readArgument(, false)
		if  != nil {
			return nil, 
		}
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	,  := .internalMath(, "", false)
	if  != nil {
		return nil, 
	}
	,  = .state.colorModel.GetColor("named", )
	if  != nil {
		return nil, translateColorError()
	}
	 := setAttributes(node("mpadded", ...), map[string]any{"mathbackground": })
	for ,  := range texcolor.PaddingProperties("5px") {
		.Attributes.Set(.Name, .Value)
	}
	if  {
		,  = .state.colorModel.GetColor("named", )
		if  != nil {
			return nil, translateColorError()
		}
		.Attributes.Set("style", "border: 2px solid "+)
	}
	return []*mml.Node{}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := keyvalOptions(, enclose.AllowedOptions)
	if  != nil {
		return nil, 
	}
	.Set("notation", strings.ReplaceAll(, ",", " "))
	return []*mml.Node{setKeyvalAttributes(node("menclose", ), )}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := keyvalOptions(, enclose.AllowedOptions)
	if  != nil {
		return nil, 
	}
	.Set("notation", map[string]string{
		"cancel": texcancel.UpDiagonalStrike, "bcancel": texcancel.DownDiagonalStrike,
		"xcancel": texcancel.UpDiagonalStrike + " " + texcancel.DownDiagonalStrike,
	}[])
	return []*mml.Node{setKeyvalAttributes(node("menclose", ), )}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .readBrackets(nil)
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := .parseArgument()
	if  != nil {
		return nil, 
	}
	,  := keyvalOptions(, enclose.AllowedOptions)
	if  != nil {
		return nil, 
	}
	.Set("notation", texcancel.CancelToNotation)
	 := node("mpadded", )
	for ,  := range texcancel.CancelToPadding {
		.Attributes.Set(.Name, .Value)
	}
	return []*mml.Node{node("msup", setKeyvalAttributes(node("menclose", ), ), )}, nil
}

func keyvalOptions( string,  []string) (*ordered.Map[any], error) {
	 := make(map[string]bool, len())
	for ,  := range  {
		[] = true
	}
	return parseUtilKeyvalOptions(, func( string) bool {
		return []
	}, false)
}

// Preserve Object.keys order when NodeFactory forwards option properties to
// MathML attributes. SVG copies surviving data-* attributes in that order.
func setKeyvalAttributes( *mml.Node,  *ordered.Map[any]) *mml.Node {
	for ,  := range .JavaScriptKeys() {
		,  := .Get()
		.Attributes.Set(, )
	}
	return 
}

func ( *parser) () (mjSourceObject, error) {
	,  := .readColor("color")
	if  != nil {
		return nil, 
	}
	// Color reads and validates its arguments before pushing a StyleItem.
	.activeColor = 
	return mjSourceObject{{Name: "mathcolor", Value: }}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	switch  {
	case "bra":
		 := .readStar()
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		// PhysicsMethods.Bra consumes an immediately following \ket and emits a
		// single bra-ket expression.  Besides being the intended shorthand,
		// this shares the middle bar; parsing the commands independently adds a
		// duplicate bar and inter-atom space (observable in D2 label widths).
		, , ,  := .physicsFollowingKet()
		if  != nil {
			return nil, 
		}
		if  {
			 := "\\left\\langle{" +  + "}\\middle\\vert{" +  + "}\\right\\rangle"
			if  ||  {
				 = "\\langle{" +  + "}\\vert{" +  + "}\\rangle"
			}
			,  := .parseChild()
			if  != nil {
				return nil, 
			}
			return unwrapInferred(), nil
		}
		 := "\\left\\langle{" +  + "}\\right\\vert{}"
		if  {
			 = "\\langle{" +  + "}\\vert"
		}
		,  := .parseChild()
		if  != nil {
			return nil, 
		}
		return unwrapInferred(), nil
	case "ket":
		 := .readStar()
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		 := "\\left\\vert{" +  + "}\\right\\rangle"
		if  {
			 = "\\vert{" +  + "}\\rangle"
		}
		,  := .parseChild()
		if  != nil {
			return nil, 
		}
		return unwrapInferred(), nil
	case "braket", "innerproduct", "ip":
		 := .readStar()
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		 := ""
		// Source GetNext commits JavaScript whitespace before optional braces.
		for .pos < len(.source) && internalTextSpace(.peekRune()) {
			.consumeRune()
		}
		if .pos < len(.source) && .source[.pos] == '{' {
			, _,  = .readArgument(, true)
			if  != nil {
				return nil, 
			}
		} else {
			 = 
		}
		 := "\\left\\langle{" +  + "}\\middle\\vert{" +  + "}\\right\\rangle"
		if  {
			 = "\\langle{" +  + "}\\vert{" +  + "}\\rangle"
		}
		,  := .parseChild()
		if  != nil {
			return nil, 
		}
		 := unwrapInferred()
		// Physics' active vertical-bar character handler creates AutoClose
		// tokens directly, so bars occurring inside braket arguments are not
		// members of Base's fixStretchy list.  The middle \vert already lacks
		// this marker; removing it here restores that package-wide distinction.
		for ,  := range  {
			.Walk(func( *mml.Node) bool {
				if .Kind == "mo" && textContent() == "|" {
					.RemoveProperty("in-lists")
				}
				return true
			})
		}
		return , nil
	case "outerproduct", "dyad", "ketbra", "op":
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		, ,  := .readArgument(, true)
		if  != nil {
			return nil, 
		}
		if  == "" {
			 = 
		}
		,  := .parseString()
		if  != nil {
			return nil, 
		}
		,  := .parseString()
		if  != nil {
			return nil, 
		}
		return []*mml.Node{.fenced("|", , "⟩", true), .fenced("⟨", , "|", true)}, nil
	case "expectationvalue", "expval", "ev":
		return .physicsExpectation()
	case "matrixelement", "matrixel", "mel":
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		,  := .parseString( + "\\middle|" +  + "\\middle|" + )
		if  != nil {
			return nil, 
		}
		return []*mml.Node{.fenced("⟨", , "⟩", true)}, nil
	}
	return nil, nil
}

// The Physics Bra/Ket/BraKet/KetBra/MatrixElement callers create one child
// TexParser for their complete generated expression. Their arguments share
// that child's budget; continuing Eval and other shared expansions do not.
func ( *parser) ( string) ([]*mml.Node, error) {
	 := .state.macroCount
	.state.macroCount = 0
	defer func() { .state.macroCount =  }()
	return .parseExpansionWithStack(, nil)
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .parseStringWithEnvironment(, .ensureStackGlobal(), nil, nil, .environmentOwner)
	if  != nil {
		return nil, 
	}
	return unwrapInferred(), nil
}

func ( *parser) ( string,  *parserStackGlobal) ([]*mml.Node, error) {
	,  := .parseStringWithStack(, )
	if  != nil {
		return nil, 
	}
	if .Kind == "mrow" && .Flags.Inferred {
		return .Children, nil
	}
	return []*mml.Node{}, nil
}

func physicsFenced( string,  *mml.Node,  string,  bool) *mml.Node {
	 := fenced(, , , )
	// Physics AutoOpen reduces through its stack item to an INNER-class row,
	// but does not install an explicit texClass property on the MML node.
	.TeXClass = mml.TeXClassInner
	return 
}

func ( *parser) ( byte) (string, error) {
	 := .pos
	 := 0
	 := 0
	 := byte(0)
	switch  {
	case ')':
		 = '('
	case ']':
		 = '['
	case '|':
		 = '|'
	}
	for .pos < len(.source) {
		 := .source[.pos]
		if  == '\\' {
			.pos++
			.readControlSequence()
			continue
		}
		if  == '{' {
			++
		} else if  == '}' &&  > 0 {
			--
		} else if  == 0 {
			if  ==  &&  !=  {
				++
			} else if  ==  {
				if  == 0 {
					 := .source[:.pos]
					.pos++
					return , nil
				}
				--
			}
		}
		.consumeRune()
	}
	return "", texError("TokenNotFoundForCommand", "Could not find closing delimiter")
}

// physicsFollowingKet ports the lookahead in PhysicsMethods.Bra. Recognizing
// the ket commits its command even when the next argument is not braced; only
// the star/argument lookahead after that command is then restored.
func ( *parser) ( string) ( string,  bool,  bool,  error) {
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	if .pos >= len(.source) || .source[.pos] != '\\' {
		return "", false, false, nil
	}
	 := .pos
	.pos++
	if .readControlSequence() != "ket" {
		.pos = 
		return "", false, false, nil
	}
	 := .pos
	 = .readStar()
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	if .pos >= len(.source) || .source[.pos] != '{' {
		.pos = 
		return "", false, true, nil
	}
	, _,  = .readArgument(, true)
	return , , true, 
}

func physicsDifferential( string) *mml.Node {
	 := token("mi", )
	if  != "d" {
		// PhysicsMethods.Differential reparses its operator string.  The
		// variation operator is \delta, which is an ordinary mi rather than a
		// nested TeXAtom; \diffd below expands through {\rm d} and does retain
		// that atom wrapper.
		return 
	}
	.Attributes.Set("mathvariant", "normal")
	return texAtom(, mml.TeXClassOrd)
}

func physicsNabla() *mml.Node {
	return physicsNablaWithOperator(operator)
}

func physicsNablaWithOperator( func(string, mml.TeXClass, map[string]any) *mml.Node) *mml.Node {
	 := texAtom(("∇", mml.TeXClassOrd, map[string]any{"mathvariant": "bold"}), mml.TeXClassOrd)
	return texAtom(, mml.TeXClassOrd)
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .readStar()
	// Both lookaheads in PhysicsMethods.Commutator call GetNext.
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	 := ""
	if .pos < len(.source) && .source[.pos] == '\\' {
		.pos++
		 = .readControlSequence()
		switch  {
		case "big", "Big", "bigg", "Bigg":
		default:
			return nil, texError("MissingArgFor", "Missing argument for %s", "\\"+)
		}
		for .pos < len(.source) && internalTextSpace(.peekRune()) {
			.consumeRune()
		}
	}
	if .pos >= len(.source) || .source[.pos] != '{' {
		return nil, texError("MissingArgFor", "Missing argument for %s", "\\"+)
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	,  := "[", "]"
	switch  {
	case "anticommutator", "acomm", "poissonbracket", "pb":
		,  = "\\{", "\\}"
	}
	// PhysicsMethods.Commutator parses both raw arguments in one child
	// expression. Their comma is a real token in the same lexical row.
	 :=  + "," + 
	switch {
	case :
		 =  + " " +  + " " + 
	case  != "":
		 = "\\" +  + "l" +  + " " +  + " " + "\\" +  + "r" + 
	default:
		 = "\\left" +  + " " +  + " " + "\\right" + 
	}
	,  := .parseChild()
	if  != nil {
		return nil, 
	}
	return unwrapInferred(), nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .readStar()
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	,  := .parseVectorString(, )
	if  != nil {
		return nil, 
	}
	return unwrapInferred(), nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .readStar()
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	 := "vec"
	if  == "vectorunit" ||  == "vu" {
		 = "hat"
	}
	 := "vb"
	if  {
		 += "*"
	}
	,  := substituteMacroArguments("\\"++"{\\"++"{#1}}", []string{})
	if  != nil {
		return nil, 
	}
	,  := macroAddArgs(, .source[.pos:], maxMacroBuffer)
	if  != nil {
		return nil, 
	}
	// PhysicsMethods.StarMacro installs the replacement and caller suffix
	// before charging. The current row then parses the same continuing program,
	// so a registered accent Macro can consume arguments from that suffix.
	.source, .pos = , 0
	.state.macroCount++
	if .state.macroCount > maxMacros {
		return nil, texError("MaxMacroSub1", "MathJax maximum macro substitution count exceeded; is here a recursive macro call?")
	}
	return nil, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	// Qqtext's GetStar/GetArgument use JavaScript GetNext whitespace.
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	 := .pos < len(.source) && .source[.pos] == '*'
	if  {
		.pos++
	}
	 := map[string]string{
		"qcc": "c.c.", "qif": "if", "qthen": "then", "qelse": "else", "qotherwise": "otherwise",
		"qunless": "unless", "qgiven": "given", "qusing": "using", "qassume": "assume", "qsince": "since",
		"qlet": "let", "qfor": "for", "qall": "all", "qeven": "even", "qodd": "odd", "qinteger": "integer",
		"qand": "and", "qor": "or", "qas": "as", "qin": "in",
	}
	 := []
	 := 0
	if  == "" {
		var  error
		for .pos < len(.source) && internalTextSpace(.peekRune()) {
			.consumeRune()
		}
		// GetCS advances once past EOF when GetArgument starts at a terminal
		// backslash. Keep the physical Go cursor safe, but retain that source
		// cursor advance for resuming Qqtext's inserted program below.
		if .pos < len(.source) && .pos+1 == len(.source) && .source[.pos] == '\\' {
			 = 1
		}
		, _,  = .readArgumentAtCursor(, false)
		if  != nil {
			return nil, 
		}
	}
	// PhysicsMethods.Qqtext inserts TeX into the calling parser. Keeping text
	// and quad as commands preserves their late-bound definitions and the
	// caller's pending items; unlike Macro, this handler does not charge a
	// substitution or create a child parser.
	 := "\\text{" +  + "}\\quad "
	if ! {
		 = "\\quad" + 
	}
	.source = .source[:.pos] +  + .source[.pos:]
	.pos += 
	return nil, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .mathtoolsPrescriptArgument(, "sup")
	if  != nil {
		return nil, 
	}
	,  := .mathtoolsPrescriptArgument(, "sub")
	if  != nil {
		return nil, 
	}
	,  := .mathtoolsPrescriptArgument(, "arg")
	if  != nil {
		return nil, 
	}
	if .Kind == "none" && .Kind == "none" {
		return unwrapInferred(), nil
	}
	// The two right-script slots remain absent until final filtering. Ordinary
	// authored scripts can fill them while mmultiscripts is the stack's base.
	 := node("mmultiscripts", , nil, nil, node("mprescripts"), , )
	.SetProperty("fixPrescript", true)
	return []*mml.Node{}, nil
}

// MathtoolsUtil.getScript trims each authored argument, represents an empty
// argument with none, and applies its position's format in a fresh child.
func ( *parser) (,  string) (*mml.Node, error) {
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	 := strings.TrimFunc(, internalTextSpace)
	if strings.HasSuffix(, "\\") && strings.HasSuffix(, " ") {
		 += " " // ParseUtil.trimSpaces preserves a terminal control-space.
	}
	if  == "" {
		return node("none"), nil
	}
	 := .mathtoolsOption("prescript-" +  + "-format")
	if  != "" &&  != "false" {
		 =  + "{" +  + "}"
	}
	return .parseChild()
}

func unwrapInferred( *mml.Node) []*mml.Node {
	if  != nil && .Kind == "mrow" && .Flags.Inferred {
		return .Children
	}
	return []*mml.Node{}
}

func ( *parser) ( string,  **derivativeAutoOpen) ([]*mml.Node, error) {
	if  == "dd" ||  == "differential" ||  == "variation" ||  == "var" {
		return .differential(, )
	}
	 := .readStar()
	, ,  := .readBrackets(nil)
	if  != nil {
		var  *Error
		if errors.As(, &) && .ID == "MissingCloseBracket" {
			return nil, texError(.ID, "Could not find closing ']' for argument to %s", "\\"+)
		}
		return nil, 
	}
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	 := []string{}
	 := 2
	 := "\\diffd"
	switch  {
	case "pdv", "pderivative", "partialderivative":
		 = 3
		 = "\\partial"
	case "fdv", "fderivative", "functionalderivative":
		 = "\\delta"
	}
	for {
		.skipNextSpaces()
		if .pos >= len(.source) || .source[.pos] != '{' || len() ==  {
			break
		}
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		 = append(, )
	}
	 := false
	,  := " ", " "
	if  > 2 && len() > 2 {
		 = "^{" + strconv.Itoa(len()-1) + "}"
		 = true
	} else if  {
		 =  > 2 && len() > 1
		 = "^{" +  + "}"
		 = 
	}
	 := "\\frac"
	if  {
		 = "\\flatfrac"
	}
	,  := "", [0]
	if len() > 1 {
		,  = [0], [1]
	}
	 := ""
	for  := 2;  < len() && [] != ""; ++ {
		 +=  + " " + []
	}
	// PhysicsMethods.Derivative reparses this literal source. In particular,
	// the denominator power belongs after the raw variable, and each order
	// occurrence is parsed independently by the actual fraction handler.
	 :=  + "{" +  +  +  + "}" +
		"{" +  + " " +  +  + " " +  + "}"
	,  := .parseChild()
	if  != nil {
		return nil, 
	}
	// Push/PushAll forwards the actual parser result, including zero or many
	// children from registered frac/flatfrac overrides. Only then may its
	// recipient activate AutoOpen on the original parser.
	* = &derivativeAutoOpen{ignore: }
	return unwrapInferred(), nil
}

func keyvalString( string) map[string]string {
	 := make(map[string]string)
	for ,  := range splitTopLevel(, ',') {
		 := strings.SplitN(, "=", 2)
		if len() == 2 {
			[strings.TrimSpace([0])] = strings.TrimSpace([1])
		}
	}
	return 
}

func numberString( any) string { return fmt.Sprint() }

func parseFloat( string) (float64, error) {
	return strconv.ParseFloat(strings.TrimSpace(), 64)
}