Lint

is the linter's core: the rule registry, the AST walker, and the public entry points (lint, lint-with, lint-source, lint-source-with). Plugin authors interact with it via register-rule!. See WRITING-RULES.md for the rule-author guide.

lint

defn

(Fn [(Ref (Array (Box Located)) a)] (Array Diagnostic))

                        (lint forms)
                    

applies every registered rule to every node in forms, recursing into compound forms. Returns one Diagnostic per finding.

lint-source

defn

(Fn [(Ref String a)] (Result (Array Diagnostic) ParseErr))

                        (lint-source src)
                    

parses src via Reader.parse and lints with every registered rule. Returns (Result (Array Diagnostic) ParseErr) so a parse failure surfaces distinctly from a clean parse with diagnostics.

lint-source-with

defn

(Fn [(Ref (Fn [(Ref String StaticLifetime)] Bool) a), (Ref String b)] (Result (Array Diagnostic) ParseErr))

                        (lint-source-with keep? src)
                    

like lint-source, but only runs rules whose names satisfy keep?.

lint-with

defn

(Fn [(Ref (Fn [(Ref String StaticLifetime)] Bool) a), (Ref (Array (Box Located)) b)] (Array Diagnostic))

                        (lint-with keep? forms)
                    

like lint, but only runs rules whose names satisfy keep?.

list-rules

defn

(Fn [] (Array Rule))

                        (list-rules)
                    

returns a copy of the currently registered rule registry. Useful for angler --list-rules and for plugins that want to inspect the active rule set.

load-rules-from-source!

defn

(Fn [(Ref String a)] (Result Int ParseErr))

                        (load-rules-from-source! src)
                    

parses src as a rules file and registers each rule found. Each top-level form must be an array literal [<pattern> "name" "message"]. Symbols starting with ? in the pattern are metavariables, just as in register-pattern-rule!. Non-conforming top-level forms are silently skipped. Returns the number of rules loaded, or a parse error.

lst-head?

defn

(Fn [(Ref Form a), (Ref String b)] Bool)

                        (lst-head? f name)
                    

true iff f is (Form.Lst …) whose first child is a Form.Sym matching name.

nth-form

defn

(Fn [(Ref (Array (Box Located)) a), Int] (Ref Form a))

                        (nth-form items i)
                    

pulls the Form out of the i-th Located child of an Array (Box Located). Most rules want the structural shape, not the position, when descending into a compound form's children.

register-pattern-rule!

defn

(Fn [String, String, (Ref String a), String] ())

                        (register-pattern-rule! name description pattern-str message)
                    

registers a lint rule that fires when pattern-str (a single Carp form) structurally matches a node. Symbols starting with ? are metavariables: they match any form, and if the same ?name appears more than once the bound forms must have equal string representations.

(Lint.register-pattern-rule! @"set-self"
                             @"(set! x x) is a no-op"
                             "(set! ?x ?x)"
                             @"(set! x x) is a no-op")

register-rule!

defn

(Fn [String, String, (Fn [(Ref Located a)] (Maybe Diagnostic))] ())

                        (register-rule! name description fn)
                    

registers a rule under name with a one-line description. Subsequent runs of Lint.lint / Lint.lint-source include it. Built-ins call this at load time; plugins do the same after loading angler.

Caveat: Carp initializes global defs in dependency-graph order, not in textual or load order. If your plugin uses a top-level def to call register-rule!, its slot in the registry — and therefore its slot in the diagnostic output for any one form — is unspecified relative to angler's built-ins. Rule firing is still correct; only the order of diagnostics on a single node varies. If you need strict ordering, register from main instead of from a top-level def.

sym?

defn

(Fn [(Ref Form a), (Ref String b)] Bool)

                        (sym? f name)
                    

true iff f is a Form.Sym whose dotted name equals name. name may itself contain . to match a multi-segment symbol — e.g. (sym? f "Parser.try") matches Parser.try.