This PR upstreams the Verso parser and adds preliminary support for Verso in docstrings. This will allow the compiler to check examples and cross-references in documentation. After a `stage0` update, a follow-up PR will add the appropriate attributes that allow the feature to be used. The parser tests from Verso also remain to be upstreamed, and user-facing documentation will be added once the feature has been used on more internals.
120 lines
4.1 KiB
Text
120 lines
4.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
|
|
-/
|
|
module
|
|
|
|
prelude
|
|
public import Lean.Log
|
|
public import Lean.Elab.Util
|
|
public import Lean.Parser.Command
|
|
meta import Lean.Parser.Command
|
|
|
|
public section
|
|
|
|
namespace Lean.Elab
|
|
namespace OpenDecl
|
|
|
|
variable [Monad m] [STWorld IO.RealWorld m] [MonadEnv m]
|
|
variable [MonadExceptOf Exception m] [MonadRef m] [AddErrorMessageContext m]
|
|
variable [AddMessageContext m] [MonadLiftT (ST IO.RealWorld) m] [MonadLog m]
|
|
|
|
/--
|
|
A local copy of name resolution state that allows us to immediately use new open decls
|
|
in further name resolution as in `open Lean Elab`.
|
|
-/
|
|
structure State where
|
|
openDecls : List OpenDecl
|
|
currNamespace : Name
|
|
|
|
abbrev M := StateRefT State m
|
|
|
|
instance : MonadResolveName (M (m := m)) where
|
|
getCurrNamespace := return (← get).currNamespace
|
|
getOpenDecls := return (← get).openDecls
|
|
|
|
def resolveId [MonadResolveName m] (ns : Name) (idStx : Syntax) : m Name := do
|
|
let declName := ns ++ idStx.getId
|
|
if (← getEnv).contains declName then
|
|
return declName
|
|
else
|
|
withRef idStx <| resolveGlobalConstNoOverloadCore declName
|
|
|
|
private def addOpenDecl (decl : OpenDecl) : M (m:=m) Unit :=
|
|
modify fun s => { s with openDecls := decl :: s.openDecls }
|
|
|
|
/--
|
|
Uniquely resolves the identifier `idStx` in the provided namespaces `nss`.
|
|
|
|
If the identifier does not indicate a name in exactly one of the namespaces, an exception is thrown.
|
|
-/
|
|
def resolveNameUsingNamespacesCore [MonadResolveName m]
|
|
(nss : List Name) (idStx : Syntax) : m Name := do
|
|
let mut exs := #[]
|
|
let mut result := #[]
|
|
for ns in nss do
|
|
try
|
|
let declName ← resolveId ns idStx
|
|
result := result.push declName
|
|
catch ex =>
|
|
exs := exs.push ex
|
|
if exs.size == nss.length then
|
|
withRef idStx do
|
|
if h : exs.size = 1 then
|
|
throw exs[0]
|
|
else
|
|
throwErrorWithNestedErrors "failed to open" exs
|
|
if h : result.size = 1 then
|
|
return result[0]
|
|
else
|
|
withRef idStx do throwError "ambiguous identifier `{idStx.getId}`, possible interpretations: {result.map mkConst}"
|
|
|
|
def elabOpenDecl [MonadResolveName m] [MonadInfoTree m] (stx : TSyntax ``Parser.Command.openDecl) : m (List OpenDecl) := do
|
|
StateRefT'.run' (s := { openDecls := (← getOpenDecls), currNamespace := (← getCurrNamespace) }) do
|
|
match stx with
|
|
| `(Parser.Command.openDecl| $nss*) =>
|
|
for ns in nss do
|
|
for ns in (← resolveNamespace ns) do
|
|
addOpenDecl (OpenDecl.simple ns [])
|
|
activateScoped ns
|
|
| `(Parser.Command.openDecl| scoped $nss*) =>
|
|
for ns in nss do
|
|
for ns in (← resolveNamespace ns) do
|
|
activateScoped ns
|
|
| `(Parser.Command.openDecl| $ns ($ids*)) =>
|
|
let nss ← resolveNamespace ns
|
|
for idStx in ids do
|
|
let declName ← resolveNameUsingNamespacesCore nss idStx
|
|
if (← getInfoState).enabled then
|
|
addConstInfo idStx declName
|
|
addOpenDecl (OpenDecl.explicit idStx.getId declName)
|
|
| `(Parser.Command.openDecl| $ns hiding $ids*) =>
|
|
let ns ← resolveUniqueNamespace ns
|
|
activateScoped ns
|
|
for id in ids do
|
|
let declName ← resolveId ns id
|
|
if (← getInfoState).enabled then
|
|
addConstInfo id declName
|
|
let ids := ids.map (·.getId) |>.toList
|
|
addOpenDecl (OpenDecl.simple ns ids)
|
|
| `(Parser.Command.openDecl| $ns renaming $[$froms -> $tos],*) =>
|
|
let ns ← resolveUniqueNamespace ns
|
|
for («from», to) in froms.zip tos do
|
|
let declName ← resolveId ns «from»
|
|
if (← getInfoState).enabled then
|
|
addConstInfo «from» declName
|
|
addConstInfo to declName
|
|
addOpenDecl (OpenDecl.explicit to.getId declName)
|
|
| _ => throwUnsupportedSyntax
|
|
return (← get).openDecls
|
|
|
|
def resolveNameUsingNamespaces [MonadResolveName m] (nss : List Name) (idStx : Ident) : m Name := do
|
|
StateRefT'.run' (s := { openDecls := (← getOpenDecls), currNamespace := (← getCurrNamespace) }) do
|
|
resolveNameUsingNamespacesCore (m := M) nss idStx
|
|
|
|
end OpenDecl
|
|
|
|
export OpenDecl (elabOpenDecl resolveNameUsingNamespaces)
|
|
|
|
end Lean.Elab
|