@@ -85,7 +85,7 @@ import System.FilePath.Posix
8585import System.Process
8686import Text.Read (readMaybe )
8787import Witch (unsafeInto )
88-
88+ import Data.Either.Extra ( maybeToEither )
8989
9090data StorageItem = StorageItem
9191 { slotType :: SlotType
@@ -285,7 +285,7 @@ makeSrcMaps = (\case (_, Fe, _) -> Nothing; x -> Just (done x))
285285 go c (xs, state, p) = (xs, internalError (" srcmap: y u " ++ show c ++ " in state" ++ show state ++ " ?!?" ), p)
286286
287287-- | Reads all solc output json files found under the provided filepath and returns them merged into a BuildOutput
288- readBuildOutput :: App m => FilePath -> ProjectType -> m (Either String BuildOutput )
288+ readBuildOutput :: App m => FilePath -> ProjectType -> m (Err BuildOutput )
289289readBuildOutput root CombinedJSON = do
290290 let outDir = root </> " out"
291291 jsons <- liftIO $ findJsonFiles outDir
@@ -342,18 +342,19 @@ lineSubrange xs (s1, n1) i =
342342 then Nothing
343343 else Just (s1 - s2, min (s2 + n2 - s1) n1)
344344
345- readSolc :: App m => ProjectType -> FilePath -> FilePath -> m (Either String BuildOutput )
345+ readSolc :: App m => ProjectType -> FilePath -> FilePath -> m (Err BuildOutput )
346346readSolc pt root fp = do
347347 -- NOTE: we cannot and must not use Data.Text.IO.readFile because that takes the locale
348348 -- and may fail with very strange errors when the JSON it's reading
349349 -- contains any UTF-8 character -- which it will with foundry
350350 fileContents <- liftIO $ fmap Data.Text.Encoding. decodeUtf8 $ Data.ByteString. readFile fp
351351 let contractName = T. pack $ takeBaseName fp
352352 case readJSON pt contractName fileContents of
353- Nothing -> pure . Left $ " unable to parse " <> show pt <> " project JSON: " <> fp <> " Contract: " <> show contractName
354- Just (contracts, asts, sources) -> do
353+ Left err -> pure . Left $ " unable to parse " <> show pt <> " project JSON: " <> fp
354+ <> " Contract: " <> show contractName <> " \n Error: " <> err
355+ Right (contracts, asts, sources) -> do
355356 conf <- readConfig
356- when (conf. debug) $ liftIO $ putStrLn $ " Parsed constract : " <> show contractName <> " file: " <> fp
357+ when (conf. debug) $ liftIO $ putStrLn $ " Parsed contract : " <> show contractName <> " file: " <> fp
357358 sourceCache <- liftIO $ makeSourceCache root sources asts
358359 pure (Right (BuildOutput contracts sourceCache))
359360
@@ -406,31 +407,31 @@ functionAbi f = do
406407force :: String -> Maybe a -> a
407408force s = fromMaybe (internalError s)
408409
409- readJSON :: ProjectType -> Text -> Text -> Maybe (Contracts , Asts , Sources )
410+ readJSON :: ProjectType -> Text -> Text -> Err (Contracts , Asts , Sources )
410411readJSON CombinedJSON _ json = readCombinedJSON json
411412readJSON _ contractName json = readFoundryJSON contractName json
412413
413414-- | Reads a foundry json output
414- readFoundryJSON :: Text -> Text -> Maybe (Contracts , Asts , Sources )
415+ readFoundryJSON :: Text -> Text -> Err (Contracts , Asts , Sources )
415416readFoundryJSON contractName json = do
416- runtime <- json ^? key " deployedBytecode"
417- runtimeCode <- (toCode contractName) . strip0x'' <$> runtime ^? key " object" % _String
417+ runtime <- maybeToEither " missing 'deployedBytecode' field" $ json ^? key " deployedBytecode"
418+ runtimeCode <- maybeToEither " missing 'deployedBytecode.object' field" $
419+ (toCode contractName) . strip0x'' <$> runtime ^? key " object" % _String
418420 runtimeSrcMap <- case runtime ^? key " sourceMap" % _String of
419- Nothing -> makeSrcMaps " "
420- smap -> makeSrcMaps =<< smap
421+ Nothing -> Right $ force " Source map creation error " $ makeSrcMaps " " -- sourceMap is optional
422+ Just smap -> maybeToEither " invalid sourceMap format " $ makeSrcMaps smap
421423
422- creation <- json ^? key " bytecode"
423- creationCode <- (toCode contractName) . strip0x'' <$> creation ^? key " object" % _String
424+ creation <- maybeToEither " missing 'bytecode' field" $ json ^? key " bytecode"
425+ creationCode <- maybeToEither " missing 'bytecode.object' field" $
426+ (toCode contractName) . strip0x'' <$> creation ^? key " object" % _String
424427 creationSrcMap <- case creation ^? key " sourceMap" % _String of
425- Nothing -> makeSrcMaps " "
426- smap -> makeSrcMaps =<< smap
427-
428- ast <- json ^? key " ast"
429- path <- ast ^? key " absolutePath" % _String
430-
431- abi <- toList <$> json ^? key " abi" % _Array
428+ Nothing -> Right $ force " Source map creation error" $ makeSrcMaps " " -- sourceMap is optional
429+ Just smap -> maybeToEither " invalid sourceMap format" $ makeSrcMaps smap
432430
433- id' <- unsafeInto <$> json ^? key " id" % _Integer
431+ ast <- maybeToEither " missing 'ast' field. Recompile with `forge clean && forge build --ast`" $ json ^? key " ast"
432+ path <- maybeToEither " missing 'ast.absolutePath' field" $ ast ^? key " absolutePath" % _String
433+ abi <- maybeToEither " missing or invalid 'abi' array" $ toList <$> json ^? key " abi" % _Array
434+ id' <- maybeToEither " missing or invalid 'id' field" $ unsafeInto <$> json ^? key " id" % _Integer
434435
435436 let contract = SolcContract
436437 { runtimeCodehash = keccak' (stripBytecodeMetadata runtimeCode)
@@ -447,10 +448,10 @@ readFoundryJSON contractName json = do
447448 , storageLayout = mkStorageLayout $ json ^? key " storageLayout"
448449 , immutableReferences = mempty -- TODO: foundry doesn't expose this?
449450 }
450- pure ( Contracts $ Map. singleton (path <> " :" <> contractName) contract
451- , Asts $ Map. singleton path ast
452- , Sources $ Map. singleton (SrcFile id' (T. unpack path)) Nothing
453- )
451+ Right ( Contracts $ Map. singleton (path <> " :" <> contractName) contract
452+ , Asts $ Map. singleton path ast
453+ , Sources $ Map. singleton (SrcFile id' (T. unpack path)) Nothing
454+ )
454455
455456-- | Parses the standard json output from solc
456457readStdJSON :: Text -> Maybe (Contracts , Asts , Sources )
@@ -508,18 +509,18 @@ readStdJSON json = do
508509 }, fromMaybe mempty srcContents))
509510
510511-- deprecate me soon
511- readCombinedJSON :: Text -> Maybe (Contracts , Asts , Sources )
512+ readCombinedJSON :: Text -> Err (Contracts , Asts , Sources )
512513readCombinedJSON json = do
513- contracts <- f . KeyMap. toHashMapText <$> (json ^? key " contracts" % _Object)
514- sources <- toList . fmap (preview _String) <$> json ^? key " sourceList" % _Array
514+ contracts <- maybeToEither " missing or invalid 'contracts' field" $ f . KeyMap. toHashMapText <$> (json ^? key " contracts" % _Object)
515+ sources <- maybeToEither " missing or invalid 'sourceList' field" $ toList . fmap (preview _String) <$> json ^? key " sourceList" % _Array
516+ astsPre <- maybeToEither " JSON lacks abstract syntax trees (ast). Recompile with `forge clean && forge build --ast`" $ json ^? key " sources" % _Object
515517 pure ( Contracts contracts
516- , Asts (Map. fromList (HMap. toList asts ))
518+ , Asts (Map. fromList (HMap. toList ( KeyMap. toHashMapText astsPre) ))
517519 , Sources $ Map. fromList $
518520 (\ (path, id') -> (SrcFile id' (T. unpack path), Nothing )) <$>
519521 zip (catMaybes sources) [0 .. ]
520522 )
521523 where
522- asts = KeyMap. toHashMapText $ fromMaybe (error " JSON lacks abstract syntax trees." ) (json ^? key " sources" % _Object)
523524 f x = Map. fromList . HMap. toList $ HMap. mapWithKey g x
524525 g s x =
525526 let
0 commit comments