100 lines
3.2 KiB
Go
100 lines
3.2 KiB
Go
package parsekit
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// Handle is used to execute other ParseHandler functions from within your
|
|
// ParseHandler function.
|
|
//
|
|
// The boolean return value is true when the parser can still continue.
|
|
// It will be false when either an error was set (using ParseAPI.Error()),
|
|
// or the parser was stopped (using ParseAPI.Stop()).
|
|
func (p *ParseAPI) Handle(parseHandler ParseHandler) bool {
|
|
p.panicWhenStoppedOrInError()
|
|
p.panicWhenParseHandlerNil(parseHandler)
|
|
parseHandler(p)
|
|
return !p.isStoppedOrInError()
|
|
}
|
|
|
|
func (p *ParseAPI) panicWhenParseHandlerNil(parseHandler ParseHandler) {
|
|
if parseHandler == nil {
|
|
caller, filepos := p.getCaller(2)
|
|
panic(fmt.Sprintf("ParseAPI.Handle() called with nil input from %s at %s", caller, filepos))
|
|
}
|
|
}
|
|
|
|
// Expects is used to let a ParseHandler function describe what input it is
|
|
// expecting. This expectation is used in error messages to provide some
|
|
// context to them.
|
|
//
|
|
// When defining an expectation inside a ParseHandler, you do not need to
|
|
// handle unexpected input yourself. When the end of the parser is reached
|
|
// without stopping it using ParseAPI.Stop() or ParseAPI.ExpectEndOfFile(),
|
|
// an automatic error will be emitted using ParseAPI.UnexpectedInput().
|
|
func (p *ParseAPI) Expects(description string) {
|
|
p.panicWhenStoppedOrInError()
|
|
p.expecting = description
|
|
}
|
|
|
|
// Stop is used by the parser impementation to tell the API that it has
|
|
// completed the parsing process successfully.
|
|
//
|
|
// When the parser implementation returns without stopping first, the
|
|
// Parser.Execute() will assume that something went wrong and calls
|
|
// ParserAPI.UnexpectedInput() to report an error about this.
|
|
//
|
|
// The parser implementation can define what was being expected, by
|
|
// providing a description to ParseAPI.Expecting().
|
|
func (p *ParseAPI) Stop() {
|
|
p.stopped = true
|
|
}
|
|
|
|
// ExpectEndOfFile can be used to check if the input is at end of file.
|
|
//
|
|
// When it finds that the end of the file was indeed reached, then the
|
|
// parser will be stopped through ParseAPI.Stop(). Otherwise unexpected
|
|
// input is reported through ParseAPI.UnexpectedInput() with "end of file"
|
|
// as the expectation.
|
|
func (p *ParseAPI) ExpectEndOfFile() {
|
|
p.panicWhenStoppedOrInError()
|
|
if p.On(A.EndOfFile).Stay() {
|
|
p.Stop()
|
|
} else {
|
|
p.Expects("end of file")
|
|
p.UnexpectedInput()
|
|
}
|
|
}
|
|
|
|
// UnexpectedInput is used to set an error that tells the user that some
|
|
// unexpected input was encountered.
|
|
//
|
|
// It can automatically produce an error message for a couple of situations:
|
|
// 1) input simply didn't match the expectation
|
|
// 2) the end of the input was reached
|
|
// 3) there was an invalid UTF8 character on the input.
|
|
//
|
|
// The parser implementation can provide some feedback for this error by
|
|
// calling ParseAPI.Expects() to set the expectation. When set, the
|
|
// expectation is included in the error message.
|
|
func (p *ParseAPI) UnexpectedInput() {
|
|
p.panicWhenStoppedOrInError()
|
|
r, err := p.tokenAPI.NextRune()
|
|
switch {
|
|
case err == nil:
|
|
p.Error("unexpected character %q%s", r, fmtExpects(p))
|
|
case err == io.EOF:
|
|
p.Error("unexpected end of file%s", fmtExpects(p))
|
|
default:
|
|
p.Error("unexpected error '%s'%s", err, fmtExpects(p))
|
|
}
|
|
}
|
|
|
|
func fmtExpects(p *ParseAPI) string {
|
|
if p.expecting == "" {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf(" (expected %s)", p.expecting)
|
|
}
|