Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4e002c9
feat: delabSubscript and delabSuperscript
gio256 Mar 17, 2025
66eb431
fix: private function application
gio256 Mar 17, 2025
f5a8774
test: restructure sub/superscript delab tests
gio256 Mar 17, 2025
d561fd0
fix: subscript partially-applied functions
gio256 Mar 17, 2025
b5ae8b9
test: better syntax for subscript test macro
gio256 Mar 17, 2025
a019c11
fix: prefer getExpr to passing around expression
gio256 Mar 17, 2025
315b848
fix: () : Unit is valid in subscripts
gio256 Mar 17, 2025
708ce39
fix: camelCase defs
gio256 Mar 17, 2025
36e3612
test: test partially-applied fn in subscript
gio256 Mar 17, 2025
04edce2
chore: make sub/superscriptable fns private
gio256 Mar 17, 2025
2355936
doc: clean up and comment
gio256 Mar 18, 2025
3fdd2b1
chore: clarify name function
gio256 Mar 18, 2025
00a22e5
doc: clarify comment
gio256 Mar 18, 2025
abc6974
chore: imports, comments, add delab section
gio256 Mar 18, 2025
9b548f3
test: add tests that don't trigger the delaborator
gio256 Mar 18, 2025
2e571a2
fix: delab first, then check subscript validity
gio256 Mar 18, 2025
a870c10
chore: clean up isSuperscriptable
gio256 Mar 18, 2025
ad05d28
chore: combine superscriptable and subscriptable
gio256 Mar 18, 2025
adc446e
test: rm smul test
gio256 Mar 18, 2025
5a5abad
doc: add comment for Superscript.isValid
gio256 Mar 18, 2025
1dfdd75
test: clean up test fn naming
gio256 Mar 18, 2025
eab471f
test: add nested superscript(subscript) tests
gio256 Mar 18, 2025
ec0c3ad
doc: fix typo
gio256 Mar 19, 2025
4b97140
test: add dot notation tests
gio256 Mar 19, 2025
272b535
chore: rm unused universe
gio256 Mar 19, 2025
fbf9915
style: use anon dot notation in delabSubscript fns
gio256 Mar 19, 2025
df5fd0c
fix: reject values that are already subscripted
gio256 Mar 19, 2025
c93827e
Merge branch 'master' into gio/subscript
gio256 Mar 19, 2025
8bb34e3
chore: clarify Superscript.isValid logic
gio256 Mar 19, 2025
e78cd37
style: golf Superscript.isValid valid helper fn
gio256 Apr 17, 2025
2f65a68
style: golf Superscript.isValid scripted helper fn
gio256 Apr 17, 2025
26e7384
restore using decl_name to guarantee SyntaxNodeKind uniqueness
kmill May 1, 2025
fb95ea2
minimize diff
kmill May 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions Mathlib/Util/Superscript.lean
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,60 @@ def scriptParser.formatter (name : String) (m : Mapping) (k : SyntaxNodeKind) (p
| .ok newStack =>
set { st with stack := stack ++ newStack }

open PrettyPrinter.Delaborator

/-- Returns the user-facing name of any constant or free variable. -/
private def name : Expr → MetaM (Option Name)
| Expr.const name _ => pure name
| Expr.fvar name => name.getUserName
| _ => pure none

/-- Returns `true` if every character in `s` can be subscripted. -/
private def isSubscriptable (s : Name) : Bool :=
s.toString.toList.all Mapping.subscript.toSpecial.contains

/-- Returns `true` if every character in `s` can be superscripted. -/
private def isSuperscriptable (s : Name) : Bool :=
s.toString.toList.all Mapping.superscript.toSpecial.contains

/-- Applies the predicate `f` to every explicit argument of `e`. -/
private def check_args (e : Expr) (f : Expr → DelabM Unit) :
DelabM Unit := do
let args := e.getAppArgs
let kinds ← getParamKinds e.getAppFn args
guard <| kinds.size == args.size
args.zipIdx.zip kinds |>.filter
(fun (_, kind) ↦ kind.isRegularExplicit) |>.forM
fun ((x, i), _) ↦ SubExpr.withNaryArg i <| f x

/-- The binary operations `+`, `-`, `=`, and `==` can be super/subscripted if
their operands can be super/subscripted. -/
private def isSpecialBinOp (e : Expr) : Bool :=
e.isAppOfArity ``HAdd.hAdd 6 ||
e.isAppOfArity ``HSub.hSub 6 ||
e.isAppOfArity ``Eq 3 ||
e.isAppOfArity ``BEq.beq 4

-- TODO: what about dot notation?
/-- Checks if the entire expression `e` can be superscripted (or subscripted). -/
private def check_expr (e : Expr) (fname : Name → Bool)
(fexpr : Expr → DelabM Unit) : DelabM Unit := do
-- Any numeral is valid in a super/subscript, as is any constant or free
-- variable with a user-facing name that is valid in a super/subscript.
if (← name e).any fname || (← delab) matches `($_:num) then return
-- Function application is valid if all explicit arguments are valid and the
-- function name is valid (or one of `+`, `-`, `=`, `==`).
guard <| isSpecialBinOp e || (e.isApp && fname e.getAppFn.constName)
check_args e fexpr

/-- Checks if the expression `e` can be subscripted. -/
partial def subscriptable (e : Expr) : DelabM Unit :=
check_expr e isSubscriptable subscriptable

/-- Checks if the expression `e` can be superscripted. -/
partial def superscriptable (e : Expr) : DelabM Unit := do
check_expr e isSuperscriptable superscriptable

end Superscript

/--
Expand Down Expand Up @@ -263,6 +317,11 @@ def superscriptTerm := leading_parser (withAnonymousAntiquot := false) superscri

initialize register_parser_alias superscript

open PrettyPrinter.Delaborator in
/-- Checks that the provided expression can be superscripted before delaborating. -/
def delabSuperscript (e : Expr) : Delab :=
Superscript.superscriptable e >>= fun () ↦ delab

/--
The parser `subscript(term)` parses a subscript. Basic usage is:
```
Expand Down Expand Up @@ -299,4 +358,9 @@ def subscriptTerm := leading_parser (withAnonymousAntiquot := false) subscript t

initialize register_parser_alias subscript

open PrettyPrinter.Delaborator in
/-- Checks that the provided expression can be subscripted before delaborating. -/
def delabSubscript (e : Expr) : Delab :=
Superscript.subscriptable e >>= fun () ↦ delab

end Mathlib.Tactic
45 changes: 45 additions & 0 deletions MathlibTest/superscript.lean
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,48 @@ run_cmd Lean.Elab.Command.liftTermElabM do
Lean.logInfo <| ← Lean.PrettyPrinter.ppTerm <| ← `(term| ($a)$α:subscript)

end

section delab

open Lean PrettyPrinter.Delaborator SubExpr
open Mathlib.Tactic.Superscript (subscriptable superscriptable)

private def check_subscript {α : Type} (_ : α) := ()
private def check_superscript {α : Type} (_ : α) := ()

@[app_delab check_subscript]
private def delabCheckSub : Delab := withOverApp 2 do
let #[_, x] := (← getExpr).getAppArgs | failure
let () ← withAppArg <| subscriptable x
`("ok")

@[app_delab check_superscript]
private def delabCheckSuper : Delab := withOverApp 2 do
let #[_, x] := (← getExpr).getAppArgs | failure
let () ← withAppArg <| superscriptable x
`("ok")

/-- `α` can not be subscripted or superscripted. -/
def α {α : Type} {β : Type} : α → β → Unit := fun _ _ ↦ ()
/-- `β` can be both subscripted and superscripted. -/
def β {α : Type} {β : Type} : α → β → Unit := fun _ _ ↦ ()

variable (n : String)

/-- info: "ok" : Unit -/
#guard_msgs in #check check_subscript (1234567890 == 1234567890)
/-- info: "ok" : Unit -/
#guard_msgs in #check check_subscript (β n (1 + 2 - 3 = 0))

/-- info: check_subscript (α 0 0) : Unit -/
#guard_msgs in #check check_subscript (α 0 0)

/-- info: "ok" : Unit -/
#guard_msgs in #check check_superscript (1234567890 == 1234567890)
/-- info: "ok" : Unit -/
#guard_msgs in #check check_superscript (β n (1 + 2 - 3 = 0))

/-- info: check_superscript (α 0 0) : Unit -/
#guard_msgs in #check check_superscript (α 0 0)

end delab
Loading