summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Scarr <adam@vektah.net>2017-08-07 22:38:34 +1000
committerAdam Scarr <adam@vektah.net>2017-08-07 22:38:34 +1000
commit4594587e3b7d1b474ce2444e821294c63cabe3da (patch)
tree05c3e1f4534d3a5edec2a024877f6b77306b0721
parentb4f5fb423e5dec43ec702987dc3ddcb9df317d75 (diff)
More perf tweaks
-rw-r--r--combinator.go73
-rw-r--r--combinator_test.go29
-rw-r--r--json/profile/json.go22
-rw-r--r--parser.go2
-rw-r--r--parser_test.go6
5 files changed, 40 insertions, 92 deletions
diff --git a/combinator.go b/combinator.go
index 48aef09..f072913 100644
--- a/combinator.go
+++ b/combinator.go
@@ -16,17 +16,16 @@ func And(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...)
return NewParser("And()", func(ps *State) Node {
- var nodes = make([]Node, 0, len(parserfied))
+ result := Node{Children: make([]Node, len(parserfied))}
startpos := ps.Pos
- for _, parser := range parserfied {
- node := parser(ps)
+ for i, parser := range parserfied {
+ result.Children[i] = parser(ps)
if ps.Errored() {
ps.Pos = startpos
- return Node{}
+ return result
}
- nodes = append(nodes, node)
}
- return Node{Children: nodes}
+ return result
})
}
@@ -71,68 +70,43 @@ func Any(parsers ...Parserish) Parser {
}
func Kleene(opScan Parserish, sepScan ...Parserish) Parser {
- return NewParser("Kleene()", manyImpl(0, opScan, nil, sepScan...))
-}
-
-func KleeneUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
- return NewParser("KleeneUntil()", manyImpl(0, opScan, untilScan, sepScan...))
+ return NewParser("Kleene()", manyImpl(0, opScan, sepScan...))
}
func Many(opScan Parserish, sepScan ...Parserish) Parser {
- return NewParser("Many()", manyImpl(1, opScan, nil, sepScan...))
+ return NewParser("Many()", manyImpl(1, opScan, sepScan...))
}
-func ManyUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
- return NewParser("ManyUntil()", manyImpl(1, opScan, untilScan, sepScan...))
-}
-
-func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
- opParser := Parsify(op)
- untilParser := Parsify(until)
- sepParser := Nil
+func manyImpl(min int, op Parserish, sep ...Parserish) Parser {
+ var opParser = Parsify(op)
+ var sepParser Parser
if len(sep) > 0 {
sepParser = Parsify(sep[0])
}
return func(ps *State) Node {
- var node Node
- nodes := make([]Node, 0, 20)
+ var result Node
startpos := ps.Pos
for {
- tempPos := ps.Pos
- if untilParser != nil {
- node = untilParser(ps)
- if !ps.Errored() {
- ps.Pos = tempPos
- if len(nodes) < min {
- ps.Pos = startpos
- ps.ErrorHere("something else")
- return Node{}
- }
- break
- }
- ps.ClearError()
- }
-
- node = opParser(ps)
+ node := opParser(ps)
if ps.Errored() {
- if len(nodes) < min {
+ if len(result.Children) < min {
ps.Pos = startpos
- return Node{}
+ return result
}
ps.ClearError()
- break
+ return result
}
+ result.Children = append(result.Children, node)
- nodes = append(nodes, node)
-
- node = sepParser(ps)
- if ps.Errored() {
- ps.ClearError()
- break
+ if sepParser != nil {
+ sepParser(ps)
+ if ps.Errored() {
+ ps.ClearError()
+ return result
+ }
}
}
- return Node{Children: nodes}
}
}
@@ -143,7 +117,6 @@ func Maybe(parser Parserish) Parser {
node := parserfied(ps)
if ps.Errored() {
ps.ClearError()
- return Node{}
}
return node
@@ -156,7 +129,7 @@ func Map(parser Parserish, f func(n Node) Node) Parser {
return NewParser("Map()", func(ps *State) Node {
node := p(ps)
if ps.Errored() {
- return Node{}
+ return node
}
return f(node)
})
diff --git a/combinator_test.go b/combinator_test.go
index 10ff788..4ac96b1 100644
--- a/combinator_test.go
+++ b/combinator_test.go
@@ -134,35 +134,6 @@ func TestMany(t *testing.T) {
})
}
-func TestKleeneUntil(t *testing.T) {
- t.Run("Matches sequence with sep", func(t *testing.T) {
- node, p2 := runParser("a,b,c,d,e,fg", KleeneUntil(Chars("abcde"), "d", ","))
- assertSequence(t, node, "a", "b", "c")
- require.Equal(t, "d,e,fg", p2.Get())
- })
-
- t.Run("Breaks if separator does not match", func(t *testing.T) {
- node, p2 := runParser("a,b,c,d,e,fg", KleeneUntil(Chars("abcdefg", 1, 1), "y", ","))
- assertSequence(t, node, "a", "b", "c", "d", "e", "f")
- require.Equal(t, "g", p2.Get())
- })
-}
-
-func TestManyUntil(t *testing.T) {
- t.Run("Matches sequence until", func(t *testing.T) {
- node, p2 := runParser("a,b,c,d,e,", ManyUntil(Chars("abcdefg"), "d", ","))
- assertSequence(t, node, "a", "b", "c")
- require.Equal(t, 6, p2.Pos)
- })
-
- t.Run("Returns error until matches early", func(t *testing.T) {
- _, p2 := runParser("a,b,c,d,e,", ManyUntil(Chars("abc"), "a", ","))
- require.Equal(t, "offset 0: Expected something else", p2.Error.Error())
- require.Equal(t, 0, p2.Pos)
- require.Equal(t, "a,b,c,d,e,", p2.Get())
- })
-}
-
type htmlTag struct {
Name string
}
diff --git a/json/profile/json.go b/json/profile/json.go
index a03d047..0579fce 100644
--- a/json/profile/json.go
+++ b/json/profile/json.go
@@ -34,7 +34,16 @@ func main() {
max := 1000000
if *memprofile != "" {
runtime.MemProfileRate = 1
- max = 10000
+ max = 100000
+ defer func() {
+ f, err := os.Create(*memprofile)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ pprof.WriteHeapProfile(f)
+ f.Close()
+ }()
}
for i := 0; i < max; i++ {
@@ -43,15 +52,4 @@ func main() {
panic(err)
}
}
-
- if *memprofile != "" {
- f, err := os.Create(*memprofile)
- if err != nil {
- log.Fatal(err)
- }
-
- pprof.WriteHeapProfile(f)
- f.Close()
- return
- }
}
diff --git a/parser.go b/parser.go
index 2477bb4..62383b9 100644
--- a/parser.go
+++ b/parser.go
@@ -85,7 +85,7 @@ func Exact(match string) Parser {
matchByte := match[0]
return NewParser(match, func(ps *State) Node {
ps.AutoWS()
- if ps.Input[ps.Pos] != matchByte {
+ if ps.Pos >= len(ps.Input) || ps.Input[ps.Pos] != matchByte {
ps.ErrorHere(match)
return Node{}
}
diff --git a/parser_test.go b/parser_test.go
index 594fcae..caa2f8b 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -72,6 +72,12 @@ func TestExact(t *testing.T) {
require.Equal(t, "o", ps.Error.Expected)
require.Equal(t, 0, ps.Pos)
})
+
+ t.Run("eof char", func(t *testing.T) {
+ _, ps := runParser("", Exact("o"))
+ require.Equal(t, "o", ps.Error.Expected)
+ require.Equal(t, 0, ps.Pos)
+ })
}
func TestChars(t *testing.T) {