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:
parent
d0d12dae22
commit
f7d1e28fa1
|
@ -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
|
||||
|
|
19
parsekit.go
19
parsekit.go
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue