goparsify/combinator.go

178 lines
3.2 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 15:32:10 +02:00
func Nil(ps *State) interface{} {
return nil
2017-08-06 06:31:35 +02:00
}
2017-08-06 15:32:10 +02:00
func Never(ps *State) interface{} {
ps.ErrorHere("not anything")
return nil
2017-08-06 06:31:35 +02:00
}
func And(parsers ...Parserish) Parser {
if len(parsers) == 0 {
return Nil
}
2017-08-06 15:32:10 +02:00
parserfied := ParsifyAll(parsers...)
2017-08-06 06:31:35 +02:00
2017-08-06 15:32:10 +02:00
return func(ps *State) interface{} {
var nodes = make([]interface{}, 0, len(parserfied))
startpos := ps.Pos
for _, parser := range parserfied {
node := parser(ps)
if ps.Errored() {
ps.Pos = startpos
return nil
2017-08-06 06:31:35 +02:00
}
2017-08-06 15:32:10 +02:00
if node != nil {
nodes = append(nodes, node)
2017-08-06 06:31:35 +02:00
}
}
2017-08-06 15:32:10 +02:00
return nodes
2017-08-06 06:31:35 +02:00
}
}
func Any(parsers ...Parserish) Parser {
if len(parsers) == 0 {
return Nil
}
2017-08-06 15:32:10 +02:00
parserfied := ParsifyAll(parsers...)
2017-08-06 06:31:35 +02:00
2017-08-06 15:32:10 +02:00
return func(ps *State) interface{} {
longestError := Error{}
startpos := ps.Pos
for _, parser := range parserfied {
node := parser(ps)
if ps.Errored() {
if ps.Error.pos > longestError.pos {
longestError = ps.Error
}
ps.ClearError()
2017-08-06 06:31:35 +02:00
continue
}
2017-08-06 15:32:10 +02:00
return node
2017-08-06 06:31:35 +02:00
}
2017-08-06 15:32:10 +02:00
ps.Error = longestError
ps.Pos = startpos
return nil
2017-08-06 06:31:35 +02:00
}
}
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])
}
2017-08-06 15:32:10 +02:00
return func(ps *State) interface{} {
var node interface{}
nodes := make([]interface{}, 0, 20)
startpos := ps.Pos
2017-08-06 06:31:35 +02:00
for {
2017-08-06 15:32:10 +02:00
tempPos := ps.Pos
node = untilParser(ps)
if !ps.Errored() {
ps.Pos = tempPos
2017-08-06 06:31:35 +02:00
if len(nodes) < min {
2017-08-06 15:32:10 +02:00
ps.Pos = startpos
ps.ErrorHere("something else")
return nil
2017-08-06 06:31:35 +02:00
}
break
}
2017-08-06 15:32:10 +02:00
ps.ClearError()
2017-08-06 06:31:35 +02:00
2017-08-06 15:32:10 +02:00
node = opParser(ps)
if ps.Errored() {
2017-08-06 06:31:35 +02:00
if len(nodes) < min {
2017-08-06 15:32:10 +02:00
ps.Pos = startpos
return nil
2017-08-06 06:31:35 +02:00
}
2017-08-06 15:32:10 +02:00
ps.ClearError()
2017-08-06 06:31:35 +02:00
break
}
2017-08-06 15:32:10 +02:00
2017-08-06 06:31:35 +02:00
nodes = append(nodes, node)
2017-08-06 15:32:10 +02:00
node = sepParser(ps)
if ps.Errored() {
ps.ClearError()
2017-08-06 06:31:35 +02:00
break
}
}
2017-08-06 15:32:10 +02:00
return nodes
2017-08-06 09:02:39 +02:00
}
}
func Maybe(parser Parserish) Parser {
2017-08-06 15:32:10 +02:00
parserfied := Parsify(parser)
2017-08-06 09:02:39 +02:00
2017-08-06 15:32:10 +02:00
return func(ps *State) interface{} {
node := parserfied(ps)
if ps.Errored() {
ps.ClearError()
return nil
2017-08-06 09:02:39 +02:00
}
2017-08-06 15:32:10 +02:00
return node
2017-08-06 09:02:39 +02:00
}
}
2017-08-06 15:32:10 +02:00
func Map(parser Parserish, f func(n interface{}) interface{}) Parser {
2017-08-06 09:02:39 +02:00
p := Parsify(parser)
2017-08-06 15:32:10 +02:00
return func(ps *State) interface{} {
node := p(ps)
if ps.Errored() {
return nil
2017-08-06 09:02:39 +02:00
}
2017-08-06 15:32:10 +02:00
return f(node)
2017-08-06 09:02:39 +02:00
}
}
2017-08-06 15:32:10 +02:00
func flatten(n interface{}) interface{} {
2017-08-06 09:02:39 +02:00
if s, ok := n.(string); ok {
return s
2017-08-06 06:31:35 +02:00
}
2017-08-06 09:02:39 +02:00
2017-08-06 15:32:10 +02:00
if nodes, ok := n.([]interface{}); ok {
2017-08-06 09:02:39 +02:00
sbuf := &bytes.Buffer{}
for _, node := range nodes {
2017-08-06 15:32:10 +02:00
sbuf.WriteString(flatten(node).(string))
2017-08-06 09:02:39 +02:00
}
return sbuf.String()
}
panic(fmt.Errorf("Dont know how to flatten %t", n))
}
func Merge(parser Parserish) Parser {
2017-08-06 15:32:10 +02:00
return Map(parser, flatten)
2017-08-06 06:31:35 +02:00
}