package parsec import ( "bytes" "fmt" ) 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 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 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 } 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) }) }