190 lines
5.3 KiB
Text
190 lines
5.3 KiB
Text
/-
|
|
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Author: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import Init.Data.Ord
|
|
namespace Lean
|
|
|
|
namespace Name
|
|
-- Remark: we export the `Name.hash` to make sure it matches the hash implemented in C++
|
|
@[export lean_name_hash_exported] def hashEx : Name → UInt64 :=
|
|
Name.hash
|
|
|
|
def getPrefix : Name → Name
|
|
| anonymous => anonymous
|
|
| str p _ => p
|
|
| num p _ => p
|
|
|
|
def getString! : Name → String
|
|
| str _ s => s
|
|
| _ => unreachable!
|
|
|
|
def getNumParts : Name → Nat
|
|
| anonymous => 0
|
|
| str p _ => getNumParts p + 1
|
|
| num p _ => getNumParts p + 1
|
|
|
|
def updatePrefix : Name → Name → Name
|
|
| anonymous, _ => anonymous
|
|
| str _ s, newP => Name.mkStr newP s
|
|
| num _ s, newP => Name.mkNum newP s
|
|
|
|
def componentsRev : Name → List Name
|
|
| anonymous => []
|
|
| str n s => Name.mkStr anonymous s :: componentsRev n
|
|
| num n v => Name.mkNum anonymous v :: componentsRev n
|
|
|
|
def components (n : Name) : List Name :=
|
|
n.componentsRev.reverse
|
|
|
|
def eqStr : Name → String → Bool
|
|
| str anonymous s, s' => s == s'
|
|
| _, _ => false
|
|
|
|
def isPrefixOf : Name → Name → Bool
|
|
| p, anonymous => p == anonymous
|
|
| p, n@(num p' _) => p == n || isPrefixOf p p'
|
|
| p, n@(str p' _) => p == n || isPrefixOf p p'
|
|
|
|
|
|
def isSuffixOf : Name → Name → Bool
|
|
| anonymous, _ => true
|
|
| str p₁ s₁, str p₂ s₂ => s₁ == s₂ && isSuffixOf p₁ p₂
|
|
| num p₁ n₁, num p₂ n₂ => n₁ == n₂ && isSuffixOf p₁ p₂
|
|
| _, _ => false
|
|
|
|
def cmp : Name → Name → Ordering
|
|
| anonymous, anonymous => Ordering.eq
|
|
| anonymous, _ => Ordering.lt
|
|
| _, anonymous => Ordering.gt
|
|
| num p₁ i₁, num p₂ i₂ =>
|
|
match cmp p₁ p₂ with
|
|
| Ordering.eq => compare i₁ i₂
|
|
| ord => ord
|
|
| num _ _, str _ _ => Ordering.lt
|
|
| str _ _, num _ _ => Ordering.gt
|
|
| str p₁ n₁, str p₂ n₂ =>
|
|
match cmp p₁ p₂ with
|
|
| Ordering.eq => compare n₁ n₂
|
|
| ord => ord
|
|
|
|
def lt (x y : Name) : Bool :=
|
|
cmp x y == Ordering.lt
|
|
|
|
def quickCmpAux : Name → Name → Ordering
|
|
| anonymous, anonymous => Ordering.eq
|
|
| anonymous, _ => Ordering.lt
|
|
| _, anonymous => Ordering.gt
|
|
| num n v, num n' v' =>
|
|
match compare v v' with
|
|
| Ordering.eq => n.quickCmpAux n'
|
|
| ord => ord
|
|
| num _ _, str _ _ => Ordering.lt
|
|
| str _ _, num _ _ => Ordering.gt
|
|
| str n s, str n' s' =>
|
|
match compare s s' with
|
|
| Ordering.eq => n.quickCmpAux n'
|
|
| ord => ord
|
|
|
|
def quickCmp (n₁ n₂ : Name) : Ordering :=
|
|
match compare n₁.hash n₂.hash with
|
|
| Ordering.eq => quickCmpAux n₁ n₂
|
|
| ord => ord
|
|
|
|
def quickLt (n₁ n₂ : Name) : Bool :=
|
|
quickCmp n₁ n₂ == Ordering.lt
|
|
|
|
/-- Returns true if the name has any numeric components. -/
|
|
def hasNum : Name → Bool
|
|
| .anonymous => false
|
|
| .str p _ => p.hasNum
|
|
| .num _ _ => true
|
|
|
|
/-- The frontend does not allow user declarations to start with `_` in any of its parts.
|
|
We use name parts starting with `_` internally to create auxiliary names (e.g., `_private`). -/
|
|
def isInternal : Name → Bool
|
|
| str p s => s.get 0 == '_' || isInternal p
|
|
| num p _ => isInternal p
|
|
| _ => false
|
|
|
|
/--
|
|
The frontend does not allow user declarations to start with `_` in any of its parts.
|
|
We use name parts starting with `_` internally to create auxiliary names (e.g., `_private`).
|
|
|
|
This function checks if any component of the name starts with `_`, or is numeric.
|
|
-/
|
|
def isInternalOrNum : Name → Bool
|
|
| .str p s => s.get 0 == '_' || isInternalOrNum p
|
|
| .num _ _ => true
|
|
| _ => false
|
|
|
|
/--
|
|
Returns true if this a part of name that is internal or dynamically
|
|
generated so that it may easily be changed.
|
|
|
|
Generally, user code should not explicitly use internal names.
|
|
-/
|
|
def isInternalDetail : Name → Bool
|
|
| .str p s =>
|
|
s.startsWith "_"
|
|
|| matchPrefix s "eq_"
|
|
|| matchPrefix s "match_"
|
|
|| matchPrefix s "proof_"
|
|
|| p.isInternalOrNum
|
|
| .num _ _ => true
|
|
| p => p.isInternalOrNum
|
|
where
|
|
/-- Check that a string begins with the given prefix, and then is only digit characters. -/
|
|
matchPrefix (s : String) (pre : String) :=
|
|
s.startsWith pre && (s |>.drop pre.length |>.all Char.isDigit)
|
|
|
|
/--
|
|
Checks whether the name is an implementation-detail hypothesis name.
|
|
|
|
Implementation-detail hypothesis names start with a double underscore.
|
|
-/
|
|
def isImplementationDetail : Name → Bool
|
|
| str anonymous s => s.startsWith "__"
|
|
| num p _ => p.isImplementationDetail
|
|
| str p _ => p.isImplementationDetail
|
|
| anonymous => false
|
|
|
|
def isAtomic : Name → Bool
|
|
| anonymous => true
|
|
| str anonymous _ => true
|
|
| num anonymous _ => true
|
|
| _ => false
|
|
|
|
def isAnonymous : Name → Bool
|
|
| anonymous => true
|
|
| _ => false
|
|
|
|
def isStr : Name → Bool
|
|
| str .. => true
|
|
| _ => false
|
|
|
|
def isNum : Name → Bool
|
|
| num .. => true
|
|
| _ => false
|
|
|
|
/--
|
|
Return `true` if `n` contains a string part `s` that satisfies `f`.
|
|
|
|
Examples:
|
|
```
|
|
#eval (`foo.bla).anyS (·.startsWith "fo") -- true
|
|
#eval (`foo.bla).anyS (·.startsWith "boo") -- false
|
|
```
|
|
-/
|
|
def anyS (n : Name) (f : String → Bool) : Bool :=
|
|
match n with
|
|
| .str p s => f s || p.anyS f
|
|
| .num p _ => p.anyS f
|
|
| _ => false
|
|
|
|
end Name
|
|
end Lean
|
|
|
|
open Lean
|