Imports
/-
Declarative property rule framework for generating formal Prop definitions
from RFC prose. Rules are composable expression trees (PropSpec) that
describe prop shapes, interpreted by a single generic function.
Three rule kinds:
- Cross-struct rules: match participial post-modifiers, generate props
spanning multiple struct fields (e.g., count fields, domain name validity)
- Field-level rules: match clause patterns in field descriptions, generate
props for individual fields (e.g., "must be zero", "reserved")
- Prose-clause rules: match NLP Clause structure (verb, subject, PPs)
in prose-only sections, generate struct fields and/or props
All are stored in `SimplePersistentEnvExtension`s and registered
declaratively via `cross_struct_rule`, `field_prop_rule`, and
`prose_clause_rule` commands.
-/
import Leanopen Lean Elab Command Metaset_option autoImplicit falsenamespace VeriDNS.RFC.PropRulesReference to a value in the generated prop expression.
inductive FieldRef whereField being processed (field-level rules)
| currentFieldSub-field that matched (cross-struct rules)
| matchedSubFieldExplicit struct field by name
| namedField (name : String)Resolve PP object NP to struct field at match time
| resolvedFromPP (prep : String)Project from first binder of forallPair
| pairLeft (inner : FieldRef)Project from second binder of forallPair
| pairRight (inner : FieldRef)BitVec.toNat of a ref
| toNat (ref : FieldRef)Array.size / ByteArray.size of a ref
| size (ref : FieldRef)Numeric literal
| lit (n : Nat)De Bruijn index (0 = innermost binder)
| bound (idx : Nat)Value extracted from clause binding (substituted at match time)
| extractedNat (bindingName : String)Cross-spec field: resolve location to type, fieldName to field
| resolvedExtField (locationBinding : String) (fieldBinding : String)Resolved field path: structName.fieldName, looked up at interpretation time
| fieldPath (structName : String) (fieldName : String)
deriving Repr, Inhabited, BEqDeclarative specification of a Prop shape. Interpreted by a single generic function to produce Lean syntax.
inductive PropSpec where∀ (msg : Struct), body
| forallStruct (body : PropSpec)∀ (a b : Struct), body
| forallPair (body : PropSpec)If Array: ∀ (i : Fin), body; else: body
| forallMatchedIndex (body : PropSpec)∃ (x : T), body
| existsTyped (typeName : String) (body : PropSpec)∀ (x), x ∈ container → body
| forallElem (container : FieldRef) (body : PropSpec)lhs = rhs
| eq (lhs rhs : FieldRef)lhs < rhs
| lt (lhs rhs : FieldRef)lhs ≤ rhs
| le (lhs rhs : FieldRef)lhs > rhs
| gt (lhs rhs : FieldRef)ante → body
| implies (ante body : PropSpec)a ∧ b
| conj (a b : PropSpec)True
| trivialDeclare a struct field: name, bitWidth. Interpreter adds to struct.
| declField (name : String) (bitWidth : FieldRef)Sequence two specs: both get processed.
| seq (a b : PropSpec)¬ body
| neg (body : PropSpec)a ∨ b
| disj (a b : PropSpec)∀ (x : T), body. T is a type name resolved from the environment.
| forallNamed (typeName : String) (body : PropSpec)∀ (a b : T), body. Two variables of the same type.
| forallNamedPair (typeName : String) (body : PropSpec)
deriving Repr, Inhabited, BEqPattern for matching participial post-modifiers in NP-only clauses. Each rule declaratively specifies what verb and PP structure to match.
structure ParticiplePattern whereAcceptable participle verbs (lowercase)
verbs : Array StringIf some, require object NP with head in this list (lowercase). If none, match regardless of object presence.
objHead : Option (Array String) := noneRequired PP patterns: (preposition, acceptable head nouns). ALL patterns must match for the rule to fire.
requiredPPs : Array (String × Array String) := #[]
deriving Repr, Inhabited, BEqA declarative cross-struct rule: match a participial pattern, emit a prop.
structure CrossStructRuleEntry where
name : String
pattern : ParticiplePattern
prop : PropSpec
deriving Repr, Inhabited, BEqPersistent environment extension for cross-struct rules.
initialize crossStructRuleExt :
SimplePersistentEnvExtension CrossStructRuleEntry (Array CrossStructRuleEntry) ←
registerSimplePersistentEnvExtension {
addEntryFn := fun arr entry => arr.push entry
addImportedFn := fun arrs => arrs.foldl (· ++ ·) #[]
}private unsafe def evalCrossStructRuleUnsafe (e : Expr) : MetaM CrossStructRuleEntry :=
evalExpr CrossStructRuleEntry (mkConst ``CrossStructRuleEntry) e@[implemented_by evalCrossStructRuleUnsafe]
private opaque evalCrossStructRule' (e : Expr) : MetaM CrossStructRuleEntry
Register a cross-struct rule declaratively. Argument is a CrossStructRuleEntry literal.
elab "cross_struct_rule " t:term : command => do
let entry ← liftTermElabM do
let e ← Term.elabTerm t (some (mkConst ``CrossStructRuleEntry))
evalCrossStructRule' e
modifyEnv fun env => crossStructRuleExt.addEntry env entryPattern for matching NLP clauses in field descriptions.
inductive ClausePattern wheresvAdj with this adjective (case-insensitive)
| adjEquals (adj : String)npOnly with word in preAdjs or head (case-insensitive)
| hasWord (word : String)unparsed text starting with given prefix (case-insensitive)
| textPrefix (pfx : String)matches unparsed text containing substring (case-insensitive)
| textContains (word : String)
deriving Repr, Inhabited, BEqA declarative field-level rule: match a clause pattern, emit a prop.
structure FieldPropRuleEntry where
name : String
pattern : ClausePattern
prop : PropSpec
deriving Repr, Inhabited, BEqPersistent environment extension for field-level rules.
initialize fieldPropRuleExt :
SimplePersistentEnvExtension FieldPropRuleEntry (Array FieldPropRuleEntry) ←
registerSimplePersistentEnvExtension {
addEntryFn := fun arr entry => arr.push entry
addImportedFn := fun arrs => arrs.foldl (· ++ ·) #[]
}private unsafe def evalFieldPropRuleUnsafe (e : Expr) : MetaM FieldPropRuleEntry :=
evalExpr FieldPropRuleEntry (mkConst ``FieldPropRuleEntry) e@[implemented_by evalFieldPropRuleUnsafe]
private opaque evalFieldPropRule' (e : Expr) : MetaM FieldPropRuleEntry
Register a field-level rule declaratively. Argument is a FieldPropRuleEntry literal.
elab "field_prop_rule " t:term : command => do
let entry ← liftTermElabM do
let e ← Term.elabTerm t (some (mkConst ``FieldPropRuleEntry))
evalFieldPropRule' e
modifyEnv fun env => fieldPropRuleExt.addEntry env entryWhere in a matched clause to extract a value.
inductive ValueSlot whereFirst numeric in PP's NP preAdjs
| ppNumeric (prep : String)Head noun of PP
| ppHead (prep : String)Word-to-number from PP's full NP text
| ppBitWidth (prep : String)Subject preAdjs concatenated (lowercased)
| subjPreAdjsProtocol qualifier from subject postMods
| subjQualifierHead noun of PP (for cross-spec resolution)
| ppLocation (prep : String)
deriving Repr, Inhabited, BEqA named binding extracted from a slot in a matched clause.
structure Extraction where
name : String
slot : ValueSlot
required : Bool := true
deriving Repr, Inhabited, BEqPattern for matching NLP Clause structure (verb, subject, PPs).
structure ProseClausePattern whereAcceptable participles/verbs
verbs : Array StringOptional subject head filter
subjHead : Option (Array String) := noneRequired PP patterns: (prep, optional head nouns)
requiredPPs : Array (String × Array String) := #[]Values to extract from matched clause
extractions : Array Extraction := #[]Also match Clause.svo?
matchActive : Bool := falseRequire negation (e.g., "should not be cached")
requireNegation : Bool := false
deriving Repr, Inhabited, BEqA declarative prose-clause rule: match clause structure, emit a unified PropSpec.
structure ProseClauseRuleEntry where
name : String
pattern : ProseClausePattern
output : PropSpec
deriving Repr, Inhabited, BEqPersistent environment extension for prose-clause rules.
initialize proseClauseRuleExt :
SimplePersistentEnvExtension ProseClauseRuleEntry (Array ProseClauseRuleEntry) ←
registerSimplePersistentEnvExtension {
addEntryFn := fun arr entry => arr.push entry
addImportedFn := fun arrs => arrs.foldl (· ++ ·) #[]
}private unsafe def evalProseClauseRuleUnsafe (e : Expr) : MetaM ProseClauseRuleEntry :=
evalExpr ProseClauseRuleEntry (mkConst ``ProseClauseRuleEntry) e@[implemented_by evalProseClauseRuleUnsafe]
private opaque evalProseClauseRule' (e : Expr) : MetaM ProseClauseRuleEntry
Register a prose-clause rule declaratively. Argument is a ProseClauseRuleEntry literal.
elab "prose_clause_rule " t:term : command => do
let entry ← liftTermElabM do
let e ← Term.elabTerm t (some (mkConst ``ProseClauseRuleEntry))
evalProseClauseRule' e
modifyEnv fun env => proseClauseRuleExt.addEntry env entryend VeriDNS.RFC.PropRules