-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcombinators.go
105 lines (95 loc) · 2.61 KB
/
combinators.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
package pars
import (
"fmt"
)
// Dry creates a Parser which will attempt to match the given Parser, but will
// restore the pre-matching state even if the given Parser matches.
func Dry(q interface{}) Parser {
p := AsParser(q)
return func(state *State, result *Result) error {
state.Push()
err := p(state, result)
state.Pop()
return err
}
}
// Seq creates a Parser which will attempt to match all of the given Parsers
// in the given order. If any of the given Parsers fail to match, the state
// will attempt to backtrack to the position before any of the given Parsers
// were applied.
func Seq(qs ...interface{}) Parser {
name := fmt.Sprintf("Seq(%d)", len(qs))
ps := AsParsers(qs...)
return func(state *State, result *Result) error {
v := make([]Result, len(ps))
state.Push()
for i, p := range ps {
if err := p(state, &v[i]); err != nil {
state.Pop()
return NewNestedError(name, err)
}
}
state.Drop()
result.SetChildren(v)
return nil
}
}
// Any creates a Parser which will attempt to match any of the given Parsers.
// If all of the given Parsers fail to match, the state will attempt to
// backtrack to the position before any of the given Parsers were applied. An
// error from the parser will be returned immediately if the state cannot be
// backtracked. Otherwise, the error from the last Parser will be returned.
func Any(qs ...interface{}) Parser {
name := fmt.Sprintf("Any(%d)", len(qs))
ps := AsParsers(qs...)
return func(state *State, result *Result) (err error) {
state.Push()
for _, p := range ps {
if err = p(state, result); err == nil {
state.Drop()
return nil
}
if !state.Pushed() {
return NewNestedError(name, err)
}
}
state.Pop()
return NewNestedError(name, err)
}
}
// Maybe creates a Parser which will attempt to match the given Parser but
// will not return an error upon a mismatch unless the state cannot be
// backtracked.
func Maybe(q interface{}) Parser {
p := AsParser(q)
return func(state *State, result *Result) error {
state.Push()
if err := p(state, result); err != nil {
if !state.Pushed() {
return NewNestedError("Maybe", err)
}
state.Pop()
return nil
}
state.Drop()
return nil
}
}
// Many creates a Parser which will attempt to match the given Parser as many
// times as possible.
func Many(q interface{}) Parser {
p := AsParser(q)
return func(state *State, result *Result) error {
v := []Result{}
start := state.Position()
for p(state, result) == nil {
if start == state.Position() {
return nil
}
v = append(v, *result)
*result = Result{}
}
result.SetChildren(v)
return nil
}
}