{-# Language TemplateHaskell #-}
{-# Language OverloadedStrings #-}

module EVM.Dapp where

import EVM (Trace, traceCodehash, traceOpIx, Env)
import EVM.ABI (Event, AbiType)
import EVM.Debug (srcMapCodePos)
import EVM.Solidity (SolcContract, CodeType (..), SourceCache (..), SrcMap, Method)
import EVM.Solidity (contractName, methodInputs)
import EVM.Solidity (runtimeCodehash, creationCodehash, abiMap)
import EVM.Solidity (runtimeSrcmap, sourceAsts, creationSrcmap, eventMap)
import EVM.Solidity (methodSignature, astIdMap, astSrcMap)
import EVM.Types (W256, abiKeccak)

import Data.Aeson (Value)
import Data.Bifunctor (first)
import Data.Text (Text, isPrefixOf, pack, unpack)
import Data.Text.Encoding (encodeUtf8)
import Data.Map (Map, toList)
import Data.Maybe (isJust, fromJust)
import Data.Word (Word32)

import Control.Arrow ((>>>))
import Control.Lens

import qualified Data.Map        as Map
import qualified Data.Sequence   as Seq
import qualified Text.Regex.TDFA as Regex

data DappInfo = DappInfo
  { DappInfo -> FilePath
_dappRoot       :: FilePath
  , DappInfo -> Map Text SolcContract
_dappSolcByName :: Map Text SolcContract
  , DappInfo -> Map W256 (CodeType, SolcContract)
_dappSolcByHash :: Map W256 (CodeType, SolcContract)
  , DappInfo -> SourceCache
_dappSources    :: SourceCache
  , DappInfo -> [(Text, [(Test, [AbiType])])]
_dappUnitTests  :: [(Text, [(Test, [AbiType])])]
  , DappInfo -> Map Word32 Method
_dappAbiMap     :: Map Word32 Method
  , DappInfo -> Map W256 Event
_dappEventMap   :: Map W256 Event
  , DappInfo -> Map Int Value
_dappAstIdMap   :: Map Int Value
  , DappInfo -> SrcMap -> Maybe Value
_dappAstSrcMap  :: SrcMap -> Maybe Value
  }

data DappContext = DappContext
  { DappContext -> DappInfo
_contextInfo :: DappInfo
  , DappContext -> Env
_contextEnv  :: Env
  }

data Test = ConcreteTest Text | SymbolicTest Text

makeLenses ''DappInfo
makeLenses ''DappContext

instance Show Test where
  show :: Test -> FilePath
show t :: Test
t = Text -> FilePath
unpack (Text -> FilePath) -> Text -> FilePath
forall a b. (a -> b) -> a -> b
$ Test -> Text
extractSig Test
t

dappInfo
  :: FilePath -> Map Text SolcContract -> SourceCache -> DappInfo
dappInfo :: FilePath -> Map Text SolcContract -> SourceCache -> DappInfo
dappInfo root :: FilePath
root solcByName :: Map Text SolcContract
solcByName sources :: SourceCache
sources =
  let
    solcs :: [SolcContract]
solcs = Map Text SolcContract -> [SolcContract]
forall k a. Map k a -> [a]
Map.elems Map Text SolcContract
solcByName
    astIds :: Map Int Value
astIds = [Value] -> Map Int Value
forall (f :: * -> *). Foldable f => f Value -> Map Int Value
astIdMap ([Value] -> Map Int Value) -> [Value] -> Map Int Value
forall a b. (a -> b) -> a -> b
$ (Text, Value) -> Value
forall a b. (a, b) -> b
snd ((Text, Value) -> Value) -> [(Text, Value)] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map Text Value -> [(Text, Value)]
forall k a. Map k a -> [(k, a)]
toList (Getting (Map Text Value) SourceCache (Map Text Value)
-> SourceCache -> Map Text Value
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Text Value) SourceCache (Map Text Value)
Lens' SourceCache (Map Text Value)
sourceAsts SourceCache
sources)

  in DappInfo :: FilePath
-> Map Text SolcContract
-> Map W256 (CodeType, SolcContract)
-> SourceCache
-> [(Text, [(Test, [AbiType])])]
-> Map Word32 Method
-> Map W256 Event
-> Map Int Value
-> (SrcMap -> Maybe Value)
-> DappInfo
DappInfo
    { _dappRoot :: FilePath
_dappRoot = FilePath
root
    , _dappUnitTests :: [(Text, [(Test, [AbiType])])]
_dappUnitTests = [SolcContract] -> [(Text, [(Test, [AbiType])])]
findAllUnitTests [SolcContract]
solcs
    , _dappSources :: SourceCache
_dappSources = SourceCache
sources
    , _dappSolcByName :: Map Text SolcContract
_dappSolcByName = Map Text SolcContract
solcByName
    , _dappSolcByHash :: Map W256 (CodeType, SolcContract)
_dappSolcByHash =
        let
          f :: Getting W256 SolcContract W256
-> CodeType -> Map W256 (CodeType, SolcContract)
f g :: Getting W256 SolcContract W256
g k :: CodeType
k = [(W256, (CodeType, SolcContract))]
-> Map W256 (CodeType, SolcContract)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Getting W256 SolcContract W256 -> SolcContract -> W256
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting W256 SolcContract W256
g SolcContract
x, (CodeType
k, SolcContract
x)) | SolcContract
x <- [SolcContract]
solcs]
        in
          Map W256 (CodeType, SolcContract)
-> Map W256 (CodeType, SolcContract)
-> Map W256 (CodeType, SolcContract)
forall a. Monoid a => a -> a -> a
mappend
           (Getting W256 SolcContract W256
-> CodeType -> Map W256 (CodeType, SolcContract)
f Getting W256 SolcContract W256
Lens' SolcContract W256
runtimeCodehash  CodeType
Runtime)
           (Getting W256 SolcContract W256
-> CodeType -> Map W256 (CodeType, SolcContract)
f Getting W256 SolcContract W256
Lens' SolcContract W256
creationCodehash CodeType
Creation)

      -- Sum up the ABI maps from all the contracts.
    , _dappAbiMap :: Map Word32 Method
_dappAbiMap   = [Map Word32 Method] -> Map Word32 Method
forall a. Monoid a => [a] -> a
mconcat ((SolcContract -> Map Word32 Method)
-> [SolcContract] -> [Map Word32 Method]
forall a b. (a -> b) -> [a] -> [b]
map (Getting (Map Word32 Method) SolcContract (Map Word32 Method)
-> SolcContract -> Map Word32 Method
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Word32 Method) SolcContract (Map Word32 Method)
Lens' SolcContract (Map Word32 Method)
abiMap) [SolcContract]
solcs)
    , _dappEventMap :: Map W256 Event
_dappEventMap = [Map W256 Event] -> Map W256 Event
forall a. Monoid a => [a] -> a
mconcat ((SolcContract -> Map W256 Event)
-> [SolcContract] -> [Map W256 Event]
forall a b. (a -> b) -> [a] -> [b]
map (Getting (Map W256 Event) SolcContract (Map W256 Event)
-> SolcContract -> Map W256 Event
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map W256 Event) SolcContract (Map W256 Event)
Lens' SolcContract (Map W256 Event)
eventMap) [SolcContract]
solcs)

    , _dappAstIdMap :: Map Int Value
_dappAstIdMap  = Map Int Value
astIds
    , _dappAstSrcMap :: SrcMap -> Maybe Value
_dappAstSrcMap = Map Int Value -> SrcMap -> Maybe Value
astSrcMap Map Int Value
astIds
    }

emptyDapp :: DappInfo
emptyDapp :: DappInfo
emptyDapp = FilePath -> Map Text SolcContract -> SourceCache -> DappInfo
dappInfo "" Map Text SolcContract
forall a. Monoid a => a
mempty (Map Int (Text, ByteString)
-> Map Int (Vector ByteString) -> Map Text Value -> SourceCache
SourceCache Map Int (Text, ByteString)
forall a. Monoid a => a
mempty Map Int (Vector ByteString)
forall a. Monoid a => a
mempty Map Text Value
forall a. Monoid a => a
mempty)

-- Dapp unit tests are detected by searching within abi methods
-- that begin with "test" or "prove", that are in a contract with
-- the "IS_TEST()" abi marker, for a given regular expression.
--
-- The regex is matched on the full test method name, including path
-- and contract, i.e. "path/to/file.sol:TestContract.test_name()".
--
-- Tests beginning with "test" are interpreted as concrete tests, whereas
-- tests beginning with "prove" are interpreted as symbolic tests.

unitTestMarkerAbi :: Word32
unitTestMarkerAbi :: Word32
unitTestMarkerAbi = ByteString -> Word32
abiKeccak (Text -> ByteString
encodeUtf8 "IS_TEST()")

findAllUnitTests :: [SolcContract] -> [(Text, [(Test, [AbiType])])]
findAllUnitTests :: [SolcContract] -> [(Text, [(Test, [AbiType])])]
findAllUnitTests = Text -> [SolcContract] -> [(Text, [(Test, [AbiType])])]
findUnitTests ".*:.*\\.(test|prove).*"

mkTest :: Text -> Maybe Test
mkTest :: Text -> Maybe Test
mkTest sig :: Text
sig
  | "test" Text -> Text -> Bool
`isPrefixOf` Text
sig = Test -> Maybe Test
forall a. a -> Maybe a
Just (Text -> Test
ConcreteTest Text
sig)
  | "prove" Text -> Text -> Bool
`isPrefixOf` Text
sig = Test -> Maybe Test
forall a. a -> Maybe a
Just (Text -> Test
SymbolicTest Text
sig)
  | Bool
otherwise = Maybe Test
forall a. Maybe a
Nothing

regexMatches :: Text -> Text -> Bool
regexMatches :: Text -> Text -> Bool
regexMatches regexSource :: Text
regexSource =
  let
    compOpts :: CompOption
compOpts =
      CompOption
forall regex compOpt execOpt.
RegexOptions regex compOpt execOpt =>
compOpt
Regex.defaultCompOpt { lastStarGreedy :: Bool
Regex.lastStarGreedy = Bool
True }
    execOpts :: ExecOption
execOpts =
      ExecOption
forall regex compOpt execOpt.
RegexOptions regex compOpt execOpt =>
execOpt
Regex.defaultExecOpt { captureGroups :: Bool
Regex.captureGroups = Bool
False }
    regex :: Regex
regex = CompOption -> ExecOption -> FilePath -> Regex
forall regex compOpt execOpt source.
RegexMaker regex compOpt execOpt source =>
compOpt -> execOpt -> source -> regex
Regex.makeRegexOpts CompOption
compOpts ExecOption
execOpts (Text -> FilePath
unpack Text
regexSource)
  in
    Regex -> Seq Char -> Bool
forall regex source.
RegexLike regex source =>
regex -> source -> Bool
Regex.matchTest Regex
regex (Seq Char -> Bool) -> (Text -> Seq Char) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Seq Char
forall a. [a] -> Seq a
Seq.fromList (FilePath -> Seq Char) -> (Text -> FilePath) -> Text -> Seq Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
unpack

findUnitTests :: Text -> ([SolcContract] -> [(Text, [(Test, [AbiType])])])
findUnitTests :: Text -> [SolcContract] -> [(Text, [(Test, [AbiType])])]
findUnitTests match :: Text
match =
  (SolcContract -> [(Text, [(Test, [AbiType])])])
-> [SolcContract] -> [(Text, [(Test, [AbiType])])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((SolcContract -> [(Text, [(Test, [AbiType])])])
 -> [SolcContract] -> [(Text, [(Test, [AbiType])])])
-> (SolcContract -> [(Text, [(Test, [AbiType])])])
-> [SolcContract]
-> [(Text, [(Test, [AbiType])])]
forall a b. (a -> b) -> a -> b
$ \c :: SolcContract
c ->
    case Getting (First Method) SolcContract Method
-> SolcContract -> Maybe Method
forall s (m :: * -> *) a.
MonadReader s m =>
Getting (First a) s a -> m (Maybe a)
preview ((Map Word32 Method -> Const (First Method) (Map Word32 Method))
-> SolcContract -> Const (First Method) SolcContract
Lens' SolcContract (Map Word32 Method)
abiMap ((Map Word32 Method -> Const (First Method) (Map Word32 Method))
 -> SolcContract -> Const (First Method) SolcContract)
-> ((Method -> Const (First Method) Method)
    -> Map Word32 Method -> Const (First Method) (Map Word32 Method))
-> Getting (First Method) SolcContract Method
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (Map Word32 Method)
-> Traversal' (Map Word32 Method) (IxValue (Map Word32 Method))
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Word32
Index (Map Word32 Method)
unitTestMarkerAbi) SolcContract
c of
      Nothing -> []
      Just _  ->
        let testNames :: [(Test, [AbiType])]
testNames = (Text -> Bool) -> SolcContract -> [(Test, [AbiType])]
unitTestMethodsFiltered (Text -> Text -> Bool
regexMatches Text
match) SolcContract
c
        in [(Getting Text SolcContract Text -> SolcContract -> Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Text SolcContract Text
Lens' SolcContract Text
contractName SolcContract
c, [(Test, [AbiType])]
testNames) | Bool -> Bool
not ([(Test, [AbiType])] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Test, [AbiType])]
testNames)]

unitTestMethodsFiltered :: (Text -> Bool) -> (SolcContract -> [(Test, [AbiType])])
unitTestMethodsFiltered :: (Text -> Bool) -> SolcContract -> [(Test, [AbiType])]
unitTestMethodsFiltered matcher :: Text -> Bool
matcher c :: SolcContract
c =
  let
    testName :: (Test, [AbiType]) -> Text
testName method :: (Test, [AbiType])
method = (Getting Text SolcContract Text -> SolcContract -> Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Text SolcContract Text
Lens' SolcContract Text
contractName SolcContract
c) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Test -> Text
extractSig ((Test, [AbiType]) -> Test
forall a b. (a, b) -> a
fst (Test, [AbiType])
method))
  in
    ((Test, [AbiType]) -> Bool)
-> [(Test, [AbiType])] -> [(Test, [AbiType])]
forall a. (a -> Bool) -> [a] -> [a]
filter (Text -> Bool
matcher (Text -> Bool)
-> ((Test, [AbiType]) -> Text) -> (Test, [AbiType]) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Test, [AbiType]) -> Text
testName) (SolcContract -> [(Test, [AbiType])]
unitTestMethods SolcContract
c)

unitTestMethods :: SolcContract -> [(Test, [AbiType])]
unitTestMethods :: SolcContract -> [(Test, [AbiType])]
unitTestMethods =
  Getting (Map Word32 Method) SolcContract (Map Word32 Method)
-> SolcContract -> Map Word32 Method
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Word32 Method) SolcContract (Map Word32 Method)
Lens' SolcContract (Map Word32 Method)
abiMap
  (SolcContract -> Map Word32 Method)
-> (Map Word32 Method -> [(Test, [AbiType])])
-> SolcContract
-> [(Test, [AbiType])]
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Map Word32 Method -> [Method]
forall k a. Map k a -> [a]
Map.elems
  (Map Word32 Method -> [Method])
-> ([Method] -> [(Test, [AbiType])])
-> Map Word32 Method
-> [(Test, [AbiType])]
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> (Method -> (Maybe Test, [AbiType]))
-> [Method] -> [(Maybe Test, [AbiType])]
forall a b. (a -> b) -> [a] -> [b]
map (\f :: Method
f -> (Text -> Maybe Test
mkTest (Text -> Maybe Test) -> Text -> Maybe Test
forall a b. (a -> b) -> a -> b
$ Getting Text Method Text -> Method -> Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Text Method Text
Lens' Method Text
methodSignature Method
f, (Text, AbiType) -> AbiType
forall a b. (a, b) -> b
snd ((Text, AbiType) -> AbiType) -> [(Text, AbiType)] -> [AbiType]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Getting [(Text, AbiType)] Method [(Text, AbiType)]
-> Method -> [(Text, AbiType)]
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting [(Text, AbiType)] Method [(Text, AbiType)]
Lens' Method [(Text, AbiType)]
methodInputs Method
f))
  ([Method] -> [(Maybe Test, [AbiType])])
-> ([(Maybe Test, [AbiType])] -> [(Test, [AbiType])])
-> [Method]
-> [(Test, [AbiType])]
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> ((Maybe Test, [AbiType]) -> Bool)
-> [(Maybe Test, [AbiType])] -> [(Maybe Test, [AbiType])]
forall a. (a -> Bool) -> [a] -> [a]
filter (Maybe Test -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Test -> Bool)
-> ((Maybe Test, [AbiType]) -> Maybe Test)
-> (Maybe Test, [AbiType])
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Test, [AbiType]) -> Maybe Test
forall a b. (a, b) -> a
fst)
  ([(Maybe Test, [AbiType])] -> [(Maybe Test, [AbiType])])
-> ([(Maybe Test, [AbiType])] -> [(Test, [AbiType])])
-> [(Maybe Test, [AbiType])]
-> [(Test, [AbiType])]
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> ((Maybe Test, [AbiType]) -> (Test, [AbiType]))
-> [(Maybe Test, [AbiType])] -> [(Test, [AbiType])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Maybe Test -> Test)
-> (Maybe Test, [AbiType]) -> (Test, [AbiType])
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Maybe Test -> Test
forall a. HasCallStack => Maybe a -> a
fromJust)

extractSig :: Test -> Text
extractSig :: Test -> Text
extractSig (ConcreteTest sig :: Text
sig) = Text
sig
extractSig (SymbolicTest sig :: Text
sig) = Text
sig

traceSrcMap :: DappInfo -> Trace -> Maybe SrcMap
traceSrcMap :: DappInfo -> Trace -> Maybe SrcMap
traceSrcMap dapp :: DappInfo
dapp trace :: Trace
trace =
  let
    h :: W256
h = Getting W256 Trace W256 -> Trace -> W256
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting W256 Trace W256
Lens' Trace W256
traceCodehash Trace
trace
    i :: Maybe Int
i = Getting (Maybe Int) Trace (Maybe Int) -> Trace -> Maybe Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Maybe Int) Trace (Maybe Int)
Lens' Trace (Maybe Int)
traceOpIx Trace
trace
  in case Getting
  (First (CodeType, SolcContract)) DappInfo (CodeType, SolcContract)
-> DappInfo -> Maybe (CodeType, SolcContract)
forall s (m :: * -> *) a.
MonadReader s m =>
Getting (First a) s a -> m (Maybe a)
preview ((Map W256 (CodeType, SolcContract)
 -> Const
      (First (CodeType, SolcContract))
      (Map W256 (CodeType, SolcContract)))
-> DappInfo -> Const (First (CodeType, SolcContract)) DappInfo
Lens' DappInfo (Map W256 (CodeType, SolcContract))
dappSolcByHash ((Map W256 (CodeType, SolcContract)
  -> Const
       (First (CodeType, SolcContract))
       (Map W256 (CodeType, SolcContract)))
 -> DappInfo -> Const (First (CodeType, SolcContract)) DappInfo)
-> (((CodeType, SolcContract)
     -> Const (First (CodeType, SolcContract)) (CodeType, SolcContract))
    -> Map W256 (CodeType, SolcContract)
    -> Const
         (First (CodeType, SolcContract))
         (Map W256 (CodeType, SolcContract)))
-> Getting
     (First (CodeType, SolcContract)) DappInfo (CodeType, SolcContract)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (Map W256 (CodeType, SolcContract))
-> Traversal'
     (Map W256 (CodeType, SolcContract))
     (IxValue (Map W256 (CodeType, SolcContract)))
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Index (Map W256 (CodeType, SolcContract))
W256
h) DappInfo
dapp of
    Nothing ->
      Maybe SrcMap
forall a. Maybe a
Nothing
    Just (Creation, solc :: SolcContract
solc) ->
      Maybe Int
i Maybe Int -> (Int -> Maybe SrcMap) -> Maybe SrcMap
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \i' :: Int
i' -> Getting (First SrcMap) SolcContract SrcMap
-> SolcContract -> Maybe SrcMap
forall s (m :: * -> *) a.
MonadReader s m =>
Getting (First a) s a -> m (Maybe a)
preview ((Seq SrcMap -> Const (First SrcMap) (Seq SrcMap))
-> SolcContract -> Const (First SrcMap) SolcContract
Lens' SolcContract (Seq SrcMap)
creationSrcmap ((Seq SrcMap -> Const (First SrcMap) (Seq SrcMap))
 -> SolcContract -> Const (First SrcMap) SolcContract)
-> ((SrcMap -> Const (First SrcMap) SrcMap)
    -> Seq SrcMap -> Const (First SrcMap) (Seq SrcMap))
-> Getting (First SrcMap) SolcContract SrcMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (Seq SrcMap)
-> Traversal' (Seq SrcMap) (IxValue (Seq SrcMap))
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Int
Index (Seq SrcMap)
i') SolcContract
solc
    Just (Runtime, solc :: SolcContract
solc) ->
      Maybe Int
i Maybe Int -> (Int -> Maybe SrcMap) -> Maybe SrcMap
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \i' :: Int
i' -> Getting (First SrcMap) SolcContract SrcMap
-> SolcContract -> Maybe SrcMap
forall s (m :: * -> *) a.
MonadReader s m =>
Getting (First a) s a -> m (Maybe a)
preview ((Seq SrcMap -> Const (First SrcMap) (Seq SrcMap))
-> SolcContract -> Const (First SrcMap) SolcContract
Lens' SolcContract (Seq SrcMap)
runtimeSrcmap ((Seq SrcMap -> Const (First SrcMap) (Seq SrcMap))
 -> SolcContract -> Const (First SrcMap) SolcContract)
-> ((SrcMap -> Const (First SrcMap) SrcMap)
    -> Seq SrcMap -> Const (First SrcMap) (Seq SrcMap))
-> Getting (First SrcMap) SolcContract SrcMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (Seq SrcMap)
-> Traversal' (Seq SrcMap) (IxValue (Seq SrcMap))
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Int
Index (Seq SrcMap)
i') SolcContract
solc

showTraceLocation :: DappInfo -> Trace -> Either Text Text
showTraceLocation :: DappInfo -> Trace -> Either Text Text
showTraceLocation dapp :: DappInfo
dapp trace :: Trace
trace =
  case DappInfo -> Trace -> Maybe SrcMap
traceSrcMap DappInfo
dapp Trace
trace of
    Nothing -> Text -> Either Text Text
forall a b. a -> Either a b
Left "<no source map>"
    Just sm :: SrcMap
sm ->
      case SourceCache -> SrcMap -> Maybe (Text, Int)
srcMapCodePos (Getting SourceCache DappInfo SourceCache -> DappInfo -> SourceCache
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting SourceCache DappInfo SourceCache
Lens' DappInfo SourceCache
dappSources DappInfo
dapp) SrcMap
sm of
        Nothing -> Text -> Either Text Text
forall a b. a -> Either a b
Left "<source not found>"
        Just (fileName :: Text
fileName, lineIx :: Int
lineIx) ->
          Text -> Either Text Text
forall a b. b -> Either a b
Right (Text
fileName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ":" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
pack (Int -> FilePath
forall a. Show a => a -> FilePath
show Int
lineIx))