package regexp2

import (
	
	
	
	
	
	
	
	

	
	
)

type Runner struct {
	re    *Regexp
	code  *syntax.Code
	debug bool

	Runtextstart int // starting point for search

	Runtext    []rune // text to search
	Runtextpos int    // current position in text
	Runtextend int

	// The backtracking stack.  Opcodes use this to store data regarding
	// what they have matched and where to backtrack to.  Each "frame" on
	// the stack takes the form of [CodePosition Data1 Data2...], where
	// CodePosition is the position of the current opcode and
	// the data values are all optional.  The CodePosition can be negative, and
	// these values (also called "back2") are used by the BranchMark family of opcodes
	// to indicate whether they are backtracking after a successful or failed
	// match.
	// When we backtrack, we pop the CodePosition off the stack, set the current
	// instruction pointer to that code position, and mark the opcode
	// with a backtracking flag ("Back").  Each opcode then knows how to
	// handle its own data.
	runtrack    []int
	Runtrackpos int

	// This stack is used to track text positions across different opcodes.
	// For example, in /(a*b)+/, the parentheses result in a SetMark/CaptureMark
	// pair. SetMark records the text position before we match a*b.  Then
	// CaptureMark uses that position to figure out where the capture starts.
	// Opcodes which push onto this stack are always paired with other opcodes
	// which will pop the value from it later.  A successful match should mean
	// that this stack is empty.
	runstack    []int
	Runstackpos int

	// The crawl stack is used to keep track of captures.  Every time a group
	// has a capture, we push its group number onto the runcrawl stack.  In
	// the case of a balanced match, we push BOTH groups onto the stack.
	runcrawl    []int
	runcrawlpos int

	runtrackcount int // count of states that may do backtracking

	runmatch *Match // result object

	ignoreTimeout bool
	timeout       time.Duration // timeout in milliseconds (needed for actual)
	deadline      fasttime

	operator        syntax.InstOp
	codepos         int
	rightToLeft     bool
	caseInsensitive bool
}

// run searches for matches and can continue from the previous match.
//
// quick is usually false, but can be true to not return matches, just put it in caches.
// textstart is -1 to start at the "beginning" (depending on Right-To-Left), otherwise an index in input.
// previousMatchLength is -1 for an initial scan. A zero value advances the current scan position while
// preserving textstart for anchors such as \G.
// textInfo is nil for quick scans that do not need returned capture text metadata.
func ( *Regexp) ( bool, ,  int,  []rune,  *matchText) (*Match, error) {

	// get a cached runner
	 := .getRunner()
	defer .putRunner()

	if  < 0 {
		if .RightToLeft() {
			 = len()
		} else {
			 = 0
		}
	}
	if  &&  == nil && .quickCode != nil {
		.code = .quickCode
	}

	return .scan(, , , , , .MatchTimeout)
}

// Scans the string to find the first match. Uses the Match object
// both to feed text in and as a place to store matches that come out.
//
// All the action is in the Go() method. Our
// responsibility is to load up the class members before
// calling Go.
//
// The optimizer can compute a set of candidate starting characters,
// and we could use a separate method Skip() that will quickly scan past
// any characters that we know can't match.
//
// The input slice is passed separately from matchText so quick scans can avoid
// allocating match metadata. When textInfo is nil, successful matches are only
// used as a boolean result and capture text is intentionally unavailable. If
// we collapsed down to just textInfo it would "escape" and hit the GC for fast
// scans without captures.
func ( *Runner) ( []rune,  *matchText, ,  int,  bool,  time.Duration) (*Match, error) {
	.timeout = 
	.ignoreTimeout = (time.Duration(math.MaxInt64) == )
	.debug = .re.Debug()
	.Runtextstart = 
	.Runtext = 
	.Runtextend = len()
	// Some internal callers use quick match tidying while still consuming
	// capture data (notably replacement). Capture elision is only safe when no
	// match text metadata was requested.

	 := .Runtextend
	 := 1

	if .re.RightToLeft() {
		 = -1
		 = 0
	}

	.Runtextpos = 
	//initted := false

	// setup our scanner functions
	 := .re.findFirstChar
	 := .re.execute
	if  &&  == nil && .re.executeQuick != nil {
		 = .re.executeQuick
	}
	if  == nil {
		 = findFirstCharDefault
	}
	if  == nil {
		 = executeDefault
	}

	 := 0
	if .code != nil && .code.FindOptimizations != nil {
		 = .code.FindOptimizations.MinRequiredLength
	}

	.initMatch()

	// An empty previous match must not be returned again. Keep Runtextstart at
	// the previous match position for \G, but move the candidate scan position.
	if  == 0 {
		if .Runtextpos ==  {
			.tidyMatch(true)
			return nil, nil
		}
		.Runtextpos += 
	}

	.startTimeoutWatch()
	for {
		if  > 0 {
			if .code.RightToLeft {
				if .Runtextpos <  {
					.tidyMatch(true)
					return nil, nil
				}
			} else if .Runtextend-.Runtextpos <  {
				.tidyMatch(true)
				return nil, nil
			}
		}

		if .debug {
			//fmt.Printf("\nSearch content: %v\n", string(r.runtext))
			fmt.Printf("\nSearch range: from 0 to %v\n", .Runtextend)
			fmt.Printf("Firstchar search starting at %v stopping at %v\n", .Runtextpos, )
		}

		if () {
			if !.ignoreTimeout {
				if  := .CheckTimeout();  != nil {
					return nil, 
				}
			}

			if .debug {
				fmt.Printf("Executing engine starting at %v\n\n", .Runtextpos)
			}

			if  := ();  != nil {
				return nil, 
			}

			if .runmatch.matchcount[0] > 0 {
				// We'll return a match even if it touches a previous empty match
				return .tidyMatch(), nil
			}

			// reset state for another go
			.Runtrackpos = len(.runtrack)
			.Runstackpos = len(.runstack)
			.runcrawlpos = len(.runcrawl)
		}

		// failure!

		if .Runtextpos ==  {
			.tidyMatch(true)
			return nil, nil
		}

		// Recognize leading []* and various anchors, and bump on failure accordingly

		// r.bump by one and start again

		.Runtextpos += 
	}
	// We never get here
}

func executeDefault( *Runner) error {

	if  := .goTo(0);  != nil {
		return 
	}
	for {

		if .debug {
			.dumpState()
		}

		if !.ignoreTimeout {
			if  := .CheckTimeout();  != nil {
				return 
			}
		}

		switch .operator {
		case syntax.Stop:
			return nil

		case syntax.Nothing:
			//noop

		case syntax.Goto:
			if  := .goTo(.operand(0));  != nil {
				return 
			}
			continue

		case syntax.Dispatch:
			// Dispatch only peeks at the next rune. It consumes it after finding a
			// matching branch, so a failed dispatch leaves the input position alone.
			if .forwardchars() < 1 {
				break
			}
			// Pick the next rune in the current execution direction.
			 := .Runtextpos
			if .rightToLeft {
				--
			}
			 := .Runtext[]
			 := .operand(0)
			 := &.code.Dispatches[]
			 := -1
			if  >= 0 &&  < 128 {
				if .ASCII != nil {
					// Larger dispatches use a direct ASCII branch lookup.
					 = int(.ASCII[]) - 1
				} else {
					// Smaller dispatches use two compact ASCII bitmasks per set.
					 := int( >> 6)
					 := uint64(1) << ( & 63)
					for  := range .Sets {
						if .ASCIIMasks[*2+]& != 0 {
							 = 
							break
						}
					}
				}
			} else {
				// Non-ASCII runes fall back to the complete character sets.
				for ,  := range .Sets {
					if .code.Sets[].CharIn() {
						 = 
						break
					}
				}
			}
			if  < 0 {
				break
			}
			// The selected branch starts with this rune, so consume it and jump
			// directly to the rest of that branch.
			.Runtextpos += .bump()
			if  := .goTo(.Branches[]);  != nil {
				return 
			}
			continue

		case syntax.Testref:
			if !.runmatch.isMatched(.operand(0)) {
				break
			}
			.advance(1)
			continue

		case syntax.Lazybranch:
			.trackPush1(.textPos())
			.advance(1)
			continue

		case syntax.Lazybranch | syntax.Back:
			.trackPop()
			.textto(.trackPeek())
			if  := .goTo(.operand(0));  != nil {
				return 
			}
			continue

		case syntax.Setmark:
			.stackPush(.textPos())
			.trackPush()
			.advance(0)
			continue

		case syntax.Nullmark:
			.stackPush(-1)
			.trackPush()
			.advance(0)
			continue

		case syntax.Setmark | syntax.Back, syntax.Nullmark | syntax.Back:
			.stackPop()

		case syntax.Getmark:
			.stackPop()
			.trackPush1(.stackPeek())
			.textto(.stackPeek())
			.advance(0)
			continue

		case syntax.Getmark | syntax.Back:
			.trackPop()
			.stackPush(.trackPeek())

		case syntax.Capturemark:
			if .operand(1) != -1 && !.runmatch.isMatched(.operand(1)) {
				break
			}
			.stackPop()
			if .operand(1) != -1 {
				.transferCapture(.operand(0), .operand(1), .stackPeek(), .textPos())
			} else {
				.Capture(.operand(0), .stackPeek(), .textPos())
			}
			.trackPush1(.stackPeek())

			.advance(2)

			continue

		case syntax.Capturemark | syntax.Back:
			.trackPop()
			.stackPush(.trackPeek())
			.uncapture()
			if .operand(0) != -1 && .operand(1) != -1 {
				.uncapture()
			}

		case syntax.Branchmark:
			.stackPop()

			 := .textPos() - .stackPeek()

			if  != 0 { // Nonempty match -> loop now
				.trackPush2(.stackPeek(), .textPos())     // Save old mark, textpos
				.stackPush(.textPos())                     // Make new mark
				if  := .goTo(.operand(0));  != nil { // Loop
					return 
				}
			} else { // Empty match -> straight now
				.trackPushNeg1(.stackPeek()) // Save old mark
				.advance(1)                   // Straight
			}
			continue

		case syntax.Branchmark | syntax.Back:
			.trackPopN(2)
			.stackPop()
			.textto(.trackPeekN(1))      // Recall position
			.trackPushNeg1(.trackPeek()) // Save old mark
			.advance(1)                   // Straight
			continue

		case syntax.Branchmark | syntax.Back2:
			.trackPop()
			.stackPush(.trackPeek()) // Recall old mark
			// Backtrack

		case syntax.Lazybranchmark:
			{
				// We hit this the first time through a lazy loop and after each
				// successful match of the inner expression.  It simply continues
				// on and doesn't loop.
				.stackPop()

				 := .stackPeek()

				if .textPos() !=  { // Nonempty match -> try to loop again by going to 'back' state
					if  != -1 {
						.trackPush2(, .textPos()) // Save old mark, textpos
					} else {
						.trackPush2(.textPos(), .textPos())
					}
				} else {
					// The inner expression found an empty match, so we'll go directly to 'back2' if we
					// backtrack. Don't touch the grouping stack here; instead, record the old mark and
					// a flag indicating that backtracking doesn't need to pop a grouping stack frame.
					.trackPushNeg2(, 0)
				}
				.advance(1)
				continue
			}

		case syntax.Lazybranchmark | syntax.Back:

			// After the first time, Lazybranchmark | syntax.Back occurs
			// with each iteration of the loop, and therefore with every attempted
			// match of the inner expression.  We'll try to match the inner expression,
			// then go back to Lazybranchmark if successful.  If the inner expression
			// fails, we go to Lazybranchmark | syntax.Back2

			.trackPopN(2)
			 := .trackPeekN(1)
			.trackPushNeg2(.trackPeek(), 1)            // Save old mark, note that we pushed a new mark
			.stackPush()                             // Make new mark
			.textto()                                // Recall position
			if  := .goTo(.operand(0));  != nil { // Loop
				return 
			}
			continue

		case syntax.Lazybranchmark | syntax.Back2:
			// The lazy loop has failed.  We'll do a true backtrack and
			// start over before the lazy loop.
			.trackPopN(2)
			 := .trackPeek()
			 := .trackPeekN(1)
			if  != 0 {
				.stackPop()
			}
			.stackPush() // Recall old mark

		case syntax.Setcount:
			.stackPush2(.textPos(), .operand(0))
			.trackPush()
			.advance(1)
			continue

		case syntax.Nullcount:
			.stackPush2(-1, .operand(0))
			.trackPush()
			.advance(1)
			continue

		case syntax.Setcount | syntax.Back:
			.stackPopN(2)

		case syntax.Nullcount | syntax.Back:
			.stackPopN(2)

		case syntax.Branchcount:
			// r.stackPush:
			//  0: Mark
			//  1: Count

			.stackPopN(2)
			 := .stackPeek()
			 := .stackPeekN(1)
			 := .textPos() - 

			if  >= .operand(1) || ( == 0 &&  >= 0) { // Max loops or empty match -> straight now
				.trackPushNeg2(, ) // Save old mark, count
				.advance(2)                 // Straight
			} else { // Nonempty match -> count+loop now
				.trackPush1()                           // remember mark
				.stackPush2(.textPos(), +1)           // Make new mark, incr count
				if  := .goTo(.operand(0));  != nil { // Loop
					return 
				}
			}
			continue

		case syntax.Branchcount | syntax.Back:
			// r.trackPush:
			//  0: Previous mark
			// r.stackPush:
			//  0: Mark (= current pos, discarded)
			//  1: Count
			.trackPop()
			.stackPopN(2)
			if .stackPeekN(1) > 0 { // Positive -> can go straight
				.textto(.stackPeek())                           // Zap to mark
				.trackPushNeg2(.trackPeek(), .stackPeekN(1)-1) // Save old mark, old count
				.advance(2)                                      // Straight
				continue
			}
			.stackPush2(.trackPeek(), .stackPeekN(1)-1) // recall old mark, old count

		case syntax.Branchcount | syntax.Back2:
			// r.trackPush:
			//  0: Previous mark
			//  1: Previous count
			.trackPopN(2)
			.stackPush2(.trackPeek(), .trackPeekN(1)) // Recall old mark, old count

		case syntax.Lazybranchcount:
			// r.stackPush:
			//  0: Mark
			//  1: Count

			.stackPopN(2)
			 := .stackPeek()
			 := .stackPeekN(1)

			if  < 0 { // Negative count -> loop now
				.trackPushNeg1()                        // Save old mark
				.stackPush2(.textPos(), +1)           // Make new mark, incr count
				if  := .goTo(.operand(0));  != nil { // Loop
					return 
				}
			} else { // Nonneg count -> straight now
				.trackPush3(, , .textPos()) // Save mark, count, position
				.advance(2)                           // Straight
			}
			continue

		case syntax.Lazybranchcount | syntax.Back:
			// r.trackPush:
			//  0: Mark
			//  1: Count
			//  2: r.textPos

			.trackPopN(3)
			 := .trackPeek()
			 := .trackPeekN(2)

			if .trackPeekN(1) < .operand(1) &&  !=  { // Under limit and not empty match -> loop
				.textto()                            // Recall position
				.stackPush2(, .trackPeekN(1)+1)     // Make new mark, incr count
				.trackPushNeg1()                        // Save old mark
				if  := .goTo(.operand(0));  != nil { // Loop
					return 
				}
				continue
			} else { // Max loops or empty match -> backtrack
				.stackPush2(.trackPeek(), .trackPeekN(1)) // Recall old mark, count
				// backtrack
			}

		case syntax.Lazybranchcount | syntax.Back2:
			// r.trackPush:
			//  0: Previous mark
			// r.stackPush:
			//  0: Mark (== current pos, discarded)
			//  1: Count
			.trackPop()
			.stackPopN(2)
			.stackPush2(.trackPeek(), .stackPeekN(1)-1) // Recall old mark, count
			// Backtrack

		case syntax.Setjump:
			.stackPush2(.trackpos(), .Crawlpos())
			.trackPush()
			.advance(0)
			continue

		case syntax.Setjump | syntax.Back:
			.stackPopN(2)

		case syntax.Backjump:
			// r.stackPush:
			//  0: Saved trackpos
			//  1: r.crawlpos
			.stackPopN(2)
			.trackto(.stackPeek())

			for .Crawlpos() != .stackPeekN(1) {
				.uncapture()
			}

		case syntax.Forejump:
			// r.stackPush:
			//  0: Saved trackpos
			//  1: r.crawlpos
			.stackPopN(2)
			.trackto(.stackPeek())
			.trackPush1(.stackPeekN(1))
			.advance(0)
			continue

		case syntax.Forejump | syntax.Back:
			// r.trackPush:
			//  0: r.crawlpos
			.trackPop()

			for .Crawlpos() != .trackPeek() {
				.uncapture()
			}

		case syntax.Bol:
			if .leftchars() > 0 && .charAt(.textPos()-1) != '\n' {
				break
			}
			.advance(0)
			continue

		case syntax.Eol:
			if .rightchars() > 0 && .charAt(.textPos()) != '\n' {
				break
			}
			.advance(0)
			continue

		case syntax.Boundary:
			if !.IsBoundary(.textPos()) {
				break
			}
			.advance(0)
			continue

		case syntax.Nonboundary:
			if .IsBoundary(.textPos()) {
				break
			}
			.advance(0)
			continue

		case syntax.ECMABoundary:
			if !.IsECMABoundary(.textPos()) {
				break
			}
			.advance(0)
			continue

		case syntax.NonECMABoundary:
			if .IsECMABoundary(.textPos()) {
				break
			}
			.advance(0)
			continue

		case syntax.Beginning:
			if .leftchars() > 0 {
				break
			}
			.advance(0)
			continue

		case syntax.Start:
			if .textPos() != .textstart() {
				break
			}
			.advance(0)
			continue

		case syntax.EndZ:
			 := .rightchars()
			if  > 1 {
				break
			}
			// RE2 and EcmaScript define $ as "asserts position at the end of the string"
			// PCRE/.NET adds "or before the line terminator right at the end of the string (if any)"
			if (.re.options & (RE2 | ECMAScript)) != 0 {
				// RE2/Ecmascript mode
				if  > 0 {
					break
				}
			} else if  == 1 && .charAt(.textPos()) != '\n' {
				// "regular" mode
				break
			}

			.advance(0)
			continue

		case syntax.End:
			if .rightchars() > 0 {
				break
			}
			.advance(0)
			continue

		case syntax.One:
			if .forwardchars() < 1 || .forwardcharnext() != rune(.operand(0)) {
				break
			}

			.advance(1)
			continue

		case syntax.Notone:
			if .forwardchars() < 1 || .forwardcharnext() == rune(.operand(0)) {
				break
			}

			.advance(1)
			continue

		case syntax.Set:

			if .forwardchars() < 1 || !.code.Sets[.operand(0)].CharIn(.forwardcharnext()) {
				break
			}

			.advance(1)
			continue

		case syntax.Multi:
			if !.runematch(.code.Strings[.operand(0)]) {
				break
			}

			.advance(1)
			continue

		case syntax.Grapheme:
			if !.TryMatchGrapheme(.rightToLeft) {
				break
			}
			.advance(0)
			continue

		case syntax.Ref:

			 := .operand(0)

			if .runmatch.isMatched() {
				if !.refmatch(.runmatch.matchIndex(), .runmatch.matchLength()) {
					break
				}
			} else {
				if (.re.options & ECMAScript) == 0 {
					break
				}
			}

			.advance(1)
			continue

		case syntax.Onerep:

			 := .operand(1)

			if .forwardchars() <  {
				break
			}

			 := rune(.operand(0))

			for  > 0 {
				if .forwardcharnext() !=  {
					goto 
				}
				--
			}

			.advance(2)
			continue

		case syntax.Notonerep:

			 := .operand(1)

			if .forwardchars() <  {
				break
			}
			 := rune(.operand(0))

			for  > 0 {
				if .forwardcharnext() ==  {
					goto 
				}
				--
			}

			.advance(2)
			continue

		case syntax.Setrep:

			 := .operand(1)

			if .forwardchars() <  {
				break
			}

			 := .code.Sets[.operand(0)]

			for  > 0 {
				if !.CharIn(.forwardcharnext()) {
					goto 
				}
				--
			}

			.advance(2)
			continue

		case syntax.Oneloop, syntax.Oneloopatomic:

			 := .operand(1)

			if  > .forwardchars() {
				 = .forwardchars()
			}

			 := rune(.operand(0))
			 := 

			for ;  > 0; -- {
				if .forwardcharnext() !=  {
					.backwardnext()
					break
				}
			}

			if  >  && .operator == syntax.Oneloop {
				.trackPush2(--1, .textPos()-.bump())
			}

			.advance(2)
			continue

		case syntax.Notoneloop, syntax.Notoneloopatomic:

			 := .operand(1)

			if  > .forwardchars() {
				 = .forwardchars()
			}

			 := rune(.operand(0))
			 := 

			for ;  > 0; -- {
				if .forwardcharnext() ==  {
					.backwardnext()
					break
				}
			}

			if  >  && .operator == syntax.Notoneloop {
				.trackPush2(--1, .textPos()-.bump())
			}

			.advance(2)
			continue

		case syntax.Setloop, syntax.Setloopatomic:

			 := .operand(1)

			if  > .forwardchars() {
				 = .forwardchars()
			}

			 := .code.Sets[.operand(0)]
			 := 

			for ;  > 0; -- {
				if !.CharIn(.forwardcharnext()) {
					.backwardnext()
					break
				}
			}

			if  >  && .operator == syntax.Setloop {
				.trackPush2(--1, .textPos()-.bump())
			}

			.advance(2)
			continue

		case syntax.Oneloop | syntax.Back, syntax.Notoneloop | syntax.Back:

			.trackPopN(2)
			 := .trackPeek()
			 := .trackPeekN(1)

			.textto()

			if  > 0 {
				.trackPush2(-1, -.bump())
			}

			.advance(2)
			continue

		case syntax.Setloop | syntax.Back:

			.trackPopN(2)
			 := .trackPeek()
			 := .trackPeekN(1)

			.textto()

			if  > 0 {
				.trackPush2(-1, -.bump())
			}

			.advance(2)
			continue

		case syntax.Onelazy, syntax.Notonelazy:

			 := .operand(1)

			if  > .forwardchars() {
				 = .forwardchars()
			}

			if  > 0 {
				.trackPush2(-1, .textPos())
			}

			.advance(2)
			continue

		case syntax.Setlazy:

			 := .operand(1)

			if  > .forwardchars() {
				 = .forwardchars()
			}

			if  > 0 {
				.trackPush2(-1, .textPos())
			}

			.advance(2)
			continue

		case syntax.Onelazy | syntax.Back:

			.trackPopN(2)
			 := .trackPeekN(1)
			.textto()

			if .forwardcharnext() != rune(.operand(0)) {
				break
			}

			 := .trackPeek()

			if  > 0 {
				.trackPush2(-1, +.bump())
			}

			.advance(2)
			continue

		case syntax.Notonelazy | syntax.Back:

			.trackPopN(2)
			 := .trackPeekN(1)
			.textto()

			if .forwardcharnext() == rune(.operand(0)) {
				break
			}

			 := .trackPeek()

			if  > 0 {
				.trackPush2(-1, +.bump())
			}

			.advance(2)
			continue

		case syntax.Setlazy | syntax.Back:

			.trackPopN(2)
			 := .trackPeekN(1)
			.textto()

			if !.code.Sets[.operand(0)].CharIn(.forwardcharnext()) {
				break
			}

			 := .trackPeek()

			if  > 0 {
				.trackPush2(-1, +.bump())
			}

			.advance(2)
			continue

		case syntax.UpdateBumpalong:
			// UpdateBumpalong should only exist in the code stream at such a point where the root
			// of the backtracking stack contains the runtextpos from the start of this Go call. Replace
			// that tracking value with the current runtextpos value if it's greater.
			 := .runtrack[len(.runtrack)-1]
			if  < .Runtextpos {
				.runtrack[len(.runtrack)-1] = .Runtextpos
			}
			.advance(0)
			continue

		default:
			return fmt.Errorf("unknown state in regex runner: %v", .operator)
		}

	:
		;

		// "break Backward" comes here:
		if  := .backtrack();  != nil {
			return 
		}
	}
}

// increase the size of stack and track storage
func ( *Runner) () error {
	if .Runstackpos < .runtrackcount*4 {
		doubleIntSlice(&.runstack, &.Runstackpos)
	}
	if .Runtrackpos < .runtrackcount*4 && !.growTrack() {
		return ErrBacktrackingStackLimit
	}
	return nil
}

func ( *Runner) ( int) {
	if .Runstackpos- < .runtrackcount*4 {
		doubleIntSlice(&.runstack, &.Runstackpos)
	}
}

func doubleIntSlice( *[]int,  *int) {
	 := len(*)
	 := make([]int, *2)

	copy([:], *)
	* += 
	* = 
}

// Save a number on the longjump unrolling stack
func ( *Runner) ( int) {
	if .runcrawlpos == 0 {
		doubleIntSlice(&.runcrawl, &.runcrawlpos)
	}
	.runcrawlpos--
	.runcrawl[.runcrawlpos] = 
}

// Remove a number from the longjump unrolling stack
func ( *Runner) () int {
	 := .runcrawl[.runcrawlpos]
	.runcrawlpos++
	return 
}

// Get the height of the stack
func ( *Runner) () int {
	return len(.runcrawl) - .runcrawlpos
}

func ( *Runner) ( int) {
	.codepos += ( + 1)
	.setOperator(.code.Codes[.codepos])
}

func ( *Runner) ( int) error {
	// when branching backward or in place, ensure storage
	if  <= .codepos {
		if  := .ensureStorage();  != nil {
			return 
		}
	}

	.setOperator(.code.Codes[])
	.codepos = 
	return nil
}

func ( *Runner) ( int) {
	.Runtextpos = 
}

func ( *Runner) ( int) {
	.Runtrackpos = len(.runtrack) - 
}

func ( *Runner) () int {
	return .Runtextstart
}

func ( *Runner) () int {
	return .Runtextpos
}

// TryMatchGrapheme consumes one Unicode extended grapheme cluster in the
// runner's current direction. It is exported for regexp2cg-generated engines.
func ( *Runner) ( bool) bool {
	var  int
	if  {
		 = syntax.PreviousGraphemeClusterBoundary(.Runtext, .Runtextpos)
	} else {
		 = syntax.NextGraphemeClusterBoundary(.Runtext, .Runtextpos)
	}
	if  < 0 {
		return false
	}
	.Runtextpos = 
	return true
}

// push onto the backtracking stack
func ( *Runner) () int {
	return len(.runtrack) - .Runtrackpos
}

func ( *Runner) () bool {
	 := len(.runtrack)
	 :=  * 2
	if  == 0 {
		 = 1
	}
	if  := .re.optimizations.MaxBacktrackingStackSize;  >= 0 &&  >  {
		 = 
	}
	if  <=  {
		return false
	}

	 := make([]int, )
	copy([-:], .runtrack)
	.Runtrackpos +=  - 
	.runtrack = 
	return true
}

func ( *Runner) () {
	.Runtrackpos--
	.runtrack[.Runtrackpos] = .codepos
}

func ( *Runner) ( int) {
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = .codepos
}

func ( *Runner) (,  int) {
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = .codepos
}

func ( *Runner) (, ,  int) {
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = .codepos
}

func ( *Runner) ( int) {
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = -.codepos
}

func ( *Runner) (,  int) {
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = 
	.Runtrackpos--
	.runtrack[.Runtrackpos] = -.codepos
}

func ( *Runner) () error {
	 := .runtrack[.Runtrackpos]
	.Runtrackpos++

	if .debug {
		if  < 0 {
			fmt.Printf("       Backtracking (back2) to code position %v\n", -)
		} else {
			fmt.Printf("       Backtracking to code position %v\n", )
		}
	}

	if  < 0 {
		 = -
		.setOperator(.code.Codes[] | int(syntax.Back2))
	} else {
		.setOperator(.code.Codes[] | int(syntax.Back))
	}

	// When branching backward, ensure storage
	if  < .codepos {
		if  := .ensureStorage();  != nil {
			return 
		}
	}

	.codepos = 
	return nil
}

func ( *Runner) ( int) {
	.caseInsensitive = (0 != ( & int(syntax.Ci)))
	.rightToLeft = (0 != ( & int(syntax.Rtl)))
	.operator = syntax.InstOp( & ^int(syntax.Rtl|syntax.Ci))
}

func ( *Runner) () {
	.Runtrackpos++
}

// pop framesize items from the backtracking stack
func ( *Runner) ( int) {
	.Runtrackpos += 
}

// Technically we are actually peeking at items already popped.  So if you want to
// get and pop the top item from the stack, you do
// r.trackPop();
// r.trackPeek();
func ( *Runner) () int {
	return .runtrack[.Runtrackpos-1]
}

// get the ith element down on the backtracking stack
func ( *Runner) ( int) int {
	return .runtrack[.Runtrackpos--1]
}

// Push onto the grouping stack
func ( *Runner) ( int) {
	.Runstackpos--
	.runstack[.Runstackpos] = 
}

func ( *Runner) (,  int) {
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
}

func ( *Runner) () {
	.Runstackpos++
}

// pop framesize items from the grouping stack
func ( *Runner) ( int) {
	.Runstackpos += 
}

// Technically we are actually peeking at items already popped.  So if you want to
// get and pop the top item from the stack, you do
// r.stackPop();
// r.stackPeek();
func ( *Runner) () int {
	return .runstack[.Runstackpos-1]
}

// get the ith element down on the grouping stack
func ( *Runner) ( int) int {
	return .runstack[.Runstackpos--1]
}

func ( *Runner) ( int) int {
	return .code.Codes[.codepos++1]
}

func ( *Runner) () int {
	return .Runtextpos
}

func ( *Runner) () int {
	return .Runtextend - .Runtextpos
}

func ( *Runner) () int {
	if .rightToLeft {
		return -1
	}
	return 1
}

func ( *Runner) () int {
	if .rightToLeft {
		return .Runtextpos
	}
	return .Runtextend - .Runtextpos
}

func ( *Runner) () rune {
	var  rune
	if .rightToLeft {
		.Runtextpos--
		 = .Runtext[.Runtextpos]
	} else {
		 = .Runtext[.Runtextpos]
		.Runtextpos++
	}

	// move this to compile time for individual runes
	/*if r.caseInsensitive {
		return unicode.ToLower(ch)
	}*/
	return 
}

func ( *Runner) ( []rune) bool {
	var  int

	 := len()
	if !.rightToLeft {
		if .Runtextend-.Runtextpos <  {
			return false
		}

		 = .Runtextpos + 
	} else {
		if .Runtextpos-0 <  {
			return false
		}

		 = .Runtextpos
	}

	if !.caseInsensitive {
		for  != 0 {
			--
			--
			if [] != .Runtext[] {
				return false
			}
		}
	} else {
		for  != 0 {
			--
			--
			if [] != unicode.ToLower(.Runtext[]) {
				return false
			}
		}
	}

	if !.rightToLeft {
		 += len()
	}

	.Runtextpos = 

	return true
}

func ( *Runner) (,  int) bool {
	var , ,  int

	if !.rightToLeft {
		if .Runtextend-.Runtextpos <  {
			return false
		}

		 = .Runtextpos + 
	} else {
		if .Runtextpos-0 <  {
			return false
		}

		 = .Runtextpos
	}
	 =  + 

	 = 

	if !.caseInsensitive {
		for  != 0 {
			--
			--
			--
			if .Runtext[] != .Runtext[] {
				return false
			}

		}
	} else {
		for  != 0 {
			--
			--
			--

			if unicode.ToLower(.Runtext[]) != unicode.ToLower(.Runtext[]) {
				return false
			}
		}
	}

	if !.rightToLeft {
		 += 
	}

	.Runtextpos = 

	return true
}

func ( *Runner) () {
	if .rightToLeft {
		.Runtextpos++
	} else {
		.Runtextpos--
	}
}

func ( *Runner) ( int) rune {
	return .Runtext[]
}

func findFirstCharDefault( *Runner) bool {
	if 0 != (.code.Anchors & (syntax.AnchorBeginning | syntax.AnchorStart | syntax.AnchorEndZ | syntax.AnchorEnd)) {
		if !.code.RightToLeft {
			if (0 != (.code.Anchors&syntax.AnchorBeginning) && .Runtextpos > 0) ||
				(0 != (.code.Anchors&syntax.AnchorStart) && .Runtextpos > .Runtextstart) {
				.Runtextpos = .Runtextend
				return false
			}
			if 0 != (.code.Anchors&syntax.AnchorEndZ) && .Runtextpos < .Runtextend-1 {
				.Runtextpos = .Runtextend - 1
			} else if 0 != (.code.Anchors&syntax.AnchorEnd) && .Runtextpos < .Runtextend {
				.Runtextpos = .Runtextend
			}
		} else {
			if (0 != (.code.Anchors&syntax.AnchorEnd) && .Runtextpos < .Runtextend) ||
				(0 != (.code.Anchors&syntax.AnchorEndZ) && (.Runtextpos < .Runtextend-1 ||
					(.Runtextpos == .Runtextend-1 && .charAt(.Runtextpos) != '\n'))) ||
				(0 != (.code.Anchors&syntax.AnchorStart) && .Runtextpos < .Runtextstart) {
				.Runtextpos = 0
				return false
			}
			if 0 != (.code.Anchors&syntax.AnchorBeginning) && .Runtextpos > 0 {
				.Runtextpos = 0
			}
		}

		if .code.BmPrefix != nil {
			return .code.BmPrefix.IsMatch(.Runtext, .Runtextpos, 0, .Runtextend)
		}

		return true // found a valid start or end anchor
	} else if .code.BmPrefix != nil {
		.Runtextpos = .code.BmPrefix.Scan(.Runtext, .Runtextpos, 0, .Runtextend)

		if .Runtextpos == -1 {
			if .code.RightToLeft {
				.Runtextpos = 0
			} else {
				.Runtextpos = .Runtextend
			}
			return false
		}

		return true
	}

	if shouldUseFindFirstCharOptimized() {
		if ,  := findFirstCharOptimized();  {
			return 
		}
	}

	if .code.FcPrefix == nil {
		return true
	}

	.rightToLeft = .code.RightToLeft
	.caseInsensitive = .code.FcPrefix.CaseInsensitive

	 := .code.FcPrefix.PrefixSet
	if .IsSingleton() {
		 := .SingletonChar()
		for  := .forwardchars();  > 0; -- {
			if  == .forwardcharnext() {
				.backwardnext()
				return true
			}
		}
	} else {
		for  := .forwardchars();  > 0; -- {
			 := .forwardcharnext()
			//fmt.Printf("%v in %v: %v\n", string(n), set.String(), set.CharIn(n))
			if .CharIn() {
				.backwardnext()
				return true
			}
		}
	}

	return false
}

func shouldUseFindFirstCharOptimized( *Runner) bool {
	if .code == nil || .code.FindOptimizations == nil {
		return false
	}

	 := .code.FindOptimizations
	switch .FindMode {
	case syntax.TrailingAnchor_FixedLength_LeftToRight_End,
		syntax.LeadingString_OrdinalIgnoreCase_LeftToRight,
		syntax.LeadingStrings_LeftToRight,
		syntax.LeadingStrings_OrdinalIgnoreCase_LeftToRight,
		syntax.FixedDistanceChar_LeftToRight,
		syntax.FixedDistanceString_LeftToRight,
		syntax.FixedDistanceSets_LeftToRight,
		syntax.LiteralAfterLoop_LeftToRight,
		syntax.RequiredLandmarkChain_LeftToRight:
		return true
	case syntax.LeadingSet_LeftToRight:
		// General Unicode sets already have a direct fallback loop below.
		// Large enumerated sets are also faster through the set's ASCII bitmap
		// than through the linear IndexOfAny helper.
		return len(.FixedDistanceSets) > 0 &&
			((len(.FixedDistanceSets[0].Chars) > 0 && len(.FixedDistanceSets[0].Chars) <= 5) ||
				.FixedDistanceSets[0].Range != nil)
	default:
		return false
	}
}

func findFirstCharOptimized( *Runner) ( bool,  bool) {
	if .code == nil || .code.FindOptimizations == nil {
		return false, false
	}

	 := .code.FindOptimizations
	switch .FindMode {
	case syntax.NoSearch:
		return false, false
	case syntax.TrailingAnchor_FixedLength_LeftToRight_End:
		return true, findTrailingFixedLengthEnd(, .MinRequiredLength)
	case syntax.LeadingString_LeftToRight:
		return true, findLeadingStringLeftToRight(, []rune(.LeadingPrefix), false)
	case syntax.LeadingString_OrdinalIgnoreCase_LeftToRight:
		return true, findLeadingStringLeftToRight(, []rune(.LeadingPrefix), true)
	case syntax.LeadingStrings_LeftToRight:
		return true, findLeadingStringsLeftToRight(, .LeadingPrefixesRunes, .LeadingPrefixFirstRunes, false)
	case syntax.LeadingStrings_OrdinalIgnoreCase_LeftToRight:
		return true, findLeadingStringsLeftToRight(, .LeadingPrefixesRunes, .LeadingPrefixFirstRunes, true)
	case syntax.LeadingSet_LeftToRight, syntax.FixedDistanceSets_LeftToRight:
		return true, findFixedDistanceSetsLeftToRight(, .FixedDistanceSets)
	case syntax.FixedDistanceChar_LeftToRight:
		return true, findFixedDistanceCharLeftToRight(, .FixedDistanceLiteral.C, .FixedDistanceLiteral.Distance)
	case syntax.FixedDistanceString_LeftToRight:
		return true, findFixedDistanceStringLeftToRight(, []rune(.FixedDistanceLiteral.S), .FixedDistanceLiteral.Distance)
	case syntax.LiteralAfterLoop_LeftToRight:
		return true, findLiteralAfterLoopLeftToRight(, .LiteralAfterLoop)
	case syntax.RequiredLandmarkChain_LeftToRight:
		return true, findRequiredLandmarkChainLeftToRight(, .LandmarkChain)
	default:
		return false, false
	}
}

func findTrailingFixedLengthEnd( *Runner,  int) bool {
	 := .Runtextend - 
	if  < .Runtextpos ||  < 0 {
		.Runtextpos = .Runtextend
		return false
	}
	.Runtextpos = 
	return true
}

func findLeadingStringLeftToRight( *Runner,  []rune,  bool) bool {
	if len() == 0 {
		return true
	}

	 := .Runtext[.Runtextpos:]
	var  int
	if  {
		if isASCIIRunes() {
			 = helpers.IndexOfIgnoreCaseAscii(, )
		} else {
			 = helpers.IndexOfIgnoreCase(, )
		}
	} else {
		 = helpers.IndexOf(, )
	}
	if  < 0 {
		.Runtextpos = .Runtextend
		return false
	}

	 := .Runtextpos + 
	if !hasRequiredLengthAt(, ) {
		.Runtextpos = .Runtextend
		return false
	}
	.Runtextpos = 
	return true
}

func findLeadingStringsLeftToRight( *Runner,  [][]rune,  []rune,  bool) bool {
	if len() == 0 {
		return false
	}

	// Unicode ordinal-ignore-case matching has more possible first-rune folds
	// than a small precomputed set can safely represent. Keep its conservative
	// position-by-position scan; the common case-sensitive path skips directly
	// between possible first runes.
	if  || len() == 0 {
		for  := .Runtextpos;  <= latestPossibleStart(); ++ {
			for ,  := range  {
				if  {
					if helpers.StartsWithIgnoreCase(.Runtext[:], ) {
						.Runtextpos = 
						return true
					}
				} else if helpers.StartsWith(.Runtext[:], ) {
					.Runtextpos = 
					return true
				}
			}
		}
		.Runtextpos = .Runtextend
		return false
	}

	 := min(latestPossibleStart(), .Runtextend-1)
	for  := .Runtextpos;  <= ; {
		 := indexOfAnyRunes(.Runtext[:+1], )
		if  < 0 {
			break
		}
		 :=  + 
		 := .Runtext[]
		for ,  := range  {
			if len() > 0 && [0] ==  && helpers.StartsWith(.Runtext[:], ) {
				.Runtextpos = 
				return true
			}
		}
		 =  + 1
	}

	.Runtextpos = .Runtextend
	return false
}

func indexOfAnyRunes(,  []rune) int {
	switch len() {
	case 0:
		return -1
	case 1:
		return helpers.IndexOfAny1(, [0])
	case 2:
		return helpers.IndexOfAny2(, [0], [1])
	case 3:
		return helpers.IndexOfAny3(, [0], [1], [2])
	default:
		return helpers.IndexOfAny(, )
	}
}

func findFixedDistanceCharLeftToRight( *Runner,  rune,  int) bool {
	 := .Runtextpos + 
	for  < .Runtextend {
		 := helpers.IndexOfAny1(.Runtext[:], )
		if  < 0 {
			.Runtextpos = .Runtextend
			return false
		}
		 :=  + 
		 :=  - 
		if  >= .Runtextpos && hasRequiredLengthAt(, ) {
			.Runtextpos = 
			return true
		}
		if  > latestPossibleStart() {
			break
		}
		 =  + 1
	}

	.Runtextpos = .Runtextend
	return false
}

func findFixedDistanceStringLeftToRight( *Runner,  []rune,  int) bool {
	if len() == 0 {
		return true
	}

	 := .Runtextpos + 
	for  <= .Runtextend-len() {
		 := helpers.IndexOf(.Runtext[:], )
		if  < 0 {
			.Runtextpos = .Runtextend
			return false
		}
		 :=  + 
		 :=  - 
		if  >= .Runtextpos && hasRequiredLengthAt(, ) {
			.Runtextpos = 
			return true
		}
		if  > latestPossibleStart() {
			break
		}
		 =  + 1
	}

	.Runtextpos = .Runtextend
	return false
}

func findFixedDistanceSetsLeftToRight( *Runner,  []syntax.FixedDistanceSet) bool {
	if len() == 0 || [0].Set == nil {
		return false
	}

	 := [0]
	 := .Runtextpos + .Distance
	for  < .Runtextend {
		 := indexOfSet(.Runtext[:], )
		if  < 0 {
			.Runtextpos = .Runtextend
			return false
		}

		 :=  + 
		 :=  - .Distance
		if  > latestPossibleStart() {
			break
		}
		if  >= .Runtextpos && hasRequiredLengthAt(, ) && fixedDistanceSetsMatchAt(, , ) {
			.Runtextpos = 
			return true
		}
		 =  + 1
	}

	.Runtextpos = .Runtextend
	return false
}

func findLiteralAfterLoopLeftToRight( *Runner,  *syntax.LiteralAfterLoop) bool {
	if  == nil || .LoopNode == nil || .LoopNode.Set == nil {
		return false
	}

	 := .Runtextpos
	for  < .Runtextend {
		 := indexOfLiteralAfterLoop(, , )
		if  < 0 {
			.Runtextpos = .Runtextend
			return false
		}

		 := 
		for  > .Runtextpos && .LoopNode.Set.CharIn(.Runtext[-1]) {
			--
		}
		if hasRequiredLengthAt(, ) {
			.Runtextpos = 
			return true
		}
		 =  + 1
	}

	.Runtextpos = .Runtextend
	return false
}

func findRequiredLandmarkChainLeftToRight( *Runner,  *syntax.RequiredLandmarkChain) bool {
	if  == nil || .LeadingLoopSet == nil || len(.Landmarks) == 0 {
		return false
	}

	for  := .Runtextpos;  <= latestPossibleStart(); {
		,  := findNextRequiredLandmarkRunes(.Runtext, , .Runtextend, .Landmarks[0])
		if ! {
			.Runtextpos = .Runtextend
			return false
		}

		 := .End
		for  := 1;  < len(.Landmarks); ++ {
			,  := findNextRequiredLandmarkRunes(.Runtext, , .Runtextend, .Landmarks[])
			if ! {
				.Runtextpos = .Runtextend
				return false
			}
			 = .End
		}

		 := .Start
		if  < .Runtextpos {
			 = .Runtextpos
		}
		for  > .Runtextpos && .LeadingLoopSet.CharIn(.Runtext[-1]) {
			--
		}
		if hasRequiredLengthAt(, ) {
			.Runtextpos = 
			return true
		}

		 = .CoreStart + 1
	}

	.Runtextpos = .Runtextend
	return false
}

type requiredLandmarkMatch struct {
	Start     int
	CoreStart int
	End       int
}

func findNextRequiredLandmarkRunes( []rune, ,  int,  syntax.RequiredLandmark) (requiredLandmarkMatch, bool) {
	for  := ;  < ; ++ {
		for ,  := range .Alternatives {
			if ,  := requiredLandmarkAlternativeMatch(, , , );  {
				return , true
			}
		}
	}
	return requiredLandmarkMatch{}, false
}

func requiredLandmarkAlternativeMatch( []rune, ,  int,  syntax.RequiredLandmarkAlternative) (requiredLandmarkMatch, bool) {
	if .RequireWhitespaceBefore &&
		( == 0 || .LeadingWhitespaceSet == nil || !.LeadingWhitespaceSet.CharIn([-1])) {
		return requiredLandmarkMatch{}, false
	}

	var  int
	if len(.Literal) > 0 {
		if +len(.Literal) >  || !helpers.StartsWith([:], .Literal) {
			return requiredLandmarkMatch{}, false
		}
		 =  + len(.Literal)
	} else if .Set != nil && .MinRepeat > 0 {
		 = 
		 := .MaxRepeat
		if  <= 0 {
			 = .MinRepeat
		}
		for  <  && - <  && .Set.CharIn([]) {
			++
		}
		if - < .MinRepeat {
			return requiredLandmarkMatch{}, false
		}
	} else {
		return requiredLandmarkMatch{}, false
	}

	if .RequireWhitespaceAfter &&
		( >=  || .TrailingWhitespaceSet == nil || !.TrailingWhitespaceSet.CharIn([])) {
		return requiredLandmarkMatch{}, false
	}

	 := 
	for  > 0 && .LeadingWhitespaceSet != nil && .LeadingWhitespaceSet.CharIn([-1]) {
		--
	}
	return requiredLandmarkMatch{Start: , CoreStart: , End: }, true
}

func indexOfLiteralAfterLoop( *Runner,  *syntax.LiteralAfterLoop,  int) int {
	switch {
	case .String != "":
		 := []rune(.String)
		if .StringIgnoreCase {
			var  int
			if isASCIIString(.String) {
				 = helpers.IndexOfIgnoreCaseAscii(.Runtext[:], )
			} else {
				 = helpers.IndexOfIgnoreCase(.Runtext[:], )
			}
			if  >= 0 {
				return  + 
			}
		} else if  := helpers.IndexOf(.Runtext[:], );  >= 0 {
			return  + 
		}
	case len(.Chars) > 0:
		if  := helpers.IndexOfAny(.Runtext[:], .Chars);  >= 0 {
			return  + 
		}
	default:
		if  := helpers.IndexOfAny1(.Runtext[:], .Char);  >= 0 {
			return  + 
		}
	}
	return -1
}

func isASCIIRunes( []rune) bool {
	for ,  := range  {
		if  > unicode.MaxASCII {
			return false
		}
	}
	return true
}

func indexOfSet( []rune,  syntax.FixedDistanceSet) int {
	if len(.Chars) > 0 && !.Negated {
		return helpers.IndexOfAny(, .Chars)
	}
	if len(.Chars) > 0 && .Negated {
		return helpers.IndexOfAnyExcept(, .Chars)
	}
	if .Range != nil {
		if .Negated {
			return helpers.IndexOfAnyExceptInRange(, .Range.First, .Range.Last)
		}
		return helpers.IndexOfAnyInRange(, .Range.First, .Range.Last)
	}
	return helpers.IndexFunc(, func( rune) bool {
		return charInFixedDistanceSet(, )
	})
}

func fixedDistanceSetsMatchAt( *Runner,  []syntax.FixedDistanceSet,  int) bool {
	for ,  := range  {
		 :=  + .Distance
		if  < 0 ||  >= .Runtextend || !charInFixedDistanceSet(, .Runtext[]) {
			return false
		}
	}
	return true
}

func charInFixedDistanceSet( syntax.FixedDistanceSet,  rune) bool {
	if len(.Chars) > 0 {
		 := slices.Contains(.Chars, )
		if .Negated {
			return !
		}
		return 
	}
	if .Range != nil {
		 :=  >= .Range.First &&  <= .Range.Last
		if .Negated {
			return !
		}
		return 
	}
	return .Set != nil && .Set.CharIn()
}

func latestPossibleStart( *Runner) int {
	if .code == nil || .code.FindOptimizations == nil {
		return .Runtextend
	}
	 := .code.FindOptimizations.MinRequiredLength
	if  <= 0 {
		return .Runtextend
	}
	return .Runtextend - 
}

func hasRequiredLengthAt( *Runner,  int) bool {
	return  >= 0 &&  <= latestPossibleStart()
}

func ( *Runner) ( *matchText) {
	// Use a hashtable'ed Match object if the capture numbers are sparse

	if .runmatch == nil {
		if .re.caps != nil {
			.runmatch = newMatchSparse(.re, .re.caps, .re.capsize, , .Runtextstart)
		} else {
			.runmatch = newMatch(.re, .re.capsize, , .Runtextstart)
		}
	} else {
		.runmatch.reset(, .Runtextstart)
	}

	// note we test runcrawl, because it is the last one to be allocated
	// If there is an alloc failure in the middle of the three allocations,
	// we may still return to reuse this instance, and we want to behave
	// as if the allocations didn't occur. (we used to test _trackcount != 0)

	if .runcrawl != nil {
		.Runtrackpos = len(.runtrack)
		.Runstackpos = len(.runstack)
		.runcrawlpos = len(.runcrawl)
		return
	}

	.initTrackCount()

	 := .runtrackcount * 8
	 := .runtrackcount * 8

	if  < 64 {
		 = 64
	}
	if  := .re.optimizations.MaxBacktrackingStackSize;  >= 0 &&  >  {
		 = 
	}
	if  < 32 {
		 = 32
	}

	.runtrack = make([]int, )
	.Runtrackpos = 

	.runstack = make([]int, )
	.Runstackpos = 

	.runcrawl = make([]int, 32)
	.runcrawlpos = 32
}

func ( *Runner) ( bool) *Match {
	if ! {
		 := .runmatch

		.runmatch = nil

		.tidy(.Runtextpos)
		return 
	} else {
		// send back our match -- it's not leaving the package, so it's safe to not clean it up
		// this reduces allocs for frequent calls to the "IsMatch" bool-only functions
		 := .runmatch
		if  == nil {
			return nil
		}
		.textpos = .Runtextpos
		if .matchcount[0] > 0 {
			 := .matches[0]
			// bytes indices aren't used so just use fast path
			.RuneIndex = [0]
			.RuneLength = [1]
		}
		return 
	}
}

// Capture captures a subexpression. Note that the
// capnum used here has already been mapped to a non-sparse
// index (by the code generator RegexWriter).
func ( *Runner) (, ,  int) {
	if  <  {
		 := 
		 = 
		 = 
	}

	.crawl()
	.runmatch.addMatch(, , -)
}

// transferCapture captures a subexpression. Note that the
// capnum used here has already been mapped to a non-sparse
// index (by the code generator RegexWriter).
func ( *Runner) (, , ,  int) {
	var ,  int

	// these are the two intervals that are cancelling each other

	if  <  {
		 := 
		 = 
		 = 
	}

	 = .runmatch.matchIndex()
	 =  + .runmatch.matchLength()

	// The new capture gets the innermost defined interval

	if  >=  {
		 = 
		 = 
	} else if  <=  {
		 = 
	} else {
		if  >  {
			 = 
		}
		if  >  {
			 = 
		}
	}

	.crawl()
	.runmatch.balanceMatch()

	if  != -1 {
		.crawl()
		.runmatch.addMatch(, , -)
	}
}

// revert the last capture
func ( *Runner) () {
	 := .popcrawl()
	.runmatch.removeMatch()
}

//debug

func ( *Runner) () {
	 := ""
	if .operator&syntax.Back != 0 {
		 = " Back"
	}
	if .operator&syntax.Back2 != 0 {
		 += " Back2"
	}
	fmt.Printf("Text:  %v\nTrack: %v\nStack: %v\n       %s%s\n\n",
		.textposDescription(),
		.stackDescription(.runtrack, .Runtrackpos),
		.stackDescription(.runstack, .Runstackpos),
		.code.OpcodeDescription(.codepos),
		)
}

func ( *Runner) ( []int,  int) string {
	 := &bytes.Buffer{}

	fmt.Fprintf(, "%v/%v", len()-, len())
	if .Len() < 8 {
		.WriteString(strings.Repeat(" ", 8-.Len()))
	}

	.WriteRune('(')
	for  := ;  < len(); ++ {
		if  >  {
			.WriteRune(' ')
		}

		.WriteString(strconv.Itoa([]))
	}

	.WriteRune(')')

	return .String()
}

func ( *Runner) () string {
	 := &bytes.Buffer{}

	.WriteString(strconv.Itoa(.Runtextpos))

	if .Len() < 8 {
		.WriteString(strings.Repeat(" ", 8-.Len()))
	}

	if .Runtextpos > 0 {
		.WriteString(syntax.CharDescription(.Runtext[.Runtextpos-1]))
	} else {
		.WriteRune('^')
	}

	.WriteRune('>')

	for  := .Runtextpos;  < .Runtextend; ++ {
		.WriteString(syntax.CharDescription(.Runtext[]))
	}
	if .Len() >= 64 {
		.Truncate(61)
		.WriteString("...")
	} else {
		.WriteRune('$')
	}

	return .String()
}

// decide whether the pos
// at the specified index is a boundary or not. It's just not worth
// emitting inline code for this logic.
func ( *Runner) ( int) bool {
	return ( > 0 && syntax.IsWordChar(.Runtext[-1])) !=
		( < .Runtextend && syntax.IsWordChar(.Runtext[]))
}

func ( *Runner) ( int) bool {
	return ( > 0 && syntax.IsECMAWordChar(.Runtext[-1])) !=
		( < .Runtextend && syntax.IsECMAWordChar(.Runtext[]))
}

func ( *Runner) () {
	if .ignoreTimeout {
		return
	}
	.deadline = makeDeadline(.timeout)
}

func ( *Runner) () error {
	if .ignoreTimeout || !.deadline.reached() {
		return nil
	}

	return fmt.Errorf("match timeout after %v on input `%v`", .timeout, string(.Runtext))
}

func ( *Runner) () {
	if .code != nil {
		.runtrackcount = .code.TrackCount
	}
}

// decodeString converts s to []rune using a shared size-classed buffer pool when
// allowed by the regexp optimization settings. Pooled slices must be returned
// after the runner is done with them.
func ( *Runner) ( string) ([]rune, *[]rune) {
	,  := pooledRuneBuffers.get(len(), .re.optimizations.MaxCachedRuneBufferLength)
	 := 0
	for ,  := range  {
		[] = 
		++
	}
	return [:], 
}

func ( *Runner) ( string,  int) ( []rune,  int,  *[]rune) {
	,  := pooledRuneBuffers.get(len(), .re.optimizations.MaxCachedRuneBufferLength)
	 := 0
	 = -1
	for ,  := range  {
		if  >= 0 &&  ==  {
			 = 
		}
		[] = 
		++
	}
	if  >= 0 &&  == len() {
		 = 
	}
	return [:], , 
}

// getRunner returns a runner to use for matching re.
func ( *Regexp) () *Runner {
	if .runnerPool == nil {
		.initCaches()
	}
	return .runnerPool.Get().(*Runner)
}

// putRunner returns a runner to the re's pool cache.
func ( *Regexp) ( *Runner) {
	.Runtext = nil
	.code = .code
	if .runmatch != nil {
		.runmatch.text = nil
	}
	.runnerPool.Put()
}

func ( *Runner) ( int,  int,  rune) int {
	for  :=  - 1;  >= ; -- {
		if .Runtext[] ==  {
			return 
		}
	}
	return -1
}

// Undo captures until it reaches the specified capture position
func ( *Runner) ( int) {
	for .Crawlpos() >  {
		.uncapture()
	}
}

func ( *Runner) () int {
	//get it
	 := .runstack[.Runstackpos]
	// pop it
	.Runstackpos++
	// return it
	return 
}

// StackDepth returns the number of integer slots currently used by the
// generated engine's backtracking stack.
func ( *Runner) () int {
	return len(.runstack) - .Runstackpos
}

func ( *Runner) ( int) {
	// check if we need to size up stack
	.ensureStack(1)
	.Runstackpos--
	.runstack[.Runstackpos] = 
}
func ( *Runner) (,  int) {
	// check if we need to size up stack
	.ensureStack(2)
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
}
func ( *Runner) (, ,  int) {
	// check if we need to size up stack
	.ensureStack(3)
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
}
func ( *Runner) (, , ,  int) {
	// check if we need to size up stack
	.ensureStack(4)
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
}
func ( *Runner) (, , , ,  int) {
	// check if we need to size up stack
	.ensureStack(5)
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
	.Runstackpos--
	.runstack[.Runstackpos] = 
}
func ( *Runner) ( ...int) {
	// check if we need to size up stack
	.ensureStack(len())
	for ,  := range  {
		.Runstackpos--
		.runstack[.Runstackpos] = 
	}
}
func ( *Runner) ( int) bool {
	return .runmatch.isMatched()
}
func ( *Runner) ( int) int {
	return .runmatch.matchLength()
}
func ( *Runner) ( int) int {
	return .runmatch.matchIndex()
}