feat: add namespace resolution
This commit is contained in:
parent
efaec02b23
commit
4aabd0aa94
2 changed files with 32 additions and 47 deletions
|
|
@ -206,37 +206,6 @@ end Command
|
|||
|
||||
/-
|
||||
|
||||
|
||||
private def getNumEndScopes : Option Name → Nat
|
||||
| none => 1
|
||||
| some n => n.getNumParts
|
||||
|
||||
private def checkAnonymousScope : List ElabScope → Bool
|
||||
| { header := Name.anonymous, .. } :: _ => true
|
||||
| _ => false
|
||||
|
||||
private def checkEndHeader : Name → List ElabScope → Bool
|
||||
| Name.anonymous, _ => true
|
||||
| Name.str p s _, { header := h, .. } :: scopes => h.eqStr s && checkEndHeader p scopes
|
||||
| _, _ => false
|
||||
|
||||
@[builtinCommandElab «end»] def elabEnd : CommandElab :=
|
||||
fun n => do
|
||||
s ← get;
|
||||
let header := (n.getArg 1).getOptionalIdent;
|
||||
let num := getNumEndScopes header;
|
||||
let scopes := s.scopes;
|
||||
if num < scopes.length then
|
||||
modify $ fun s => { scopes := s.scopes.drop num, .. s }
|
||||
else do {
|
||||
-- we keep "root" scope
|
||||
modify $ fun s => { scopes := s.scopes.drop (s.scopes.length - 1), .. s };
|
||||
throw "invalid 'end', insufficient scopes"
|
||||
};
|
||||
match header with
|
||||
| none => unless (checkAnonymousScope scopes) $ throw "invalid 'end', name is missing"
|
||||
| some header => unless (checkEndHeader header scopes) $ throw "invalid 'end', name mismatch"
|
||||
|
||||
@[builtinCommandElab «export»] def elabExport : CommandElab :=
|
||||
fun n => do
|
||||
-- `n` is of the form (Command.export "export" <namespace> "(" (null <ids>*) ")")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ def rootNamespace := `_root_
|
|||
def removeRoot (n : Name) : Name :=
|
||||
n.replacePrefix rootNamespace Name.anonymous
|
||||
|
||||
/- Name resolution -/
|
||||
|
||||
/- Check whether `ns ++ id` is a valid namepace name and/or there are aliases names `ns ++ id`. -/
|
||||
private def resolveQualifiedName (env : Environment) (ns : Name) (id : Name) : List Name :=
|
||||
let resolvedId := ns ++ id;
|
||||
|
|
@ -79,24 +81,38 @@ private def resolveNameAux (env : Environment) (ns : Name) (openDecls : List Ope
|
|||
| [] => resolveNameAux p (projSize + 1)
|
||||
| _, _ => []
|
||||
|
||||
def resolveName (env : Environment) (ns : Name) (openDecls : List OpenDecl) (id : Name) : List (Nat × Name) :=
|
||||
resolveNameAux env ns openDecls id 0
|
||||
|
||||
/- Namespace resolution -/
|
||||
|
||||
def resolveNamespaceUsingScope (env : Environment) (n : Name) : Name → Option Name
|
||||
| Name.anonymous => none
|
||||
| ns@(Name.str p _ _) => if isNamespace env (ns ++ n) then some (ns ++ n) else resolveNamespaceUsingScope p
|
||||
| _ => unreachable!
|
||||
|
||||
def resolveNamespaceUsingOpenDecls (env : Environment) (n : Name) : List OpenDecl → Option Name
|
||||
| [] => none
|
||||
| OpenDecl.simple ns [] :: ds => if isNamespace env (ns ++ n) then some (ns ++ n) else resolveNamespaceUsingOpenDecls ds
|
||||
| _ :: ds => resolveNamespaceUsingOpenDecls ds
|
||||
|
||||
/-
|
||||
def resolveName (id : Name) : Elab (List (Nat × Name)) :=
|
||||
do env ← getEnv;
|
||||
ns ← getNamespace;
|
||||
openDecls ← getOpenDecls;
|
||||
pure $ resolveNameAux env ns openDecls id 0
|
||||
|
||||
private partial def preresolveNamesAux {α} (env : Environment) (ns : Name) (openDecls : List OpenDecl) : Syntax α → Syntax α
|
||||
| Syntax.node k args => Syntax.node k (args.map preresolveNamesAux)
|
||||
| Syntax.ident info rawVal val _ => Syntax.ident info rawVal val (resolveNameAux env ns openDecls val 0)
|
||||
| stx => stx
|
||||
|
||||
def preresolveNames {α} (stx : Syntax α) : Elab (Syntax α) :=
|
||||
do env ← getEnv;
|
||||
ns ← getNamespace;
|
||||
openDecls ← getOpenDecls;
|
||||
pure $ preresolveNamesAux env ns openDecls stx
|
||||
Given a name `id` try to find namespace it refers to. The resolution procedure works as follows
|
||||
1- If `id` is the extact name of an existing namespace, then return `id`
|
||||
2- If `id` is in the scope of `namespace` commands the namespace `s_1. ... . s_n`,
|
||||
then return `s_1 . ... . s_i ++ n` if it is the name of an existing namespace. We search "backwards".
|
||||
3- Finally, for each command `open N`, return `N ++ n` if it is the name of an existing namespace.
|
||||
We search "backwards" again. That is, we try the most recent `open` command first.
|
||||
We only consider simple `open` commands.
|
||||
-/
|
||||
def resolveNamespace (env : Environment) (ns : Name) (openDecls : List OpenDecl) (id : Name) : Option Name :=
|
||||
if isNamespace env id then some id
|
||||
else match resolveNamespaceUsingScope env id ns with
|
||||
| some n => some n
|
||||
| none =>
|
||||
match resolveNamespaceUsingOpenDecls env id openDecls with
|
||||
| some n => some n
|
||||
| none => none
|
||||
|
||||
end Elab
|
||||
end Lean
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue