refactor parsing phase

This commit is contained in:
Arpad Ryszka 2017-12-31 17:34:10 +01:00
parent c4591babe0
commit 6d3fe17ddb
6 changed files with 88 additions and 100 deletions

View File

@ -131,24 +131,6 @@ func (d *choiceDefinition) parser() parser {
func (d *choiceDefinition) builder() builder { return d.cbuilder } func (d *choiceDefinition) builder() builder { return d.cbuilder }
func (d *choiceDefinition) format(r *registry, f formatFlags) string {
var chars []rune
for i := range d.options {
if i > 0 {
chars = append(chars, []rune(" | ")...)
}
optionDef, _ := r.definition(d.options[i])
if optionDef.commitType()&userDefined != 0 {
chars = append(chars, []rune(optionDef.nodeName())...)
} else {
chars = append(chars, []rune(optionDef.format(r, f))...)
}
}
return string(chars)
}
func (p *choiceParser) nodeName() string { return p.name } func (p *choiceParser) nodeName() string { return p.name }
func (p *choiceParser) nodeID() int { return p.id } func (p *choiceParser) nodeID() int { return p.id }
func (p *choiceParser) commitType() CommitType { return p.commit } func (p *choiceParser) commitType() CommitType { return p.commit }
@ -164,17 +146,19 @@ func (p *choiceParser) parse(c *context) {
} }
c.results.markPending(c.offset, p.id) c.results.markPending(c.offset, p.id)
var (
match bool
optionIndex int
foundMatch bool
failingParser parser
)
from := c.offset from := c.offset
to := c.offset to := c.offset
var match bool
var optionIndex int
var foundMatch bool
initialFailOffset := c.failOffset initialFailOffset := c.failOffset
initialFailingParser := c.failingParser initialFailingParser := c.failingParser
failOffset := initialFailOffset failOffset := initialFailOffset
var failingParser parser
for { for {
foundMatch = false foundMatch = false
@ -288,3 +272,21 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
tokens: c.tokens, tokens: c.tokens,
}}, true }}, true
} }
func (d *choiceDefinition) format(r *registry, f formatFlags) string {
var chars []rune
for i := range d.options {
if i > 0 {
chars = append(chars, []rune(" | ")...)
}
optionDef, _ := r.definition(d.options[i])
if optionDef.commitType()&userDefined != 0 {
chars = append(chars, []rune(optionDef.nodeName())...)
} else {
chars = append(chars, []rune(optionDef.format(r, f))...)
}
}
return string(chars)
}

View File

@ -136,25 +136,18 @@ func (c *context) finalizeParse(root parser) error {
} }
to, match, found := c.results.longestResult(0, root.nodeID()) to, match, found := c.results.longestResult(0, root.nodeID())
if !found || !match || found && match && to < c.readOffset {
if found && match && to < c.readOffset {
return c.parseError(p) return c.parseError(p)
} }
if !found || !match { c.read()
return c.parseError(p) if c.eof {
return nil
} }
if !c.eof { if c.readErr != nil {
c.read() return c.readErr
if !c.eof {
if c.readErr != nil {
return c.readErr
}
return c.parseError(root)
}
} }
return nil return c.parseError(root)
} }

View File

@ -13,12 +13,6 @@ type errorTestItem struct {
perr ParseError perr ParseError
} }
func checkParseError(left, right ParseError) bool {
left.registry = nil
right.registry = nil
return reflect.DeepEqual(left, right)
}
func testParseErrorItem(s *Syntax, test errorTestItem) func(t *testing.T) { func testParseErrorItem(s *Syntax, test errorTestItem) func(t *testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := s.Parse(bytes.NewBufferString(test.doc)) _, err := s.Parse(bytes.NewBufferString(test.doc))
@ -32,9 +26,8 @@ func testParseErrorItem(s *Syntax, test errorTestItem) func(t *testing.T) {
} }
perr.Input = "" perr.Input = ""
perr.registry = nil
if !checkParseError(*perr, test.perr) { if !reflect.DeepEqual(*perr, test.perr) {
t.Error("invalid error returned") t.Error("invalid error returned")
t.Log("got: ", *perr) t.Log("got: ", *perr)
t.Log("expected:", test.perr) t.Log("expected:", test.perr)

View File

@ -6,24 +6,44 @@ type results struct {
isPending [][]int isPending [][]int
} }
func (r *results) ensureOffset(offset int) { func ensureOffsetInts(ints [][]int, offset int) [][]int {
if len(r.match) > offset { if len(ints) > offset {
return return ints
} }
if cap(r.match) > offset { if cap(ints) > offset {
r.match = r.match[:offset+1] ints = ints[:offset+1]
return return ints
} }
r.match = r.match[:cap(r.match)] ints = ints[:cap(ints)]
for i := len(r.match); i <= offset; i++ { for i := len(ints); i <= offset; i++ {
r.match = append(r.match, nil) ints = append(ints, nil)
} }
return ints
}
func ensureOffsetIDs(ids []*idSet, offset int) []*idSet {
if len(ids) > offset {
return ids
}
if cap(ids) > offset {
ids = ids[:offset+1]
return ids
}
ids = ids[:cap(ids)]
for i := len(ids); i <= offset; i++ {
ids = append(ids, nil)
}
return ids
} }
func (r *results) setMatch(offset, id, to int) { func (r *results) setMatch(offset, id, to int) {
r.ensureOffset(offset) r.match = ensureOffsetInts(r.match, offset)
for i := 0; i < len(r.match[offset]); i += 2 { for i := 0; i < len(r.match[offset]); i += 2 {
if r.match[offset][i] != id || r.match[offset][i+1] != to { if r.match[offset][i] != id || r.match[offset][i+1] != to {
@ -47,17 +67,7 @@ func (r *results) setNoMatch(offset, id int) {
} }
} }
if len(r.noMatch) <= offset { r.noMatch = ensureOffsetIDs(r.noMatch, offset)
if cap(r.noMatch) > offset {
r.noMatch = r.noMatch[:offset+1]
} else {
r.noMatch = r.noMatch[:cap(r.noMatch)]
for i := cap(r.noMatch); i <= offset; i++ {
r.noMatch = append(r.noMatch, nil)
}
}
}
if r.noMatch[offset] == nil { if r.noMatch[offset] == nil {
r.noMatch[offset] = &idSet{} r.noMatch[offset] = &idSet{}
} }
@ -146,17 +156,7 @@ func (r *results) pending(offset, id int) bool {
} }
func (r *results) markPending(offset, id int) { func (r *results) markPending(offset, id int) {
if len(r.isPending) <= id { r.isPending = ensureOffsetInts(r.isPending, id)
if cap(r.isPending) > id {
r.isPending = r.isPending[:id+1]
} else {
r.isPending = r.isPending[:cap(r.isPending)]
for i := cap(r.isPending); i <= id; i++ {
r.isPending = append(r.isPending, nil)
}
}
}
for i := range r.isPending[id] { for i := range r.isPending[id] {
if r.isPending[id][i] == -1 { if r.isPending[id][i] == -1 {
r.isPending[id][i] = offset r.isPending[id][i] = offset

View File

@ -196,34 +196,37 @@ func (p *sequenceParser) parse(c *context) {
c.results.markPending(c.offset, p.id) c.results.markPending(c.offset, p.id)
} }
var (
currentCount int
parsed bool
)
itemIndex := 0 itemIndex := 0
var currentCount int
from := c.offset from := c.offset
to := c.offset to := c.offset
var parsed bool
for itemIndex < len(p.items) { for itemIndex < len(p.items) {
p.items[itemIndex].parse(c) p.items[itemIndex].parse(c)
if !c.matchLast { if !c.matchLast {
if currentCount < p.ranges[itemIndex][0] { if currentCount >= p.ranges[itemIndex][0] {
if c.failingParser == nil && itemIndex++
p.commitType()&userDefined != 0 && currentCount = 0
p.commitType()&Whitespace == 0 && continue
p.commitType()&FailPass == 0 {
c.failingParser = p
}
c.fail(from)
if !p.allChars {
c.results.unmarkPending(from, p.id)
}
return
} }
itemIndex++ if c.failingParser == nil &&
currentCount = 0 p.commitType()&userDefined != 0 &&
continue p.commitType()&Whitespace == 0 &&
p.commitType()&FailPass == 0 {
c.failingParser = p
}
c.fail(from)
if !p.allChars {
c.results.unmarkPending(from, p.id)
}
return
} }
parsed = c.offset > to parsed = c.offset > to

View File

@ -61,8 +61,6 @@ type ParseError struct {
// Definition tells the right-most unmatched parser definition. // Definition tells the right-most unmatched parser definition.
Definition string Definition string
registry *registry
} }
type Syntax struct { type Syntax struct {
@ -442,7 +440,6 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) {
if err := c.finalizeParse(s.parser); err != nil { if err := c.finalizeParse(s.parser); err != nil {
if perr, ok := err.(*ParseError); ok { if perr, ok := err.(*ParseError); ok {
perr.Input = "<input>" perr.Input = "<input>"
perr.registry = s.registry
} }
return nil, err return nil, err