package syntax

import (
	
	
	
	
)

type FindOptimizations struct {
	rightToLeft  bool
	asciiLookups [][]uint

	FindMode                FindNextStartingPositionMode
	LeadingAnchor           NodeType
	TrailingAnchor          NodeType
	MinRequiredLength       int
	MaxPossibleLength       int
	LeadingPrefix           string
	LeadingPrefixes         []string
	LeadingPrefixesRunes    [][]rune
	//LeadingStrings    *helpers.StringSearchValues

	FixedDistanceLiteral FixedDistanceLiteral
	FixedDistanceSets    []FixedDistanceSet
	LiteralAfterLoop     *LiteralAfterLoop
	LandmarkChain        *RequiredLandmarkChain
	LeadingPrefixFirstRunes []rune
}

type LiteralAfterLoop struct {
	String           string
	StringIgnoreCase bool
	Char             rune
	Chars            []rune

	LoopNode *RegexNode
}

type FixedDistanceSet struct {
	Set      *CharSet
	Chars    []rune
	Negated  bool
	Range    *SingleRange
	Distance int
}

type FixedDistanceLiteral struct {
	S        string
	C        rune
	Distance int
}

type RequiredLandmarkChain struct {
	// LeadingLoopSet is the unbounded leading set loop that precedes every
	// landmark in the original concatenation. At run time, after the first
	// landmark alternative is found, the scanner walks backward over this set
	// to recover the earliest plausible regex start position.
	LeadingLoopSet *CharSet

	// Landmarks must all be found, in slice order, for the chain prefilter to
	// produce a candidate. Each landmark is satisfied by exactly one matching
	// alternative; alternatives are tried independently by the runner.
	Landmarks []RequiredLandmark
}

type RequiredLandmark struct {
	// Alternatives describes the mutually exclusive shapes that can satisfy
	// this single required landmark. A landmark matches when any one alternative
	// matches at a position in the input.
	Alternatives []RequiredLandmarkAlternative
}

type RequiredLandmarkAlternative struct {
	// Literal is the core token for literal alternatives. When non-empty, it
	// must match exactly at the candidate core position, and Set must be nil.
	Literal []rune

	// Set is the core token for character-class alternatives. When non-nil, it
	// must match between MinRepeat and MaxRepeat runes at the candidate core
	// position, and Literal must be empty. The analyzer only builds set
	// alternatives for non-negated sets that can be cheaply enumerated, but the
	// runner uses Set for membership checks.
	Set *CharSet

	// LeadingWhitespaceSet is the optional or required whitespace immediately
	// before the core token. If RequireWhitespaceBefore is true, at least one
	// rune from this set must precede the core. When this alternative is the
	// first matched landmark, the runner may rewind over additional contiguous
	// leading whitespace from this set before rewinding over LeadingLoopSet.
	LeadingWhitespaceSet *CharSet

	// TrailingWhitespaceSet is the optional or required whitespace immediately
	// after the core token. If RequireWhitespaceAfter is true, at least one rune
	// from this set must follow the core. The runner validates the requirement,
	// but does not consume optional trailing whitespace into the landmark end.
	TrailingWhitespaceSet *CharSet

	// MinRepeat and MaxRepeat describe the core token width. Literal alternatives
	// use 1..1 regardless of literal length because the literal is matched as one
	// fixed core token; Set alternatives use the source set repetition.
	MinRepeat int
	MaxRepeat int

	RequireWhitespaceBefore bool
	RequireWhitespaceAfter  bool
}

type FindNextStartingPositionMode int

const (
	NoSearch FindNextStartingPositionMode = iota
	// A "beginning" anchor at the beginning of the pattern.
	LeadingAnchor_LeftToRight_Beginning
	// A "start" anchor at the beginning of the pattern.
	LeadingAnchor_LeftToRight_Start
	// An "endz" anchor at the beginning of the pattern.  This is rare.
	LeadingAnchor_LeftToRight_EndZ
	// An "end" anchor at the beginning of the pattern.  This is rare.
	LeadingAnchor_LeftToRight_End
	// A "beginning" anchor at the beginning of the right-to-left pattern.
	LeadingAnchor_RightToLeft_Beginning
	// A "start" anchor at the beginning of the right-to-left pattern.
	LeadingAnchor_RightToLeft_Start
	// An "endz" anchor at the beginning of the right-to-left pattern.  This is rare.
	LeadingAnchor_RightToLeft_EndZ
	// An "end" anchor at the beginning of the right-to-left pattern.  This is rare.
	LeadingAnchor_RightToLeft_End
	// An "end" anchor at the end of the pattern, with the pattern always matching a fixed-length expression.
	TrailingAnchor_FixedLength_LeftToRight_End
	// An "endz" anchor at the end of the pattern, with the pattern always matching a fixed-length expression.
	TrailingAnchor_FixedLength_LeftToRight_EndZ
	// A multi-character substring at the beginning of the pattern.
	LeadingString_LeftToRight
	// A multi-character substring at the beginning of the right-to-left pattern.
	LeadingString_RightToLeft
	// A multi-character ordinal case-insensitive substring at the beginning of the pattern.
	LeadingString_OrdinalIgnoreCase_LeftToRight
	// Multiple leading prefix strings
	LeadingStrings_LeftToRight
	// Multiple leading ordinal case-insensitive prefix strings
	LeadingStrings_OrdinalIgnoreCase_LeftToRight

	// A set starting the pattern.
	LeadingSet_LeftToRight
	// A set starting the right-to-left pattern.
	LeadingSet_RightToLeft

	// A single character at the start of the right-to-left pattern.
	LeadingChar_RightToLeft

	// A single character at a fixed distance from the start of the pattern.
	FixedDistanceChar_LeftToRight
	// A multi-character case-sensitive string at a fixed distance from the start of the pattern.
	FixedDistanceString_LeftToRight

	// One or more sets at a fixed distance from the start of the pattern.
	FixedDistanceSets_LeftToRight

	// A literal (single character, multi-char string, or set with small number of characters) after a non-overlapping set loop at the start of the pattern.
	LiteralAfterLoop_LeftToRight

	// A sequence of required landmarks after a leading loop.
	RequiredLandmarkChain_LeftToRight
)

func ( FindNextStartingPositionMode) () string {
	switch  {
	case NoSearch:
		return "NoSearch"
	case LeadingAnchor_LeftToRight_Beginning:
		return "LeadingAnchor_LeftToRight_Beginning"
	case LeadingAnchor_LeftToRight_Start:
		return "LeadingAnchor_LeftToRight_Start"
	case LeadingAnchor_LeftToRight_EndZ:
		return "LeadingAnchor_LeftToRight_EndZ"
	case LeadingAnchor_LeftToRight_End:
		return "LeadingAnchor_LeftToRight_End"
	case LeadingAnchor_RightToLeft_Beginning:
		return "LeadingAnchor_RightToLeft_Beginning"
	case LeadingAnchor_RightToLeft_Start:
		return "LeadingAnchor_RightToLeft_Start"
	case LeadingAnchor_RightToLeft_EndZ:
		return "LeadingAnchor_RightToLeft_EndZ"
	case LeadingAnchor_RightToLeft_End:
		return "LeadingAnchor_RightToLeft_End"
	case TrailingAnchor_FixedLength_LeftToRight_End:
		return "TrailingAnchor_FixedLength_LeftToRight_End"
	case TrailingAnchor_FixedLength_LeftToRight_EndZ:
		return "TrailingAnchor_FixedLength_LeftToRight_EndZ"
	case LeadingString_LeftToRight:
		return "LeadingString_LeftToRight"
	case LeadingString_RightToLeft:
		return "LeadingString_RightToLeft"
	case LeadingString_OrdinalIgnoreCase_LeftToRight:
		return "LeadingString_OrdinalIgnoreCase_LeftToRight"
	case LeadingStrings_LeftToRight:
		return "LeadingStrings_LeftToRight"
	case LeadingStrings_OrdinalIgnoreCase_LeftToRight:
		return "LeadingStrings_OrdinalIgnoreCase_LeftToRight"
	case LeadingSet_LeftToRight:
		return "LeadingSet_LeftToRight"
	case LeadingSet_RightToLeft:
		return "LeadingSet_RightToLeft"
	case LeadingChar_RightToLeft:
		return "LeadingChar_RightToLeft"
	case FixedDistanceChar_LeftToRight:
		return "FixedDistanceChar_LeftToRight"
	case FixedDistanceString_LeftToRight:
		return "FixedDistanceString_LeftToRight"
	case FixedDistanceSets_LeftToRight:
		return "FixedDistanceSets_LeftToRight"
	case LiteralAfterLoop_LeftToRight:
		return "LiteralAfterLoop_LeftToRight"
	case RequiredLandmarkChain_LeftToRight:
		return "RequiredLandmarkChain_LeftToRight"
	default:
		return fmt.Sprintf("FindNextStartingPositionMode(%d)", int())
	}
}

func ( *FindOptimizations) () string {
	 := &bytes.Buffer{}
	if  == nil {
		fmt.Fprintln(, "Find mode:  n/a")
		return .String()
	}

	fmt.Fprintf(, "Find mode:  %s\n", .FindMode)
	fmt.Fprintf(, "Min length: %d\n", .MinRequiredLength)
	if .MaxPossibleLength > 0 {
		fmt.Fprintf(, "Max length: %d\n", .MaxPossibleLength)
	}

	switch .FindMode {
	case LeadingAnchor_LeftToRight_Beginning, LeadingAnchor_LeftToRight_Start,
		LeadingAnchor_LeftToRight_EndZ, LeadingAnchor_LeftToRight_End,
		LeadingAnchor_RightToLeft_Beginning, LeadingAnchor_RightToLeft_Start,
		LeadingAnchor_RightToLeft_EndZ, LeadingAnchor_RightToLeft_End:
		fmt.Fprintf(, "Anchor:     %v\n", .LeadingAnchor)

	case TrailingAnchor_FixedLength_LeftToRight_End, TrailingAnchor_FixedLength_LeftToRight_EndZ:
		fmt.Fprintf(, "Anchor:     %v\n", .TrailingAnchor)

	case LeadingString_LeftToRight, LeadingString_RightToLeft, LeadingString_OrdinalIgnoreCase_LeftToRight:
		fmt.Fprintf(, "Prefix:     %q\n", .LeadingPrefix)

	case LeadingStrings_LeftToRight, LeadingStrings_OrdinalIgnoreCase_LeftToRight:
		fmt.Fprintf(, "Prefixes:   %q\n", .LeadingPrefixes)

	case FixedDistanceChar_LeftToRight:
		fmt.Fprintf(, "Literal:    %q at distance %d\n", .FixedDistanceLiteral.C, .FixedDistanceLiteral.Distance)

	case FixedDistanceString_LeftToRight:
		fmt.Fprintf(, "Literal:    %q at distance %d\n", .FixedDistanceLiteral.S, .FixedDistanceLiteral.Distance)

	case FixedDistanceSets_LeftToRight:
		for ,  := range .FixedDistanceSets {
			fmt.Fprintf(, "Set[%d]:     distance=%d %s\n", , .Distance, fixedDistanceSetDescription())
		}

	case LiteralAfterLoop_LeftToRight:
		fmt.Fprintf(, "Literal:    %s\n", literalAfterLoopDescription(.LiteralAfterLoop))

	case RequiredLandmarkChain_LeftToRight:
		fmt.Fprintf(, "Landmarks:  %s\n", landmarkChainDescription(.LandmarkChain))
	}

	return .String()
}

func fixedDistanceSetDescription( FixedDistanceSet) string {
	switch {
	case len(.Chars) > 0:
		return fmt.Sprintf("chars=%q negated=%t", string(.Chars), .Negated)
	case .Range != nil:
		return fmt.Sprintf("range=%q-%q negated=%t", .Range.First, .Range.Last, .Negated)
	case .Set != nil:
		return fmt.Sprintf("set=%s", .Set.String())
	default:
		return "set=<nil>"
	}
}

func literalAfterLoopDescription( *LiteralAfterLoop) string {
	if  == nil {
		return "<nil>"
	}
	 := "<nil>"
	if .LoopNode != nil && .LoopNode.Set != nil {
		 = .LoopNode.Set.String()
	}
	switch {
	case .String != "":
		return fmt.Sprintf("string=%q ignoreCase=%t after loop set %s", .String, .StringIgnoreCase, )
	case len(.Chars) > 0:
		return fmt.Sprintf("chars=%q after loop set %s", string(.Chars), )
	default:
		return fmt.Sprintf("char=%q after loop set %s", .Char, )
	}
}

func landmarkChainDescription( *RequiredLandmarkChain) string {
	if  == nil {
		return "<nil>"
	}
	 := "<nil>"
	if .LeadingLoopSet != nil {
		 = .LeadingLoopSet.String()
	}
	 := &bytes.Buffer{}
	fmt.Fprintf(, "leadingLoop=%s", )
	for ,  := range .Landmarks {
		fmt.Fprintf(, " landmark[%d]=", )
		for ,  := range .Alternatives {
			if  > 0 {
				.WriteString("|")
			}
			.WriteString(requiredLandmarkAlternativeDescription())
		}
	}
	return .String()
}

func requiredLandmarkAlternativeDescription( RequiredLandmarkAlternative) string {
	 := ""
	switch {
	case len(.Literal) > 0:
		 = fmt.Sprintf("literal=%q", string(.Literal))
	case .Set != nil:
		 = fmt.Sprintf("set=%s repeat=%d..%d", .Set.String(), .MinRepeat, .MaxRepeat)
	default:
		 = "<empty>"
	}
	if .LeadingWhitespaceSet != nil {
		 += fmt.Sprintf(" leadingWhitespace=%s required=%t", .LeadingWhitespaceSet.String(), .RequireWhitespaceBefore)
	}
	if .TrailingWhitespaceSet != nil {
		 += fmt.Sprintf(" trailingWhitespace=%s required=%t", .TrailingWhitespaceSet.String(), .RequireWhitespaceAfter)
	}
	return 
}

func newFindOptimizations( *RegexTree,  ParseOptions) *FindOptimizations {
	 := newFindOptimizationsForNode(.Root, , false)

	if !.rightToLeft && !.isUseful() {
		if ,  := findLeadingPositiveLookahead(.Root);  != nil {
			 := newFindOptimizationsForNode(.Children[0], , true)

			// Lookaheads don't currently factor into the whole-pattern length analysis,
			// as they can overlap with the rest of the expression. Keep the whole-pattern
			// minimum if it's larger, and preserve any max from the original expression.
			.MinRequiredLength = max(.MinRequiredLength, .MinRequiredLength)
			.MaxPossibleLength = .MaxPossibleLength
			 = 
		}
	}

	return 
}

func newFindOptimizationsForNode( *RegexNode,  ParseOptions,  bool) *FindOptimizations {
	 := &FindOptimizations{
		rightToLeft:       .RegexOptions&RightToLeft != 0,
		MinRequiredLength: .ComputeMinLength(),
		LeadingAnchor:     findLeadingOrTrailingAnchor(, true),
		MaxPossibleLength: -1,
	}

	if .rightToLeft && .LeadingAnchor == NtBol {
		// Filter out Bol for RightToLeft, as we don't currently optimize for it.
		.LeadingAnchor = NtUnknown
	}

	.FindMode = getFindMode(.rightToLeft, .LeadingAnchor)
	if .FindMode != NoSearch {
		return 
	}

	// Compute any anchor trailing the expression.  If there is one, and we can also compute a fixed length
	// for the whole expression, we can use that to quickly jump to the right location in the input.
	if !.rightToLeft && ! {
		.TrailingAnchor = findLeadingOrTrailingAnchor(, false)
		if .TrailingAnchor == NtEnd || .TrailingAnchor == NtEndZ {
			.MaxPossibleLength = .computeMaxLength()
			if .MinRequiredLength == .MaxPossibleLength {
				if .TrailingAnchor == NtEnd {
					.FindMode = TrailingAnchor_FixedLength_LeftToRight_End
				} else {
					.FindMode = TrailingAnchor_FixedLength_LeftToRight_EndZ
				}
				return 
			}
		}
	}

	// If there's a leading substring, just use IndexOf and inherit all of its optimizations.
	 := findPrefix()
	if len() > 1 {
		.LeadingPrefix = 
		if .rightToLeft {
			.FindMode = LeadingString_RightToLeft
		} else {
			.FindMode = LeadingString_LeftToRight
		}
		return 
	}

	// At this point there are no fast-searchable anchors or case-sensitive prefixes. We can now analyze the
	// pattern for sets and then use any found sets to determine what kind of search to perform.

	// If we're generating code, then the code generation process already handles sets that reduce to a single literal,
	// so we can simplify and just always go for the sets.
	 := false                   //(opt&NonBacktracking) != 0
	 := .CodeGen && ! // for now, we never generate code for NonBacktracking, so treat it as non-codegen
	 := ! && !
	//usesRfoTryFind := !codeGen

	// For interpreter, we want to employ optimizations, but we don't want to make construction significantly
	// more expensive. regexp2cg can opt into more expensive analysis with OptionIsCodeGen. So for the
	// interpreter we focus only on creating a set for the first character. Same for right-to-left, which
	// is used very rarely and thus we don't need to invest in special-casing it.
	if .rightToLeft {
		// Determine a set for anything that can possibly start the expression.
		 := findFirstCharClass()
		if  != nil {
			var  []rune
			if !.IsNegated() {
				// See if the set is limited to holding only a few characters.
				 = .GetSetChars(5)
			}

			if ! && len() == 1 {
				// The set contains one and only one character, meaning every match starts
				// with the same literal value (potentially case-insensitive). Search for that.
				.FixedDistanceLiteral.C = [0]
				.FindMode = LeadingChar_RightToLeft
			} else {
				// The set may match multiple characters.  Search for that.
				.FixedDistanceSets = []FixedDistanceSet{{
					Chars:    ,
					Set:      ,
					Distance: 0,
				}}
				.FindMode = LeadingSet_RightToLeft
				.asciiLookups = make([][]uint, 1)
			}
		}
		return 
	}

	// We're now left-to-right only.

	 = findPrefixOrdinalCaseInsensitive()
	if len() > 1 {
		.LeadingPrefix = 
		.FindMode = LeadingString_OrdinalIgnoreCase_LeftToRight
		return 
	}

	// We're now left-to-right only and looking for multiple prefixes and/or sets.

	// If there are multiple leading strings, we can search for any of them.
	// this works in the interpreter, but we avoid it due to additional cost during construction

	if ! {
		 := findPrefixes(, true)
		if len() > 1 {
			.LeadingPrefixes = 
			.LeadingPrefixesRunes = toRunePrefixes()
			.LeadingPrefixFirstRunes = leadingPrefixFirstRunes(.LeadingPrefixesRunes)
			.FindMode = LeadingStrings_OrdinalIgnoreCase_LeftToRight
			/*SYSTEM_TEXT_REGULAREXPRESSIONS
			if usesRfoTryFind {
						f.LeadingStrings = helpers.NewSearchValues(f.LeadingPrefixes, true)
			}*/
			return 
		}
	}

	// Build up a list of all of the sets that are a fixed distance from the start of the expression.
	 := findFixedDistanceSets(, !)

	// See if we can make a string of at least two characters long out of those sets.  We should have already caught
	// one at the beginning of the pattern, but there may be one hiding at a non-zero fixed distance into the pattern.
	if len() > 0 {
		 := findFixedDistanceString()
		if  != nil {
			.FindMode = FixedDistanceString_LeftToRight
			.FixedDistanceLiteral = *
			return 
		}
	}

	// A landmark chain is more selective than a single leading set for shapes like
	// /name-separator host-separator domain/. Prefer it before falling back to
	// one-position or one-literal candidate searches.
	if  := findRequiredLandmarkChain();  != nil {
		.FindMode = RequiredLandmarkChain_LeftToRight
		.LandmarkChain = 
		return 
	}

	// As a backup, see if we can find a literal after a leading atomic loop.  That might be better than whatever sets we find, so
	// we want to know whether we have one in our pocket before deciding whether to use a leading set (we'll prefer a leading
	// set if it's something for which we can search efficiently).
	 := findLiteralFollowingLeadingLoop()

	// If we got such sets, we'll likely use them.  However, if the best of them is something that doesn't support an efficient
	// search and we did successfully find a literal after an atomic loop we could search instead, we prefer the efficient search.
	// For example, if we have a negated set, we will still prefer the literal-after-an-atomic-loop because negated sets typically
	// contain _many_ characters (e.g. [^a] is everything but 'a') and are thus more likely to very quickly match, which means any
	// vectorization employed is less likely to kick in and be worth the startup overhead.
	if len() > 0 {
		// Sort the sets by "quality", such that whatever set is first is the one deemed most efficient to use.
		// In some searches, we may use multiple sets, so we want the subsequent ones to also be the efficiency runners-up.
		slices.SortFunc(, compareFixedDistanceSetsByQuality)

		// If the best fixed-distance set is composed of high-frequency characters, IndexOfAny on
		// those characters is likely to match too many positions. Prefer a case-sensitive
		// multi-prefix search when one is available.
		if ! && !mayContainCaseInsensitiveMatching() && hasHighFrequencyChars([0]) {
			 := findPrefixes(, false)
			if len() > 1 {
				.LeadingPrefixes = 
				.LeadingPrefixesRunes = toRunePrefixes()
				.LeadingPrefixFirstRunes = leadingPrefixFirstRunes(.LeadingPrefixesRunes)
				.FindMode = LeadingStrings_LeftToRight
				return 
			}
		}

		// If there is no literal after the loop, use whatever set we got.
		// If there is a literal after the loop, consider it to be better than a negated set and better than a set with many characters.
		if  == nil || (len([0].Chars) > 0 && ![0].Negated) {
			// Determine whether to do searching based on one or more sets or on a single literal. Code-generated engines
			// don't need to special-case literals as they already do codegen to create the optimal lookup based on
			// the set's characteristics.
			if ! && len() == 1 && len([0].Chars) == 1 &&
				![0].Negated {
				.FixedDistanceLiteral = FixedDistanceLiteral{
					C:        [0].Chars[0],
					Distance: [0].Distance,
				}
				.FindMode = FixedDistanceChar_LeftToRight
			} else {
				// Limit how many sets we use to avoid doing lots of unnecessary work.  The list was already
				// sorted from best to worst, so just keep the first ones up to our limit.
				const  = 3 // arbitrary tuned limit
				if len() >  {
					 = [:]
				}

				// Store the sets, and compute which mode to use.
				.FixedDistanceSets = 
				if len() == 1 && [0].Distance == 0 {
					.FindMode = LeadingSet_LeftToRight
				} else {
					.FindMode = FixedDistanceSets_LeftToRight
				}
				.asciiLookups = make([][]uint, len())
			}
			return 
		}
	}

	// If we found a literal we can search for after a leading set loop, use it.
	if  != nil {
		.FindMode = LiteralAfterLoop_LeftToRight
		.LiteralAfterLoop = 
		.asciiLookups = make([][]uint, 1)
	}

	return 
}

func ( *FindOptimizations) () bool {
	return .FindMode != NoSearch || .LeadingAnchor == NtBol
}

func toRunePrefixes( []string) [][]rune {
	if len() == 0 {
		return nil
	}
	 := make([][]rune, len())
	for ,  := range  {
		[] = []rune()
	}
	return 
}

func leadingPrefixFirstRunes( [][]rune) []rune {
	 := make([]rune, 0, len())
	for ,  := range  {
		if len() > 0 && !slices.Contains(, [0]) {
			 = append(, [0])
		}
	}
	return 
}

func getFindMode( bool,  NodeType) FindNextStartingPositionMode {
	if  {
		switch  {
		case NtBeginning:
			return LeadingAnchor_RightToLeft_Beginning
		case NtStart:
			return LeadingAnchor_RightToLeft_Start
		case NtEnd:
			return LeadingAnchor_RightToLeft_End
		case NtEndZ:
			return LeadingAnchor_RightToLeft_EndZ
		}
	} else {
		switch  {
		case NtBeginning:
			return LeadingAnchor_LeftToRight_Beginning
		case NtStart:
			return LeadingAnchor_LeftToRight_Start
		case NtEnd:
			return LeadingAnchor_LeftToRight_End
		case NtEndZ:
			return LeadingAnchor_LeftToRight_EndZ
		}
	}

	return NoSearch
}

// Analyzes a list of fixed-distance sets to extract a case-sensitive string at a fixed distance.</summary>
func findFixedDistanceString( []FixedDistanceSet) *FixedDistanceLiteral {
	var  *FixedDistanceLiteral

	// A result string must be at least two characters in length; therefore we require at least that many sets.
	if len() >= 2 {
		// We're walking the sets from beginning to end, so we need them sorted by distance.
		slices.SortFunc(, func(,  FixedDistanceSet) int {
			return cmp.Compare(.Distance, .Distance)
		})

		 := &bytes.Buffer{}

		// Looking for strings of length >= 2
		 := -1
		for  := 0;  < len()+1; ++ {
			 := []rune(nil)
			if  < len() {
				 = [].Chars
			}
			 := len() != 1 || [].Negated

			// If the current set ends a sequence (or we've walked off the end), see whether
			// what we've gathered constitues a valid string, and if it's better than the
			// best we've already seen, store it.  Regardless, reset the sequence in order
			// to continue analyzing.
			if  || ( > 0 && [].Distance != [-1].Distance+1) {
				 := 2
				if  != nil {
					 = len(.S)
				}
				if  != -1 && - >=  {
					 = &FixedDistanceLiteral{
						S:        .String(),
						Distance: [].Distance,
					}
				}

				.Reset()
				 = -1
				if  {
					continue
				}
			}

			if  == -1 {
				 = 
			}

			.WriteRune([0])
		}
	}

	return 
}