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
|
|
|
}
|