// Copyright 2017-2022 The MathJax Consortium // SPDX-License-Identifier: Apache-2.0 // Based on BaseMethods.Prime and BaseItems.PrimeItem/SubsupItem (MathJax 3.2.2).
package tex import ( ) // pendingPrime belongs to a single parseRow stack. Keep the actual original // node and prime token until a stack item finalizes or consumes them; an eager // msup loses this distinction and wrongly treats x'^n as a double exponent. type pendingPrime struct{ base, prime *mml.Node } func isPrimeRune( rune) bool { return == '\'' || == '\u2019' } func ( *parser) ( *mml.Node) (*pendingPrime, error) { , := .Property(limitsScriptOrigin) := .Kind == "msub" || .Kind == "msup" || .Kind == "msubsup" || .Kind == "mmultiscripts" := .Kind == "msup" && != true if && ! && ((.Kind == "msup" && len(.Children) > 1) || ((.Kind == "msubsup" || .Kind == "mmultiscripts") && len(.Children) > 2 && .Children[2] != nil)) { return nil, texError("DoubleExponentPrime", "Prime causes double exponent: use braces to clarify") } := 1 for .pos < len(.source) { // Prime uses TexParser.GetNext, whose JavaScript whitespace set differs // from Go's unicode.IsSpace for U+FEFF and U+0085. Keep this lookahead // local so argument and row parsing retain their existing policy. for .pos < len(.source) && isPrimeSpace(.peekRune()) { .consumeRune() } if .pos >= len(.source) || !isPrimeRune(.peekRune()) { break } .consumeRune() ++ } := []string{"", "′", "″", "‴", "⁗"} := strings.Repeat("′", ) if < len() { = [] } := .token("mo", ) .SetProperty("variantForm", true) return &pendingPrime{, }, nil } func isPrimeSpace( rune) bool { return >= '\t' && <= '\r' || == ' ' || == '\u00a0' || == '\u1680' || >= '\u2000' && <= '\u200a' || == '\u2028' || == '\u2029' || == '\u202f' || == '\u205f' || == '\u3000' || == '\ufeff' } func ( *pendingPrime) () *mml.Node { if .base.Kind == "mmultiscripts" { := append([]*mml.Node(nil), .base.Children...) [2] = .prime .base.SetChildren() refreshDynamicFlags(.base) return .base } , := .base.Property(limitsScriptOrigin) if .base.Kind == "msub" || .base.Kind == "msubsup" || (.base.Kind == "msup" && == true) { var *mml.Node if .base.Kind != "msup" && len(.base.Children) > 1 { = .base.Children[1] } if != nil { if .base.Kind != "msub" || == true { .base.Kind = "msubsup" } .base.Flags.Arity = 3 .base.SetChildren([]*mml.Node{.base.Children[0], , .prime}) } else { .base.Kind = "msup" .base.Flags.Arity = 2 .base.SetChildren([]*mml.Node{.base.Children[0], .prime}) } refreshDynamicFlags(.base) return .base } return node("msup", .base, .prime) } func ( *pendingPrime) ( *mml.Node, byte) (*mml.Node, error) { , := .base.Property("movesupsub") if == '^' { .prime.SetProperty("variantForm", true) = node("mrow", .prime, ) } , := attachScriptBase(.base, , , limitsTruthy()) if != nil { return nil, } if == '_' { if .Kind == "mmultiscripts" { := append([]*mml.Node(nil), .Children...) [2] = .prime .SetChildren() refreshDynamicFlags() } else { .Kind = map[bool]string{false: "msubsup", true: "munderover"}[.Kind == "munder" || .Kind == "mover" || .Kind == "munderover"] .Flags.Arity = 3 .SetChildren([]*mml.Node{.Children[0], .Children[1], .prime}) refreshDynamicFlags() } } .Flags.Embellished = .base.Flags.Embellished .Flags.CoreIndex = 0 .SetProperty(limitsScriptOrigin, true) if { .SetProperty("movesupsub", ) } return , nil }