{- Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. -} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -Wno-orphans #-} module Glean.Glass.SymbolId.Hack ( {- instances and -} hackGlobalNamespaceAliases ) where import Control.Monad (forM) import qualified Data.Map.Strict as Map import Data.Text (Text, intercalate) import Data.Hashable import qualified Glean import Glean.Angle import Glean.Glass.SymbolId.Class import Glean.Glass.Types (Name(..)) import Glean.Haxl.Repos (RepoHaxl) import qualified Glean.Glass.Utils as Utils import qualified Glean.Schema.Hack.Types as Hack import qualified Haxl.Core.Memo as Haxl -- -- Hack language name boilerplate -- instance Symbol Hack.Declaration where toSymbol e = case e of Hack.Declaration_method x -> toSymbolPredicate x Hack.Declaration_enumerator x -> toSymbolPredicate x Hack.Declaration_container x -> toSymbol x Hack.Declaration_function_ x -> toSymbolPredicate x Hack.Declaration_classConst x -> toSymbolPredicate x Hack.Declaration_property_ x -> toSymbolPredicate x Hack.Declaration_typeConst x -> toSymbolPredicate x Hack.Declaration_globalConst x -> toSymbolPredicate x Hack.Declaration_namespace_ x -> toSymbolPredicate x Hack.Declaration_typedef_ x -> toSymbolPredicate x Hack.Declaration_module x -> toSymbolPredicate x Hack.Declaration_EMPTY -> return [] instance Symbol Hack.TypeConstDeclaration_key where toSymbol (Hack.TypeConstDeclaration_key name container) = container <:> name instance Symbol Hack.PropertyDeclaration_key where toSymbol (Hack.PropertyDeclaration_key name container) = do xs <- toSymbol container x <- (":prop" :) <$> toSymbol name return $ xs ++ x instance Symbol Hack.ClassConstDeclaration_key where toSymbol (Hack.ClassConstDeclaration_key name container) = container <:> name instance Symbol Hack.MethodDeclaration_key where toSymbol (Hack.MethodDeclaration_key name container) = container <:> name instance Symbol Hack.ModuleDeclaration_key where toSymbol (Hack.ModuleDeclaration_key name) = ("module" :) <$> toSymbol name instance Symbol Hack.EnumDeclaration_key where toSymbol (Hack.EnumDeclaration_key qn) = toSymbol qn instance Symbol Hack.EnumDeclaration where toSymbol k = Glean.keyOf k >>= toSymbol instance Symbol Hack.Enumerator_key where toSymbol (Hack.Enumerator_key name decl) = decl <:> name instance Symbol Hack.FunctionDeclaration_key where toSymbol (Hack.FunctionDeclaration_key qn) = ("fun" :) <$> toSymbol qn instance Symbol Hack.ContainerDeclaration where toSymbol (Hack.ContainerDeclaration_class_ c) = toSymbolPredicate c toSymbol (Hack.ContainerDeclaration_enum_ c) = toSymbolPredicate c toSymbol (Hack.ContainerDeclaration_interface_ c) = toSymbolPredicate c toSymbol (Hack.ContainerDeclaration_trait c) = toSymbolPredicate c toSymbol Hack.ContainerDeclaration_EMPTY = return [] instance Symbol Hack.ClassDeclaration_key where toSymbol (Hack.ClassDeclaration_key qn) = toSymbol qn instance Symbol Hack.InterfaceDeclaration_key where toSymbol (Hack.InterfaceDeclaration_key qn) = toSymbol qn instance Symbol Hack.TraitDeclaration_key where toSymbol (Hack.TraitDeclaration_key qn) = toSymbol qn instance Symbol Hack.TypedefDeclaration_key where toSymbol (Hack.TypedefDeclaration_key qn) = toSymbol qn instance Symbol Hack.NamespaceDeclaration_key where toSymbol (Hack.NamespaceDeclaration_key qn) = ("ns" :) <$> toSymbol qn instance Symbol Hack.NamespaceDeclaration where toSymbol k = Glean.keyOf k >>= toSymbol instance Symbol Hack.NamespaceQName where toSymbol k = Glean.keyOf k >>= toSymbol instance Symbol Hack.NamespaceQName_key where toSymbol (Hack.NamespaceQName_key name parent) = parent <:> name instance Symbol Hack.GlobalConstDeclaration_key where toSymbol (Hack.GlobalConstDeclaration_key qn) = ("const" :) <$> toSymbol qn instance Symbol Hack.QName where toSymbol k = Glean.keyOf k >>= toSymbol instance Symbol Hack.QName_key where toSymbol (Hack.QName_key name Nothing) = toSymbol name toSymbol (Hack.QName_key name (Just ns)) = ns <:> name instance Symbol Hack.Name where toSymbol k = do v <- Glean.keyOf k return [v] -- -- And searching for Hack Entities -- instance ToQName Hack.Declaration where toQName e = case e of Hack.Declaration_classConst x -> Glean.keyOf x >>= toQName Hack.Declaration_container x -> toQName x Hack.Declaration_enumerator x -> Glean.keyOf x >>= toQName Hack.Declaration_function_ x -> Glean.keyOf x >>= toQName Hack.Declaration_globalConst x -> Glean.keyOf x >>= toQName Hack.Declaration_method x -> Glean.keyOf x >>= toQName Hack.Declaration_module x -> Glean.keyOf x >>= toQName Hack.Declaration_namespace_ x -> Glean.keyOf x >>= toQName Hack.Declaration_property_ x -> Glean.keyOf x >>= toQName Hack.Declaration_typeConst x -> Glean.keyOf x >>= toQName Hack.Declaration_typedef_ x -> Glean.keyOf x >>= toQName Hack.Declaration_EMPTY -> return $ Left "unknown Declaration" instance ToQName Hack.ClassConstDeclaration_key where toQName (Hack.ClassConstDeclaration_key name container) = Right <$> symbolPairToQName "\\" name container instance ToQName Hack.ModuleDeclaration_key where toQName (Hack.ModuleDeclaration_key name) = Right . (, Name "") . Name . intercalate "/" <$> toSymbol name instance ToQName Hack.ContainerDeclaration where toQName (Hack.ContainerDeclaration_class_ x) = Glean.keyOf x >>= toQName toQName (Hack.ContainerDeclaration_enum_ x) = Glean.keyOf x >>= toQName toQName (Hack.ContainerDeclaration_interface_ x) = Glean.keyOf x >>= toQName toQName (Hack.ContainerDeclaration_trait x) = Glean.keyOf x >>= toQName toQName Hack.ContainerDeclaration_EMPTY = return $ Left "unknown ContainerDeclaration" instance ToQName Hack.EnumDeclaration_key where toQName (Hack.EnumDeclaration_key qn) = toQName qn instance ToQName Hack.Enumerator_key where toQName (Hack.Enumerator_key name container) = Right <$> symbolPairToQName "\\" name container instance ToQName Hack.TypeConstDeclaration_key where toQName (Hack.TypeConstDeclaration_key name container) = Right <$> symbolPairToQName "\\" name container instance ToQName Hack.GlobalConstDeclaration_key where toQName (Hack.GlobalConstDeclaration_key qn) = toQName qn instance ToQName Hack.PropertyDeclaration_key where toQName (Hack.PropertyDeclaration_key name container) = Right <$> symbolPairToQName "\\" name container instance ToQName Hack.MethodDeclaration_key where toQName (Hack.MethodDeclaration_key name container) = Right <$> symbolPairToQName "\\" name container instance ToQName Hack.FunctionDeclaration_key where toQName (Hack.FunctionDeclaration_key qname) = toQName qname instance ToQName Hack.ClassDeclaration_key where toQName (Hack.ClassDeclaration_key qn) = toQName qn instance ToQName Hack.InterfaceDeclaration_key where toQName (Hack.InterfaceDeclaration_key qn) = toQName qn instance ToQName Hack.TraitDeclaration_key where toQName (Hack.TraitDeclaration_key qn) = toQName qn instance ToQName Hack.TypedefDeclaration_key where toQName (Hack.TypedefDeclaration_key qn) = toQName qn instance ToQName Hack.NamespaceDeclaration_key where toQName (Hack.NamespaceDeclaration_key qn) = toQName qn instance ToQName Hack.NamespaceQName where toQName nsqname@Hack.NamespaceQName{} = do mShort <- Map.lookup (Glean.getId nsqname) <$> hackGlobalNamespaceAliases case mShort of -- exact key is an alias (e.g. FlibSL\Vec) Just name -> return $ Right (Name name, Name "") Nothing -> Glean.keyOf nsqname >>= toQName -- break it apart and try again instance ToQName Hack.NamespaceQName_key where toQName (Hack.NamespaceQName_key name Nothing) = do nameStr <- Name <$> Glean.keyOf name return $ Right (nameStr, Name "") toQName (Hack.NamespaceQName_key name (Just parent)) = do nameStr <- Name <$> Glean.keyOf name mParent <- toQName parent -- might need to shorten return $ case mParent of Right (parentName, Name "") -> Right (nameStr, parentName) Right (Name p, Name ps) -> Right (nameStr, Name (ps <> "\\" <> p)) Left e -> Left e instance ToQName Hack.QName where toQName x = Glean.keyOf x >>= toQName instance ToQName Hack.QName_key where toQName (Hack.QName_key name Nothing) = do nameStr <- Name <$> Glean.keyOf name return $ Right (nameStr, Name "") toQName (Hack.QName_key name (Just nsqname)) = do nameStr <- Name <$> Glean.keyOf name mParent <- toQName nsqname return $ case mParent of Right (parentName, Name "") -> Right (nameStr, parentName) Right (Name p, Name ps) -> Right (nameStr, Name (ps <> "\\" <> p)) Left e -> Left e newtype Glass_SymbolId_Hack_ShortNamespace_Key = Glass_SymbolId_Hack_ShortNamespace_Key (Glean.Repo, Text) deriving (Eq, Hashable, Ord, Show) -- Memoize implementation of short namespace lookup -- hackGlobalNamespaceAliases :: RepoHaxl u w (Map.Map (Glean.IdOf Hack.NamespaceQName) Text) hackGlobalNamespaceAliases = do repo <- Glean.haxlRepo -- use repo as memo hash as we store Ids Haxl.memo (Glass_SymbolId_Hack_ShortNamespace_Key (repo, "Glean.Glass.SymbolId.Hack"::Text)) $ do (pairs,_lim) <- Utils.searchRecursiveWithLimit (Just maxMappings) query Map.fromList <$> forM pairs (\alias -> do Hack.GlobalNamespaceAlias_key{..} <- Glean.keyOf alias let nsQName = Glean.getId globalNamespaceAlias_key_to shortName <- Glean.keyOf globalNamespaceAlias_key_from return (nsQName, shortName) ) where query = predicate @Hack.GlobalNamespaceAlias wild maxMappings = 100 -- there's only about 15 actually