summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Scarr <adam@vektah.net>2017-08-13 16:56:12 +1000
committerAdam Scarr <adam@vektah.net>2017-08-13 16:56:12 +1000
commit0dc37ae5bc10cc0669f88ab9febbc039a28f23d1 (patch)
tree0395aac5ab5223a4390eb03b22455ed3c98b6c90
parentf633909141dc1e2c2e49b94e5e478e99be51a9cb (diff)
Remove a few allocs from Run
-rw-r--r--.gitignore1
-rw-r--r--errors.go26
-rw-r--r--parser.go5
-rw-r--r--perf_test.go1
-rw-r--r--scripts/benchalloc.sh12
-rw-r--r--state.go14
6 files changed, 42 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 321d49b..dee607c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
cpu.out
mem.out
/vendor
+trace.log
diff --git a/errors.go b/errors.go
new file mode 100644
index 0000000..3f8787c
--- /dev/null
+++ b/errors.go
@@ -0,0 +1,26 @@
+package goparsify
+
+import "fmt"
+
+// Error represents a parse error. These will often be set, the parser will back up a little and
+// find another viable path. In general when combining errors the longest error should be returned.
+type Error struct {
+ pos int
+ expected string
+}
+
+// Pos is the offset into the document the error was found
+func (e *Error) Pos() int { return e.pos }
+
+// Error satisfies the golang error interface
+func (e *Error) Error() string { return fmt.Sprintf("offset %d: expected %s", e.pos, e.expected) }
+
+// UnparsedInputError is returned by Run when not all of the input was consumed. There may still be a valid result
+type UnparsedInputError struct {
+ remaining string
+}
+
+// Error satisfies the golang error interface
+func (e UnparsedInputError) Error() string {
+ return "left unparsed: " + e.remaining
+}
diff --git a/parser.go b/parser.go
index 87705ad..86f2e05 100644
--- a/parser.go
+++ b/parser.go
@@ -1,7 +1,6 @@
package goparsify
import (
- "errors"
"fmt"
"regexp"
"strings"
@@ -90,11 +89,11 @@ func Run(parser Parserish, input string, ws ...VoidParser) (result interface{},
ps.AutoWS()
if ps.Error.expected != "" {
- return ret.Result, ps.Error
+ return ret.Result, &ps.Error
}
if ps.Get() != "" {
- return ret.Result, errors.New("left unparsed: " + ps.Get())
+ return ret.Result, UnparsedInputError{ps.Get()}
}
return ret.Result, nil
diff --git a/perf_test.go b/perf_test.go
index d6a0092..7a2911e 100644
--- a/perf_test.go
+++ b/perf_test.go
@@ -5,6 +5,7 @@ import "testing"
func BenchmarkAny(b *testing.B) {
p := Any("hello", "goodbye", "help")
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = Run(p, "hello")
_, _ = Run(p, "hello world")
diff --git a/scripts/benchalloc.sh b/scripts/benchalloc.sh
new file mode 100644
index 0000000..8409938
--- /dev/null
+++ b/scripts/benchalloc.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+if [ $# != 1 ] ; then
+ echo Run this in a directory containing benchmarks and pass it the name of a benchmark. It will dump allocations out to trace.log
+ exit
+fi
+
+set -eu
+
+go test -c
+
+GODEBUG=allocfreetrace=1 ./$(basename $(pwd)).test.exe -test.run=none -test.bench=$1 -test.benchmem -test.benchtime=1ns 2> >(sed -n '/benchmark.go:75/,$p' > trace.log)
diff --git a/state.go b/state.go
index 8aab3e2..e567777 100644
--- a/state.go
+++ b/state.go
@@ -1,24 +1,10 @@
package goparsify
import (
- "fmt"
"unicode"
"unicode/utf8"
)
-// Error represents a parse error. These will often be set, the parser will back up a little and
-// find another viable path. In general when combining errors the longest error should be returned.
-type Error struct {
- pos int
- expected string
-}
-
-// Pos is the offset into the document the error was found
-func (e Error) Pos() int { return e.pos }
-
-// Error satisfies the golang error interface
-func (e Error) Error() string { return fmt.Sprintf("offset %d: expected %s", e.pos, e.expected) }
-
// State is the current parse state. It is entirely public because parsers are expected to mutate it during the parse.
type State struct {
// The full input string