2017-08-07 12:07:29 +02:00
|
|
|
package goparsify
|
2017-08-06 06:31:35 +02:00
|
|
|
|
2017-08-06 09:02:39 +02:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
)
|
|
|
|
|
2017-08-09 11:35:15 +02:00
|
|
|
func Seq(parsers ...Parserish) Parser {
|
2017-08-06 15:32:10 +02:00
|
|
|
parserfied := ParsifyAll(parsers...)
|
2017-08-06 06:31:35 +02:00
|
|
|
|
2017-08-09 11:35:15 +02:00
|
|
|
return NewParser("Seq()", func(ps *State) Node {
|
2017-08-08 15:11:47 +02:00
|
|
|
result := Node{Child: make([]Node, len(parserfied))}
|
2017-08-06 15:32:10 +02:00
|
|
|
startpos := ps.Pos
|
2017-08-07 14:38:34 +02:00
|
|
|
for i, parser := range parserfied {
|
2017-08-08 15:11:47 +02:00
|
|
|
result.Child[i] = parser(ps)
|
2017-08-06 15:32:10 +02:00
|
|
|
if ps.Errored() {
|
|
|
|
ps.Pos = startpos
|
2017-08-07 14:38:34 +02:00
|
|
|
return result
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-07 14:38:34 +02:00
|
|
|
return result
|
2017-08-07 12:07:29 +02:00
|
|
|
})
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
|
2017-08-07 13:20:30 +02:00
|
|
|
func NoAutoWS(parser Parserish) Parser {
|
|
|
|
parserfied := Parsify(parser)
|
2017-08-07 13:45:12 +02:00
|
|
|
return func(ps *State) Node {
|
2017-08-07 13:20:30 +02:00
|
|
|
ps.NoAutoWS = true
|
|
|
|
|
|
|
|
ret := parserfied(ps)
|
|
|
|
|
|
|
|
ps.NoAutoWS = false
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-06 06:31:35 +02:00
|
|
|
func Any(parsers ...Parserish) Parser {
|
2017-08-06 15:32:10 +02:00
|
|
|
parserfied := ParsifyAll(parsers...)
|
2017-08-06 06:31:35 +02:00
|
|
|
|
2017-08-07 13:45:12 +02:00
|
|
|
return NewParser("Any()", func(ps *State) Node {
|
2017-08-06 15:32:10 +02:00
|
|
|
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
|
2017-08-07 13:45:12 +02:00
|
|
|
return Node{}
|
2017-08-07 12:07:29 +02:00
|
|
|
})
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
|
2017-08-09 11:35:15 +02:00
|
|
|
func Some(opScan Parserish, sepScan ...Parserish) Parser {
|
|
|
|
return NewParser("Some()", manyImpl(0, opScan, sepScan...))
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func Many(opScan Parserish, sepScan ...Parserish) Parser {
|
2017-08-07 14:38:34 +02:00
|
|
|
return NewParser("Many()", manyImpl(1, opScan, sepScan...))
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
|
2017-08-07 14:38:34 +02:00
|
|
|
func manyImpl(min int, op Parserish, sep ...Parserish) Parser {
|
|
|
|
var opParser = Parsify(op)
|
|
|
|
var sepParser Parser
|
2017-08-06 06:31:35 +02:00
|
|
|
if len(sep) > 0 {
|
|
|
|
sepParser = Parsify(sep[0])
|
|
|
|
}
|
|
|
|
|
2017-08-07 13:45:12 +02:00
|
|
|
return func(ps *State) Node {
|
2017-08-07 14:38:34 +02:00
|
|
|
var result Node
|
2017-08-06 15:32:10 +02:00
|
|
|
startpos := ps.Pos
|
2017-08-06 06:31:35 +02:00
|
|
|
for {
|
2017-08-07 14:38:34 +02:00
|
|
|
node := opParser(ps)
|
2017-08-06 15:32:10 +02:00
|
|
|
if ps.Errored() {
|
2017-08-08 15:11:47 +02:00
|
|
|
if len(result.Child) < min {
|
2017-08-06 15:32:10 +02:00
|
|
|
ps.Pos = startpos
|
2017-08-07 14:38:34 +02:00
|
|
|
return result
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
2017-08-06 15:32:10 +02:00
|
|
|
ps.ClearError()
|
2017-08-07 14:38:34 +02:00
|
|
|
return result
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
2017-08-08 15:11:47 +02:00
|
|
|
result.Child = append(result.Child, node)
|
2017-08-06 15:32:10 +02:00
|
|
|
|
2017-08-07 14:38:34 +02:00
|
|
|
if sepParser != nil {
|
|
|
|
sepParser(ps)
|
|
|
|
if ps.Errored() {
|
|
|
|
ps.ClearError()
|
|
|
|
return result
|
|
|
|
}
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
}
|
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-07 13:45:12 +02:00
|
|
|
return NewParser("Maybe()", func(ps *State) Node {
|
2017-08-06 15:32:10 +02:00
|
|
|
node := parserfied(ps)
|
|
|
|
if ps.Errored() {
|
|
|
|
ps.ClearError()
|
2017-08-06 09:02:39 +02:00
|
|
|
}
|
2017-08-06 15:32:10 +02:00
|
|
|
|
|
|
|
return node
|
2017-08-07 12:07:29 +02:00
|
|
|
})
|
2017-08-06 09:02:39 +02:00
|
|
|
}
|
|
|
|
|
2017-08-07 14:57:06 +02:00
|
|
|
func Bind(parser Parserish, val interface{}) Parser {
|
|
|
|
p := Parsify(parser)
|
|
|
|
|
|
|
|
return func(ps *State) Node {
|
|
|
|
node := p(ps)
|
|
|
|
if ps.Errored() {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
node.Result = val
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-07 13:45:12 +02:00
|
|
|
func Map(parser Parserish, f func(n Node) Node) Parser {
|
2017-08-06 09:02:39 +02:00
|
|
|
p := Parsify(parser)
|
|
|
|
|
2017-08-07 13:45:12 +02:00
|
|
|
return NewParser("Map()", func(ps *State) Node {
|
2017-08-06 15:32:10 +02:00
|
|
|
node := p(ps)
|
|
|
|
if ps.Errored() {
|
2017-08-07 14:38:34 +02:00
|
|
|
return node
|
2017-08-06 09:02:39 +02:00
|
|
|
}
|
2017-08-06 15:32:10 +02:00
|
|
|
return f(node)
|
2017-08-07 12:07:29 +02:00
|
|
|
})
|
2017-08-06 09:02:39 +02:00
|
|
|
}
|
|
|
|
|
2017-08-07 13:45:12 +02:00
|
|
|
func flatten(n Node) string {
|
2017-08-07 10:25:23 +02:00
|
|
|
if n.Token != "" {
|
|
|
|
return n.Token
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
2017-08-06 09:02:39 +02:00
|
|
|
|
2017-08-08 15:11:47 +02:00
|
|
|
if len(n.Child) > 0 {
|
2017-08-06 09:02:39 +02:00
|
|
|
sbuf := &bytes.Buffer{}
|
2017-08-08 15:11:47 +02:00
|
|
|
for _, node := range n.Child {
|
2017-08-07 10:25:23 +02:00
|
|
|
sbuf.WriteString(flatten(node))
|
2017-08-06 09:02:39 +02:00
|
|
|
}
|
|
|
|
return sbuf.String()
|
|
|
|
}
|
|
|
|
|
2017-08-07 10:25:23 +02:00
|
|
|
return ""
|
2017-08-06 09:02:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func Merge(parser Parserish) Parser {
|
2017-08-07 13:45:12 +02:00
|
|
|
return NewParser("Merge()", Map(parser, func(n Node) Node {
|
|
|
|
return Node{Token: flatten(n)}
|
2017-08-07 12:07:29 +02:00
|
|
|
}))
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|