lean4-htt/src/Init/Lean/Elab/ResolveName.lean
2019-12-10 10:21:14 -08:00

118 lines
4.7 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Sebastian Ullrich
-/
prelude
import Init.Lean.Modifiers
import Init.Lean.Elab.Alias
namespace Lean
namespace Elab
inductive OpenDecl
| simple (ns : Name) (except : List Name)
| explicit (id : Name) (declName : Name)
namespace OpenDecl
instance : Inhabited OpenDecl := ⟨simple Name.anonymous []⟩
instance : HasToString OpenDecl :=
⟨fun decl => match decl with
| explicit id decl => toString id ++ " → " ++ toString decl
| simple ns ex => toString ns ++ (if ex == [] then "" else " hiding " ++ toString ex)⟩
end OpenDecl
def rootNamespace := `_root_
def removeRoot (n : Name) : Name :=
n.replacePrefix rootNamespace Name.anonymous
/- Global 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;
let resolvedIds := getAliases env resolvedId;
if env.contains resolvedId && (!id.isAtomic || !isProtected env resolvedId) then resolvedId :: resolvedIds
else resolvedIds
/- Check surrounding namespaces -/
private def resolveUsingNamespace (env : Environment) (id : Name) : Name → List Name
| ns@(Name.str p _ _) =>
match resolveQualifiedName env ns id with
| [] => resolveUsingNamespace p
| resolvedIds => resolvedIds
| _ => []
/- Check exact name -/
private def resolveExact (env : Environment) (id : Name) : Option Name :=
if id.isAtomic then none
else
let resolvedId := id.replacePrefix rootNamespace Name.anonymous;
if env.contains resolvedId then some resolvedId else none
/- Check open namespaces -/
private def resolveOpenDecls (env : Environment) (id : Name) : List OpenDecl → List Name → List Name
| [], resolvedIds => resolvedIds
| OpenDecl.simple ns exs :: openDecls, resolvedIds =>
if exs.elem id then resolveOpenDecls openDecls resolvedIds
else
let newResolvedIds := resolveQualifiedName env ns id;
resolveOpenDecls openDecls (newResolvedIds ++ resolvedIds)
| OpenDecl.explicit openedId resolvedId :: openDecls, resolvedIds =>
let resolvedIds := if id == openedId then resolvedId :: resolvedIds else resolvedIds;
resolveOpenDecls openDecls resolvedIds
private def resolveGlobalNameAux (env : Environment) (ns : Name) (openDecls : List OpenDecl) : Name → List String → List (Name × List String)
| id@(Name.str p s _), projs =>
match resolveUsingNamespace env id ns with
| resolvedIds@(_ :: _) => resolvedIds.eraseDups.map $ fun id => (id, projs)
| [] =>
match resolveExact env id with
| some newId => [(newId, projs)]
| none =>
let resolvedIds := if env.contains id then [id] else [];
let resolvedIds := resolveOpenDecls env id openDecls resolvedIds;
let resolvedIds := getAliases env id ++ resolvedIds;
match resolvedIds with
| resolvedIds@(_ :: _) => resolvedIds.eraseDups.map $ fun id => (id, projs)
| [] => resolveGlobalNameAux p (s::projs)
| _, _ => []
def resolveGlobalName (env : Environment) (ns : Name) (openDecls : List OpenDecl) (id : Name) : List (Name × List String) :=
resolveGlobalNameAux env ns openDecls id []
/- 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
/-
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