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) 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) nodeID() int { return p.id }
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)
var (
match bool
optionIndex int
foundMatch bool
failingParser parser
)
from := c.offset
to := c.offset
var match bool
var optionIndex int
var foundMatch bool
initialFailOffset := c.failOffset
initialFailingParser := c.failingParser
failOffset := initialFailOffset
var failingParser parser
for {
foundMatch = false
@ -288,3 +272,21 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
tokens: c.tokens,
}}, 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())
if found && match && to < c.readOffset {
if !found || !match || found && match && to < c.readOffset {
return c.parseError(p)
}
if !found || !match {
return c.parseError(p)
}
if !c.eof {
c.read()
if !c.eof {
if c.eof {
return nil
}
if c.readErr != nil {
return c.readErr
}
return c.parseError(root)
}
}
return nil
}

View File

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

View File

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

View File

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

View File

@ -61,8 +61,6 @@ type ParseError struct {
// Definition tells the right-most unmatched parser definition.
Definition string
registry *registry
}
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 perr, ok := err.(*ParseError); ok {
perr.Input = "<input>"
perr.registry = s.registry
}
return nil, err