forked from alecthomas/chroma
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mutators.go
131 lines (113 loc) · 3.33 KB
/
mutators.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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, "")
}