{- 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. -} module Glean.Glass.Pretty.Fbthrift ( prettyFbthriftSignature ) where import System.FilePath ( dropExtension, takeBaseName ) import Data.Text ( Text, unpack ) import Compat.Prettyprinter import Glean.Glass.Types ( SymbolId(..), RepoName(..) ) import qualified Glean import qualified Glean.Haxl.Repos as Glean import Glean.Schema.CodeFbthrift.Types as Fbthrift ( Entity(..) ) import qualified Glean.Schema.Fbthrift.Types as Fbthrift import qualified Glean.Schema.Src.Types as Src -- Type of Fbthrift entity signatures to capture the the subset we generate -- We use this to separate the processing of the Glean type from the text -- we wish to generate newtype File = File Text newtype Identifier = Identifier Text data NamedKind = Typedef | Enum | Struct | Union data FieldKind = FUnion | FStruct | FException data QualName = QualName File Identifier data Declaration = IncludeFile File | Named QualName NamedKind -- user declared type | Service QualName | Exception QualName | Constant QualName | Function QualName Identifier | EnumValue QualName NamedKind Identifier | FieldDecl QualName FieldKind Identifier -- The returned DocStream is annotated with SymbolId (links from sig -- tokens to their definition). This isn't supported yet for thrift. -- It'll be always Nothing, and () in the returned Doc types. prettyFbthriftSignature :: LayoutOptions -> RepoName -> SymbolId -> Fbthrift.Entity -> Glean.RepoHaxl u w (Maybe (SimpleDocStream (Maybe SymbolId))) prettyFbthriftSignature opts _repo sym (Fbthrift.Entity_decl d) = do mDecl <- fromAngleDeclaration d case mDecl of Nothing -> return Nothing Just decl -> let doc = layoutSmart opts $ prettyDecl opts sym decl annDoc = reAnnotateS (\() -> Nothing) doc in return $ Just annDoc prettyFbthriftSignature _ _ _ Fbthrift.Entity_EMPTY = return Nothing ppKind :: NamedKind -> Doc () ppKind kind = case kind of Typedef -> "typedef" Enum -> "enum" Struct -> "struct" Union -> "union" ppFieldKind :: FieldKind -> Doc () ppFieldKind kind = case kind of FUnion -> "union" FStruct -> "struct" FException -> "exception" ppFile :: File -> Doc () ppFile (File f) = pretty f ppQualName :: QualName -> Doc () ppQualName (QualName (File file) (Identifier id)) = pretty (dropExtension (takeBaseName (unpack file)) <> "." <> unpack id) ppScopedId :: QualName -> Identifier -> Doc () ppScopedId (QualName (File file) (Identifier idService)) (Identifier id) = pretty $ mconcat [ dropExtension (takeBaseName (unpack file)), ".", unpack idService, "::", unpack id ] prettyDecl :: LayoutOptions -> SymbolId -> Declaration -> Doc () prettyDecl _ _sym (Service qName ) = "service" <+> ppQualName qName prettyDecl _ _sym (Exception qName ) = "exception" <+> ppQualName qName prettyDecl _ _sym (Constant qName ) = "constant" <+> ppQualName qName prettyDecl _ _sym (IncludeFile file) = "include" <+> ppFile file prettyDecl _ _sym (Named qName kind) = ppKind kind <+> ppQualName qName prettyDecl _ _sym (Function qName id) = "function" <+> ppScopedId qName id prettyDecl _ _sym (EnumValue qName _kd id) = "enum value" <+> ppScopedId qName id prettyDecl _ _sym (FieldDecl qName kind id) = ppFieldKind kind <+> "field" <+> ppScopedId qName id fromFile :: Src.File -> Glean.RepoHaxl u w File fromFile file = File <$> Glean.keyOf file fromKind :: Fbthrift.NamedKind -> NamedKind fromKind kind = case kind of Fbthrift.NamedKind_typedef_ -> Typedef Fbthrift.NamedKind_enum_ -> Enum Fbthrift.NamedKind_struct_ -> Struct Fbthrift.NamedKind_union_ -> Union Fbthrift.NamedKind__UNKNOWN _ -> error "unexpected NamedKind" fromFieldKind :: Fbthrift.FieldKind -> FieldKind fromFieldKind kind = case kind of Fbthrift.FieldKind_exception_ -> FException Fbthrift.FieldKind_struct_ -> FStruct Fbthrift.FieldKind_union_ -> FUnion Fbthrift.FieldKind__UNKNOWN _ -> error "unexpected FieldKind" fromQualName :: Fbthrift.QualName_key -> Glean.RepoHaxl u w QualName fromQualName (Fbthrift.QualName_key file id) = do id <- Identifier <$> Glean.keyOf id file <- fromFile =<< Glean.keyOf file return $ QualName file id fromNamedDecl :: Fbthrift.NamedDecl_key -> Glean.RepoHaxl u w Declaration fromNamedDecl (Fbthrift.NamedDecl_key namedType) = do let Fbthrift.NamedType qName kind = namedType qName <- fromQualName =<< Glean.keyOf qName return $ Named qName (fromKind kind) fromExceptionName :: Fbthrift.ExceptionName_key -> Glean.RepoHaxl u w Declaration fromExceptionName (Fbthrift.ExceptionName_key qName) = do qName <- fromQualName =<< Glean.keyOf qName return $ Exception qName fromServiceName :: Fbthrift.ServiceName_key -> Glean.RepoHaxl u w Declaration fromServiceName (Fbthrift.ServiceName_key qName) = do qName <- fromQualName =<< Glean.keyOf qName return $ Service qName fromConstant :: Fbthrift.Constant_key -> Glean.RepoHaxl u w Declaration fromConstant (Fbthrift.Constant_key qName) = do qName <- fromQualName =<< Glean.keyOf qName return $ Constant qName fromEnumValue :: Fbthrift.EnumValue_key -> Glean.RepoHaxl u w Declaration fromEnumValue (Fbthrift.EnumValue_key enum name) = do let Fbthrift.NamedType qname kind = enum qualName <- fromQualName =<< Glean.keyOf qname id <- Identifier <$> Glean.keyOf name return $ EnumValue qualName (fromKind kind) id fromFieldDecl :: Fbthrift.FieldDecl_key -> Glean.RepoHaxl u w Declaration fromFieldDecl (Fbthrift.FieldDecl_key qname kind name) = do qualName <- fromQualName =<< Glean.keyOf qname id <- Identifier <$> Glean.keyOf name return $ FieldDecl qualName (fromFieldKind kind) id fromFunctionName :: Fbthrift.FunctionName_key -> Glean.RepoHaxl u w Declaration fromFunctionName (Fbthrift.FunctionName_key service name) = do Fbthrift.ServiceName_key serviceName <- Glean.keyOf service qName <- fromQualName =<< Glean.keyOf serviceName id <- Identifier <$> Glean.keyOf name return $ Function qName id -- -- Process the raw declaration result from Glean to build up a cleaner -- `Declaration` description of the type signature, possibly pulling in -- some related information as we go -- fromAngleDeclaration :: Fbthrift.Declaration -> Glean.RepoHaxl u w (Maybe Declaration) fromAngleDeclaration d = case d of Fbthrift.XRefTarget_include_ file -> Just . IncludeFile <$> (fromFile =<< Glean.keyOf file) Fbthrift.XRefTarget_named namedDecl -> Just <$> (fromNamedDecl =<< Glean.keyOf namedDecl) Fbthrift.XRefTarget_exception_ exceptionName -> Just <$> (fromExceptionName =<< Glean.keyOf exceptionName) Fbthrift.XRefTarget_service_ serviceName -> Just <$> (fromServiceName =<< Glean.keyOf serviceName) Fbthrift.XRefTarget_constant constant -> Just <$> (fromConstant =<< Glean.keyOf constant) Fbthrift.XRefTarget_enumValue enumValue -> Just <$> (fromEnumValue =<< Glean.keyOf enumValue) Fbthrift.XRefTarget_function_ functionName -> Just <$> (fromFunctionName =<< Glean.keyOf functionName) Fbthrift.XRefTarget_field fieldDecl -> Just <$> (fromFieldDecl =<< Glean.keyOf fieldDecl) Fbthrift.XRefTarget_EMPTY -> return Nothing