// Copyright 2017-2022 The MathJax Consortium // SPDX-License-Identifier: Apache-2.0 // Based on BaseMethods.Subscript and BaseMethods.Superscript (MathJax 3.2.2).
package tex import // attachScriptBase preserves authored annotation ownership. The source tests // family/subtype and occupied slots before choosing whether to reuse a script // wrapper or wrap the entire base. This parser's own eager compact subtypes // represent an unfinished generic family; their transient origin bridges that // representation only. Pending PrimeItems pass their original base here. func attachScriptBase(, *mml.Node, byte, bool) (*mml.Node, error) { , := prepareScriptAttachment(, , ) if != nil { return nil, } return .fill(), nil } // scriptAttachment is a read-only decision until a real argument is available. // The pending argument uses the same family/occupied-slot policy as final fill. type scriptAttachment struct { base, under, over *mml.Node marker byte moves, limits, reuse bool } func prepareScriptAttachment( *mml.Node, byte, bool) (*scriptAttachment, error) { , := .Property(limitsScriptOrigin) := == true := .Kind == "msub" || .Kind == "msup" || .Kind == "msubsup" || .Kind == "mmultiscripts" := .Kind == "munder" || .Kind == "mover" || .Kind == "munderover" := .Kind == "msup" && ! := .Kind == "mover" && ! var , *mml.Node if || { if len(.Children) > 1 { if .Kind == "msup" || .Kind == "mover" { = .Children[1] } else { = .Children[1] } } if len(.Children) > 2 { = .Children[2] } } := if == '^' { = } , := .Property("subsupOK") if ( && ! && != nil) || ( && ! && != nil && !limitsTruthy()) { if == '_' { return nil, texError("DoubleSubscripts", "Double subscripts: use braces to clarify") } return nil, texError("DoubleExponent", "Double exponent: use braces to clarify") } := && ! if ! && { = && ! && == nil } return &scriptAttachment{, , , , , , }, nil } // pendingBase exposes the source's unfinished generic family only to read-only // handler checks. It shares the actual children and own maps, without changing // their parent pointers or publishing a temporary wrapper into the MML tree. func ( *scriptAttachment) () *mml.Node { := "msubsup" if .limits && .reuse || .moves && !.reuse { = "munderover" } if .reuse { := *.base if , := .base.Property(limitsScriptOrigin); == true && .base.Kind != "mmultiscripts" { .Kind = if .base.Kind == "msup" || .base.Kind == "mover" { .Children = []*mml.Node{.base.Children[0], nil, .over} } } return & } := node() .Children = []*mml.Node{.base} if .moves { .SetProperty("movesupsub", true) } return } func ( *scriptAttachment) ( *mml.Node) *mml.Node { , , := .base, .under, .over , , , := .marker, .moves, .limits, .reuse if ! { := "msub" if == '^' { = "msup" } if { = "munder" if == '^' { = "mover" } } := node(, , ) if { .SetProperty("movesupsub", true) } return } if == '_' { = } else { = } if .Kind == "mmultiscripts" { := append([]*mml.Node(nil), .Children...) [1], [2] = , .SetChildren() refreshDynamicFlags() return } := []*mml.Node{.Children[0]} := "msubsup" if { = "munderover" } if != nil && != nil { = append(, , ) } else if != nil { = append(, ) = map[bool]string{false: "msub", true: "munder"}[] } else { = append(, ) = map[bool]string{false: "msup", true: "mover"}[] } .Kind = .Flags.Arity = len() .SetChildren() refreshDynamicFlags() return }