More perf tweaks
This commit is contained in:
parent
b4f5fb423e
commit
4594587e3b
@ -16,17 +16,16 @@ 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))
|
result := Node{Children: make([]Node, len(parserfied))}
|
||||||
startpos := ps.Pos
|
startpos := ps.Pos
|
||||||
for _, parser := range parserfied {
|
for i, parser := range parserfied {
|
||||||
node := parser(ps)
|
result.Children[i] = parser(ps)
|
||||||
if ps.Errored() {
|
if ps.Errored() {
|
||||||
ps.Pos = startpos
|
ps.Pos = startpos
|
||||||
return Node{}
|
return result
|
||||||
}
|
}
|
||||||
nodes = append(nodes, node)
|
|
||||||
}
|
}
|
||||||
return Node{Children: nodes}
|
return result
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,68 +70,43 @@ 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, nil, sepScan...))
|
return NewParser("Kleene()", manyImpl(0, opScan, sepScan...))
|
||||||
}
|
|
||||||
|
|
||||||
func KleeneUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
|
|
||||||
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, nil, sepScan...))
|
return NewParser("Many()", manyImpl(1, opScan, sepScan...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ManyUntil(opScan Parserish, untilScan Parserish, sepScan ...Parserish) Parser {
|
func manyImpl(min int, op Parserish, sep ...Parserish) Parser {
|
||||||
return NewParser("ManyUntil()", manyImpl(1, opScan, untilScan, sepScan...))
|
var opParser = Parsify(op)
|
||||||
}
|
var sepParser Parser
|
||||||
|
|
||||||
func manyImpl(min int, op Parserish, until Parserish, sep ...Parserish) Parser {
|
|
||||||
opParser := Parsify(op)
|
|
||||||
untilParser := Parsify(until)
|
|
||||||
sepParser := Nil
|
|
||||||
if len(sep) > 0 {
|
if len(sep) > 0 {
|
||||||
sepParser = Parsify(sep[0])
|
sepParser = Parsify(sep[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ps *State) Node {
|
return func(ps *State) Node {
|
||||||
var node Node
|
var result Node
|
||||||
nodes := make([]Node, 0, 20)
|
|
||||||
startpos := ps.Pos
|
startpos := ps.Pos
|
||||||
for {
|
for {
|
||||||
tempPos := ps.Pos
|
node := opParser(ps)
|
||||||
if untilParser != nil {
|
|
||||||
node = untilParser(ps)
|
|
||||||
if !ps.Errored() {
|
|
||||||
ps.Pos = tempPos
|
|
||||||
if len(nodes) < min {
|
|
||||||
ps.Pos = startpos
|
|
||||||
ps.ErrorHere("something else")
|
|
||||||
return Node{}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ps.ClearError()
|
|
||||||
}
|
|
||||||
|
|
||||||
node = opParser(ps)
|
|
||||||
if ps.Errored() {
|
if ps.Errored() {
|
||||||
if len(nodes) < min {
|
if len(result.Children) < min {
|
||||||
ps.Pos = startpos
|
ps.Pos = startpos
|
||||||
return Node{}
|
return result
|
||||||
}
|
}
|
||||||
ps.ClearError()
|
ps.ClearError()
|
||||||
break
|
return result
|
||||||
}
|
}
|
||||||
|
result.Children = append(result.Children, node)
|
||||||
|
|
||||||
nodes = append(nodes, node)
|
if sepParser != nil {
|
||||||
|
sepParser(ps)
|
||||||
node = sepParser(ps)
|
if ps.Errored() {
|
||||||
if ps.Errored() {
|
ps.ClearError()
|
||||||
ps.ClearError()
|
return result
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Node{Children: nodes}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +117,6 @@ func Maybe(parser Parserish) Parser {
|
|||||||
node := parserfied(ps)
|
node := parserfied(ps)
|
||||||
if ps.Errored() {
|
if ps.Errored() {
|
||||||
ps.ClearError()
|
ps.ClearError()
|
||||||
return Node{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
@ -156,7 +129,7 @@ func Map(parser Parserish, f func(n Node) Node) 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 Node{}
|
return node
|
||||||
}
|
}
|
||||||
return f(node)
|
return f(node)
|
||||||
})
|
})
|
||||||
|
@ -134,35 +134,6 @@ func TestMany(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKleeneUntil(t *testing.T) {
|
|
||||||
t.Run("Matches sequence with sep", func(t *testing.T) {
|
|
||||||
node, p2 := runParser("a,b,c,d,e,fg", KleeneUntil(Chars("abcde"), "d", ","))
|
|
||||||
assertSequence(t, node, "a", "b", "c")
|
|
||||||
require.Equal(t, "d,e,fg", p2.Get())
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Breaks if separator does not match", func(t *testing.T) {
|
|
||||||
node, p2 := runParser("a,b,c,d,e,fg", KleeneUntil(Chars("abcdefg", 1, 1), "y", ","))
|
|
||||||
assertSequence(t, node, "a", "b", "c", "d", "e", "f")
|
|
||||||
require.Equal(t, "g", p2.Get())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestManyUntil(t *testing.T) {
|
|
||||||
t.Run("Matches sequence until", func(t *testing.T) {
|
|
||||||
node, p2 := runParser("a,b,c,d,e,", ManyUntil(Chars("abcdefg"), "d", ","))
|
|
||||||
assertSequence(t, node, "a", "b", "c")
|
|
||||||
require.Equal(t, 6, p2.Pos)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Returns error until matches early", func(t *testing.T) {
|
|
||||||
_, p2 := runParser("a,b,c,d,e,", ManyUntil(Chars("abc"), "a", ","))
|
|
||||||
require.Equal(t, "offset 0: Expected something else", p2.Error.Error())
|
|
||||||
require.Equal(t, 0, p2.Pos)
|
|
||||||
require.Equal(t, "a,b,c,d,e,", p2.Get())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type htmlTag struct {
|
type htmlTag struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,16 @@ func main() {
|
|||||||
max := 1000000
|
max := 1000000
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
runtime.MemProfileRate = 1
|
runtime.MemProfileRate = 1
|
||||||
max = 10000
|
max = 100000
|
||||||
|
defer func() {
|
||||||
|
f, err := os.Create(*memprofile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pprof.WriteHeapProfile(f)
|
||||||
|
f.Close()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < max; i++ {
|
for i := 0; i < max; i++ {
|
||||||
@ -43,15 +52,4 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *memprofile != "" {
|
|
||||||
f, err := os.Create(*memprofile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pprof.WriteHeapProfile(f)
|
|
||||||
f.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ func Exact(match string) Parser {
|
|||||||
matchByte := match[0]
|
matchByte := match[0]
|
||||||
return NewParser(match, func(ps *State) Node {
|
return NewParser(match, func(ps *State) Node {
|
||||||
ps.AutoWS()
|
ps.AutoWS()
|
||||||
if ps.Input[ps.Pos] != matchByte {
|
if ps.Pos >= len(ps.Input) || ps.Input[ps.Pos] != matchByte {
|
||||||
ps.ErrorHere(match)
|
ps.ErrorHere(match)
|
||||||
return Node{}
|
return Node{}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,12 @@ func TestExact(t *testing.T) {
|
|||||||
require.Equal(t, "o", ps.Error.Expected)
|
require.Equal(t, "o", ps.Error.Expected)
|
||||||
require.Equal(t, 0, ps.Pos)
|
require.Equal(t, 0, ps.Pos)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("eof char", func(t *testing.T) {
|
||||||
|
_, ps := runParser("", Exact("o"))
|
||||||
|
require.Equal(t, "o", ps.Error.Expected)
|
||||||
|
require.Equal(t, 0, ps.Pos)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChars(t *testing.T) {
|
func TestChars(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user