Zulip Chat Archive
Stream: lean4
Topic: position dependent macros
Mario Carneiro (Jul 13 2021 at 23:12):
One nice thing about the rust panic!
macro (and other macros like it) is that it will report the file position of the macro call itself along with the panic message. I'm wondering what it would take to do something like this in lean 4. Here's my attempt:
import Lean
open Lean
macro:max "throw!"%tk interpStr:interpolatedStr(term) : term => do
let head := Syntax.mkStrLit $ match tk.getPos? with
| none => "[?]: "
| some x => s!"[{x}]: "
let str ← interpStr.expandInterpolatedStr (← `(String)) (← `(toString))
`(throwError (($head : MessageData) ++ $str))
def foo : CoreM Unit := throw!"nope"
-- ^ this is character 343
#eval foo -- [343]: nope
This is okay, but I would much rather get a line number than a byte position in the file, and I'm not sure how to get that info out of MacroM
Mario Carneiro (Jul 13 2021 at 23:13):
(it's also not clear to me why the position I get is the beginning of the string instead of the throw!
token)
Wojciech Nawrocki (Jul 14 2021 at 00:11):
I wanna say this is currently impossible because MacroM
does not contain a FileMap
. Probably a way to turn String.Pos
into a position could be added to Methods
, but why not use a custom elaborator like panic!
?
Mac (Jul 14 2021 at 00:45):
To elaborate on @Wojciech Nawrocki point. The fileMap
of a source file is available through an InputContext
. Said fileMap
has a method toPosition
that converts a String.Pos
to a Position
that consists of a line and column number. An example of this being used in Parsers can be seen here: in toErrorMsg
. Unfortunately, neither the InputContext
nor an alternative method of producing Position
from String.Pos
is available to macros.
Mario Carneiro (Jul 14 2021 at 01:46):
Okay, this is slightly improved:
import Lean
open Lean
elab:max "throw!" interpStr:interpolatedStr(term) : term <= ty => do
let pos ← Elab.getRefPosition
let head := Syntax.mkStrLit $ mkErrorStringWithPos (← read).fileName pos ""
let str ← Elab.liftMacroM <| interpStr.expandInterpolatedStr (← `(String)) (← `(toString))
Elab.Term.elabTerm (← `(throwError (($head : MessageData) ++ $str))) ty
def foo : CoreM Unit := throw!"nope"
#eval foo -- <input>:10:24: nope
Unfortunately it seems the provided file name is a dummy
Wojciech Nawrocki (Jul 14 2021 at 01:50):
Try running that from the command line :) <input>
is used by the LSP server. I guess we can use the real URI there, although sometimes it is a weird virtual one.
Last updated: Dec 20 2023 at 11:08 UTC