|
- 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, "")
- }
|