-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.go
155 lines (137 loc) · 3.21 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
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package mapaccess
import (
"fmt"
"strconv"
"strings"
)
type token struct {
typ tokenType
val string
}
type parser struct {
tokens chan token // channel of parsed token
items chan item // chan to send tokens for client
buf *item // have a buffer of 1 item for parser
lex *lexer // input lexer
}
type tokenType int
const (
tokenError tokenType = iota
tokenEnd
tokenIdentifier
tokenArrayIndex
)
type parseStateFn func(*parser) parseStateFn
func parse(input string) *parser {
p := &parser{
tokens: make(chan token),
lex: lex(input),
}
go p.run()
return p
}
// errorf returns an error token and terminates the scan by passing
// back a nil pointer that will be the next state.
func (p *parser) errorf(format string, args ...interface{}) parseStateFn {
p.tokens <- token{tokenError, fmt.Sprintf(format, args...)}
return nil
}
// emit passes a token back to the client.
func (p *parser) emit(t token) {
p.tokens <- t
}
// nextItem returns the next item when it becomes available
func (p *parser) nextItem() token {
return <-p.tokens
}
func (p *parser) run() {
defer close(p.tokens)
for state := parseStart; state != nil; {
state = state(p)
}
}
func (p *parser) getBufOrNext() item {
if p.buf != nil {
item := *p.buf
p.buf = nil
return item
}
return p.lex.nextItem()
}
// parseStart scans for either an identifier, or an array index
func parseStart(p *parser) parseStateFn {
item := p.getBufOrNext()
p.buf = &item
switch item.typ {
case itemArrayIndex:
return parseArrayIndex
case itemIdentifier:
return parseIdentifier
case itemEOF:
p.emit(token{tokenEnd, ""})
return nil
default:
return p.errorf("expected array index or identifier")
}
}
// parseIdentifier scans for identifiers
func parseIdentifier(p *parser) parseStateFn {
item := p.getBufOrNext()
if item.typ == itemIdentifier {
// we already did rune checking in the lexer, good to go
p.emit(token{tokenIdentifier, item.val})
next := p.lex.nextItem()
p.buf = &next
switch next.typ {
case itemDot:
return parseDot
case itemArrayIndex:
return parseArrayIndex
case itemEOF:
p.emit(token{tokenEnd, ""})
return nil
default:
return p.errorf("expected dot or array index")
}
}
if item.typ == itemEOF {
p.emit(token{tokenEnd, ""})
return nil
}
return p.errorf("expected identifier")
}
// parseDot scans for dots
func parseDot(p *parser) parseStateFn {
item := p.getBufOrNext()
if item.typ != itemDot {
return p.errorf("expected dot")
}
// do nothing, ingest dot
return parseIdentifier
}
// parseArrayIndex scans for dots
func parseArrayIndex(p *parser) parseStateFn {
item := p.getBufOrNext()
if item.typ != itemArrayIndex {
return p.errorf("expected array index")
}
// lexer already checked that the val is starting and ending with brackets []
index := strings.Trim(item.val, "[]")
if _, err := strconv.Atoi(index); err != nil {
return p.errorf("expected a integer")
}
p.emit(token{tokenArrayIndex, index})
i := p.lex.nextItem()
p.buf = &i
switch p.buf.typ {
case itemDot:
return parseDot
case itemArrayIndex:
return parseArrayIndex
case itemEOF:
p.emit(token{tokenEnd, ""})
return nil
default:
return p.errorf("expected dot or array index after array index")
}
}