package chroma

import (
	
	
	
)

// A Mutator modifies the behaviour of the lexer.
type Mutator interface {
	// Mutate the lexer state machine as it is processing.
	Mutate(state *LexerState) error
}

// SerialisableMutator is a Mutator that can be serialised and deserialised.
type SerialisableMutator interface {
	Mutator
	MutatorKind() string
}

// A LexerMutator is an additional interface that a Mutator can implement
// to modify the lexer when it is compiled.
type LexerMutator interface {
	// MutateLexer can be implemented to mutate the lexer itself.
	//
	// Rules are the lexer rules, state is the state key for the rule the mutator is associated with.
	MutateLexer(rules CompiledRules, state string, rule int) error
}

// A MutatorFunc is a Mutator that mutates the lexer state machine as it is processing.
type MutatorFunc func(state *LexerState) error

func ( MutatorFunc) ( *LexerState) error { return () } // nolint

type multiMutator struct {
	Mutators []Mutator `xml:"mutator"`
}

func ( *multiMutator) ( *xml.Decoder,  xml.StartElement) error {
	for {
		,  := .Token()
		if  != nil {
			return 
		}
		switch token := .(type) {
		case xml.StartElement:
			,  := unmarshalMutator(, )
			if  != nil {
				return 
			}
			.Mutators = append(.Mutators, )

		case xml.EndElement:
			return nil
		}
	}
}

func ( *multiMutator) ( *xml.Encoder,  xml.StartElement) error {
	 := xml.Name{Local: "mutators"}
	if  := .EncodeToken(xml.StartElement{Name: });  != nil {
		return 
	}
	for ,  := range .Mutators {
		if  := marshalMutator(, );  != nil {
			return 
		}
	}
	return .EncodeToken(xml.EndElement{Name: })
}

func ( *multiMutator) () string { return "mutators" }

func ( *multiMutator) ( *LexerState) error {
	for ,  := range .Mutators {
		if  := .Mutate();  != nil {
			return 
		}
	}
	return nil
}

// Mutators applies a set of Mutators in order.
func ( ...Mutator) Mutator {
	return &multiMutator{}
}

type includeMutator struct {
	State string `xml:"state,attr"`
}

// Include the given state.
func ( string) Rule {
	return Rule{Mutator: &includeMutator{}}
}

func ( *includeMutator) () string { return "include" }

func ( *includeMutator) ( *LexerState) error {
	return fmt.Errorf("should never reach here Include(%q)", .State)
}

func ( *includeMutator) ( CompiledRules,  string,  int) error {
	,  := [.State]
	if ! {
		return fmt.Errorf("invalid include state %q", .State)
	}
	[] = append([][:], append(, [][+1:]...)...)
	return nil
}

type combinedMutator struct {
	States []string `xml:"state,attr"`
}

func ( *combinedMutator) () string { return "combined" }

// Combined creates a new anonymous state from the given states, and pushes that state.
func ( ...string) Mutator {
	return &combinedMutator{}
}

func ( *combinedMutator) ( *LexerState) error {
	return fmt.Errorf("should never reach here Combined(%v)", .States)
}

func ( *combinedMutator) ( CompiledRules,  string,  int) error {
	 := "__combined_" + strings.Join(.States, "__")
	if ,  := []; ! {
		 := []*CompiledRule{}
		for ,  := range .States {
			,  := []
			if ! {
				return fmt.Errorf("invalid combine state %q", )
			}
			 = append(, ...)
		}
		[] = 
	}
	[][].Mutator = Push()
	return nil
}

type pushMutator struct {
	States []string `xml:"state,attr"`
}

func ( *pushMutator) () string { return "push" }

func ( *pushMutator) ( *LexerState) error {
	if len(.States) == 0 {
		.Stack = append(.Stack, .State)
	} else {
		for ,  := range .States {
			if  == "#pop" {
				.Stack = .Stack[:len(.Stack)-1]
			} else {
				.Stack = append(.Stack, )
			}
		}
	}
	return nil
}

// Push states onto the stack.
func ( ...string) Mutator {
	return &pushMutator{}
}

type popMutator struct {
	Depth int `xml:"depth,attr"`
}

func ( *popMutator) () string { return "pop" }

func ( *popMutator) ( *LexerState) error {
	if len(.Stack) == 0 {
		return fmt.Errorf("nothing to pop")
	}
	.Stack = .Stack[:len(.Stack)-.Depth]
	return nil
}

// Pop state from the stack when rule matches.
func ( int) Mutator {
	return &popMutator{}
}

// Default returns a Rule that applies a set of Mutators.
func ( ...Mutator) Rule {
	return Rule{Mutator: Mutators(...)}
}

// Stringify returns the raw string for a set of tokens.
func ( ...Token) string {
	 := []string{}
	for ,  := range  {
		 = append(, .Value)
	}
	return strings.Join(, "")
}