This repository has been archived by the owner on Jun 28, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpo.go
290 lines (237 loc) · 6.58 KB
/
po.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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
package pogo
import (
"fmt"
"reflect"
)
type Parser func(p ParseState) (Parsed, ParseState)
// NilParsed is returned when nothing could be parsed, but no error was raised
var NilParsed = NilParsedType{}
// ErrParsed is returned when nothing could be parsed, and an error was raised
var ErrParsed = ErrParsedType{}
var EOF = Tok(TOK_EOF)
var Debug = false
// Tok is a parser which matches a given TokenType. The token is only consumed if it matches.
func Tok(token TokenType) Parser {
return func(ps ParseState) (Parsed, ParseState) {
item := peekTok(ps)
if item.Token == token {
return nextTok(ps)
}
ps = addError(ps, item, fmt.Errorf("expected '%v' got '%v'", token, item))
return ErrParsed, ps
}
}
// Char is a shortcut for parsing single character tokens
func Char(c rune) Parser {
return Tok(TokenType(c))
}
// Parses a named production
func Prod(ident string, p interface{}) Parser {
VisitorTemplate.ProductionOrder = append(VisitorTemplate.ProductionOrder, ident)
VisitorTemplate.Productions[ident] = nil
return func(ps ParseState) (Parsed, ParseState) {
if Debug {
fmt.Printf("parsing prod %v at %v: %v\n", ident, ps.Pos(), ps.Lexer().At(ps))
}
var children Sequence
var res Parsed
res, ps = Do(p, ps)
switch res := res.(type) {
case Item:
children = Sequence{res}
case Production:
children = Sequence{res}
case Sequence:
children = res.Flatten()
case NilParsedType:
case ErrParsedType:
if Debug {
fmt.Printf("prod %v failed at %v: %v\n", ident, ps.Pos(), ps.Lexer().At(ps))
}
return res, ps
default:
panic(fmt.Sprintf("don't know what to do with %T\n", res))
}
if Debug {
fmt.Printf("prod %v at %v: %v -> %v\n", ident, ps.Pos(), ps.Lexer().At(ps), res)
}
return Production{
Ident: ident,
Children: children,
}, ps
}
}
func Named(ident string, p interface{}) Parser {
return func(ps ParseState) (Parsed, ParseState) {
if Debug {
fmt.Printf("parsing named %v at %v: %v\n", ident, ps.Pos(), ps.Lexer().At(ps))
}
var value Parsed
value, ps = Do(p, ps)
if value == ErrParsed {
return value, ps
}
return NamedValue{
Name: ident,
Value: value,
}, ps
}
}
// Parses a named and typed production
func TypedProd(ident string, typ interface{}, p interface{}) Parser {
parser := Prod(ident, p)
VisitorTemplate.Productions[ident] = reflect.TypeOf(typ)
return parser
}
// Parses a named and typed production. Special case for interface typed productions.
// Usage: TypedProdIface("prod", (*MyIface)(nil))
func TypedProdIface(ident string, typ interface{}, p interface{}) Parser {
parser := Prod(ident, p)
VisitorTemplate.Productions[ident] = reflect.TypeOf(typ).Elem()
return parser
}
// Sequence accepts 1..n parsers and expects them to succeed in their defined sequence
func Seq(p ...interface{}) Parser {
return func(ps ParseState) (Parsed, ParseState) {
results := make(Sequence, len(p))
for i, p := range p {
results[i], ps = Do(p, ps)
// If any in the sequence fail, return error
if results[i] == ErrParsed {
return ErrParsed, ps
}
}
return results, ps
}
}
// Maybe executes a parser which may fail. If it fails no input is consumed and NilParsed is returned.
// Errors are not sent to the error handler.
func Maybe(p interface{}) Parser {
return TryRecover(p, func(start, end ParseState) (Parsed, ParseState) {
return NilParsed, start
})
}
// Peek parses p without consuming any input.
// Errors are sent to the error handler.
func Peek(p interface{}) Parser {
return func(ps ParseState) (Parsed, ParseState) {
res, _ := Do(p, ps)
return res, ps
}
}
// MaybePeek parses p without consuming any input. If it fails, NilParsed is returned.
// Errors are not sent to the error handler.
func MaybePeek(p interface{}) Parser {
return Peek(Maybe(p))
}
func Many(p interface{}) Parser {
return func(ps ParseState) (Parsed, ParseState) {
results := make(Sequence, 0)
for {
var res Parsed
res, ps = Do(Maybe(p), ps)
// Maybe() will return NilParsed when the parser fails; exit cleanly
if res == NilParsed {
break
}
results = append(results, res)
}
return results, ps
}
}
func Many1(p interface{}) Parser {
return func(ps ParseState) (Parsed, ParseState) {
var results Sequence
var value Parsed
value, ps = Do(p, ps)
results = Sequence{value}
value, ps = Do(Many(p), ps)
results = append(results, value.(Sequence)...)
return results, ps
}
}
func SepBy(p, delim interface{}) Parser {
return doSepBy(p, delim, nil, false)
}
func SepByTerm(p, delim, terminator interface{}) Parser {
return doSepBy(p, delim, terminator, false)
}
func SepBy1(p, delim interface{}) Parser {
return doSepBy(p, delim, nil, true)
}
func SepBy1Term(p, delim, terminator interface{}) Parser {
return doSepBy(p, delim, terminator, true)
}
func doSepBy(p, delim, terminator interface{}, requireOne bool) Parser {
return func(ps ParseState) (Parsed, ParseState) {
results := make(Sequence, 0)
required := false
if requireOne {
required = true
}
var res Parsed
for {
// Parse the subject (must succeed unless required == true)
// FIXME pretty sure this is backwards?
if !required {
res, ps = Do(Maybe(p), ps)
if res == NilParsed {
break
}
} else {
res, ps = Do(p, ps)
}
if res == ErrParsed {
return res, ps
}
results = append(results, res)
required = false
// Parse the delimiter (may fail the parser gracefully)
res, ps = Do(Maybe(delim), ps)
if res == NilParsed {
break
}
}
if terminator != nil {
res, ps = Do(terminator, ps)
if res == ErrParsed {
return res, ps
}
}
return results, ps
}
}
// Or accepts 1..n parsers and attempts them one by one. The first successful match is returned.
// If no parsers succeed, then the error of the most successful (by length) parser is raised.
func Or(p ...interface{}) Parser {
return func(ps ParseState) (Parsed, ParseState) {
longestParse := -1
var longestParseState ParseState
var res Parsed
for _, p := range p {
res, ps = Do(TryRecover(p, func(start, end ParseState) (Parsed, ParseState) {
thisParseLength := end.Pos() - start.Pos()
if thisParseLength > longestParse {
longestParseState = end
longestParse = thisParseLength
}
// Backtrack to the point that we started at
return ErrParsed, start
}), ps)
if res != ErrParsed {
return res, ps
}
}
return ErrParsed, longestParseState
}
}
func Do(p interface{}, ps ParseState) (Parsed, ParseState) {
switch p := p.(type) {
case Parser:
return p(ps)
case *Parser:
return (*p)(ps)
default:
panic(fmt.Sprintf("Not a parser: %T", p))
}
}