Add an Until function

This commit is contained in:
Adam Scarr 2017-08-13 22:11:27 +10:00
parent 139e7606f4
commit ddb61bdfc0
3 changed files with 49 additions and 1 deletions

View File

@ -26,7 +26,7 @@ func NoAutoWS(parser Parserish) Parser {
parserfied := Parsify(parser)
return func(ps *State, node *Result) {
oldWS := ps.WS
ps.WS = func(ps *State) {}
ps.WS = NoWhitespace
parserfied(ps, node)
ps.WS = oldWS
}
@ -145,6 +145,36 @@ func Maybe(parser Parserish) Parser {
})
}
// Until will consume all input until one of the given parsers match. This is running every parser over every byte,
// so its probably going to be slow.
func Until(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...)
return NewParser("Until()", func(ps *State, node *Result) {
ws := ps.WS
ps.WS = NoWhitespace
defer func() {
ps.WS = ws
}()
startPos := ps.Pos
for ps.Pos < len(ps.Input) {
endPos := ps.Pos
for _, p := range parserfied {
ps.Pos = endPos
p(ps, node)
if !ps.Errored() {
node.Token = ps.Input[startPos:endPos]
return
}
ps.Recover()
}
ps.Pos++
}
node.Token = ps.Input[startPos:ps.Pos]
})
}
// Bind will set the node .Result when the given parser matches
// This is useful for giving a value to keywords and constant literals
// like true and false. See the json parser for an example.

View File

@ -181,6 +181,20 @@ func TestMap(t *testing.T) {
})
}
func TestUntil(t *testing.T) {
parser := Until("world", ".")
t.Run("success", func(t *testing.T) {
result, _ := runParser("this is the end of the world", parser)
require.Equal(t, "this is the end of the ", result.Token)
})
t.Run("eof", func(t *testing.T) {
result, _ := runParser("this is the end of it all", parser)
require.Equal(t, "this is the end of it all", result.Token)
})
}
func TestBind(t *testing.T) {
parser := Bind("true", true)

View File

@ -44,6 +44,10 @@ func UnicodeWhitespace(s *State) {
}
s.Pos += w
}
}
// NoWhitespace disables automatic whitespace matching
func NoWhitespace(s *State) {
}