Zulip Chat Archive

Stream: new members

Topic: What parsers parses the "(ab : α×β)" in a "fun ... => ..."?


Eduardo Ochs (Jun 26 2024 at 12:05):

Hi all,

sorry if this looks like a question that is being asked too early... I was checking how much, or how little, I know about how Lean parsers certain expressions, and I saw that in

#check fun {α β} (ab : α×β) => let (a,_) := ab; a

the {α β} is parsed by funImplicitBinder, but I couldn't find the name of the (sub)parser that funBinder uses to parse the (ab : α×β)... hints, please?

Eduardo Ochs (Jun 26 2024 at 12:07):

Here's some more context. I'm writing my (guess for a) parse tree in this format,

import Lean
open   Lean Elab Command Meta Term

#check fun {α β}         (ab : α×β) => let (a,_) := ab; a
#check fun {α β} [BEq α] (ab : α×β) => let (a,_) := ab; a==a

-- #check fun   {α           β          } (ab : α×β) =>   let (a,_) := ab ;            a
--        -----  ----------- -----------  ---------- ----     ----------- ------------ ----------
--        "fun"  binderIdent binderIdent      ?      "=>"     letDecl?    optSemicolon termParser
--              ------------------------- ----------      ---------------------------------------
--              funImplicitBinder         funBinder?      termParser?
--              -------------------------
--              funBinder
--              ---------------------------------------------------------------------------------
--              basicFun

-- Hyperlinks to the parsers:
#check Lean.Parser.Term.basicFun
#check Lean.Parser.Term.binderIdent
#check Lean.Parser.Term.funBinder
#check Lean.Parser.Term.funImplicitBinder
#check Lean.Parser.Term.funStrictImplicitBinder
#check Lean.Parser.Term.letDecl
#check Lean.Parser.Term.letPatDecl
#check Lean.Parser.Term.matchAlts
#check Lean.Parser.Termfun»
#check Lean.Parser.Termlet»
#check Lean.Parser.termParser

Eduardo Ochs (Jun 26 2024 at 12:12):

...and I'm working on a program that processes the tree in ASCII art and LaTeXes it as a diagram with underbraces that looks like this:

Eduardo Ochs (Jun 26 2024 at 12:12):

sshot-cropped.png

Eduardo Ochs (Jun 26 2024 at 12:17):

I still have lots of doubts about how to complete that parse tree, but most of these doubts are about parsing combinators... and I hope that understanding funBinder will help me with the rest.

Eric Wieser (Jun 26 2024 at 12:48):

If you use

#check `(fun {α β} [BEq α] (ab : α×β) => let (a,_) := ab; a==a)

then the names of all most of the parsers are embedded in the output

Eduardo Ochs (Jun 26 2024 at 13:44):

Thanks!!!
New diagram:

Eduardo Ochs (Jun 26 2024 at 13:45):

sshot.png

Eduardo Ochs (Jun 26 2024 at 14:49):

Is there an easy way to extract the expression inside the raw := ... from a syntax quotation? How? Let's consider this smaller example:

import Lean
open   Lean.Elab.Term.Quotation
#check mkSyntaxQuotation
#check  `(42 + "foo")
#check (`(42 + "foo") : Lean.MacroM (Lean.TSyntax `term))

Eric Wieser (Jun 26 2024 at 15:34):

You probably want to parse it inside run_cmd do

Eric Wieser (Jun 26 2024 at 15:38):

That is, something like

run_cmd do
  let stx <- `(fun {α β} [BEq α] (ab : α×β) => let (a,_) := ab; a==a)
  -- process stx
  Lean.logInfo m!"{stx}"

Eduardo Ochs (Jun 26 2024 at 21:32):

Perfect! Thanks! :smile:
For the sake of completeness, here's what I've got...
It's just a prototype, but I think it's nice anyway.

Eduardo Ochs (Jun 26 2024 at 21:32):

sshot.png

Eduardo Ochs (Jun 26 2024 at 21:33):

import Lean
import Init.Data.Format
open   Lean SourceInfo Parser
open   Std Format

def pile : (List Format)  Format
  | []           => ""
  | [item]       => item
  | item :: rest => item ++ line ++ pile rest

def zpile (head : String) (fmts : List Format) :=
  nest (1 + String.length head) <| head ++ align true ++ (pile fmts)

class  ToPrettier (α : Type) where toPrettier : α  Format
export ToPrettier (toPrettier)

def    toPrettier_Nat (n : Nat) : Format := toString n
def    toPrettier_Int (n : Int) : Format := toString n
def    toPrettier_List  [ToPrettier α] (as : List α)  : Format :=
  zpile "[]"  (List.map  toPrettier as)
def    toPrettier_Array [ToPrettier α] (as : Array α) : Format :=
  zpile "#[]" (List.map toPrettier (as.toList))
def    toPrettier_SourceInfo (_ : Sourceinfo) : Format := ".sourceinfo"
def    toPrettier_Name : Name  Format
  | .anonymous .. => ".anonymous"
  | .num name i   => toPrettier_Name name ++ " " ++ toString i
  | .str _ str    => "name: " ++ str

instance : ToPrettier Nat        where toPrettier := toPrettier_Nat
instance : ToPrettier Int        where toPrettier := toPrettier_Int
instance : ToPrettier Name       where toPrettier := toPrettier_Name
instance : ToPrettier SourceInfo where toPrettier := toPrettier_SourceInfo
instance {α} [ToPrettier α] : ToPrettier (List α)  where toPrettier := toPrettier_List
instance {α} [ToPrettier α] : ToPrettier (Array α) where toPrettier := toPrettier_Array

def toPrettier_SyntaxNodeKind  : SyntaxNodeKind   Format := toPrettier_Name
def toPrettier_SyntaxNodeKinds : SyntaxNodeKinds  Format := toPrettier_List
instance : ToPrettier SyntaxNodeKind  where toPrettier := toPrettier_SyntaxNodeKind
instance : ToPrettier SyntaxNodeKinds where toPrettier := toPrettier_SyntaxNodeKinds

partial def toPrettier_Syntax : Syntax  Format
  | .missing          => ".missing"
  | .atom _ str       => ".atom: " ++ str
  | .ident _ _ name _ => ".ident: " ++ toPrettier_Name name
  | .node _ kind args =>
       let k     := toPrettier_SyntaxNodeKind kind
       let sargs := List.map toPrettier_Syntax (args.toList)
       zpile ".node" (k :: sargs)

instance : ToPrettier Syntax where toPrettier := toPrettier_Syntax

partial def toPrettier_TSyntax {ks : SyntaxNodeKinds} (ts : TSyntax ks) : Format :=
  zpile "TSyntax" [toPrettier ks, toPrettier ts.raw]

instance : ToPrettier (TSyntax ks) where toPrettier := toPrettier_TSyntax

run_cmd do
  let stx <- `(fun {α β} [BEq α] (ab : α×β) => let (a,_) := ab; a==a)
  -- let stx <- `(fun (x : Nat) => x*x)
  -- process stx
  Lean.logInfo m!"{stx}"
  -- Lean.logInfo s!"{repr stx}"
  Lean.logInfo s!"{toPrettier stx}"

Eric Wieser (Jun 26 2024 at 22:08):

Eduardo Ochs said:

sshot.png

Note that in some sense here you are reinventing the UX of the infoview; it would be possible to have a command that displays syntax in the infoview, and lets you hover over its pieces to see which parser they are (instead of the usual behavior of hovering over an expression and seeing the types of the subexpressions)

Sebastian Ullrich (Jun 27 2024 at 04:18):

trace.Elab.command does similar non interactive output


Last updated: May 02 2025 at 03:31 UTC