goparsify/combinator.go

167 lines
3.1 KiB
Go
Raw Normal View History

2017-08-06 06:31:35 +02:00
package parsec
2017-08-06 09:02:39 +02:00
import (
"bytes"
"fmt"
)
2017-08-06 06:31:35 +02:00
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)
}
2017-08-06 09:02:39 +02:00
return nodes, newP
2017-08-06 06:31:35 +02:00
}
}
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
}
}
2017-08-06 09:02:39 +02:00
return nodes, newP
}
}
func Maybe(parser Parserish) Parser {
realParser := Parsify(parser)
return func(p Pointer) (Node, Pointer) {
node, newP := realParser(p)
if IsError(node) {
return nil, p
}
return node, newP
}
}
func Map(parser Parserish, f func(n Node) Node) Parser {
p := Parsify(parser)
return func(ptr Pointer) (Node, Pointer) {
node, newPtr := p(ptr)
if IsError(node) {
return node, ptr
}
return f(node), newPtr
}
}
func flatten(n Node) string {
if s, ok := n.(string); ok {
return s
2017-08-06 06:31:35 +02:00
}
2017-08-06 09:02:39 +02:00
if nodes, ok := n.([]Node); ok {
sbuf := &bytes.Buffer{}
for _, node := range nodes {
sbuf.WriteString(flatten(node))
}
return sbuf.String()
}
panic(fmt.Errorf("Dont know how to flatten %t", n))
}
func Merge(parser Parserish) Parser {
return Map(parser, func(n Node) Node {
return flatten(n)
})
2017-08-06 06:31:35 +02:00
}