From 132876fce437c35fc861b0796cd231405250bbd5 Mon Sep 17 00:00:00 2001 From: Adam Scarr Date: Mon, 7 Aug 2017 21:38:46 +1000 Subject: [PATCH] Small perf tweaks --- combinator.go | 43 ++++++++++++++++++++----------------------- combinator_test.go | 8 -------- parser.go | 2 ++ state.go | 18 ++++++++++-------- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/combinator.go b/combinator.go index 12991a3..15e6cea 100644 --- a/combinator.go +++ b/combinator.go @@ -8,11 +8,6 @@ var Nil = NewParser("Nil", func(ps *State) *Node { return nil }) -var Never = NewParser("Never", func(ps *State) *Node { - ps.ErrorHere("not anything") - return nil -}) - func And(parsers ...Parserish) Parser { if len(parsers) == 0 { return Nil @@ -20,7 +15,7 @@ func And(parsers ...Parserish) Parser { parserfied := ParsifyAll(parsers...) - return NewParser("And", 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 { @@ -56,7 +51,7 @@ func Any(parsers ...Parserish) Parser { parserfied := ParsifyAll(parsers...) - return NewParser("Any", func(ps *State) *Node { + return NewParser("Any()", func(ps *State) *Node { longestError := Error{} startpos := ps.Pos for _, parser := range parserfied { @@ -78,19 +73,19 @@ func Any(parsers ...Parserish) Parser { } func Kleene(opScan Parserish, sepScan ...Parserish) Parser { - return NewParser("Kleene", manyImpl(0, opScan, Never, sepScan...)) + 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("KleeneUntil()", manyImpl(0, opScan, untilScan, sepScan...)) } func Many(opScan Parserish, sepScan ...Parserish) Parser { - return NewParser("Many", manyImpl(1, opScan, Never, sepScan...)) + return NewParser("Many()", manyImpl(1, opScan, nil, sepScan...)) } func ManyUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser { - return NewParser("ManyUntil", manyImpl(1, opScan, untilScan, sepScan...)) + return NewParser("ManyUntil()", manyImpl(1, opScan, untilScan, sepScan...)) } func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { @@ -107,17 +102,19 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { startpos := ps.Pos for { tempPos := ps.Pos - node = untilParser(ps) - if !ps.Errored() { - ps.Pos = tempPos - if len(nodes) < min { - ps.Pos = startpos - ps.ErrorHere("something else") - return nil + if untilParser != nil { + node = untilParser(ps) + if !ps.Errored() { + ps.Pos = tempPos + if len(nodes) < min { + ps.Pos = startpos + ps.ErrorHere("something else") + return nil + } + break } - break + ps.ClearError() } - ps.ClearError() node = opParser(ps) if ps.Errored() { @@ -144,7 +141,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser { func Maybe(parser Parserish) Parser { parserfied := Parsify(parser) - return NewParser("Maybe", func(ps *State) *Node { + return NewParser("Maybe()", func(ps *State) *Node { node := parserfied(ps) if ps.Errored() { ps.ClearError() @@ -158,7 +155,7 @@ func Maybe(parser Parserish) Parser { func Map(parser Parserish, f func(n *Node) *Node) Parser { p := Parsify(parser) - return NewParser("Map", func(ps *State) *Node { + return NewParser("Map()", func(ps *State) *Node { node := p(ps) if ps.Errored() { return nil @@ -184,7 +181,7 @@ func flatten(n *Node) string { } func Merge(parser Parserish) Parser { - return NewParser("Merge", Map(parser, func(n *Node) *Node { + return NewParser("Merge()", Map(parser, func(n *Node) *Node { return &Node{Token: flatten(n)} })) } diff --git a/combinator_test.go b/combinator_test.go index dbf2b50..5fd23eb 100644 --- a/combinator_test.go +++ b/combinator_test.go @@ -14,14 +14,6 @@ func TestNil(t *testing.T) { require.False(t, p2.Errored()) } -func TestNever(t *testing.T) { - node, p2 := runParser("hello world", Never) - - require.Nil(t, node) - require.Equal(t, 0, p2.Pos) - require.True(t, p2.Errored()) -} - func TestAnd(t *testing.T) { parser := And("hello", "world") diff --git a/parser.go b/parser.go index 25a907e..2da450f 100644 --- a/parser.go +++ b/parser.go @@ -33,6 +33,8 @@ type Parserish interface{} func Parsify(p Parserish) Parser { switch p := p.(type) { + case nil: + return nil case func(*State) *Node: return NewParser("anonymous func", p) case Parser: diff --git a/state.go b/state.go index 99e6021..e624082 100644 --- a/state.go +++ b/state.go @@ -2,8 +2,6 @@ package goparsify import ( "fmt" - "strings" - "unicode/utf8" ) type Error struct { @@ -18,7 +16,7 @@ type State struct { Input string Pos int Error Error - WSChars string + WSChars []byte NoAutoWS bool } @@ -35,13 +33,17 @@ func (s *State) AutoWS() { } func (s *State) WS() { +loop: for s.Pos < len(s.Input) { - r, w := utf8.DecodeRuneInString(s.Input[s.Pos:]) - if !strings.ContainsRune(s.WSChars, r) { - return + // Pretty sure this is unicode safe as long as WSChars is only in the ascii range... + for _, ws := range s.WSChars { + if s.Input[s.Pos] == ws { + s.Pos++ + continue loop + } } - s.Pos += w + return } } @@ -66,5 +68,5 @@ func (s *State) Errored() bool { } func InputString(input string) *State { - return &State{Input: input, WSChars: "\t\n\v\f\r \x85\xA0"} + return &State{Input: input, WSChars: []byte("\t\n\v\f\r ")} }