mirror of
				https://github.com/alecthomas/chroma.git
				synced 2025-10-30 23:57:49 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			132 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package chroma
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // A Mutator modifies the behaviour of the lexer.
 | |
| type Mutator interface {
 | |
| 	// Mutate the lexer state machine as it is processing.
 | |
| 	Mutate(state *LexerState) error
 | |
| }
 | |
| 
 | |
| // A LexerMutator is an additional interface that a Mutator can implement
 | |
| // to modify the lexer when it is compiled.
 | |
| type LexerMutator interface {
 | |
| 	// 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 (m MutatorFunc) Mutate(state *LexerState) error { return m(state) } // nolint
 | |
| 
 | |
| // Mutators applies a set of Mutators in order.
 | |
| func Mutators(modifiers ...Mutator) MutatorFunc {
 | |
| 	return func(state *LexerState) error {
 | |
| 		for _, modifier := range modifiers {
 | |
| 			if err := modifier.Mutate(state); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type includeMutator struct {
 | |
| 	state string
 | |
| }
 | |
| 
 | |
| // Include the given state.
 | |
| func Include(state string) Rule {
 | |
| 	return Rule{Mutator: &includeMutator{state}}
 | |
| }
 | |
| 
 | |
| func (i *includeMutator) Mutate(s *LexerState) error {
 | |
| 	return fmt.Errorf("should never reach here Include(%q)", i.state)
 | |
| }
 | |
| 
 | |
| func (i *includeMutator) MutateLexer(rules CompiledRules, state string, rule int) error {
 | |
| 	includedRules, ok := rules[i.state]
 | |
| 	if !ok {
 | |
| 		return fmt.Errorf("invalid include state %q", i.state)
 | |
| 	}
 | |
| 	rules[state] = append(rules[state][:rule], append(includedRules, rules[state][rule+1:]...)...)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type combinedMutator struct {
 | |
| 	states []string
 | |
| }
 | |
| 
 | |
| // Combined creates a new anonymous state from the given states, and pushes that state.
 | |
| func Combined(states ...string) Mutator {
 | |
| 	return &combinedMutator{states}
 | |
| }
 | |
| 
 | |
| func (c *combinedMutator) Mutate(s *LexerState) error {
 | |
| 	return fmt.Errorf("should never reach here Combined(%v)", c.states)
 | |
| }
 | |
| 
 | |
| func (c *combinedMutator) MutateLexer(rules CompiledRules, state string, rule int) error {
 | |
| 	name := "__combined_" + strings.Join(c.states, "__")
 | |
| 	if _, ok := rules[name]; !ok {
 | |
| 		combined := []*CompiledRule{}
 | |
| 		for _, state := range c.states {
 | |
| 			rules, ok := rules[state]
 | |
| 			if !ok {
 | |
| 				return fmt.Errorf("invalid combine state %q", state)
 | |
| 			}
 | |
| 			combined = append(combined, rules...)
 | |
| 		}
 | |
| 		rules[name] = combined
 | |
| 	}
 | |
| 	rules[state][rule].Mutator = Push(name)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Push states onto the stack.
 | |
| func Push(states ...string) MutatorFunc {
 | |
| 	return func(s *LexerState) error {
 | |
| 		if len(states) == 0 {
 | |
| 			s.Stack = append(s.Stack, s.State)
 | |
| 		} else {
 | |
| 			for _, state := range states {
 | |
| 				if state == "#pop" {
 | |
| 					s.Stack = s.Stack[:len(s.Stack)-1]
 | |
| 				} else {
 | |
| 					s.Stack = append(s.Stack, state)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Pop state from the stack when rule matches.
 | |
| func Pop(n int) MutatorFunc {
 | |
| 	return func(state *LexerState) error {
 | |
| 		if len(state.Stack) == 0 {
 | |
| 			return fmt.Errorf("nothing to pop")
 | |
| 		}
 | |
| 		state.Stack = state.Stack[:len(state.Stack)-n]
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Default returns a Rule that applies a set of Mutators.
 | |
| func Default(mutators ...Mutator) Rule {
 | |
| 	return Rule{Mutator: Mutators(mutators...)}
 | |
| }
 | |
| 
 | |
| // Stringify returns the raw string for a set of tokens.
 | |
| func Stringify(tokens ...Token) string {
 | |
| 	out := []string{}
 | |
| 	for _, t := range tokens {
 | |
| 		out = append(out, t.Value)
 | |
| 	}
 | |
| 	return strings.Join(out, "")
 | |
| }
 |