package regexp2

import (
	
	
	
	
	
	
	
	

	
)

type runner struct {
	re   *Regexp
	code *syntax.Code

	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
// input is the string to search for our regex pattern
func ( *Regexp) ( bool,  int,  []rune) (*Match, error) {

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

	if  < 0 {
		if .RightToLeft() {
			 = len()
		} else {
			 = 0
		}
	}

	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.
func ( *runner) ( []rune,  int,  bool,  time.Duration) (*Match, error) {
	.timeout = 
	.ignoreTimeout = (time.Duration(math.MaxInt64) == )
	.runtextstart = 
	.runtext = 
	.runtextend = len()

	 := .runtextend
	 := 1

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

	.runtextpos = 
	 := false

	.startTimeoutWatch()
	for {
		if .re.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 .findFirstChar() {
			if  := .checkTimeout();  != nil {
				return nil, 
			}

			if ! {
				.initMatch()
				 = true
			}

			if .re.Debug() {
				fmt.Printf("Executing engine starting at %v\n\n", .runtextpos)
			}

			if  := .execute();  != 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 ( *runner) () error {

	.goTo(0)

	for {

		if .re.Debug() {
			.dumpState()
		}

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

		switch .operator {
		case syntax.Stop:
			return nil

		case syntax.Nothing:
			break

		case syntax.Goto:
			.goTo(.operand(0))
			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())
			.goTo(.operand(0))
			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()
			break

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

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

		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()
			}

			break

		case syntax.Branchmark:
			.stackPop()

			 := .textPos() - .stackPeek()

			if  != 0 { // Nonempty match -> loop now
				.trackPush2(.stackPeek(), .textPos()) // Save old mark, textpos
				.stackPush(.textPos())                 // Make new mark
				.goTo(.operand(0))                     // Loop
			} 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
			break                      // 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.  In this case, we need to push something on the stack, since back2 pops.
					// However, in the case of ()+? or similar, this empty match may be legitimate, so push the text
					// position associated with that empty match.
					.stackPush()

					.trackPushNeg1(.stackPeek()) // Save old mark
				}
				.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)
			.trackPushNeg1(.trackPeek()) // Save old mark
			.stackPush()               // Make new mark
			.textto()                  // Recall position
			.goTo(.operand(0))           // Loop
			continue

		case syntax.Lazybranchmark | syntax.Back2:
			// The lazy loop has failed.  We'll do a true backtrack and
			// start over before the lazy loop.
			.stackPop()
			.trackPop()
			.stackPush(.trackPeek()) // Recall old mark
			break

		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)
			break

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

		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
				.goTo(.operand(0))               // Loop
			}
			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
			break

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

		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
				.goTo(.operand(0))               // Loop
			} 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
				.goTo(.operand(0))                     // Loop
				continue
			} else { // Max loops or empty match -> backtrack
				.stackPush2(.trackPeek(), .trackPeekN(1)) // Recall old mark, count
				break                                        // 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
			break                                          // Backtrack

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

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

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

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

			break

		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()
			}

			break

		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(), 0, .runtextend) {
				break
			}
			.advance(0)
			continue

		case syntax.Nonboundary:
			if .isBoundary(.textPos(), 0, .runtextend) {
				break
			}
			.advance(0)
			continue

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

		case syntax.NonECMABoundary:
			if .isECMABoundary(.textPos(), 0, .runtextend) {
				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.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:

			 := .operand(1)

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

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

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

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

			.advance(2)
			continue

		case syntax.Notoneloop:

			 := .operand(1)

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

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

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

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

			.advance(2)
			continue

		case syntax.Setloop:

			 := .operand(1)

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

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

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

			if  >  {
				.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

		default:
			return errors.New("unknown state in regex runner")
		}

	:
		;

		// "break Backward" comes here:
		.backtrack()
	}
}

// increase the size of stack and track storage
func ( *runner) () {
	if .runstackpos < .runtrackcount*4 {
		doubleIntSlice(&.runstack, &.runstackpos)
	}
	if .runtrackpos < .runtrackcount*4 {
		doubleIntSlice(&.runtrack, &.runtrackpos)
	}
}

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) {
	// when branching backward or in place, ensure storage
	if  <= .codepos {
		.ensureStorage()
	}

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

func ( *runner) ( int) {
	.runtextpos = 
}

func ( *runner) ( int) {
	.runtrackpos = len(.runtrack) - 
}

func ( *runner) () int {
	return .runtextstart
}

func ( *runner) () int {
	return .runtextpos
}

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

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) () {
	 := .runtrack[.runtrackpos]
	.runtrackpos++

	if .re.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[] | syntax.Back2)
	} else {
		.setOperator(.code.Codes[] | syntax.Back)
	}

	// When branching backward, ensure storage
	if  < .codepos {
		.ensureStorage()
	}

	.codepos = 
}

func ( *runner) ( int) {
	.caseInsensitive = (0 != ( & syntax.Ci))
	.rightToLeft = (0 != ( & syntax.Rtl))
	.operator = syntax.InstOp( & ^(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++
	}

	if .caseInsensitive {
		return unicode.ToLower()
	}
	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 ( *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
	} else 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 ( *runner) () {
	// 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, .runtext, .runtextstart)
		} else {
			.runmatch = newMatch(.re, .re.capsize, .runtext, .runtextstart)
		}
	} else {
		.runmatch.reset(.runtext, .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  < 32 {
		 = 32
	}
	if  < 16 {
		 = 16
	}

	.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
		return .runmatch
	}
}

// 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 ( >  && syntax.IsWordChar(.runtext[-1])) !=
		( <  && syntax.IsWordChar(.runtext[]))
}

func ( *runner) (, ,  int) bool {
	return ( >  && syntax.IsECMAWordChar(.runtext[-1])) !=
		( <  && syntax.IsECMAWordChar(.runtext[]))
}

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

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

	if .re.Debug() {
		//Debug.WriteLine("")
		//Debug.WriteLine("RegEx match timeout occurred!")
		//Debug.WriteLine("Specified timeout:       " + TimeSpan.FromMilliseconds(_timeout).ToString())
		//Debug.WriteLine("Timeout check frequency: " + TimeoutCheckFrequency)
		//Debug.WriteLine("Search pattern:          " + _runregex._pattern)
		//Debug.WriteLine("Input:                   " + r.runtext)
		//Debug.WriteLine("About to throw RegexMatchTimeoutException.")
	}

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

func ( *runner) () {
	.runtrackcount = .code.TrackCount
}

// getRunner returns a run to use for matching re.
// It uses the re's runner cache if possible, to avoid
// unnecessary allocation.
func ( *Regexp) () *runner {
	.muRun.Lock()
	if  := len(.runner);  > 0 {
		 := .runner[-1]
		.runner = .runner[:-1]
		.muRun.Unlock()
		return 
	}
	.muRun.Unlock()
	 := &runner{
		re:   ,
		code: .code,
	}
	return 
}

// putRunner returns a runner to the re's cache.
// There is no attempt to limit the size of the cache, so it will
// grow to the maximum number of simultaneous matches
// run using re.  (The cache empties when re gets garbage collected.)
func ( *Regexp) ( *runner) {
	.muRun.Lock()
	.runtext = nil
	if .runmatch != nil {
		.runmatch.text = nil
	}
	.runner = append(.runner, )
	.muRun.Unlock()
}