Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: noWs
Arthur Paulino (Apr 15 2025 at 12:53):
Hi, I'm trying to write an elaborator for syntax like 0u1
and 1u1
My current code is as simple as this:
import Lean
open Lean Elab Meta
declare_syntax_cat primitive
syntax num noWs "u1" : primitive
def elabPrimitive : TSyntax `primitive → TermElabM Expr
| `(primitive| $n:num u1) => sorry -- expected no space before
| _ => throwUnsupportedSyntax
But if I delete the whitespace, it complains differently (but expectedly)
| `(primitive| $n:numu1) => sorry -- unexpected token '$'; expected 'num', 'primitive' or numeral
Is there a workaround for this?
Arthur Paulino (Apr 15 2025 at 13:03):
Alternatively I'm using a dash:
...
syntax num noWs "-u1" : primitive
def elabPrimitive : TSyntax `primitive → TermElabM Expr
| `(primitive| $n:num-u1) => sorry
...
But this is not ideal
Edward van de Meent (Apr 15 2025 at 13:07):
the best workaround might be to match witout a quotation... i.e. match on Syntax.node ...
Edward van de Meent (Apr 15 2025 at 13:09):
i.e. with something like | ⟨.node info ``u1_primitive ts⟩ => sorry
Eric Wieser (Apr 15 2025 at 13:10):
This works:
import Lean
open Lean Elab Meta Parser Term
declare_syntax_cat primitive
@[primitive_parser]
def u1Parser := leading_parser num >> withAntiquot (mkAntiquot "noWs" `noWs) checkNoWsBefore >> "u1"
def elabPrimitive : TSyntax `primitive → TermElabM Expr
| `(primitive| $n:num$t:noWs u1) => sorry -- expected no space before
| _ => throwUnsupportedSyntax
#check `(primitive|1u1)
#check `(primitive|1 u1)
Eric Wieser (Apr 15 2025 at 13:11):
Should checkNoWsBefore
include this mkAntiquot
component in core?
Arthur Paulino (Apr 15 2025 at 14:45):
Edward van de Meent said:
i.e. with something like
| ⟨.node info ``u1_primitive ts⟩ => sorry
For the record, the anonymous constructor for TSyntax
is not accepted here. I think it's missing the match-pattern
tag or something
Edward van de Meent (Apr 15 2025 at 15:01):
that's odd... the following works on live:
import Lean
open Lean Elab Meta
declare_syntax_cat primitive
syntax num noWs "u1" : primitive
def elabPrimitive : TSyntax `primitive → TermElabM Expr
| ⟨.node info ``primitive__U1 ts⟩ => sorry
| _ => throwUnsupportedSyntax
Arthur Paulino (Apr 15 2025 at 15:03):
Ah, thanks. ``primitive__U1
fixed it
Edward van de Meent (Apr 15 2025 at 15:05):
yea, key is figuring out what the parser for your syntax is called
Edward van de Meent (Apr 15 2025 at 15:05):
apparently it's [category]_[CapitalizedSyntaxParts]_*
Edward van de Meent (Apr 15 2025 at 15:06):
or something along those lines
Arthur Paulino (Apr 15 2025 at 15:18):
I'm trying Edward's solution now because Eric's fails when trying
elab "⟪" p:primitive "⟫" : term => elabPrimitive p
#reduce ⟪1u1⟫
-- unexpected syntax
-- ⟪1u1⟫
But I'm struggling to get the Nat
from info
and ts
like I would do with n.getNat
Eric Wieser (Apr 15 2025 at 15:27):
Cast the Syntax
back into a TSyntax
Arthur Paulino (Apr 15 2025 at 15:32):
I have
| ⟨.node info ``primitive__U1 ts⟩ =>
let x : NumLit := ⟨Syntax.node info `num ts⟩
dbg_trace x
dbg_trace x.getNat
mkAppM ``Primitive.u1 #[ToExpr.toExpr $ x.getNat % 2 == 0]
But
#reduce ⟪3u1⟫
-- (num (num "3") "u1")
-- 0
-- Primitive.u1 true
getNat
should return 3
and the elaborated Primitive
should be Primitive.u1 false
Arthur Paulino (Apr 15 2025 at 15:35):
Apparently it works with let x := mkNode numLitKind #[ts[0]![0]!]
, but idk what I'm doing at this point
Eric Wieser (Apr 15 2025 at 15:36):
I think you want let x : NumLit := ⟨ts[0]!⟩
Arthur Paulino (Apr 15 2025 at 15:37):
That works. Thanks again!
Kyle Miller (Apr 15 2025 at 17:29):
Edward van de Meent said:
yea, key is figuring out what the parser for your syntax is called
Better, name the syntax:
syntax (name := mySyntax) ...
Arthur Paulino (Apr 15 2025 at 18:30):
Thanks a lot everyone. This is the resulting code:
declare_syntax_cat primitive
syntax (name := primitiveU1) num noWs "u1" : primitive
syntax (name := primitiveU8) num noWs "u8" : primitive
syntax (name := primitiveU16) num noWs "u16" : primitive
syntax (name := primitiveU32) num noWs "u32" : primitive
syntax (name := primitiveU64) num noWs "u64" : primitive
def elabPrimitive : TSyntax `primitive → TermElabM Expr
| ⟨.node _ ``primitiveU1 ts⟩ => mkPrimitive ts (· % 2 == 0) ``Primitive.u1
| ⟨.node _ ``primitiveU8 ts⟩ => mkPrimitive ts UInt8.ofNat ``Primitive.u8
| ⟨.node _ ``primitiveU16 ts⟩ => mkPrimitive ts UInt16.ofNat ``Primitive.u16
| ⟨.node _ ``primitiveU32 ts⟩ => mkPrimitive ts UInt32.ofNat ``Primitive.u32
| ⟨.node _ ``primitiveU64 ts⟩ => mkPrimitive ts UInt64.ofNat ``Primitive.u64
| _ => throwUnsupportedSyntax
where mkPrimitive {α} [ToExpr α] ts (f : Nat → α) ctorName :=
let n : NumLit := ⟨ts[0]!⟩
mkAppM ctorName #[ToExpr.toExpr $ f n.getNat]
Last updated: May 02 2025 at 03:31 UTC