package parsekit import ( "fmt" "reflect" "runtime" ) // New takes an input string and a start state, // and initializes the parser for it. func New(input string, startState StateFn) *P { return &P{ input: input, len: len(input), nextState: startState, items: make(chan Item, 2), } } // Next retrieves the next parsed item. // When a valid item was found, then the boolean return parameter will be true. // On error or when successfully reaching the end of the input, false is returned. // When an error occurred, it will be set in the error return value, nil otherwise. func (p *P) Next() (Item, *Error, bool) { for { select { case i := <-p.items: switch { case i.Type == ItemEOF: return i, nil, false case i.Type == ItemError: p.err = &Error{i.Value, p.cursorRow, p.cursorColumn} return i, p.err, false default: p.item = i return i, nil, true } default: // When implementing a parser, a state function must provide // a routing decision in every state function execution. // When no route is specified, then it is considered a but // in the parser implementation. // An exception is when a function specified its expectation // using the Expects() method. In that case, an unexpected // input error is emitted. if p.nextState == nil { if p.expecting != "" { p.UnexpectedInput() continue } else { name := runtime.FuncForPC(reflect.ValueOf(p.state).Pointer()).Name() panic(fmt.Sprintf("StateFn implementation bug: %s did not set next state or input expectation", name)) } } p.state = p.nextState p.nextState = nil p.expecting = "" p.state(p) } } } // ToArray returns Parser items as an array (mainly intended for testing purposes) // When an error occurs during scanning, a partial result will be // returned, accompanied by the error that occurred. func (p *P) ToArray() ([]Item, *Error) { var items []Item for { item, err, more := p.Next() if !more { return items, err } items = append(items, item) } }