Package pego/lint
import "github.com/ornew/pego/lint"
Generated from the source of this version. Also on pkg.go.dev.
Overview
Package lint reports likely mistakes in PEGO grammars: rules and alternatives that can never match, expressions that have no effect, captures that are never read, and grammar shapes that defeat incremental parsing.
Config.Run compiles a grammar to check it before it lints it; Config.RunUnchecked lints a grammar its caller has already compiled. The checks work on the grammar AST alone. Each check reports only what it can prove from the grammar (the exceptions are the performance hints, which have the severity Hint); see docs/design/records/018-grammar-linting.md for the reasoning behind each one.
Index
Constants
const (
CheckUnreachableRule = "unreachable-rule"
CheckShadowedAlt = "shadowed-alternative"
CheckNeverMatches = "never-matches"
CheckUselessLookahead = "useless-lookahead"
CheckNullableRepetition = "nullable-repetition"
CheckRedundantOptional = "redundant-optional"
CheckUnusedCapture = "unused-capture"
CheckDuplicateCapture = "duplicate-capture"
CheckCharClass = "char-class"
CheckRightRecursion = "right-recursion"
CheckPositions = "positions"
CheckLongLookahead = "long-lookahead"
CheckCaseInsensitive = "case-insensitive-literal"
CheckDirective = "lint-directive"
)
Names of the checks.
Types
type Check source
type Check struct {
Name string
// Severity is the highest severity the check reports.
Severity Severity
Summary string
}
Check describes a check.
func Checks source
func Checks() []Check
Checks returns every check, in the order of the documentation.
type Config source
type Config struct {
// Disable holds the names of the checks not to run (see Checks).
Disable []string
}
Config configures a lint run. The zero value runs every check.
func (Config) Run source
func (c Config) Run(ctx context.Context, g *grammar.Grammar, start string) ([]Finding, error)
Run lints the grammar g from its start rule start: it reports rules the start rules never use, alternatives and expressions that can never match or have no effect, captures that are never read, and grammar shapes that slow down incremental parsing. The findings are sorted by position. unreachable-rule reports the rules that neither start nor another @start rule reaches. Comments of the form "// lint:ignore check reason" in the source suppress findings (see the directive syntax in docs/guide/linting.md).
An empty start selects the default start rule. Run returns an error, and no findings, if g does not compile, if start is not a start rule of g, if c.Disable names an unknown check, or if ctx ends; cancellation stops both the compilation and the checks and discards all findings.
func (Config) RunUnchecked source
func (c Config) RunUnchecked(ctx context.Context, g *grammar.Grammar, start string) ([]Finding, error)
RunUnchecked lints g from start as Run does, without compiling g: it is for a caller that has already compiled g, such as an editor that lints after each change. Its precondition is that g compiles and that start is a start rule of g (the default start rule of a compiled grammar is pego.Parser.DefaultStart); Run checks this, RunUnchecked does not, and the findings for any other g or start are unspecified. It returns an error only if c.Disable names an unknown check or ctx ends; cancellation discards all findings.
type Finding source
type Finding struct {
// Pos is where the problem is in the source. It is the zero Pos for a grammar without
// positions (decoded from JSON, or loaded from a compiled grammar).
Pos grammar.Pos
Severity Severity
// Check is the name of the check that reported the finding (see Checks).
Check string
// Rule is the rule the finding is in, if any.
Rule string
Message string
// Fix is a suggested change, or "" if there is no single obvious one.
Fix string
}
Finding is a problem found in a grammar.
func (Finding) String source
func (f Finding) String() string
type Rewrite source
type Rewrite struct {
Start, End grammar.Pos
NewText string
}
A Rewrite is a change to the source of a grammar that fixes a finding without changing what the grammar matches or the values it builds. Only three findings have one, each when the proof for its kind holds, and a tool that applies a Rewrite still checks the result:
- char-class, for ranges that overlap or repeat: the class is replaced by one with merged ranges. The proof is that both classes contain the same code points, checked at the ends of every range, and that negation is unchanged. A class that also matches punctuation between letters, such as [A-z], has no Rewrite, because the writer must say which characters were meant.
- useless-lookahead, for a lookahead that always succeeds: it is removed, but only where it is itself an item of a sequence of at least three items, so that the sequence keeps at least two and stays a tuple. Under a discard "-", a label or any operator it is not removed, because the "-" would move onto the next item and change the values. The proof is that the lookahead matches only a combination of literals, character classes, any-character, groups, sequences, choices, options and repetitions, so it holds no capture, cut, call, predicate, recovery or attribute, and a lookahead consumes nothing and has no value.
- unreachable-rule: the rule is removed. The proof is that no start rule reaches it, directly or through an inline action, so nothing calls it and no parse starts at it.
Start and End delimit the source to replace by NewText, with End exclusive. For a rule the span is the whole definition including its attributes.
func Rewrites source
func Rewrites(ctx context.Context, g *grammar.Grammar, start string, findings []Finding) (out []Rewrite, err error)
Rewrites returns, for each finding of the lint run of g from start, its Rewrite or the zero Rewrite. The findings must come from Config.Run or Config.RunUnchecked on the same g and start. Like RunUnchecked, Rewrites does not check its precondition that g compiles and start is a start rule of g. Cancellation discards the result.
func (Rewrite) IsValid source
func (r Rewrite) IsValid() bool
IsValid reports whether the Rewrite holds a change.
const (
// Hint is a suggestion, usually about performance; the grammar is correct as written.
Hint Severity = iota + 1
// Warning is a likely mistake, or an expression that has no effect.
Warning
// Error is a certain mistake: part of the grammar can never take effect.
Error
)
func (Severity) MarshalText source
func (s Severity) MarshalText() ([]byte, error)
MarshalText encodes the severity as its name.
func (Severity) String source
func (s Severity) String() string
func (*Severity) UnmarshalText source
func (s *Severity) UnmarshalText(text []byte) error
UnmarshalText decodes the name of a severity.