Small perf tweaks

This commit is contained in:
Adam Scarr 2017-08-07 21:38:46 +10:00
parent a656dc0d78
commit 132876fce4
4 changed files with 32 additions and 39 deletions

View File

@ -8,11 +8,6 @@ var Nil = NewParser("Nil", func(ps *State) *Node {
return nil return nil
}) })
var Never = NewParser("Never", func(ps *State) *Node {
ps.ErrorHere("not anything")
return nil
})
func And(parsers ...Parserish) Parser { func And(parsers ...Parserish) Parser {
if len(parsers) == 0 { if len(parsers) == 0 {
return Nil return Nil
@ -20,7 +15,7 @@ func And(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...) parserfied := ParsifyAll(parsers...)
return NewParser("And", 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 {
@ -56,7 +51,7 @@ func Any(parsers ...Parserish) Parser {
parserfied := ParsifyAll(parsers...) parserfied := ParsifyAll(parsers...)
return NewParser("Any", 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 {
@ -78,19 +73,19 @@ func Any(parsers ...Parserish) Parser {
} }
func Kleene(opScan Parserish, sepScan ...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 { 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 { 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 { 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 { func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
@ -107,6 +102,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
startpos := ps.Pos startpos := ps.Pos
for { for {
tempPos := ps.Pos tempPos := ps.Pos
if untilParser != nil {
node = untilParser(ps) node = untilParser(ps)
if !ps.Errored() { if !ps.Errored() {
ps.Pos = tempPos ps.Pos = tempPos
@ -118,6 +114,7 @@ func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
break break
} }
ps.ClearError() ps.ClearError()
}
node = opParser(ps) node = opParser(ps)
if ps.Errored() { if ps.Errored() {
@ -144,7 +141,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 NewParser("Maybe", 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()
@ -158,7 +155,7 @@ func Maybe(parser Parserish) Parser {
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 NewParser("Map", 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
@ -184,7 +181,7 @@ func flatten(n *Node) string {
} }
func Merge(parser Parserish) Parser { 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)} return &Node{Token: flatten(n)}
})) }))
} }

View File

@ -14,14 +14,6 @@ func TestNil(t *testing.T) {
require.False(t, p2.Errored()) 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) { func TestAnd(t *testing.T) {
parser := And("hello", "world") parser := And("hello", "world")

View File

@ -33,6 +33,8 @@ type Parserish interface{}
func Parsify(p Parserish) Parser { func Parsify(p Parserish) Parser {
switch p := p.(type) { switch p := p.(type) {
case nil:
return nil
case func(*State) *Node: case func(*State) *Node:
return NewParser("anonymous func", p) return NewParser("anonymous func", p)
case Parser: case Parser:

View File

@ -2,8 +2,6 @@ package goparsify
import ( import (
"fmt" "fmt"
"strings"
"unicode/utf8"
) )
type Error struct { type Error struct {
@ -18,7 +16,7 @@ type State struct {
Input string Input string
Pos int Pos int
Error Error Error Error
WSChars string WSChars []byte
NoAutoWS bool NoAutoWS bool
} }
@ -35,13 +33,17 @@ func (s *State) AutoWS() {
} }
func (s *State) WS() { func (s *State) WS() {
loop:
for s.Pos < len(s.Input) { for s.Pos < len(s.Input) {
r, w := utf8.DecodeRuneInString(s.Input[s.Pos:]) // Pretty sure this is unicode safe as long as WSChars is only in the ascii range...
if !strings.ContainsRune(s.WSChars, r) { for _, ws := range s.WSChars {
return 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 { 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 ")}
} }