Dropped the whole channel support for the parser internals. It seems a nice idea to work with, but it's hard to predict how much buffering the channel should have to make all parsers work. When the buffer is too small, then a StateHandler that emits more items than can be buffered will end up in a deadlock and stall the application. It is easy enough to replace the channel with a slice of Items, so I did.

This commit is contained in:
Maurice Makaay 2019-05-26 11:32:45 +00:00
parent d0d12dae22
commit f7d1e28fa1
4 changed files with 12 additions and 13 deletions

View File

@ -1,4 +1,4 @@
// In this example, a Parser is created which can parse and normalize Dutch postcodes
// In this example, a Paparserrser is created which can parse and normalize Dutch postcodes
// The implementation uses only TokenHandler functions and does not implement a
// full-fledged state-based Parser for it.
package parsekit_test

View File

@ -30,7 +30,7 @@ type ParseRun struct {
}
// Parse starts a parse run on the provided input data.
// To retrieve parser Items from the run, make use of the ParseRun.Next() method.
// To retrieve emitted parser Items from the run, make use of the ParseRun.Next() method.
func (p *Parser) Parse(input string) *ParseRun {
return &ParseRun{
p: &ParseAPI{
@ -39,7 +39,6 @@ func (p *Parser) Parse(input string) *ParseRun {
cursorLine: 1,
cursorColumn: 1,
nextState: p.startState,
items: make(chan Item, 2),
},
}
}
@ -53,15 +52,15 @@ func (p *Parser) Parse(input string) *ParseRun {
func (run *ParseRun) Next() (Item, *Error, bool) {
// State handling loop: we handle states, until an Item is ready to be returned.
for {
select {
// If a state handler has emitted an (error) Item, then the state handling
// loop is stopped and the Item is returned to the caller.
case i := <-run.p.items:
return run.makeReturnValues(i)
// Otherwise, the next state handler is looked up and invoked.
default:
run.runNextStateHandler()
// If a state handler has emitted one or more parser Items, then the next
// available Item is returned to the caller.
if len(run.p.items) > 0 {
item, rest := run.p.items[0], run.p.items[1:]
run.p.items = rest
return run.makeReturnValues(item)
}
// Otherwise, the next state handler is looked up and invoked.
run.runNextStateHandler()
}
}

View File

@ -24,7 +24,7 @@ type ParseAPI struct {
newline bool // keep track of when we have scanned a newline
expecting string // a description of what the current state expects to find (see P.Expects())
buffer stringBuffer // an efficient buffer, used to build string values (see P.Accept())
items chan Item // channel of resulting Parser items (see P.Emit())
items []Item // a slice of resulting Parser items (see P.Emit())
item Item // the current item as reached by Next() and retrieved by Get()
err *Error // an error when lexing failed, retrieved by Error()

View File

@ -27,7 +27,7 @@ const ItemError ItemType = -2
// Emit passes a Parser item to the client, including the provided string.
func (p *ParseAPI) Emit(t ItemType, v string) {
p.items <- Item{t, v}
p.items = append(p.items, Item{t, v})
p.buffer.reset()
}