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 ( import (
"bytes" "bytes"
) )
func Nil(ps *State) *Node { var Nil = NewParser("Nil", func(ps *State) *Node {
return nil return nil
} })
func Never(ps *State) *Node { var Never = NewParser("Never", func(ps *State) *Node {
ps.ErrorHere("not anything") ps.ErrorHere("not anything")
return nil return nil
} })
func And(parsers ...Parserish) Parser { func And(parsers ...Parserish) Parser {
if len(parsers) == 0 { if len(parsers) == 0 {
@ -20,7 +20,7 @@ func And(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...) parserfied := ParsifyAll(parsers...)
return func(ps *State) *Node { return NewParser("And", func(ps *State) *Node {
var nodes = make([]*Node, 0, len(parserfied)) var nodes = make([]*Node, 0, len(parserfied))
startpos := ps.Pos startpos := ps.Pos
for _, parser := range parserfied { for _, parser := range parserfied {
@ -34,7 +34,7 @@ func And(parsers ...Parserish) Parser {
} }
} }
return &Node{Children: nodes} return &Node{Children: nodes}
} })
} }
func Any(parsers ...Parserish) Parser { func Any(parsers ...Parserish) Parser {
@ -44,7 +44,7 @@ func Any(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...) parserfied := ParsifyAll(parsers...)
return func(ps *State) *Node { return NewParser("Any", func(ps *State) *Node {
longestError := Error{} longestError := Error{}
startpos := ps.Pos startpos := ps.Pos
for _, parser := range parserfied { for _, parser := range parserfied {
@ -62,23 +62,23 @@ func Any(parsers ...Parserish) Parser {
ps.Error = longestError ps.Error = longestError
ps.Pos = startpos ps.Pos = startpos
return nil return nil
} })
} }
func Kleene(opScan Parserish, sepScan ...Parserish) Parser { 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 { 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 { 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 { 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 { 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 { func Maybe(parser Parserish) Parser {
parserfied := Parsify(parser) parserfied := Parsify(parser)
return func(ps *State) *Node { return NewParser("Maybe", func(ps *State) *Node {
node := parserfied(ps) node := parserfied(ps)
if ps.Errored() { if ps.Errored() {
ps.ClearError() ps.ClearError()
@ -140,19 +140,19 @@ func Maybe(parser Parserish) Parser {
} }
return node return node
} })
} }
func Map(parser Parserish, f func(n *Node) *Node) Parser { func Map(parser Parserish, f func(n *Node) *Node) Parser {
p := Parsify(parser) p := Parsify(parser)
return func(ps *State) *Node { return NewParser("Map", func(ps *State) *Node {
node := p(ps) node := p(ps)
if ps.Errored() { if ps.Errored() {
return nil return nil
} }
return f(node) return f(node)
} })
} }
func flatten(n *Node) string { func flatten(n *Node) string {
@ -172,7 +172,7 @@ func flatten(n *Node) string {
} }
func Merge(parser Parserish) Parser { 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)} return &Node{Token: flatten(n)}
}) }))
} }

View File

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

View File

@ -1,4 +1,4 @@
package parsec package goparsify
import ( import (
"bytes" "bytes"
@ -33,8 +33,8 @@ type Parserish interface{}
func Parsify(p Parserish) Parser { func Parsify(p Parserish) Parser {
switch p := p.(type) { switch p := p.(type) {
case func(*State) *Node: //case func(*State) *Node:
return Parser(p) // return NewParser("anonymous func", p)
case Parser: case Parser:
return p return p
case *Parser: case *Parser:
@ -70,7 +70,7 @@ func ParseString(parser Parserish, input string) (result interface{}, remaining
} }
func Exact(match string) Parser { func Exact(match string) Parser {
return func(ps *State) *Node { return NewParser(match, func(ps *State) *Node {
if !strings.HasPrefix(ps.Get(), match) { if !strings.HasPrefix(ps.Get(), match) {
ps.ErrorHere(match) ps.ErrorHere(match)
return nil return nil
@ -79,7 +79,7 @@ func Exact(match string) Parser {
ps.Advance(len(match)) ps.Advance(len(match))
return &Node{Token: match} return &Node{Token: match}
} })
} }
func parseRepetition(defaultMin, defaultMax int, repetition ...int) (min int, max int) { 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 { 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 { 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 { 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 { func WS(ps *State) *Node {
ws(ps) ws(ps)
@ -181,7 +181,7 @@ func WS(ps *State) *Node {
} }
func String(quote rune) Parser { func String(quote rune) Parser {
return func(ps *State) *Node { return NewParser("string", func(ps *State) *Node {
var r rune var r rune
var w int var w int
var matched int var matched int
@ -213,5 +213,5 @@ func String(quote rune) Parser {
ps.ErrorHere("\"") ps.ErrorHere("\"")
return nil return nil
} })
} }

View File

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

View File

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

View File

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