package syntax

import (
	
	
	
	
)

func ( *RegexTree) (*Code, error) {
	 := writer{
		intStack:   make([]int, 0, 32),
		emitted:    make([]int, 2),
		stringhash: make(map[string]int),
		sethash:    make(map[string]int),
	}

	,  := .codeFromTree()

	if .options&Debug > 0 &&  != nil {
		os.Stdout.WriteString(.Dump())
		os.Stdout.WriteString("\n")
	}

	return , 
}

type writer struct {
	emitted []int

	intStack    []int
	curpos      int
	stringhash  map[string]int
	stringtable [][]rune
	sethash     map[string]int
	settable    []*CharSet
	counting    bool
	count       int
	trackcount  int
	caps        map[int]int
}

const (
	beforeChild nodeType = 64
	afterChild           = 128
	//MaxPrefixSize is the largest number of runes we'll use for a BoyerMoyer prefix
	MaxPrefixSize = 50
)

// The top level RegexCode generator. It does a depth-first walk
// through the tree and calls EmitFragment to emits code before
// and after each child of an interior node, and at each leaf.
//
// It runs two passes, first to count the size of the generated
// code, and second to generate the code.
//
// We should time it against the alternative, which is
// to just generate the code and grow the array as we go.
func ( *writer) ( *RegexTree) (*Code, error) {
	var (
		  *regexNode
		 int
		  int
	)
	// construct sparse capnum mapping if some numbers are unused

	if .capnumlist == nil || .captop == len(.capnumlist) {
		 = .captop
		.caps = nil
	} else {
		 = len(.capnumlist)
		.caps = .caps
		for  := 0;  < len(.capnumlist); ++ {
			.caps[.capnumlist[]] = 
		}
	}

	.counting = true

	for {
		if !.counting {
			.emitted = make([]int, .count)
		}

		 = .root
		 = 0

		.emit1(Lazybranch, 0)

		for {
			if len(.children) == 0 {
				.emitFragment(.t, , 0)
			} else if  < len(.children) {
				.emitFragment(.t|beforeChild, , )

				 = .children[]

				.pushInt()
				 = 0
				continue
			}

			if .emptyStack() {
				break
			}

			 = .popInt()
			 = .next

			.emitFragment(.t|afterChild, , )
			++
		}

		.patchJump(0, .curPos())
		.emit(Stop)

		if !.counting {
			break
		}

		.counting = false
	}

	 := getFirstCharsPrefix()
	 := getPrefix()
	 := (.options & RightToLeft) != 0

	var  *BmPrefix
	//TODO: benchmark string prefixes
	if  != nil && len(.PrefixStr) > 0 && MaxPrefixSize > 0 {
		if len(.PrefixStr) > MaxPrefixSize {
			// limit prefix changes to 10k
			.PrefixStr = .PrefixStr[:MaxPrefixSize]
		}
		 = newBmPrefix(.PrefixStr, .CaseInsensitive, )
	} else {
		 = nil
	}

	return &Code{
		Codes:       .emitted,
		Strings:     .stringtable,
		Sets:        .settable,
		TrackCount:  .trackcount,
		Caps:        .caps,
		Capsize:     ,
		FcPrefix:    ,
		BmPrefix:    ,
		Anchors:     getAnchors(),
		RightToLeft: ,
	}, nil
}

// The main RegexCode generator. It does a depth-first walk
// through the tree and calls EmitFragment to emits code before
// and after each child of an interior node, and at each leaf.
func ( *writer) ( nodeType,  *regexNode,  int) error {
	 := InstOp(0)

	if  <= ntRef {
		if (.options & RightToLeft) != 0 {
			 |= Rtl
		}
		if (.options & IgnoreCase) != 0 {
			 |= Ci
		}
	}
	 := nodeType()

	switch  {
	case ntConcatenate | beforeChild, ntConcatenate | afterChild, ntEmpty:
		break

	case ntAlternate | beforeChild:
		if  < len(.children)-1 {
			.pushInt(.curPos())
			.emit1(Lazybranch, 0)
		}

	case ntAlternate | afterChild:
		if  < len(.children)-1 {
			 := .popInt()
			.pushInt(.curPos())
			.emit1(Goto, 0)
			.patchJump(, .curPos())
		} else {
			for  := 0;  < ; ++ {
				.patchJump(.popInt(), .curPos())
			}
		}
		break

	case ntTestref | beforeChild:
		if  == 0 {
			.emit(Setjump)
			.pushInt(.curPos())
			.emit1(Lazybranch, 0)
			.emit1(Testref, .mapCapnum(.m))
			.emit(Forejump)
		}

	case ntTestref | afterChild:
		if  == 0 {
			 := .popInt()
			.pushInt(.curPos())
			.emit1(Goto, 0)
			.patchJump(, .curPos())
			.emit(Forejump)
			if len(.children) <= 1 {
				.patchJump(.popInt(), .curPos())
			}
		} else if  == 1 {
			.patchJump(.popInt(), .curPos())
		}

	case ntTestgroup | beforeChild:
		if  == 0 {
			.emit(Setjump)
			.emit(Setmark)
			.pushInt(.curPos())
			.emit1(Lazybranch, 0)
		}

	case ntTestgroup | afterChild:
		if  == 0 {
			.emit(Getmark)
			.emit(Forejump)
		} else if  == 1 {
			 := .popInt()
			.pushInt(.curPos())
			.emit1(Goto, 0)
			.patchJump(, .curPos())
			.emit(Getmark)
			.emit(Forejump)
			if len(.children) <= 2 {
				.patchJump(.popInt(), .curPos())
			}
		} else if  == 2 {
			.patchJump(.popInt(), .curPos())
		}

	case ntLoop | beforeChild, ntLazyloop | beforeChild:

		if .n < math.MaxInt32 || .m > 1 {
			if .m == 0 {
				.emit1(Nullcount, 0)
			} else {
				.emit1(Setcount, 1-.m)
			}
		} else if .m == 0 {
			.emit(Nullmark)
		} else {
			.emit(Setmark)
		}

		if .m == 0 {
			.pushInt(.curPos())
			.emit1(Goto, 0)
		}
		.pushInt(.curPos())

	case ntLoop | afterChild, ntLazyloop | afterChild:

		 := .curPos()
		 := ( - (ntLoop | afterChild))

		if .n < math.MaxInt32 || .m > 1 {
			if .n == math.MaxInt32 {
				.emit2(InstOp(Branchcount+), .popInt(), math.MaxInt32)
			} else {
				.emit2(InstOp(Branchcount+), .popInt(), .n-.m)
			}
		} else {
			.emit1(InstOp(Branchmark+), .popInt())
		}

		if .m == 0 {
			.patchJump(.popInt(), )
		}

	case ntGroup | beforeChild, ntGroup | afterChild:

	case ntCapture | beforeChild:
		.emit(Setmark)

	case ntCapture | afterChild:
		.emit2(Capturemark, .mapCapnum(.m), .mapCapnum(.n))

	case ntRequire | beforeChild:
		// NOTE: the following line causes lookahead/lookbehind to be
		// NON-BACKTRACKING. It can be commented out with (*)
		.emit(Setjump)

		.emit(Setmark)

	case ntRequire | afterChild:
		.emit(Getmark)

		// NOTE: the following line causes lookahead/lookbehind to be
		// NON-BACKTRACKING. It can be commented out with (*)
		.emit(Forejump)

	case ntPrevent | beforeChild:
		.emit(Setjump)
		.pushInt(.curPos())
		.emit1(Lazybranch, 0)

	case ntPrevent | afterChild:
		.emit(Backjump)
		.patchJump(.popInt(), .curPos())
		.emit(Forejump)

	case ntGreedy | beforeChild:
		.emit(Setjump)

	case ntGreedy | afterChild:
		.emit(Forejump)

	case ntOne, ntNotone:
		.emit1(InstOp(.t|), int(.ch))

	case ntNotoneloop, ntNotonelazy, ntOneloop, ntOnelazy:
		if .m > 0 {
			if .t == ntOneloop || .t == ntOnelazy {
				.emit2(Onerep|, int(.ch), .m)
			} else {
				.emit2(Notonerep|, int(.ch), .m)
			}
		}
		if .n > .m {
			if .n == math.MaxInt32 {
				.emit2(InstOp(.t|), int(.ch), math.MaxInt32)
			} else {
				.emit2(InstOp(.t|), int(.ch), .n-.m)
			}
		}

	case ntSetloop, ntSetlazy:
		if .m > 0 {
			.emit2(Setrep|, .setCode(.set), .m)
		}
		if .n > .m {
			if .n == math.MaxInt32 {
				.emit2(InstOp(.t|), .setCode(.set), math.MaxInt32)
			} else {
				.emit2(InstOp(.t|), .setCode(.set), .n-.m)
			}
		}

	case ntMulti:
		.emit1(InstOp(.t|), .stringCode(.str))

	case ntSet:
		.emit1(InstOp(.t|), .setCode(.set))

	case ntRef:
		.emit1(InstOp(.t|), .mapCapnum(.m))

	case ntNothing, ntBol, ntEol, ntBoundary, ntNonboundary, ntECMABoundary, ntNonECMABoundary, ntBeginning, ntStart, ntEndZ, ntEnd:
		.emit(InstOp(.t))

	default:
		return fmt.Errorf("unexpected opcode in regular expression generation: %v", )
	}

	return nil
}

// To avoid recursion, we use a simple integer stack.
// This is the push.
func ( *writer) ( int) {
	.intStack = append(.intStack, )
}

// Returns true if the stack is empty.
func ( *writer) () bool {
	return len(.intStack) == 0
}

// This is the pop.
func ( *writer) () int {
	//get our item
	 := len(.intStack) - 1
	 := .intStack[]
	//trim our slice
	.intStack = .intStack[:]
	return 
}

// Returns the current position in the emitted code.
func ( *writer) () int {
	return .curpos
}

// Fixes up a jump instruction at the specified offset
// so that it jumps to the specified jumpDest.
func ( *writer) (,  int) {
	.emitted[+1] = 
}

// Returns an index in the set table for a charset
// uses a map to eliminate duplicates.
func ( *writer) ( *CharSet) int {
	if .counting {
		return 0
	}

	 := &bytes.Buffer{}

	.mapHashFill()
	 := .String()
	,  := .sethash[]
	if ! {
		 = len(.sethash)
		.sethash[] = 
		.settable = append(.settable, )
	}
	return 
}

// Returns an index in the string table for a string.
// uses a map to eliminate duplicates.
func ( *writer) ( []rune) int {
	if .counting {
		return 0
	}

	 := string()
	,  := .stringhash[]
	if ! {
		 = len(.stringhash)
		.stringhash[] = 
		.stringtable = append(.stringtable, )
	}

	return 
}

// When generating code on a regex that uses a sparse set
// of capture slots, we hash them to a dense set of indices
// for an array of capture slots. Instead of doing the hash
// at match time, it's done at compile time, here.
func ( *writer) ( int) int {
	if  == -1 {
		return -1
	}

	if .caps != nil {
		return .caps[]
	}

	return 
}

// Emits a zero-argument operation. Note that the emit
// functions all run in two modes: they can emit code, or
// they can just count the size of the code.
func ( *writer) ( InstOp) {
	if .counting {
		.count++
		if opcodeBacktracks() {
			.trackcount++
		}
		return
	}
	.emitted[.curpos] = int()
	.curpos++
}

// Emits a one-argument operation.
func ( *writer) ( InstOp,  int) {
	if .counting {
		.count += 2
		if opcodeBacktracks() {
			.trackcount++
		}
		return
	}
	.emitted[.curpos] = int()
	.curpos++
	.emitted[.curpos] = 
	.curpos++
}

// Emits a two-argument operation.
func ( *writer) ( InstOp, ,  int) {
	if .counting {
		.count += 3
		if opcodeBacktracks() {
			.trackcount++
		}
		return
	}
	.emitted[.curpos] = int()
	.curpos++
	.emitted[.curpos] = 
	.curpos++
	.emitted[.curpos] = 
	.curpos++
}