-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathcombinator.go
233 lines (221 loc) · 5.55 KB
/
combinator.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
package goparsec
import "strings"
func Try(parser Parser) Parser {
return func(st ParseState) (interface{}, error) {
pos := st.Pos()
result, err := parser(st)
if err == nil {
return result, nil
} else {
st.SeekTo(pos)
return nil, err
}
}
}
func Bind(parser Parser, fun func(interface{}) Parser) Parser {
return func(st ParseState) (interface{}, error) {
result, err := parser(st)
if err != nil {
return nil, err
}
return fun(result)(st)
}
}
func Bind_(parserx, parsery Parser) Parser {
return func(st ParseState) (interface{}, error) {
_, err := parserx(st)
if err != nil {
return nil, err
}
return parsery(st)
}
}
// try one parser, if it fails (without consuming input) try the next
func Either(parserx, parsery Parser) Parser {
return func(st ParseState) (interface{}, error) {
pos := st.Pos()
x, err := parserx(st)
if err == nil {
return x, nil
} else {
if st.Pos() == pos {
return parsery(st)
}
}
return nil, err
}
}
func Return(v interface{}) Parser {
return func(st ParseState) (interface{}, error) {
return v, nil
}
}
func Option(v interface{}, parser Parser) Parser {
return func(st ParseState) (interface{}, error) {
return Either(parser, Return(v))(st)
}
}
func Many1(parser Parser) Parser {
head := func(value interface{}) Parser {
tail := func(values interface{}) Parser {
return Return(append([]interface{}{value}, values.([]interface{})...))
}
return Bind(Many(parser), tail)
}
return Bind(parser, head)
}
func Many(parser Parser) Parser {
return func(st ParseState) (interface{}, error) {
return Option([]interface{}{}, Many1(parser))(st)
}
}
func Fail(message string) Parser {
return func(st ParseState) (interface{}, error) {
return nil, st.Trap(message)
}
}
func OneOf(runes string) Parser {
return func(st ParseState) (interface{}, error) {
r, ok, err := st.Next(func(ru rune) bool { return strings.IndexRune(runes, ru) >= 0 })
if err != nil {
return nil, err
}
if ok {
return r, nil
} else {
return nil, st.Trap("expected one of \"%s\" but got '%c'", runes, r)
}
}
}
func NoneOf(runes string) Parser {
return func(st ParseState) (interface{}, error) {
r, ok, err := st.Next(func(ru rune) bool { return strings.IndexRune(runes, ru) < 0 })
if err != nil {
return nil, err
}
if ok {
return r, nil
} else {
return nil, st.Trap("expected none of \"%s\" but got '%c'", string(runes), r)
}
}
}
func Between(start, end, p Parser) Parser {
keep := func(x interface{}) Parser {
return Bind_(end, Return(x))
}
return Bind_(start, Bind(p, keep))
}
func SepBy1(p, sep Parser) Parser {
head := func(x interface{}) Parser {
tail := func(xs interface{}) Parser {
return Return(append([]interface{}{x}, xs.([]interface{})...))
}
return Bind(Many(Bind_(sep, p)), tail)
}
return Bind(p, head)
}
func SepBy(p, sep Parser) Parser {
return Option([]interface{}{}, SepBy1(p, sep))
}
func ManyTil(p, end Parser) Parser {
head := func(x interface{}) Parser {
tail := func(xs interface{}) Parser {
return Return(append([]interface{}{x}, xs.([]interface{})...))
}
return Bind(ManyTil(p, end), tail)
}
term := Bind_(Try(end), Return([]interface{}{}))
return Either(term, Bind(p, head))
}
func Maybe(p Parser) Parser {
return Option(nil, Bind_(p, Return(nil)))
}
func Skip(p Parser) Parser {
return Maybe(Many(p))
}
func Union(parsers ...Parser) Parser {
return func(st ParseState) (interface{}, error) {
var ret = make([]interface{}, 0, len(parsers))
for _, parser := range parsers {
val, err := parser(st)
if err == nil {
if val != nil {
ret = append(ret, val)
}
} else {
return nil, err
}
}
return ret, nil
}
}
func UnionAll(parsers ...Parser) Parser {
return func(st ParseState) (interface{}, error) {
var ret = make([]interface{}, 0, len(parsers))
for _, parser := range parsers {
val, err := parser(st)
if err == nil {
ret = append(ret, val)
} else {
return nil, err
}
}
return ret, nil
}
}
// Choice 实现为以下逻辑的迭代版本:
// func Choice(parsers ...Parser) Parser {
// switch len(parsers) {
// case 0:
// panic(errors.New("empty choice chain"))
// case 1:
// return parsers[0]
// case 2:
// return Either(Try(parsers[0]), Try(parsers[1]))
// default:
// return Either(Try(parsers[0]), Choice(parsers[1:]))
// }
// }
// 其实我比较希望把下面那个东西实现成上面这个样子,就是好像在golang里不太经济……
func Choice(parsers ...Parser) Parser {
return func(st ParseState) (interface{}, error) {
var err error
var result interface{}
for _, parser := range parsers {
result, err = parser(st)
if err == nil {
return result, nil
}
}
return nil, err
}
}
// Binds 相当于用 Bind 对一个 func(interface{})Parser 链做左折叠,起始参数为 first
func Binds(first Parser, then ...func(interface{}) Parser) Parser {
if len(then) == 0 {
return Fail("need args formal as func(interface{})Parser more than 1st.")
}
if len(then) == 1 {
return Bind(first, then[0])
}
return func(st ParseState) (interface{}, error) {
ret, err := first(st)
if err != nil {
return nil, err
}
next := then[0](ret)
return Binds(next, then[1:]...)(st)
}
}
// Binds_ 逐个尝试每一个 Parser,直至发生错误或者到达最后,如果到达最后一个 Parser,
// 返回其结果
func Binds_(parsers ...Parser) Parser {
if len(parsers) < 2 {
return Fail("combinator Binds_ need parsers more than 2 as args")
}
if len(parsers) == 2 {
return Bind_(parsers[0], parsers[1])
}
return Bind_(parsers[0], Binds_(parsers[1:]...))
}