...

Source file src/github.com/alecthomas/chroma/v2/mutators.go

Documentation: github.com/alecthomas/chroma/v2

     1  package chroma
     2  
     3  import (
     4  	"encoding/xml"
     5  	"fmt"
     6  	"strings"
     7  )
     8  
     9  // A Mutator modifies the behaviour of the lexer.
    10  type Mutator interface {
    11  	// Mutate the lexer state machine as it is processing.
    12  	Mutate(state *LexerState) error
    13  }
    14  
    15  // SerialisableMutator is a Mutator that can be serialised and deserialised.
    16  type SerialisableMutator interface {
    17  	Mutator
    18  	MutatorKind() string
    19  }
    20  
    21  // A LexerMutator is an additional interface that a Mutator can implement
    22  // to modify the lexer when it is compiled.
    23  type LexerMutator interface {
    24  	// MutateLexer can be implemented to mutate the lexer itself.
    25  	//
    26  	// Rules are the lexer rules, state is the state key for the rule the mutator is associated with.
    27  	MutateLexer(rules CompiledRules, state string, rule int) error
    28  }
    29  
    30  // A MutatorFunc is a Mutator that mutates the lexer state machine as it is processing.
    31  type MutatorFunc func(state *LexerState) error
    32  
    33  func (m MutatorFunc) Mutate(state *LexerState) error { return m(state) } // nolint
    34  
    35  type multiMutator struct {
    36  	Mutators []Mutator `xml:"mutator"`
    37  }
    38  
    39  func (m *multiMutator) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    40  	for {
    41  		token, err := d.Token()
    42  		if err != nil {
    43  			return err
    44  		}
    45  		switch token := token.(type) {
    46  		case xml.StartElement:
    47  			mutator, err := unmarshalMutator(d, token)
    48  			if err != nil {
    49  				return err
    50  			}
    51  			m.Mutators = append(m.Mutators, mutator)
    52  
    53  		case xml.EndElement:
    54  			return nil
    55  		}
    56  	}
    57  }
    58  
    59  func (m *multiMutator) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    60  	name := xml.Name{Local: "mutators"}
    61  	if err := e.EncodeToken(xml.StartElement{Name: name}); err != nil {
    62  		return err
    63  	}
    64  	for _, m := range m.Mutators {
    65  		if err := marshalMutator(e, m); err != nil {
    66  			return err
    67  		}
    68  	}
    69  	return e.EncodeToken(xml.EndElement{Name: name})
    70  }
    71  
    72  func (m *multiMutator) MutatorKind() string { return "multiple" }
    73  
    74  func (m *multiMutator) Mutate(state *LexerState) error {
    75  	for _, modifier := range m.Mutators {
    76  		if err := modifier.Mutate(state); err != nil {
    77  			return err
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  // Mutators applies a set of Mutators in order.
    84  func Mutators(modifiers ...Mutator) Mutator {
    85  	return &multiMutator{modifiers}
    86  }
    87  
    88  type includeMutator struct {
    89  	State string `xml:"state,attr"`
    90  }
    91  
    92  // Include the given state.
    93  func Include(state string) Rule {
    94  	return Rule{Mutator: &includeMutator{state}}
    95  }
    96  
    97  func (i *includeMutator) MutatorKind() string { return "include" }
    98  
    99  func (i *includeMutator) Mutate(s *LexerState) error {
   100  	return fmt.Errorf("should never reach here Include(%q)", i.State)
   101  }
   102  
   103  func (i *includeMutator) MutateLexer(rules CompiledRules, state string, rule int) error {
   104  	includedRules, ok := rules[i.State]
   105  	if !ok {
   106  		return fmt.Errorf("invalid include state %q", i.State)
   107  	}
   108  	rules[state] = append(rules[state][:rule], append(includedRules, rules[state][rule+1:]...)...)
   109  	return nil
   110  }
   111  
   112  type combinedMutator struct {
   113  	States []string `xml:"state,attr"`
   114  }
   115  
   116  func (c *combinedMutator) MutatorKind() string { return "combined" }
   117  
   118  // Combined creates a new anonymous state from the given states, and pushes that state.
   119  func Combined(states ...string) Mutator {
   120  	return &combinedMutator{states}
   121  }
   122  
   123  func (c *combinedMutator) Mutate(s *LexerState) error {
   124  	return fmt.Errorf("should never reach here Combined(%v)", c.States)
   125  }
   126  
   127  func (c *combinedMutator) MutateLexer(rules CompiledRules, state string, rule int) error {
   128  	name := "__combined_" + strings.Join(c.States, "__")
   129  	if _, ok := rules[name]; !ok {
   130  		combined := []*CompiledRule{}
   131  		for _, state := range c.States {
   132  			rules, ok := rules[state]
   133  			if !ok {
   134  				return fmt.Errorf("invalid combine state %q", state)
   135  			}
   136  			combined = append(combined, rules...)
   137  		}
   138  		rules[name] = combined
   139  	}
   140  	rules[state][rule].Mutator = Push(name)
   141  	return nil
   142  }
   143  
   144  type pushMutator struct {
   145  	States []string `xml:"state,attr"`
   146  }
   147  
   148  func (p *pushMutator) MutatorKind() string { return "push" }
   149  
   150  func (p *pushMutator) Mutate(s *LexerState) error {
   151  	if len(p.States) == 0 {
   152  		s.Stack = append(s.Stack, s.State)
   153  	} else {
   154  		for _, state := range p.States {
   155  			if state == "#pop" {
   156  				s.Stack = s.Stack[:len(s.Stack)-1]
   157  			} else {
   158  				s.Stack = append(s.Stack, state)
   159  			}
   160  		}
   161  	}
   162  	return nil
   163  }
   164  
   165  // Push states onto the stack.
   166  func Push(states ...string) Mutator {
   167  	return &pushMutator{states}
   168  }
   169  
   170  type popMutator struct {
   171  	Depth int `xml:"depth,attr"`
   172  }
   173  
   174  func (p *popMutator) MutatorKind() string { return "pop" }
   175  
   176  func (p *popMutator) Mutate(state *LexerState) error {
   177  	if len(state.Stack) == 0 {
   178  		return fmt.Errorf("nothing to pop")
   179  	}
   180  	state.Stack = state.Stack[:len(state.Stack)-p.Depth]
   181  	return nil
   182  }
   183  
   184  // Pop state from the stack when rule matches.
   185  func Pop(n int) Mutator {
   186  	return &popMutator{n}
   187  }
   188  
   189  // Default returns a Rule that applies a set of Mutators.
   190  func Default(mutators ...Mutator) Rule {
   191  	return Rule{Mutator: Mutators(mutators...)}
   192  }
   193  
   194  // Stringify returns the raw string for a set of tokens.
   195  func Stringify(tokens ...Token) string {
   196  	out := []string{}
   197  	for _, t := range tokens {
   198  		out = append(out, t.Value)
   199  	}
   200  	return strings.Join(out, "")
   201  }
   202  

View as plain text