Research source · Plain text

Syntax.lean

site/public/formal/persistent-stacks/lean/FPRDTransfer/PEG/Syntax.lean

117 lines. Source is displayed for inspection; it is not executed by this page.

File fingerprint

SHA-256: 80f378eac3db98c57e241906c33255ec0877b5a00b2244448a7b655bcd3c8f62

import FPRDTransfer.FiniteEnum

namespace FPRD

universe uNT uNT' uSym

/-- Ordinary parsing expressions with ordered choice and negative lookahead. -/
inductive Expr (NT : Type uNT) (Sym : Type uSym) where
  | eps
  | fail
  | any
  | term (symbol : Sym)
  | nonterm (name : NT)
  | seq (left right : Expr NT Sym)
  | alt (left right : Expr NT Sym)
  | notP (body : Expr NT Sym)

namespace Expr

/-- Positive lookahead is double negative lookahead and is not primitive. -/
def pos (body : Expr NT Sym) : Expr NT Sym := .notP (.notP body)

/-- A finite sequence; the empty sequence is epsilon. -/
def seqAll : List (Expr NT Sym) → Expr NT Sym :=
  List.foldr .seq .eps

/-- A finite ordered choice; no alternatives means failure, never epsilon. -/
def altAll : List (Expr NT Sym) → Expr NT Sym :=
  List.foldr .alt .fail

/-- Ordered alternatives for the terminals in an executable alphabet list. -/
def termAlt (symbols : List Sym) : Expr NT Sym :=
  altAll (symbols.map .term)

end Expr

/-- A parsing-expression grammar with one start nonterminal. -/
structure Grammar (NT : Type uNT) (Sym : Type uSym) where
  start : NT
  rule : NT → Expr NT Sym

theorem Grammar.ext {G H : Grammar NT Sym}
    (start_eq : G.start = H.start) (rule_eq : G.rule = H.rule) : G = H := by
  cases G
  cases H
  simp_all

/-- A grammar bundled with exhaustive alphabet and nonterminal enumerations. -/
structure FiniteGrammar (Sym : Type uSym) (NT : Type uNT) where
  alphabet : FiniteEnum Sym
  nonterminals : FiniteEnum NT
  grammar : Grammar NT Sym

/-- Rename every nonterminal occurring in an expression. -/
def transportExpr (e : FiniteEquiv NT NT') : Expr NT Sym → Expr NT' Sym
  | .eps => .eps
  | .fail => .fail
  | .any => .any
  | .term symbol => .term symbol
  | .nonterm name => .nonterm (e name)
  | .seq left right => .seq (transportExpr e left) (transportExpr e right)
  | .alt left right => .alt (transportExpr e left) (transportExpr e right)
  | .notP body => .notP (transportExpr e body)

@[simp] theorem transportExpr_symm_apply
    (e : FiniteEquiv NT NT') (expr : Expr NT Sym) :
    transportExpr e.symm (transportExpr e expr) = expr := by
  induction expr <;> simp_all [transportExpr]

@[simp] theorem transportExpr_apply_symm
    (e : FiniteEquiv NT NT') (expr : Expr NT' Sym) :
    transportExpr e (transportExpr e.symm expr) = expr := by
  induction expr <;> simp_all [transportExpr]

/-- Rename a grammar along a proved nonterminal equivalence. -/
def transportGrammar (e : FiniteEquiv NT NT') (G : Grammar NT Sym) :
    Grammar NT' Sym where
  start := e G.start
  rule name := transportExpr e (G.rule (e.symm name))

@[simp] theorem transportGrammar_start
    (e : FiniteEquiv NT NT') (G : Grammar NT Sym) :
    (transportGrammar e G).start = e G.start := rfl

@[simp] theorem transportGrammar_rule_apply
    (e : FiniteEquiv NT NT') (G : Grammar NT Sym) (name : NT) :
    (transportGrammar e G).rule (e name) = transportExpr e (G.rule name) := by
  simp [transportGrammar]

@[simp] theorem transportGrammar_symm_apply
    (e : FiniteEquiv NT NT') (G : Grammar NT Sym) :
    transportGrammar e.symm (transportGrammar e G) = G := by
  cases G with
  | mk start rule =>
      apply Grammar.ext
      · simp [transportGrammar]
      · funext name
        simp [transportGrammar]

@[simp] theorem transportGrammar_apply_symm
    (e : FiniteEquiv NT NT') (G : Grammar NT' Sym) :
    transportGrammar e (transportGrammar e.symm G) = G := by
  cases G with
  | mk start rule =>
      apply Grammar.ext
      · simp [transportGrammar]
      · funext name
        simp [transportGrammar]

/-- Transport both the grammar and its exhaustive nonterminal enumeration. -/
def transportFiniteGrammar (e : FiniteEquiv NT NT')
    (G : FiniteGrammar Sym NT) : FiniteGrammar Sym NT' where
  alphabet := G.alphabet
  nonterminals := FiniteEnum.ofEquiv G.nonterminals e
  grammar := transportGrammar e G.grammar

end FPRD