82 lines
3.8 KiB
Text
82 lines
3.8 KiB
Text
/-
|
|
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura, Sebastian Ullrich
|
|
-/
|
|
import Lean.Parser.Attr
|
|
import Lean.Attributes
|
|
import Lean.MonadEnv
|
|
import Lean.Elab.Util
|
|
namespace Lean.Elab
|
|
|
|
structure Attribute where
|
|
kind : AttributeKind := AttributeKind.global
|
|
name : Name
|
|
stx : Syntax := Syntax.missing
|
|
deriving Inhabited
|
|
|
|
instance : ToFormat Attribute where
|
|
format attr :=
|
|
let kindStr := match attr.kind with
|
|
| AttributeKind.global => ""
|
|
| AttributeKind.local => "local "
|
|
| AttributeKind.scoped => "scoped "
|
|
Format.bracket "@[" f!"{kindStr}{attr.name}{toString attr.stx}" "]"
|
|
|
|
/--
|
|
```
|
|
attrKind := leading_parser optional («scoped» <|> «local»)
|
|
```
|
|
-/
|
|
def toAttributeKind (attrKindStx : Syntax) : MacroM AttributeKind := do
|
|
if attrKindStx[0].isNone then
|
|
return AttributeKind.global
|
|
else if attrKindStx[0][0].getKind == ``Lean.Parser.Term.scoped then
|
|
if (← Macro.getCurrNamespace).isAnonymous then
|
|
throw <| Macro.Exception.error (← getRef) "scoped attributes must be used inside namespaces"
|
|
return AttributeKind.scoped
|
|
else
|
|
return AttributeKind.local
|
|
|
|
def mkAttrKindGlobal : Syntax :=
|
|
mkNode ``Lean.Parser.Term.attrKind #[mkNullNode]
|
|
|
|
def elabAttr [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadInfoTree m] [MonadLiftT IO m] (attrInstance : Syntax) : m Attribute := do
|
|
/- attrInstance := ppGroup $ leading_parser attrKind >> attrParser -/
|
|
let attrKind ← liftMacroM <| toAttributeKind attrInstance[0]
|
|
let attr := attrInstance[1]
|
|
let attr ← liftMacroM <| expandMacros attr
|
|
let attrName ← if attr.getKind == ``Parser.Attr.simple then
|
|
pure attr[0].getId.eraseMacroScopes
|
|
else match attr.getKind with
|
|
| .str _ s => pure <| Name.mkSimple s
|
|
| _ => throwErrorAt attr "unknown attribute"
|
|
let .ok impl := getAttributeImpl (← getEnv) attrName
|
|
| throwError "unknown attribute [{attrName}]"
|
|
let attrSyntaxNodeKind := attrInstance[1].getKind
|
|
-- `Lean.Parser.Attr.simple` is a generic `attribute` parser used in simple attributes.
|
|
-- We don't want to create an info tree node from a simple attribute to the generic parser.
|
|
let declTarget := if attrSyntaxNodeKind == ``Lean.Parser.Attr.simple then impl.ref else attrSyntaxNodeKind
|
|
if (← getEnv).contains declTarget && (← getInfoState).enabled then
|
|
pushInfoLeaf <| .ofCommandInfo {
|
|
elaborator := declTarget -- not truly an elaborator, but a sensible target for go-to-definition
|
|
stx := attrInstance[1][0] -- We want to associate the information to the first atom only
|
|
}
|
|
/- The `AttrM` does not have sufficient information for expanding macros in `args`.
|
|
So, we expand them before here before we invoke the attributer handlers implemented using `AttrM`. -/
|
|
return { kind := attrKind, name := attrName, stx := attr }
|
|
|
|
def elabAttrs [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadInfoTree m] [MonadLiftT IO m] (attrInstances : Array Syntax) : m (Array Attribute) := do
|
|
let mut attrs := #[]
|
|
for attr in attrInstances do
|
|
try
|
|
attrs := attrs.push (← withRef attr do elabAttr attr)
|
|
catch ex =>
|
|
logException ex
|
|
return attrs
|
|
|
|
-- leading_parser "@[" >> sepBy1 attrInstance ", " >> "]"
|
|
def elabDeclAttrs [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadInfoTree m] [MonadLiftT IO m] (stx : Syntax) : m (Array Attribute) :=
|
|
elabAttrs stx[1].getSepArgs
|
|
|
|
end Lean.Elab
|