summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Scarr <adam@vektah.net>2018-06-11 11:54:35 +1000
committerAdam Scarr <adam@vektah.net>2018-06-11 11:54:35 +1000
commit8a5260ae50486c5e424d9778b7ec824b27842b9d (patch)
tree8cbd8a6fffe8491fda32f6e69f4e878730f53fe5
parent981f4347b18e79a0b3fbaa73b2a1c31bba1a4da4 (diff)
remove branch predictor in Any
fixes #2
-rw-r--r--combinator.go14
-rw-r--r--combinator_test.go45
2 files changed, 19 insertions, 40 deletions
diff --git a/combinator.go b/combinator.go
index 38145ee..5b0d584 100644
--- a/combinator.go
+++ b/combinator.go
@@ -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
}
diff --git a/combinator_test.go b/combinator_test.go
index c1eedb3..aa16e21 100644
--- a/combinator_test.go
+++ b/combinator_test.go
@@ -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)
- 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)
+ require.False(t, ps.Errored())
+ require.Equal(t, "a", node.Child[0].Token)
+ require.Equal(t, "ab", node.Child[1].Token)
})
- 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)
- })
+ t.Run("ab a", func(t *testing.T) {
+ node, ps := runParser("ab a", p)
+
+ 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)
})
})
}