@@ -37,7 +37,7 @@ builtin_initialize
37
37
/--
38
38
Elaborates the term, ensuring the result has no expression metavariables.
39
39
If there would be unsolved-for metavariables, tries hinting that the resulting type
40
- is a monadic value with the `CommandElabM`, `TermElabM`, or `IO` monads.
40
+ is a monadic value with the `CommandElabM`, `TermElabM`, `MarcoM`, or `IO` monads.
41
41
Throws errors if the term is a proof or a type, but lifts props to `Bool` using `mkDecide`.
42
42
-/
43
43
private def elabTermForEval (term : Syntax) (expectedType? : Option Expr) : TermElabM Expr := do
63
63
catch ex =>
64
64
let exS ← saveState
65
65
-- Try hinting that `ty` is a monad application.
66
- for m in #[``CommandElabM, ``TermElabM, ``IO] do
66
+ for m in #[``CommandElabM, ``TermElabM, ``MacroM, `` IO] do
67
67
s.restore true
68
68
try
69
69
if ← isDefEq ty (← mkFreshMonadApp m) then
@@ -159,8 +159,34 @@ private structure EvalAction where
159
159
If `some`, the expression is what type to use for the type ascription when `pp.type` is true. -/
160
160
printVal : Option Expr
161
161
162
- unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? : Option Expr) : CommandElabM Unit := withRef tk do
162
+ def elabEvalCoreAux (tk term : Syntax) (expectedType? : Option Expr)
163
+ (mkAct : Name → Expr → TermElabM EvalAction) : CommandElabM Unit := withRef tk do
163
164
let declName := `_eval
165
+ let (output, exOrRes) ← IO.FS.withIsolatedStreams do
166
+ try
167
+ -- Generate an action without executing it. We use `withoutModifyingEnv` to ensure
168
+ -- we don't pollute the environment with auxiliary declarations.
169
+ let act : EvalAction ← liftTermElabM do Term.withDeclName declName do withoutModifyingEnv do
170
+ let e ← elabTermForEval term expectedType?
171
+ -- If there is an elaboration error, don't evaluate!
172
+ if e.hasSyntheticSorry then throwAbortTerm
173
+ mkAct declName e
174
+ let res ← act.eval
175
+ return Sum.inr (res, act.printVal)
176
+ catch ex =>
177
+ return Sum.inl ex
178
+ if !output.isEmpty then logInfoAt tk output
179
+ match exOrRes with
180
+ | .inl ex => logException ex
181
+ | .inr (_, none) => pure ()
182
+ | .inr (res, some type) =>
183
+ if eval.type.get (← getOptions) then
184
+ logInfo m!"{res} : {type}"
185
+ else
186
+ logInfo res
187
+
188
+ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? : Option Expr) : CommandElabM Unit := do
189
+ elabEvalCoreAux tk term expectedType? fun declName e => do
164
190
-- `t` is either `MessageData` or `Format`, and `mkT` is for synthesizing an expression that yields a `t`.
165
191
-- The `toMessageData` function adapts `t` to `MessageData`.
166
192
let mkAct {t : Type } [Inhabited t] (toMessageData : t → MessageData) (mkT : Expr → MetaM Expr) (e : Expr) : TermElabM EvalAction := do
@@ -185,8 +211,8 @@ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? :
185
211
if let some act ← mkMAct? ``CommandElabM CommandElabM e
186
212
-- Fallbacks in case we are in the Lean package but don't have `CommandElabM` yet
187
213
<||> mkMAct? ``TermElabM TermElabM e <||> mkMAct? ``MetaM MetaM e <||> mkMAct? ``CoreM CoreM e
188
- -- Fallback in case nothing is imported
189
- <||> mkMAct? ``IO IO e then
214
+ -- Fallbacks in case nothing is imported
215
+ <||> mkMAct? ``MacroM MacroM e <||> mkMAct? `` IO IO e then
190
216
return act
191
217
else
192
218
-- Otherwise, assume this is a pure value.
@@ -208,33 +234,12 @@ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? :
208
234
-- `evalConst` may emit IO, but this is collected by `withIsolatedStreams` below.
209
235
let r ← toMessageData <$> evalConst t declName
210
236
return { eval := pure r, printVal := some (← inferType e) }
211
- let (output, exOrRes) ← IO.FS.withIsolatedStreams do
212
- try
213
- -- Generate an action without executing it. We use `withoutModifyingEnv` to ensure
214
- -- we don't pollute the environment with auxiliary declarations.
215
- let act : EvalAction ← liftTermElabM do Term.withDeclName declName do withoutModifyingEnv do
216
- let e ← elabTermForEval term expectedType?
217
- -- If there is an elaboration error, don't evaluate!
218
- if e.hasSyntheticSorry then throwAbortTerm
219
- -- We want `#eval` to work even in the core library, so if `ofFormat` isn't available,
220
- -- we fall back on a `Format`-based approach.
221
- if (← getEnv).contains ``Lean.MessageData.ofFormat then
222
- mkAct id (mkMessageData ·) e
223
- else
224
- mkAct Lean.MessageData.ofFormat (mkFormat ·) e
225
- let res ← act.eval
226
- return Sum.inr (res, act.printVal)
227
- catch ex =>
228
- return Sum.inl ex
229
- if !output.isEmpty then logInfoAt tk output
230
- match exOrRes with
231
- | .inl ex => logException ex
232
- | .inr (_, none) => pure ()
233
- | .inr (res, some type) =>
234
- if eval.type.get (← getOptions) then
235
- logInfo m!"{res} : {type}"
236
- else
237
- logInfo res
237
+ -- We want `#eval` to work even in the core library, so if `ofFormat` isn't available,
238
+ -- we fall back on a `Format`-based approach.
239
+ if (← getEnv).contains ``Lean.MessageData.ofFormat then
240
+ mkAct id (mkMessageData ·) e
241
+ else
242
+ mkAct Lean.MessageData.ofFormat (mkFormat ·) e
238
243
239
244
@[implemented_by elabEvalCoreUnsafe]
240
245
opaque elabEvalCore (bang : Bool) (tk term : Syntax) (expectedType? : Option Expr) : CommandElabM Unit
@@ -274,4 +279,23 @@ def elabRunMeta : CommandElab := fun stx =>
274
279
elabEvalCore false tk (← `(discard do $elems)) (mkApp (mkConst ``MetaM) (mkConst ``Unit))
275
280
| _ => throwUnsupportedSyntax
276
281
282
+ @[builtin_command_elab runMacro]
283
+ def elabRunMacro : CommandElab := fun stx =>
284
+ match stx with
285
+ | `(run_macro%$tk $elems:doSeq) => do
286
+ elabEvalCore false tk (← `(discard do $elems)) (mkApp (mkConst ``MacroM) (mkConst ``Unit))
287
+ | _ => throwUnsupportedSyntax
288
+
289
+ @[builtin_command_elab runCmdMacro]
290
+ def elabRunCmdMacro : CommandElab
291
+ | `(run_cmd_macro%$tk $elems:doSeq) => do
292
+ let mkAct declName e : TermElabM EvalAction := do
293
+ addAndCompileExprForEval declName e
294
+ -- Safety: `e` has the (expected) type `MacroM Command`,
295
+ -- which we are assuming is defined appropriately in the environment.
296
+ let mf : MacroM Command ← unsafe evalConst (MacroM Command) declName
297
+ return { eval := do elabCommand =<< MonadEvalT.monadEval mf; pure "" , printVal := none }
298
+ elabEvalCoreAux tk (← `(do $elems)) (mkApp (mkConst ``MacroM) (mkConst ``Command)) mkAct
299
+ | _ => throwUnsupportedSyntax
300
+
277
301
end Lean.Elab.Command
0 commit comments