indigo-0.4: src/Indigo/Compilation/Hooks.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
{-# LANGUAGE NoRebindableSyntax #-}
module Indigo.Compilation.Hooks
( CommentsVerbosity (..)
, CommentSettings (..)
, defaultCommentSettings
, CommentHooks (..)
, settingsToHooks
) where
import Lens.Micro.TH (makeLensesFor)
import Prelude
import GHC.Stack.Types (SrcLoc(..))
import Indigo.Compilation.Sequential
(InstrCollector(..), Instruction(..), SequentialHooks(..), stmtHookL)
import Indigo.Internal.State
import Indigo.Lorentz
import qualified Lorentz.Instr as L
import qualified Michelson.Typed.Convert as M
import qualified Michelson.Typed.Instr as M
---------------------------------------------
--- Comments settings
---------------------------------------------
data CommentSettings = CommentSettings
{ csVerbosity :: CommentsVerbosity
, csPrintFullStackTrace :: Bool
, csPrintFileName :: Bool
} deriving stock (Eq, Show)
defaultCommentSettings :: CommentsVerbosity -> CommentSettings
defaultCommentSettings verb = CommentSettings verb False False
data CommentsVerbosity
= NoComments
| LogTopLevelFrontendStatements
| LogBackendStatements
| LogAuxCode
| LogExpressionsComputations
deriving stock (Show, Eq, Ord, Bounded, Enum)
instance Default CommentSettings where
def = CommentSettings NoComments False False
makeLensesFor [ ("csVerbosity", "verbosityL")] ''CommentSettings
---------------------------------------------
--- Comments actions
---------------------------------------------
data CommentHooks = CommentHooks
{ chFrontendHooks :: SequentialHooks
, chBackendHooks :: GenCodeHooks
}
instance Semigroup CommentHooks where
CommentHooks f b <> CommentHooks f1 b1 = CommentHooks (f <> f1) (b <> b1)
instance Monoid CommentHooks where
mempty = CommentHooks mempty mempty
makeLensesFor [ ("chFrontendHooks", "frontendHooksL")
, ("chBackendHooks", "backendHooksL")]
''CommentHooks
-- | Basically copy-pasted version of 'prettyCallStack' with fixed 'prettySrcLoc'.
prettyFrontendCallStack :: Bool -> Bool -> (String, String) -> CallStack -> ([Text], Text)
prettyFrontendCallStack printFullStk fileName (strt, ends) cs = case getCallStack cs of
(fn, loc) : rest ->
( prettyTop (fn ++ " " ++ strt, loc) :
if printFullStk && not (null rest) then
("Full stacktrace for " <> fromString fn <> ": ") :
zipWith (\i c -> fromString $ replicate (i * indentSpaces) ' ' ++ prettyCallSite c)
[1..] rest
else []
, prettyTop (fn ++ " " ++ ends, loc)
)
[] -> error "empty call stack in prettyFrontendCallStack"
where
prettyTop (fn, loc) = fromString $ prettyCallSite (fn, loc)
indentSpaces = 2
prettyCallSite (f, loc) = f ++ " (called at " ++ prettySrcLoc' loc ++ ")"
prettySrcLoc' :: SrcLoc -> String
prettySrcLoc' SrcLoc {..} = concat $
[ srcLocModule, ":", show srcLocStartLine, ":", show srcLocStartCol]
++ if fileName then [" in ", srcLocFile] else []
-- | Convert from enum-based verbosity description to specific actions.
settingsToHooks :: CommentSettings -> CommentHooks
settingsToHooks (CommentSettings NoComments _ _) = mempty
settingsToHooks c@(CommentSettings LogTopLevelFrontendStatements p f) = settingsToHooks (c & verbosityL .~ NoComments)
& frontendHooksL . stmtHookL .~ \cs blk -> do
let (stCallStk, en) = prettyFrontendCallStack p f ("[fr-stmt starts]", "[fr-stmt ends]") cs
modify $ \iColl -> iColl {instrList = Comment en : reverse blk ++ map Comment (reverse stCallStk) ++ instrList iColl}
settingsToHooks c@(CommentSettings LogBackendStatements _ _) = settingsToHooks (c & verbosityL .~ LogTopLevelFrontendStatements) &
-- There was needed some extra hussle to define lenses for GenCodeHooks so I forwent this idea.
backendHooksL %~ \bh -> bh
{gchStmtHook = \t cd ->
L.comment (M.JustComment $ t <> " [bk-stmt starts]") #
cd #
L.comment (M.JustComment $ t <> " [bk-stmt ends]")
}
settingsToHooks c@(CommentSettings LogAuxCode _ _) = settingsToHooks (c & verbosityL .~ LogBackendStatements) &
backendHooksL %~ \bh -> bh
{ gchAuxiliaryHook = \t cd ->
let commInstr = L.comment (M.JustComment $ t <> " [bk-aux starts]") in
-- Compile the passed code with default optimisation settings
let resLorBlock = compileLorentz cd in
-- Check if after an optimisation we get empty code block
-- then omit comment instruction to make it less noisy
if (M.instrToOps resLorBlock == M.instrToOps M.Nop)
then cd
else commInstr # cd
}
settingsToHooks c@(CommentSettings LogExpressionsComputations _ _) = settingsToHooks (c & verbosityL .~ LogAuxCode) &
backendHooksL %~ \bh -> bh
{ gchExprHook = \expr cd ->
L.comment (M.JustComment $ expr <> " [bk-expr starts]") #
cd #
L.comment (M.JustComment $ expr <> " [bk-expr ends]")
}