add debugging

This commit is contained in:
Adam Scarr 2017-08-07 20:07:29 +10:00
parent 02103782eb
commit cc9d18219a
9 changed files with 129 additions and 33 deletions

View File

@ -1,17 +1,17 @@
package parsec
package goparsify
import (
"bytes"
)
func Nil(ps *State) *Node {
var Nil = NewParser("Nil", func(ps *State) *Node {
return nil
}
})
func Never(ps *State) *Node {
var Never = NewParser("Never", func(ps *State) *Node {
ps.ErrorHere("not anything")
return nil
}
})
func And(parsers ...Parserish) Parser {
if len(parsers) == 0 {
@ -20,7 +20,7 @@ func And(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...)
return func(ps *State) *Node {
return NewParser("And", func(ps *State) *Node {
var nodes = make([]*Node, 0, len(parserfied))
startpos := ps.Pos
for _, parser := range parserfied {
@ -34,7 +34,7 @@ func And(parsers ...Parserish) Parser {
}
}
return &Node{Children: nodes}
}
})
}
func Any(parsers ...Parserish) Parser {
@ -44,7 +44,7 @@ func Any(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...)
return func(ps *State) *Node {
return NewParser("Any", func(ps *State) *Node {
longestError := Error{}
startpos := ps.Pos
for _, parser := range parserfied {
@ -62,23 +62,23 @@ func Any(parsers ...Parserish) Parser {
ps.Error = longestError
ps.Pos = startpos
return nil
}
})
}
func Kleene(opScan Parserish, sepScan ...Parserish) Parser {
return manyImpl(0, opScan, Never, sepScan...)
return NewParser("Kleene", manyImpl(0, opScan, Never, sepScan...))
}
func KleeneUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
return manyImpl(0, opScan, untilScan, sepScan...)
return NewParser("KleeneUntil", manyImpl(0, opScan, untilScan, sepScan...))
}
func Many(opScan Parserish, sepScan ...Parserish) Parser {
return manyImpl(1, opScan, Never, sepScan...)
return NewParser("Many", manyImpl(1, opScan, Never, sepScan...))
}
func ManyUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
return manyImpl(1, opScan, untilScan, sepScan...)
return NewParser("ManyUntil", manyImpl(1, opScan, untilScan, sepScan...))
}
func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
@ -132,7 +132,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
func Maybe(parser Parserish) Parser {
parserfied := Parsify(parser)
return func(ps *State) *Node {
return NewParser("Maybe", func(ps *State) *Node {
node := parserfied(ps)
if ps.Errored() {
ps.ClearError()
@ -140,19 +140,19 @@ func Maybe(parser Parserish) Parser {
}
return node
}
})
}
func Map(parser Parserish, f func(n *Node) *Node) Parser {
p := Parsify(parser)
return func(ps *State) *Node {
return NewParser("Map", func(ps *State) *Node {
node := p(ps)
if ps.Errored() {
return nil
}
return f(node)
}
})
}
func flatten(n *Node) string {
@ -172,7 +172,7 @@ func flatten(n *Node) string {
}
func Merge(parser Parserish) Parser {
return Map(parser, func(n *Node) *Node {
return NewParser("Merge", Map(parser, func(n *Node) *Node {
return &Node{Token: flatten(n)}
})
}))
}

View File

@ -1,4 +1,4 @@
package parsec
package goparsify
import (
"testing"

11
debugoff.go Normal file
View File

@ -0,0 +1,11 @@
// +build !debug
package goparsify
func NewParser(description string, p Parser) Parser {
return p
}
func DumpDebugStats() {
}

83
debugon.go Normal file
View File

@ -0,0 +1,83 @@
// +build debug
package goparsify
import (
"fmt"
"runtime"
"sort"
"strings"
"time"
)
var parsers []*DebugParser
type DebugParser struct {
Description string
Caller string
Next Parser
Time time.Duration
Calls int
}
func (dp *DebugParser) Parse(ps *State) *Node {
start := time.Now()
ret := dp.Next(ps)
dp.Time = dp.Time + time.Since(start)
dp.Calls++
return ret
}
func getPackageName(f *runtime.Func) string {
parts := strings.Split(f.Name(), ".")
pl := len(parts)
if parts[pl-2][0] == '(' {
return strings.Join(parts[0:pl-2], ".")
} else {
return strings.Join(parts[0:pl-1], ".")
}
}
func NewParser(description string, p Parser) Parser {
fpcs := make([]uintptr, 1)
caller := ""
for i := 1; i < 10; i++ {
n := runtime.Callers(i, fpcs)
if n != 0 {
frame := runtime.FuncForPC(fpcs[0] - 1)
pkg := getPackageName(frame)
if pkg != "github.com/vektah/goparsify" {
file, line := frame.FileLine(fpcs[0] - 1)
caller = fmt.Sprintf("%s:%d", file, line)
break
}
}
}
dp := &DebugParser{
Description: description,
Next: p,
Caller: caller,
}
parsers = append(parsers, dp)
return dp.Parse
}
func DumpDebugStats() {
sort.Slice(parsers, func(i, j int) bool {
return parsers[i].Time >= parsers[j].Time
})
fmt.Println("Parser stats:")
for _, parser := range parsers {
fmt.Printf("%20s\t%10s\t%10d\tcalls\t%s\n", parser.Description, parser.Time.String(), parser.Calls, parser.Caller)
}
}

View File

@ -6,6 +6,7 @@ import (
parsecJson "github.com/prataprc/goparsec/json"
"github.com/stretchr/testify/require"
"github.com/vektah/goparsify"
)
func TestUnmarshal(t *testing.T) {
@ -58,6 +59,7 @@ func BenchmarkUnmarshalParsify(b *testing.B) {
_, err := Unmarshal(benchmarkString)
require.NoError(b, err)
}
goparsify.DumpDebugStats()
}
func BenchmarkUnmarshalStdlib(b *testing.B) {

View File

@ -1,4 +1,4 @@
package parsec
package goparsify
import (
"bytes"
@ -33,8 +33,8 @@ type Parserish interface{}
func Parsify(p Parserish) Parser {
switch p := p.(type) {
case func(*State) *Node:
return Parser(p)
//case func(*State) *Node:
// return NewParser("anonymous func", p)
case Parser:
return p
case *Parser:
@ -70,7 +70,7 @@ func ParseString(parser Parserish, input string) (result interface{}, remaining
}
func Exact(match string) Parser {
return func(ps *State) *Node {
return NewParser(match, func(ps *State) *Node {
if !strings.HasPrefix(ps.Get(), match) {
ps.ErrorHere(match)
return nil
@ -79,7 +79,7 @@ func Exact(match string) Parser {
ps.Advance(len(match))
return &Node{Token: match}
}
})
}
func parseRepetition(defaultMin, defaultMax int, repetition ...int) (min int, max int) {
@ -126,11 +126,11 @@ func parseMatcher(matcher string) (matches string, ranges [][]rune) {
}
func Chars(matcher string, repetition ...int) Parser {
return charsImpl(matcher, false, repetition...)
return NewParser("["+matcher+"]", charsImpl(matcher, false, repetition...))
}
func NotChars(matcher string, repetition ...int) Parser {
return charsImpl(matcher, true, repetition...)
return NewParser("!["+matcher+"]", charsImpl(matcher, true, repetition...))
}
func charsImpl(matcher string, stopOn bool, repetition ...int) Parser {
@ -173,7 +173,7 @@ func charsImpl(matcher string, stopOn bool, repetition ...int) Parser {
}
}
var ws = Chars("\t\n\v\f\r \x85\xA0", 0)
var ws = NewParser("WS", Chars("\t\n\v\f\r \x85\xA0", 0))
func WS(ps *State) *Node {
ws(ps)
@ -181,7 +181,7 @@ func WS(ps *State) *Node {
}
func String(quote rune) Parser {
return func(ps *State) *Node {
return NewParser("string", func(ps *State) *Node {
var r rune
var w int
var matched int
@ -213,5 +213,5 @@ func String(quote rune) Parser {
ps.ErrorHere("\"")
return nil
}
})
}

View File

@ -1,4 +1,4 @@
package parsec
package goparsify
import (
"testing"

View File

@ -1,4 +1,4 @@
package parsec
package goparsify
import "fmt"

View File

@ -1,4 +1,4 @@
package parsec
package goparsify
import (
"testing"