// Copyright (c) 2009-2022 The MathJax Consortium // SPDX-License-Identifier: Apache-2.0 // Source: BaseMethods.BeginEnd, BeginItem/EndItem, CasesMethods.NumCases, // and MathtoolsMethods.SpreadLines.
package tex import // Environment ownership belongs to one executing input, not shared macro // configuration. A genuine TexParser child starts without an outer owner. // Captured legacy owners are retained as barriers, but never charge at EOF. type environmentFrame struct { name string parent *environmentFrame stream, closed bool ordinaryArray bool casesBegin *casesBeginItem } // Only the builtin BeginEnd handler can produce this item. Dynamic command // maps and argument readers run first; neither raw capture nor EOF creates it. type environmentEndItem struct { name string spread bool } func ( *environmentEndItem) () error { return texError("MissingBeginExtraEnd", "Missing \\begin{%s} or extra \\end{%s}", .name, .name) } func ( *environmentFrame) () error { return texError("EnvMissingEnd", "Missing \\end{%s}", .name) } func ( *parser) ( string) ([]*mml.Node, error) { , := .readEnvironmentName() if != nil { return nil, } , := .sourceEndDefinition() if ! { // BeginEnd charges before its environment handler touches the stack. if := .countEnvironment(); != nil { return nil, } } if ! { return nil, texError("UnknownEnv", "Unknown environment '%s'", ) } if .environmentOwner == nil && == "spreadlines" && !.liveMatrix { // An orphan SpreadLines executes Pop rather than emitting EndItem. // Its source runtime failure remains a separate bounded diagnostic. return nil, texError("ExtraEnd", "Extra \\end{%s}", ) } .commandEnvironmentEnd = &environmentEndItem{name: , spread: == "spreadlines"} return nil, nil } func ( *parser) ( *environmentFrame, *environmentEndItem) error { if == nil { return .extra() } if .name != .name { return texError("EnvBadEnd", "\\begin{%s} ended with \\end{%s}", .name, .name) } if := .casesBegin; != nil { // Cases pushes one Begin object twice. The first End removes // its upper entry and flips the shared end property; decoration // executes while the remaining entry still owns these nodes. .entries-- if .end { .end = false .closing = } .closed = .entries == 0 } else { .closed = true } .pendingEnvironmentEnd = nil return nil } // SpreadLines is an open BeginItem on this same input. Parse from the current // cursor until its executing handler pops that item; return the updated input // and cursor unchanged by any artificial body capture or EOF callback. func ( *parser) ( *environmentFrame) (*mml.Node, error) { , := .environmentRow, .ordinaryArray , , , := .arrayCell, .matrixClose, .cdArrayEntry, .braketOwner .environmentRow, .ordinaryArray = , nil .arrayCell, .matrixClose, .cdArrayEntry, .braketOwner = nil, false, false, nil defer func() { .environmentRow, .ordinaryArray = , .arrayCell, .matrixClose, .cdArrayEntry, .braketOwner = , , , }() , , := .parseRowContinuation(0, false, false, nil, "", nil) if != nil { return nil, } if !.closed { return nil, .missing() } return row(, true), nil }