-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlex.go
140 lines (119 loc) · 2 KB
/
lex.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
132
133
134
135
136
137
138
139
140
package braceexpansion
import (
"strings"
"unicode/utf8"
)
type item struct {
typ itemType
val string
}
type itemType int
const (
itemError itemType = iota
itemOpen
itemClose
itemSeparator
itemText
itemEOF
)
const eof = -1
type stateFn func(*lexer) stateFn
type lexer struct {
input string
start int
pos int
width int
items chan item
opts ParseOpts
}
func (l *lexer) next() rune {
if l.pos >= len(l.input) {
l.width = 0
return eof
}
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
l.width = w
l.pos += l.width
return r
}
func (l *lexer) peek() rune {
r := l.next()
l.backup()
return r
}
func (l *lexer) backup() {
l.pos -= l.width
}
func (l *lexer) emit(t itemType) {
l.items <- item{t, l.input[l.start:l.pos]}
l.start = l.pos
}
func (l *lexer) nextItem() item {
item := <-l.items
return item
}
func (l *lexer) drain() {
for range l.items {
}
}
func lex(input string, opts ParseOpts) *lexer {
l := &lexer{
input: input,
items: make(chan item),
opts: opts,
}
go l.run()
return l
}
func (l *lexer) run() {
for state := lexText; state != nil; {
state = state(l)
}
close(l.items)
}
// state functions
func lexText(l *lexer) stateFn {
for {
if strings.HasPrefix(l.input[l.pos:], l.opts.OpenBrace) {
if l.pos > l.start {
l.emit(itemText)
}
return lexOpen
}
if strings.HasPrefix(l.input[l.pos:], l.opts.CloseBrace) {
if l.pos > l.start {
l.emit(itemText)
}
return lexClose
}
if strings.HasPrefix(l.input[l.pos:], l.opts.Separator) {
if l.pos > l.start {
l.emit(itemText)
}
return lexSeparator
}
if l.next() == eof {
break
}
}
if l.pos > l.start {
l.emit(itemText)
}
l.emit(itemEOF)
return nil
}
func lexOpen(l *lexer) stateFn {
l.pos += len(l.opts.OpenBrace)
l.emit(itemOpen)
return lexText
}
func lexClose(l *lexer) stateFn {
l.pos += len(l.opts.CloseBrace)
l.emit(itemClose)
return lexText
}
func lexSeparator(l *lexer) stateFn {
l.pos += len(l.opts.Separator)
l.emit(itemSeparator)
return lexText
}