parent
981f4347b1
commit
8a5260ae50
@ -36,7 +36,6 @@ func NoAutoWS(parser Parserish) Parser {
|
||||
func Any(parsers ...Parserish) Parser {
|
||||
parserfied := ParsifyAll(parsers...)
|
||||
// Records which parser was successful for each byte, and will use it first next time.
|
||||
predictor := [255]int{}
|
||||
|
||||
return NewParser("Any()", func(ps *State, node *Result) {
|
||||
ps.WS(ps)
|
||||
@ -45,13 +44,6 @@ func Any(parsers ...Parserish) Parser {
|
||||
return
|
||||
}
|
||||
startpos := ps.Pos
|
||||
predictorChar := ps.Input[startpos]
|
||||
predicted := predictor[predictorChar]
|
||||
|
||||
parserfied[predicted](ps, node)
|
||||
if !ps.Errored() {
|
||||
return
|
||||
}
|
||||
|
||||
longestError := ps.Error
|
||||
if ps.Cut <= startpos {
|
||||
@ -60,10 +52,7 @@ func Any(parsers ...Parserish) Parser {
|
||||
return
|
||||
}
|
||||
|
||||
for i, parser := range parserfied {
|
||||
if i == predicted {
|
||||
continue
|
||||
}
|
||||
for _, parser := range parserfied {
|
||||
parser(ps, node)
|
||||
if ps.Errored() {
|
||||
if ps.Error.pos >= longestError.pos {
|
||||
@ -75,7 +64,6 @@ func Any(parsers ...Parserish) Parser {
|
||||
ps.Recover()
|
||||
continue
|
||||
}
|
||||
predictor[predictorChar] = i
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"os"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func TestSeq(t *testing.T) {
|
||||
@ -62,38 +64,27 @@ func TestAny(t *testing.T) {
|
||||
require.Equal(t, 0, p2.Pos)
|
||||
})
|
||||
|
||||
t.Run("branch prediction", func(t *testing.T) {
|
||||
p := Any("hello", Seq("{", Cut(), "world", "}"), Seq("[", Cut(), "a", "]"))
|
||||
// warm up the predictor
|
||||
_, _ = Run(p, "hello")
|
||||
_, _ = Run(p, "{world}")
|
||||
t.Run("overlapping longest match", func(t *testing.T) {
|
||||
EnableLogging(os.Stdout)
|
||||
p := Many(Any("ab", "a"))
|
||||
|
||||
t.Run("matches", func(t *testing.T) {
|
||||
node, ps := runParser("hello world!", p)
|
||||
require.Equal(t, "hello", node.Token)
|
||||
require.Equal(t, 5, ps.Pos)
|
||||
t.Run("a ab", func(t *testing.T) {
|
||||
node, ps := runParser("a ab", p)
|
||||
|
||||
require.False(t, ps.Errored())
|
||||
require.Equal(t, "a", node.Child[0].Token)
|
||||
require.Equal(t, "ab", node.Child[1].Token)
|
||||
})
|
||||
|
||||
t.Run("errors", func(t *testing.T) {
|
||||
_, ps := runParser("help world!", p)
|
||||
require.Equal(t, "offset 0: expected [", ps.Error.Error())
|
||||
require.Equal(t, 0, ps.Error.Pos())
|
||||
require.Equal(t, 0, ps.Pos)
|
||||
})
|
||||
t.Run("ab a", func(t *testing.T) {
|
||||
node, ps := runParser("ab a", p)
|
||||
|
||||
t.Run("errors with cuts", func(t *testing.T) {
|
||||
_, ps := runParser("{world", p)
|
||||
require.Equal(t, "offset 6: expected }", ps.Error.Error())
|
||||
require.Equal(t, 6, ps.Error.Pos())
|
||||
require.Equal(t, 0, ps.Pos)
|
||||
})
|
||||
fmt.Println(node)
|
||||
|
||||
require.False(t, ps.Errored())
|
||||
require.Equal(t, "ab", node.Child[0].Token)
|
||||
require.Equal(t, "a", node.Child[1].Token)
|
||||
|
||||
t.Run("misprededicted cut", func(t *testing.T) {
|
||||
// This should probably only happen when the predictor is cold
|
||||
_, ps := runParser("[a", p)
|
||||
require.Equal(t, "offset 2: expected ]", ps.Error.Error())
|
||||
require.Equal(t, 2, ps.Error.Pos())
|
||||
require.Equal(t, 0, ps.Pos)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user