-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.go
93 lines (78 loc) · 2.18 KB
/
parser.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
package window
import (
"regexp"
"strings"
)
type Parser struct {
text string
pos int
}
func startParsing(text string) *Parser {
return &Parser{
text: strings.ToLower(text),
}
}
// expectAny compares the remaining string against any of given alternatives
// returns the consumed alternative (empty string if not matched)
func (p *Parser) expectAny(alts []string) string {
for _, alt := range alts {
if p.expect(alt) {
return alt
}
}
return "" // matched nothing
}
// expect consumes the given string if it matched the current remainder
func (p *Parser) expect(expected string) bool {
if len(expected) <= len(p.text[p.pos:]) && expected == p.text[p.pos:p.pos+len(expected)] {
p.pos += len(expected)
return true
}
return false
}
// consumeUntil consumes all bytes from the text until it meets one of the alternatives (the alt is NOT consumed)
// it returns the consumed string and the found alternative
// it advances the position to after the found alternative
func (p *Parser) consumeUntil(alts []string) (consumed, matchedAlt string) {
for p.pos < len(p.text) {
for _, alt := range alts {
if len(alt) <= len(p.text[p.pos:]) && alt == p.text[p.pos:p.pos+len(alt)] {
matchedAlt = alt
return
}
}
// not matched, consume the char
consumed = string(append([]byte(consumed), p.text[p.pos]))
p.pos += 1
}
return
}
// consumeRE consumes all characters that match the given pattern.
// Pattern matches only the beginning of the string
func (p *Parser) consumeRE(pattern string) (matched string) {
if p.isEof() {
return ""
}
re := regexp.MustCompile(pattern)
matched = re.FindString(p.getRemainder())
p.pos += len(matched)
return matched
}
// eatWs advances the pos to the next non-whitespace character in the text
func (p *Parser) eatWs() (eaten int) {
for !p.isEof() {
ch := p.text[p.pos]
if ch == ' ' || ch == '\t' || ch == '\n' {
p.pos++
eaten++
continue
}
break
}
return
}
func (p *Parser) getRemainder() string { return p.text[p.pos:] }
// rollback reset the pos back to i steps
func (p *Parser) rollback(i int) { p.pos -= i }
func (p *Parser) rollbackAt(pos int) { p.pos = pos }
func (p *Parser) isEof() bool { return p.pos >= len(p.text) }