lean4-htt/src/Lean/Elab/Macro.lean
2024-02-18 14:55:17 -08:00

46 lines
2.1 KiB
Text

/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Elab.MacroArgUtil
namespace Lean.Elab.Command
open Lean.Syntax
open Lean.Parser.Term hiding macroArg
open Lean.Parser.Command
@[builtin_command_elab Lean.Parser.Command.macro] def elabMacro : CommandElab
| `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind
macro%$tk$[:$prec?]? $[(name := $name?)]? $[(priority := $prio?)]? $args:macroArg* : $cat => $rhs) =>
-- exclude command prefix from synthetic position used for e.g. jumping to the macro definition
withRef (mkNullNode #[tk, rhs]) do
let prio ← liftMacroM <| evalOptPrio prio?
let (stxParts, patArgs) := (← args.mapM expandMacroArg).unzip
-- name
let name ← match name? with
| some name => pure name.getId
| none => addMacroScopeIfLocal (← liftMacroM <| mkNameFromParserSyntax cat.getId (mkNullNode stxParts)) attrKind
/- The command `syntax [<kind>] ...` adds the current namespace to the syntax node kind.
So, we must include current namespace when we create a pattern for the following `macro_rules` commands. -/
let pat := ⟨mkNode ((← getCurrNamespace) ++ name) patArgs⟩
let stxCmd ← `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind
syntax$[:$prec?]?
(name := $(name?.getD (mkIdentFrom tk name (canonical := true))))
(priority := $(quote prio):num)
$[$stxParts]* : $cat)
let rhs := rhs.raw
let macroRulesCmd ← if rhs.getArgs.size == 1 then
-- `rhs` is a `term`
let rhs := ⟨rhs[0]⟩
`($[$doc?:docComment]? macro_rules | `($pat) => Functor.map (@TSyntax.raw $(quote cat.getId.eraseMacroScopes)) $rhs)
else
-- TODO(gabriel): remove after bootstrap
-- `rhs` is of the form `` `( $body ) ``
let rhsBody := ⟨rhs[1]⟩
`($[$doc?:docComment]? macro_rules | `($pat) => `($rhsBody))
elabCommand <| mkNullNode #[stxCmd, macroRulesCmd]
| _ => throwUnsupportedSyntax
end Lean.Elab.Command