-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathregexp_parse.go
95 lines (83 loc) · 2.18 KB
/
regexp_parse.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
package quamina
import (
"fmt"
"unicode/utf8"
)
// regexpParse represents the state of a regexp read, validate, and parse project
type regexpParse struct {
bytes []byte
index int
lastIndex int
nesting []regexpRoot
features *regexpFeatureChecker
tree regexpRoot
}
func (p *regexpParse) nest() {
p.nesting = append(p.nesting, p.tree)
p.tree = regexpRoot{}
}
// unNest is only called after isNested. We've been building up a subtree in p.tree, so we need to
// save that subtree, pop whatever was on the nesting stack back into p.tree, and then return the
// sub tree so it can be built into a quantifiedAtom
func (p *regexpParse) unNest() regexpRoot {
subtree := p.tree
p.tree = p.nesting[len(p.nesting)-1]
p.nesting = p.nesting[0 : len(p.nesting)-1]
return subtree
}
func (p *regexpParse) isNested() bool {
return len(p.nesting) > 0
}
func newRxParseState(t []byte) *regexpParse {
return ®expParse{
bytes: t,
features: defaultRegexpFeatureChecker(),
tree: regexpRoot{},
}
}
func (p *regexpParse) nextRune() (rune, error) {
if p.index >= len(p.bytes) {
return 0, errRegexpEOF
}
p.lastIndex = p.index
c, length := utf8.DecodeRune(p.bytes[p.index:])
if c == utf8.RuneError {
return 0, fmt.Errorf("UTF-8 encoding error at offset %d", p.lastOffset())
}
p.index += length
return c, nil
}
// require checks to see if the first rune matches the supplied argument. If it fails, it doesn't back up or
// recover or anything, on the assumption that you're giving up.
func (p *regexpParse) require(wanted rune) error {
got, err := p.nextRune()
if err != nil {
return err
}
if got != wanted {
return fmt.Errorf("incorrect character at %d; got %c wanted %c", p.lastOffset(), got, wanted)
}
return nil
}
func (p *regexpParse) bypassOptional(c rune) (bool, error) {
next, err := p.nextRune()
if err != nil {
return false, err
}
if next != c {
p.backup1(next)
}
return next == c, nil
}
func (p *regexpParse) backup1(oneRune rune) {
p.index -= utf8.RuneLen(oneRune)
}
func (p *regexpParse) offset() int {
return p.index
}
func (p *regexpParse) lastOffset() int {
return p.lastIndex
}
func (p *regexpParse) isEmpty() bool {
return p.index >= len(p.bytes)
}