go-parsekit/parse/parse.go

65 lines
2.6 KiB
Go

// Package parse provides tooling to build a state machine-style recursive descent parser.
package parse
import (
"git.makaay.nl/mauricem/go-parsekit/tokenize"
)
// Func is the function signature as returned by New: a function that takes
// any supported type of input, executes a parse run and returns an error
// (or nil when all went right).
type Func func(interface{}) error
// New instantiates a new parser.
//
// The parser is a state machine-style recursive descent parser, in which
// parse.Handler functions are used to move the state machine forward during
// parsing. This style of parser is typically used for parsing programming
// languages and structured data formats (like json, xml, toml, etc.)
//
// The startHandler argument points the parser to the parse.Handler function
// that must be executed at the start of the parsing process. From there on
// other parse.Handler functions can be invoked recursively to implement the
// parsing process.
//
// This function returns a function that can be invoked to run the parser
// against the provided input data. For an overview of allowed inputs, take a
// look at the documentation for parsekit.read.New().
func New(startHandler Handler) Func {
return new(startHandler, true)
}
// NewWithoutSanityChecks instantiates a new parser, which does not have
// parsekit's built-in sanith checks enabled (e.g. checks for loops or
// or calls to parse.API methods after an error or Stop()).
//
// Disabling sanity checks does improve parsing performance, but for
// most use cases this is not an issue. Only disable sanity checks when
// you really need the extra performance.
// You can of course create a normal sanity-checked parser that is used
// during development / unit testing, and an unchecked one for production.
func NewWithoutSanityChecks(startHandler Handler) Func {
return new(startHandler, false)
}
func new(startHandler Handler, sanityChecksEnabled bool) Func {
if startHandler == nil {
callerPanic("New", "parsekit.parse.{name}(): {name}() called with nil input at {caller}")
}
return func(input interface{}) error {
api := &API{
tokenAPI: tokenize.NewAPI(input),
loopCheck: make(map[filepos]bool),
sanityChecksEnabled: sanityChecksEnabled,
}
if api.Handle(startHandler) {
// Handle returned true, indicating that parsing could still continue.
// There was no error and that the parsing has not actively been Stop()-ed.
// Let's assume that we actually reached the end of the parsing successfully
// and try to make the best of it.
api.ExpectEndOfFile()
}
return api.err
}
}