phino 0.0.0.51 → 0.0.0.52
raw patch · 9 files changed
+224/−132 lines, 9 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Hide: hide :: [Rewritten] -> [Expression] -> [Rewritten]
- Hide: hide' :: Program -> [Expression] -> Program
+ Filter: exclude :: [Rewritten] -> [Expression] -> [Rewritten]
+ Filter: include :: [Rewritten] -> [Expression] -> [Rewritten]
Files
- phino.cabal +3/−3
- src/CLI.hs +49/−22
- src/Dataize.hs +4/−4
- src/Filter.hs +65/−0
- src/Hide.hs +0/−42
- src/Merge.hs +1/−1
- test/CLISpec.hs +42/−15
- test/FilterSpec.hs +60/−0
- test/HideSpec.hs +0/−45
phino.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: phino-version: 0.0.0.51+version: 0.0.0.52 license: MIT synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>@@ -41,8 +41,8 @@ Dataize Deps Encoding+ Filter Functions- Hide LaTeX Lining Logger@@ -117,8 +117,8 @@ ConditionSpec CSTSpec DataizeSpec+ FilterSpec FunctionsSpec- HideSpec MatcherSpec MergeSpec MiscSpec
src/CLI.hs view
@@ -14,7 +14,7 @@ import Condition (parseConditionThrows) import Control.Exception (Exception (displayException), SomeException, handle, throw, throwIO) import Control.Exception.Base-import Control.Monad (when, (>=>))+import Control.Monad (unless, when, (>=>)) import Data.Char (toLower, toUpper) import Data.Foldable (for_) import qualified Data.Foldable@@ -25,9 +25,9 @@ import Dataize (DataizeContext (DataizeContext), dataize) import Deps (SaveStepFunc, saveStep) import Encoding (Encoding (ASCII, UNICODE))+import qualified Filter as F import Functions (buildTerm) import qualified Functions-import qualified Hide as H import LaTeX (LatexContext (LatexContext), explainRules, programToLaTeX, rewrittensToLatex) import Lining (LineFormat (MULTILINE, SINGLELINE)) import Logger@@ -97,9 +97,11 @@ nonumber :: Bool, sequence :: Bool, depthSensitive :: Bool,+ quiet :: Bool, maxDepth :: Integer, maxCycles :: Integer, hide :: [String],+ show' :: [String], expression :: Maybe String, label :: Maybe String, stepsDir :: Maybe FilePath,@@ -136,6 +138,7 @@ maxCycles :: Integer, rules :: [FilePath], hide :: [String],+ show' :: [String], expression :: Maybe String, label :: Maybe String, targetFile :: Maybe FilePath,@@ -251,6 +254,18 @@ optHide :: Parser [String] optHide = many (strOption (long "hide" <> metavar "FQN" <> help "Location of object to exclude from result and intermediate programs after rewriting. Must be a valid dispatch expression; e.g. Q.org.eolang")) +optShow :: Parser [String]+optShow =+ many+ ( strOption+ ( long "show"+ <> metavar "FQN"+ <> help+ "Location of object to include to result and intermediate programs after rewriting. \+ \Must be a valid dispatch expression; e.g. Q.org.eolang. Unlike --hide, can be used only once"+ )+ )+ optNormalize :: Parser Bool optNormalize = switch (long "normalize" <> help "Use built-in normalization rules") @@ -311,9 +326,11 @@ <*> optNonumber <*> optSequence <*> optDepthSensitive+ <*> switch (long "quiet" <> help "Don't print the result of dataization") <*> optMaxDepth <*> optMaxCycles <*> optHide+ <*> optShow <*> optExpression <*> optLabel <*> optStepsDir@@ -351,6 +368,7 @@ <*> optMaxCycles <*> optRule <*> optHide+ <*> optShow <*> optExpression <*> optLabel <*> optTarget@@ -430,7 +448,8 @@ case cmd of CmdRewrite OptsRewrite {..} -> do validateOpts- exclude <- expressionsToHide hide+ excluded <- expressionsToFilter "hide" hide+ included <- expressionsToFilter "show" show' logDebug (printf "Amount of rewriting cycles across all the rules: %d, per rule: %d" maxCycles maxDepth) input <- readInput inputFile rules' <- getRules normalize shuffle rules@@ -438,9 +457,10 @@ let listing = if null rules' then const input else (\prog -> P.printProgram' prog (sugarType, UNICODE, flat)) xmirCtx = XmirContext omitListing omitComments listing printCtx = PrintProgCtx sugarType flat xmirCtx nonumber expression label outputFormat- canonize' = if canonize then C.canonize else id- hide' = (`H.hide` exclude)- rewrittens <- rewrite' program rules' (context printCtx) <&> hide' . canonize'+ _canonize = if canonize then C.canonize else id+ _hide = (`F.exclude` excluded)+ _show = (`F.include` included)+ rewrittens <- rewrite' program rules' (context printCtx) <&> _canonize . _hide . _show let rewrittens' = if sequence then rewrittens else [last rewrittens] logDebug (printf "Printing rewritten 𝜑-program as %s" (show outputFormat)) progs <- printRewrittens printCtx rewrittens'@@ -454,6 +474,7 @@ when (inPlace && isJust targetFile) (invalidCLIArguments "The options --in-place and --target cannot be used together")+ when (length show' > 1) (invalidCLIArguments "The option --show can be used only once") validateLatexOptions outputFormat nonumber expression label validateMust' must validateXmirOptions outputFormat omitListing omitComments@@ -481,18 +502,22 @@ (saveStepFunc stepsDir ctx) CmdDataize OptsDataize {..} -> do validateOpts- exclude <- expressionsToHide hide+ excluded <- expressionsToFilter "hide" hide+ included <- expressionsToFilter "show" show' input <- readInput inputFile prog <- parseProgram input inputFormat let printCtx = PrintProgCtx sugarType flat defaultXmirContext nonumber expression label outputFormat+ _hide = (`F.exclude` excluded)+ _show = (`F.include` included) (maybeBytes, seq) <- dataize prog (context prog printCtx)- when sequence (putStrLn =<< printRewrittens printCtx (H.hide seq exclude))- putStrLn (maybe (P.printExpression ExTermination) P.printBytes maybeBytes)+ when sequence (printRewrittens printCtx (_hide (_show seq)) >>= putStrLn)+ unless quiet (putStrLn (maybe (P.printExpression ExTermination) P.printBytes maybeBytes)) where validateOpts :: IO () validateOpts = do validateLatexOptions outputFormat nonumber expression label validateXmirOptions outputFormat omitListing omitComments+ when (length show' > 1) (invalidCLIArguments "The option --show can be used only once") context :: Program -> PrintProgramContext -> DataizeContext context program ctx = DataizeContext@@ -556,20 +581,22 @@ | otherwise = show outputFormat -- Get list of expressions which must be hidden in printed programs-expressionsToHide :: [String] -> IO [Expression]-expressionsToHide = traverse (parseExpressionThrows >=> canBeHidden)+expressionsToFilter :: String -> [String] -> IO [Expression]+expressionsToFilter opt = traverse (parseExpressionThrows >=> asFilter) where- canBeHidden :: Expression -> IO Expression- canBeHidden expr = canBeHidden' expr expr- canBeHidden' :: Expression -> Expression -> IO Expression- canBeHidden' exp@(ExDispatch ExGlobal _) _ = pure exp- canBeHidden' exp@(ExDispatch expr attr) full = canBeHidden' expr full >> pure exp- canBeHidden' _ full =- invalidCLIArguments- ( printf- "Only dispatch expression started with Φ (or Q) can be used in --hide, but given: %s"- (P.printExpression' full P.logPrintConfig)- )+ asFilter :: Expression -> IO Expression+ asFilter expr = asFilter' expr+ where+ asFilter' :: Expression -> IO Expression+ asFilter' exp@(ExDispatch ExGlobal _) = pure exp+ asFilter' exp@(ExDispatch expr attr) = asFilter' expr >> pure exp+ asFilter' _ =+ invalidCLIArguments+ ( printf+ "Only dispatch expression started with Φ (or Q) can be used in --%s, but given: %s"+ opt+ (P.printExpression' expr P.logPrintConfig)+ ) -- Validate LaTeX options validateLatexOptions :: IOFormat -> Bool -> Maybe String -> Maybe String -> IO ()
src/Dataize.hs view
@@ -72,7 +72,7 @@ case lambda of Just (BiLambda func) -> do obj <- atom func (ExFormation bds') ctx- pure (Just (obj, "M(lambda)"))+ pure (Just (obj, "Mlambda")) _ -> pure Nothing -- Resolve dispatch from global object (Q.tau) for PHI Morphing rule.@@ -88,7 +88,7 @@ boundExpr :: [Binding] -> Maybe (Expression, String) boundExpr [] = Nothing boundExpr (bd : bds) = case bd of- BiTau (AtLabel attr) expr' -> if attr == tau then Just (expr', "M(phi)") else boundExpr bds+ BiTau (AtLabel attr) expr' -> if attr == tau then Just (expr', "Mphi") else boundExpr bds _ -> boundExpr bds -- Resolve tail PHI and LAMBDA Morphing rules.@@ -131,12 +131,12 @@ -- PHI: M(Q.tau * t) -> M(e * t) if Q -> [B1, tau -> e, B2], t is tail started with dispatch -- M(e) -> ⊥ otherwise morph :: Morphed -> DataizeContext -> IO Morphed-morph (ExTermination, seq) _ = pure (ExTermination, leadsTo seq "M(prim)" ExTermination) -- PRIM+morph (ExTermination, seq) _ = pure (ExTermination, leadsTo seq "Mprim" ExTermination) -- PRIM morph (form@(ExFormation bds), seq) ctx = do resolved <- withTail form ctx case resolved of Just (expr, rule) -> morph (expr, leadsTo seq rule expr) ctx -- LAMBDA or PHI- _ -> pure (form, leadsTo seq "M(prim)" form) -- PRIM+ _ -> pure (form, leadsTo seq "Mprim" form) -- PRIM morph (expr, seq) ctx = do resolved <- withTail expr ctx case resolved of
+ src/Filter.hs view
@@ -0,0 +1,65 @@+-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com+-- SPDX-License-Identifier: MIT++module Filter (include, exclude) where++import AST+import Logger (logDebug)+import Misc+import Printer (logPrintConfig, printExpression, printExpression', printProgram)+import Rewriter+import Text.Printf (printf)++fqnToAttrs :: Expression -> [Attribute]+fqnToAttrs = reverse . fqnToAttrs'+ where+ fqnToAttrs' :: Expression -> [Attribute]+ fqnToAttrs' (ExDispatch ExGlobal attr) = [attr]+ fqnToAttrs' (ExDispatch expr attr) = attr : fqnToAttrs' expr+ fqnToAttrs' expr = []++exclude' :: Program -> [Expression] -> Program+exclude' prog [] = prog+exclude' (Program expr@(ExFormation _)) (fqn : rest) = exclude' (Program (excludedFormation expr (fqnToAttrs fqn))) rest+ where+ excludedFormation :: Expression -> [Attribute] -> Expression+ excludedFormation (ExFormation bds) [attr] = ExFormation [bd | bd <- bds, attributeFromBinding bd /= Just attr]+ excludedFormation (ExFormation bds) attrs = ExFormation (excludedBindings bds attrs)+ where+ excludedBindings :: [Binding] -> [Attribute] -> [Binding]+ excludedBindings [] _ = []+ excludedBindings (bd@(BiTau attr form@(ExFormation _)) : bds) attrs@(attr' : rest)+ | attr == attr' = BiTau attr (excludedFormation form rest) : bds+ | otherwise = bd : excludedBindings bds attrs+ excludedBindings (bd : bds) attrs = bd : excludedBindings bds attrs+ excludedFormation expr _ = expr+exclude' prog _ = prog++exclude :: [Rewritten] -> [Expression] -> [Rewritten]+exclude [] _ = []+exclude rs [] = rs+exclude ((program, maybeRule) : rest) exprs = (exclude' program exprs, maybeRule) : exclude rest exprs++include' :: Program -> Expression -> Program+include' prog@(Program expr@(ExFormation _)) fqn = case includedFormation expr (fqnToAttrs fqn) of+ Just expr -> Program expr+ _ -> Program (ExFormation [BiVoid AtRho])+ where+ includedFormation :: Expression -> [Attribute] -> Maybe Expression+ includedFormation (ExFormation bds) [attr] =+ let bds' = [bd | bd <- bds, attributeFromBinding bd == Just attr]+ in if null bds' then Nothing else Just (ExFormation (withVoidRho bds'))+ includedFormation (ExFormation bds) attrs = includedBindings bds attrs >>= (Just . ExFormation . (: [BiVoid AtRho]))+ where+ includedBindings :: [Binding] -> [Attribute] -> Maybe Binding+ includedBindings (bd@(BiTau attr form@(ExFormation _)) : bds) attrs@(attr' : rest)+ | attr == attr' = includedFormation form rest >>= Just . BiTau attr+ | otherwise = includedBindings bds attrs+ includedBindings _ _ = Nothing+ includedFormation _ _ = Nothing+include' _ _ = Program (ExFormation [BiVoid AtRho])++include :: [Rewritten] -> [Expression] -> [Rewritten]+include [] _ = []+include rs [] = rs+include ((program, maybeRule) : rest) (expr : _) = (include' program expr, maybeRule) : include rest [expr]
− src/Hide.hs
@@ -1,42 +0,0 @@--- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com--- SPDX-License-Identifier: MIT--module Hide (hide, hide') where--import AST-import Logger (logDebug)-import Misc-import Printer (logPrintConfig, printExpression')-import Rewriter-import Text.Printf (printf)--fqnToAttrs :: Expression -> [Attribute]-fqnToAttrs = reverse . fqnToAttrs'- where- fqnToAttrs' :: Expression -> [Attribute]- fqnToAttrs' (ExDispatch ExGlobal attr) = [attr]- fqnToAttrs' (ExDispatch expr attr) = attr : fqnToAttrs' expr- fqnToAttrs' expr = []--hide' :: Program -> [Expression] -> Program-hide' prog [] = prog-hide' (Program expr@(ExFormation _)) (fqn : rest) = hide' (Program (hiddenFormation expr (fqnToAttrs fqn))) rest- where- hiddenFormation :: Expression -> [Attribute] -> Expression- hiddenFormation (ExFormation bds) [attr] =- let bds' = [bd | bd <- bds, attributeFromBinding bd /= Just attr]- in ExFormation bds'- hiddenFormation (ExFormation bds) attrs = ExFormation (hiddenBindings bds attrs)- where- hiddenBindings :: [Binding] -> [Attribute] -> [Binding]- hiddenBindings [] _ = []- hiddenBindings (bd@(BiTau attr form@(ExFormation _)) : bds) attrs@(attr' : rest)- | attr == attr' = BiTau attr (hiddenFormation form rest) : bds- | otherwise = bd : hiddenBindings bds attrs- hiddenBindings (bd : bds) attrs = bd : hiddenBindings bds attrs- hiddenFormation expr attr = expr-hide' prog (fqn : rest) = prog--hide :: [Rewritten] -> [Expression] -> [Rewritten]-hide [] _ = []-hide ((program, maybeRule) : rest) exprs = (hide' program exprs, maybeRule) : hide rest exprs
src/Merge.hs view
@@ -59,7 +59,7 @@ Program (ExFormation bds') <- merge' rest merged <- mergeBindings bds' bds pure (Program (ExFormation merged))-merge' (prog : rest) = throwIO (WrongProgramFormat prog)+merge' (prog : _) = throwIO (WrongProgramFormat prog) merge :: [Program] -> IO Program merge progs = merge' (reverse progs)
test/CLISpec.hs view
@@ -73,13 +73,18 @@ testCLI' :: [String] -> [String] -> Either ExitCode () -> Expectation testCLI' args outputs exit = do (out, result) <- withStdout (try (runCLI args) :: IO (Either ExitCode ()))- forM_- outputs- ( \output ->- unless (output `isInfixOf` out) $- expectationFailure- ("Expected that output contains:\n" ++ output ++ "\nbut got:\n" ++ out)- )+ if null outputs+ then+ unless (null out) $+ expectationFailure ("Expected that output is empty, but got:\n" ++ out)+ else+ forM_+ outputs+ ( \output ->+ unless (output `isInfixOf` out) $+ expectationFailure+ ("Expected that output contains:\n" ++ output ++ "\nbut got:\n" ++ out)+ ) result `shouldBe` exit testCLISucceeded :: [String] -> [String] -> Expectation@@ -205,6 +210,18 @@ ["rewrite", "--hide=Q.x(Q.y)"] ["[ERROR]: Invalid set of arguments: Only dispatch expression", "but given: Φ.x( Φ.y )"] + it "with many --show options" $+ withStdin "{[[]]}" $+ testCLIFailed+ ["rewrite", "--show=Q.x.y", "--show=hello"]+ ["The option --show can be used only once"]+ + it "with wrong --show option" $+ withStdin "{[[]]}" $+ testCLIFailed+ ["rewrite", "--show=Q.x(Q.y)"]+ ["[ERROR]:", "Only dispatch expression started with Φ (or Q) can be used in --show"]+ it "saves steps to dir with --steps-dir" $ do let dir = "test-steps-temp" dirExists <- doesDirectoryExist dir@@ -497,6 +514,12 @@ ["rewrite", "--sweet", "--flat", "--hide=Q.org.eolang", "--hide=Q.org.yegor256"] ["{⟦ org ↦ ⟦⟧, x ↦ 42 ⟧}"] + it "shows and hides" $+ withStdin "{[[ org -> [[ eolang -> Q.x, yegor256 -> Q.y ]], x -> 42 ]]}" $+ testCLISucceeded+ ["rewrite", "--sweet", "--flat", "--show=Q.org", "--hide=Q.org.eolang"]+ ["{⟦ org ↦ ⟦ yegor256 ↦ Φ.y ⟧ ⟧}"]+ it "prints in line with --flat" $ withStdin "Q -> [[ x -> 5, y -> \"hey\", z -> [[ w -> [[ ]] ]] ]]" $ testCLISucceeded@@ -557,13 +580,17 @@ " \\leadsto \\Big\\{[[ |x| -> [[ D> 01-, |y| -> ? ]]( |y| -> [[]] ) ]].|x|\\Big\\} \\leadsto_{\\nameref{r:copy}}", " \\leadsto \\Big\\{[[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]].|x|\\Big\\} \\leadsto_{\\nameref{r:dot}}", " \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]] ]]( ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] )\\Big\\} \\leadsto_{\\nameref{r:copy}}",- " \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]], ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] ]]\\Big\\} \\leadsto_{\\nameref{r:M(prim)}}",+ " \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]], ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] ]]\\Big\\} \\leadsto_{\\nameref{r:Mprim}}", " \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]], ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] ]]\\Big\\}.", "\\end{phiquation}", "01-" ] ] + it "does not print bytes with --quiet" $+ withStdin "Q -> [[ D> 01- ]]" $+ testCLISucceeded ["dataize", "--quiet"] []+ describe "fails" $ do it "with --output != latex and --nonumber" $ withStdin "{[[]]}" $@@ -674,23 +701,23 @@ testCLIFailed ["merge"] ["At least one input file must be specified for 'merge' command"]- + describe "match" $ do it "takes from stdin" $ withStdin "{[[]]}" $ testCLISucceeded ["match"] ["[INFO]"]- + it "takes from file" $ testCLISucceeded ["match", "test-resources/cli/foo.phi"] ["[INFO]"]- + it "does not print substitutions without pattern" $ withStdin "{[[]]}" $ testCLISucceeded ["match"] ["[INFO]: The --pattern is not provided, no substitutions are built"]- + it "prints one substitution" $ withStdin "{[[ x -> Q.x ]]}" $ testCLISucceeded ["match", "--pattern=Q.!a"] ["a >> x"]- + it "prints many substitutions" $ withStdin "{[[ x -> Q.x, y -> Q.y ]]}" $ testCLISucceeded ["match", "--pattern=Q.!a"] ["a >> x\n------\na >> y"]@@ -700,12 +727,12 @@ testCLISucceeded ["match", "--pattern=[[ !a -> Q.y, !B ]].!a", "--when=and(not(alpha(!a)),eq(length(!B),1))"] ["B >> ⟦ ρ ↦ ∅ ⟧\na >> x"]- + it "builds with condition from file" $ testCLISucceeded ["match", "--pattern=[[ !B ]]", "--when=eq(length(!B),2)", "test-resources/cli/foo.phi"] ["B >> ⟦\n foo ↦ Φ.org.eolang.x,\n ρ ↦ ∅\n⟧"]- + it "fails on parsing --when condition" $ withStdin "{[[]]}" $ testCLIFailed
+ test/FilterSpec.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}++-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com+-- SPDX-License-Identifier: MIT++module FilterSpec where++import Control.Monad+import Data.Aeson+import Data.Yaml qualified as Yaml+import Encoding (Encoding (UNICODE))+import Filter qualified as F+import GHC.Generics (Generic)+import Lining (LineFormat (MULTILINE))+import Misc+import Parser (parseExpressionThrows, parseProgramThrows)+import Printer (printProgram')+import Sugar (SugarType (SALTY))+import System.FilePath+import Test.Hspec++data YamlPack = YamlPack+ { program :: String,+ shown :: [String],+ hidden :: [String],+ result :: String+ }+ deriving (Generic, Show, FromJSON)++yamlPack :: FilePath -> IO YamlPack+yamlPack = Yaml.decodeFileThrow++spec :: Spec+spec =+ describe "filter packs" $ do+ let resources = "test-resources/filter-packs"+ packs <- runIO (allPathsIn resources)+ forM_+ packs+ ( \pth -> it (makeRelative resources pth) $ do+ YamlPack {..} <- yamlPack pth+ prog <- parseProgramThrows program+ included <- traverse parseExpressionThrows shown+ excluded <- traverse parseExpressionThrows hidden+ res <- parseProgramThrows result+ let [(prog', _)] = F.exclude (F.include [(prog, Nothing)] included) excluded+ prog' `shouldBe` res+ when+ (prog' /= res)+ ( expectationFailure+ ( "Expected:\n"+ ++ printProgram' res (SALTY, UNICODE, MULTILINE)+ ++ "\nbut got:\n"+ ++ printProgram' prog' (SALTY, UNICODE, MULTILINE)+ )+ )+ )
− test/HideSpec.hs
@@ -1,45 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE RecordWildCards #-}-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}---- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com--- SPDX-License-Identifier: MIT--module HideSpec where--import Control.Monad-import Data.Aeson-import Data.Yaml qualified as Yaml-import GHC.Generics (Generic)-import Hide (hide)-import Misc-import Parser (parseExpressionThrows, parseProgramThrows)-import System.FilePath-import Test.Hspec--data YamlPack = YamlPack- { program :: String,- hidden :: String,- result :: String- }- deriving (Generic, Show, FromJSON)--yamlPack :: FilePath -> IO YamlPack-yamlPack = Yaml.decodeFileThrow--spec :: Spec-spec =- describe "hide packs" $ do- let resources = "test-resources/hide-packs"- packs <- runIO (allPathsIn resources)- forM_- packs- ( \pth -> it (makeRelative resources pth) $ do- YamlPack {..} <- yamlPack pth- prog <- parseProgramThrows program- expr <- parseExpressionThrows hidden- res <- parseProgramThrows result- let [(prog', _)] = hide [(prog, Nothing)] [expr]- prog' `shouldBe` res- )