summaryrefslogtreecommitdiff
path: root/combinator.go
diff options
context:
space:
mode:
authorAdam Scarr <adam@vektah.net>2017-08-06 14:31:35 +1000
committerAdam Scarr <adam@vektah.net>2017-08-06 14:31:35 +1000
commit68cde88125e1f016c5706ca8d0b3db6ba06624a2 (patch)
treecdd2de679892179f537b22ab05bfe3820dc7b4bf /combinator.go
Initial commit
Diffstat (limited to 'combinator.go')
-rw-r--r--combinator.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/combinator.go b/combinator.go
new file mode 100644
index 0000000..2b6b8a3
--- /dev/null
+++ b/combinator.go
@@ -0,0 +1,114 @@
+package parsec
+
+func Nil(p Pointer) (Node, Pointer) {
+ return nil, p
+}
+
+func Never(p Pointer) (Node, Pointer) {
+ return Error{p.pos, "Never matches"}, p
+}
+
+func And(parsers ...Parserish) Parser {
+ if len(parsers) == 0 {
+ return Nil
+ }
+
+ ps := ParsifyAll(parsers...)
+
+ return func(p Pointer) (Node, Pointer) {
+ var nodes = make([]Node, 0, len(ps))
+ var node Node
+ newP := p
+ for _, parser := range ps {
+ node, newP = parser(newP)
+ if node == nil {
+ continue
+ }
+ if IsError(node) {
+ return node, p
+ }
+ nodes = append(nodes, node)
+ }
+ return NewSequence(p.pos, nodes...), newP
+ }
+}
+
+func Any(parsers ...Parserish) Parser {
+ if len(parsers) == 0 {
+ return Nil
+ }
+
+ ps := ParsifyAll(parsers...)
+
+ return func(p Pointer) (Node, Pointer) {
+ errors := []Error{}
+ for _, parser := range ps {
+ node, newP := parser(p)
+ if err, isErr := node.(Error); isErr {
+ errors = append(errors, err)
+ continue
+ }
+ return node, newP
+ }
+
+ longestError := errors[0]
+ for _, e := range errors[1:] {
+ if e.pos > longestError.pos {
+ longestError = e
+ }
+ }
+
+ return longestError, p
+ }
+}
+
+func Kleene(opScan Parserish, sepScan ...Parserish) Parser {
+ return manyImpl(0, opScan, Never, sepScan...)
+}
+
+func KleeneUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
+ return manyImpl(0, opScan, untilScan, sepScan...)
+}
+
+func Many(opScan Parserish, sepScan ...Parserish) Parser {
+ return manyImpl(1, opScan, Never, sepScan...)
+}
+
+func ManyUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
+ return manyImpl(1, opScan, untilScan, sepScan...)
+}
+
+func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
+ opParser := Parsify(op)
+ untilParser := Parsify(until)
+ sepParser := Nil
+ if len(sep) > 0 {
+ sepParser = Parsify(sep[0])
+ }
+
+ return func(p Pointer) (Node, Pointer) {
+ var node Node
+ nodes := make([]Node, 0)
+ newP := p
+ for {
+ if node, _ := untilParser(newP); !IsError(node) {
+ if len(nodes) < min {
+ return NewError(newP.pos, "Unexpected input"), p
+ }
+ break
+ }
+
+ if node, newP = opParser(newP); IsError(node) {
+ if len(nodes) < min {
+ return node, p
+ }
+ break
+ }
+ nodes = append(nodes, node)
+ if node, newP = sepParser(newP); IsError(node) {
+ break
+ }
+ }
+ return NewSequence(p.pos, nodes...), newP
+ }
+}