{-# OPTIONS -Wall #-} module Language.Haskell.HBB.SmartInline ( smartinline, smartinlineM, showSmartInlineResult, showSmartInlineResultAsByteString, NonFirstLinesIndenting(..), BufLoc(..), BufSpan(..), RealSrcSpan(..), TTree(..), LineBuf, encodeTTreeToJSON, decodeTTreeFromJSON ) where import Language.Haskell.HBB.Internal.InternalTTreeCreation import Language.Haskell.HBB.Internal.InterfaceTypes import Language.Haskell.HBB.Internal.InternalTTree import Language.Haskell.HBB.Internal.GHCHighlevel import Language.Haskell.HBB.Internal.TTreeJSON (encodeTTreeToJSON,decodeTTreeFromJSON) import Language.Haskell.HBB.Internal.SrcSpan import Language.Haskell.HBB.Internal.TTree import Language.Haskell.HBB.Internal.GHC import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.ByteString.Char8 as B import Control.Monad.Reader import GHC.Paths (libdir) import SrcLoc import GHC (GhcMonad) -- | This function implements the mode 'smart-inline'. -- -- Smart-inline takes a location or a span within a file which should be a -- function binding (as of 2014-09-16 excluding any parameter) and tries to -- produce an inlined version of the function. The inlined version of the -- function is described as transformation to the original source code. The -- transformation is a JSON string which is formatted according to the -- descriptions in the documentation. -- -- > main :: IO () -- > main = do -- > res <- smartinline ["-isrc"] IgnoreIndOfTargetEnv "example/Example.hs" (BufLoc 14 13) -- > LazyByteString.putStr $ encodeTTreeToJSON res -- > putStrLn "" -- -- If a second location isn't passed this function will use GHCs lexer to find -- out where the end of the variable or function name is. Consequently to -- smart-inline a function and to simultaneously apply it to its arguments -- (which is not supported as of 2014-09-16) the second location must be -- passed. -- -- The first two command line parameters are: -- -- - The GHC options as string list (as they should appear on the command line) -- -- - Some options to the mode 'inline' that change the functions behaviour -- smartinline :: [String] -> NonFirstLinesIndenting -> FilePath -> BufLoc -> Maybe BufLoc -> IO (RealSrcSpan,TTree LineBuf (RealSrcSpan,Int) BufSpan) smartinline ghcOptions ai fn sl mbEndLoc = runGhcWithCmdLineFlags ghcOptions (Just libdir) $ smartinlineM ai fn sl mbEndLoc -- | Converts the result of smartinline and smartinlineM to JSON. -- -- The resulting string has exactly the format that should be understood by -- text editors that are using mode smart-inline. showSmartInlineResult :: (RealSrcSpan,TTree LineBuf (RealSrcSpan,Int) BufSpan) -> String showSmartInlineResult spanAndTree = B.unpack $ B.concat $ BL.toChunks $ showSmartInlineResultAsByteString spanAndTree -- | This function is a performance optimization to showSmartInlineResult as -- the resulting bytestring isn't converted back to string. showSmartInlineResultAsByteString :: (RealSrcSpan,TTree LineBuf (RealSrcSpan,Int) BufSpan) -> BL.ByteString showSmartInlineResultAsByteString spanAndTree = BL.snoc (encodeTTreeToJSON spanAndTree) '\n' -- | This function is similar to smartinline except that it runs in a GhcMonad -- instance. smartinlineM :: GhcMonad m => NonFirstLinesIndenting -> FilePath -> BufLoc -> Maybe BufLoc -> m (RealSrcSpan,TTree LineBuf (RealSrcSpan,Int) BufSpan) smartinlineM ai filename startLoc mbEndLoc = do sti@(SearchedTokenInfo { result = (binding,_) }) <- searchFunctionBindingM filename startLoc mbEndLoc let produceClientTTree :: FunBindInfo -> ClientTTree produceClientTTree bi = let richTTree = runReader (toTTree $ binding) ProduceLambda inlCol = ((srcLocCol $ realSrcSpanStart $ occSpan bi)) insSpan = pointBufSpan 1 (case ai of AdaptIndToTargetEnv -> inlCol IgnoreIndOfTargetEnv -> 1) in snd $ applyIndentation (IncInline insSpan,richTTree) return (occSpan sti,produceClientTTree sti)