package parsekit // Handle is used to execute other ParseHandler functions from within your // ParseHandler function. func (p *ParseAPI) Handle(handlers ...ParseHandler) { for _, handler := range handlers { // When some previous parsing step yielded an error, skip this operation. if p.err != nil { break } handler(p) } } // RouteTo tells the parser what ParseHandler function to invoke on // the next parse cycle. func (p *ParseAPI) RouteTo(handler ParseHandler) *RouteFollowupAction { p.nextState = handler return &RouteFollowupAction{p} } // RouteRepeat tells the parser that on the next parsing cycle, the current // ParseHandler must be reinvoked. func (p *ParseAPI) RouteRepeat() { p.RouteTo(p.state) } // RouteReturn tells the parser that on the next cycle the last ParseHandler // that was pushed on the route stack must be invoked. // // Using this method is optional. When implementating a ParseHandler that // is used as a sort of subroutine (using constructions like // p.RouteTo(subroutine).ThenReturnHere()), you can refrain from // providing an explicit routing decision from that handler. The parser will // automatically assume a RouteReturn() in that case. func (p *ParseAPI) RouteReturn() { p.nextState = p.popRoute() } // RouteFollowupAction chains parsing routes. // It allows for routing code like p.RouteTo(handlerA).ThenTo(handlerB). type RouteFollowupAction struct { p *ParseAPI } // ThenTo schedules a ParseHandler that must be invoked after the RouteTo // ParseHandler has been completed. // For example: // // p.RouteTo(handlerA).ThenTo(handlerB) func (a *RouteFollowupAction) ThenTo(state ParseHandler) { a.p.pushRoute(state) } // ThenReturnHere schedules the current ParseHandler to be invoked after // the RouteTo ParseHandler has been completed. // For example: // // p.RouteTo(handlerA).ThenReturnHere() func (a *RouteFollowupAction) ThenReturnHere() { a.p.pushRoute(a.p.state) } // pushRoute adds the ParseHandler to the route stack. // This is used for implementing nested parsing. func (p *ParseAPI) pushRoute(state ParseHandler) { p.routeStack = append(p.routeStack, state) } // popRoute pops the last pushed ParseHandler from the route stack. func (p *ParseAPI) popRoute() ParseHandler { last := len(p.routeStack) - 1 head, tail := p.routeStack[:last], p.routeStack[last] p.routeStack = head return tail } // ExpectEndOfFile can be used to check if the input is at end of file. // Intended use: // // func yourParseHandler(p *parsekit.ParseAPI) { // ... // p.ExpectEndOfFile() // } // // This will execute the end of file test right away. If you want to // use the end of file check as a StateHandler instead, you can also // make use of another form, for example: // // func yourParseHandler(p *parsekit.ParseAPI) { // p.RouteTo(yourHandler).ThenTo(parsekit.ExpectEndOfFile) // } func (p *ParseAPI) ExpectEndOfFile() { // When some previous parsing step yielded an error, skip this operation. if p.err == nil { if p.On(A.EndOfFile).Stay() { p.EmitEOF() } else { p.Expects("end of file") p.UnexpectedInput() } } } // ExpectEndOfFile can be scheduled as a ParseHandler function. // It makes sure that the input is at the end of file. // Intended use: // // func yourParseHandler(p *parsekit.ParseAPI) { // ... // p.RouteTo(parsekit.ExpectEndOfFile) // } // // It is not mandatory to use this ParseHandler. You can take care fo EOF // yourself too. Simply emit an ItemEOF when the end of the input was reached // to stop the parser loop: // // p.EmitEOF() // TODO meh, get rid of this one, once we don't use state scheduling anymore. func ExpectEndOfFile(p *ParseAPI) { p.Expects("end of file") if p.On(A.EndOfFile).Stay() { p.EmitEOF() } }