/- 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