packages feed

phino 0.0.0.66 → 0.0.0.67

raw patch · 12 files changed

+101/−48 lines, 12 filesdep ~randomPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: random

API changes (from Hackage documentation)

+ CLI.Parsers: optBreakpoint :: Parser (Maybe FilePath)
+ CLI.Parsers: optMust :: Parser Must
+ CLI.Types: EmptySubstsOnMatch :: CmdException
+ CLI.Types: [_breakpoint] :: OptsRewrite -> Maybe String
+ Rewriter: [_breakpoint] :: RewriteContext -> Maybe String
- CLI.Types: OptsRewrite :: LogLevel -> Int -> IOFormat -> IOFormat -> SugarType -> LineFormat -> Must -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Int -> Int -> Int -> Maybe Int -> Maybe Int -> [FilePath] -> [String] -> [String] -> String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe FilePath -> Maybe FilePath -> Maybe FilePath -> OptsRewrite
+ CLI.Types: OptsRewrite :: LogLevel -> Int -> IOFormat -> IOFormat -> SugarType -> LineFormat -> Must -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Int -> Int -> Int -> Maybe Int -> Maybe Int -> [FilePath] -> [String] -> [String] -> String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe FilePath -> Maybe FilePath -> Maybe FilePath -> OptsRewrite
- Rewriter: RewriteContext :: Expression -> Int -> Int -> Bool -> BuildTermFunc -> Must -> SaveStepFunc -> RewriteContext
+ Rewriter: RewriteContext :: Expression -> Int -> Int -> Bool -> BuildTermFunc -> Must -> Maybe String -> SaveStepFunc -> RewriteContext
- Yaml: Rule :: Maybe String -> Maybe String -> Expression -> Expression -> Maybe Condition -> Maybe [Extra] -> Maybe Condition -> Rule
+ Yaml: Rule :: String -> Maybe String -> Expression -> Expression -> Maybe Condition -> Maybe [Extra] -> Maybe Condition -> Rule
- Yaml: [name] :: Rule -> Maybe String
+ Yaml: [name] :: Rule -> String

Files

README.md view
@@ -29,7 +29,7 @@  ```bash cabal update-cabal install --overwrite-policy=always phino-0.0.0.65+cabal install --overwrite-policy=always phino-0.0.0.66 phino --version ``` @@ -44,7 +44,8 @@  Download paths are: -* Ubuntu: <http://phino.objectionary.com/releases/ubuntu-24.04/phino-latest>+* Ubuntu 22.04: <http://phino.objectionary.com/releases/ubuntu-22.04/phino-latest>+* Ubuntu 24.04: <http://phino.objectionary.com/releases/ubuntu-24.04/phino-latest> * MacOS (ARM): <http://phino.objectionary.com/releases/macos-15/phino-latest> * MacOS (Intel): <http://phino.objectionary.com/releases/macos-14-large/phino-latest> * Windows: <http://phino.objectionary.com/releases/windows-2022/phino-latest.exe>@@ -224,7 +225,7 @@  ```bnfc Rule:-  name: String?+  name: String   pattern: String   result: String   when: Condition?       # predicate, works with substitutions before extension
phino.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: phino-version: 0.0.0.66+version: 0.0.0.67 license: MIT synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>@@ -89,7 +89,7 @@     filepath >=1.4.200 && <1.6,     megaparsec >=9.5 && <9.8,     optparse-applicative >=0.18 && <0.20,-    random >=1.2 && <1.3,+    random >=1.2 && <1.4,     regex-pcre-builtin >=0.95.2 && <0.96,     scientific >=0.3.7 && <0.4,     text >=2.0.2 && <2.2,
src/CLI/Parsers.hs view
@@ -133,6 +133,9 @@ optMeetPrefix :: Parser (Maybe String) optMeetPrefix = optional (strOption (long "meet-prefix" <> metavar "PREFIX" <> help "Prefix to be inserted before index in \\phiMeet{} and \\phiAgain{} LaTeX functions, e.g. \\phiMeet{foo:1}")) +optBreakpoint :: Parser (Maybe FilePath)+optBreakpoint = optional (strOption (long "breakpoint" <> metavar "FILE" <> help "The name of the first unmatched rule which leads to stopping entire rewriting process and returning original program"))+ optHide :: Parser [String] optHide =   many@@ -192,6 +195,17 @@ optLineFormat' :: Parser LineFormat optLineFormat' = flag MULTILINE SINGLELINE (long "flat" <> help "Print result 𝜑-program in one line") +optMust :: Parser Must+optMust =+  option+    auto+    ( long "must"+        <> metavar "RANGE"+        <> help "Must-rewrite range (e.g., '3', '..5', '3..', '3..5'). Stops execution if number of rules applied is not in range. Use 0 to disable."+        <> value MtDisabled+        <> showDefaultWith show+    )+ optOmitListing :: Parser Bool optOmitListing = switch (long "omit-listing" <> help "Omit full program listing in XMIR output") @@ -260,14 +274,7 @@             <*> optOutputFormat             <*> optSugar             <*> optLineFormat-            <*> option-              auto-              ( long "must"-                  <> metavar "RANGE"-                  <> help "Must-rewrite range (e.g., '3', '..5', '3..', '3..5'). Stops execution if number of rules applied is not in range. Use 0 to disable."-                  <> value MtDisabled-                  <> showDefaultWith show-              )+            <*> optMust             <*> optNormalize             <*> optShuffle             <*> optOmitListing@@ -291,6 +298,7 @@             <*> optExpression             <*> optLabel             <*> optMeetPrefix+            <*> optBreakpoint             <*> optTarget             <*> optStepsDir             <*> argInputFile
src/CLI/Runners.hs view
@@ -14,6 +14,7 @@ import Condition (parseConditionThrows) import Control.Exception import Control.Monad (unless, when)+import Data.List (intercalate) import qualified Data.List.NonEmpty as NE import Data.Maybe (fromJust, isJust, isNothing) import Dataize@@ -39,10 +40,11 @@   included <- validatedDispatches "show" _show   [loc] <- validatedDispatches "locator" [_locator]   [foc] <- validatedDispatches "focus" [_focus]-  logDebug (printf "Amount of rewriting cycles across all the rules: %d, per rule: %d" _maxCycles _maxDepth)-  input <- readInput _inputFile   rules <- getRules _normalize _shuffle _rules+  validateBreakpoint _breakpoint rules+  input <- readInput _inputFile   program <- parseProgram input _inputFormat+  logDebug (printf "Amount of rewriting cycles across all the rules: %d, per rule: %d" _maxCycles _maxDepth)   let listing = case (rules, _inputFormat, _outputFormat) of         ([], XMIR, XMIR) -> (\_ -> escapeXML input)         ([], _, _) -> const input@@ -70,6 +72,13 @@         [(_meetPopularity, "meet-popularity"), (_meetLength, "meet-length")]       validateMust' _must       validateXmirOptions _outputFormat [(_omitListing, "omit-listing"), (_omitComments, "omit-comments")] _focus+    validateBreakpoint :: Maybe String -> [Y.Rule] -> IO ()+    validateBreakpoint Nothing _ = pure ()+    validateBreakpoint (Just rule) rules =+      let names = map Y.name rules+       in unless+            (rule `elem` names)+            (invalidCLIArguments (printf "The rule '%s' provided in '--breakpoint' option is absent across given rewriting rules: %s" rule (intercalate ", " names)))     output :: Maybe FilePath -> String -> IO ()     output target prog = case (_inPlace, target, _inputFile) of       (True, _, Just file) -> do@@ -86,7 +95,7 @@         logDebug "The option '--target' is not specified, printing to console..."         putStrLn prog     context :: Expression -> PrintProgramContext -> RewriteContext-    context loc ctx = RewriteContext loc _maxDepth _maxCycles _depthSensitive buildTerm _must (saveStepFunc _stepsDir ctx)+    context loc ctx = RewriteContext loc _maxDepth _maxCycles _depthSensitive buildTerm _must _breakpoint (saveStepFunc _stepsDir ctx)     printProgCtx :: XmirContext -> Expression -> PrintProgramContext     printProgCtx xmirCtx focus =       PrintProgCtx@@ -205,8 +214,8 @@       condition <- traverse parseConditionThrows _when       substs <- matchProgramWithRule prog (rule ptn condition) (RuleContext buildTerm)       if null substs-        then logDebug "Provided pattern was not matched, no substitutions are built"+        then throwIO EmptySubstsOnMatch         else putStrLn (P.printSubsts' substs (_sugarType, UNICODE, _flat, defaultMargin))   where     rule :: Expression -> Maybe Y.Condition -> Y.Rule-    rule ptn cnd = Y.Rule Nothing Nothing ptn ExGlobal cnd Nothing Nothing+    rule ptn cnd = Y.Rule "custom" Nothing ptn ExGlobal cnd Nothing Nothing
src/CLI/Types.hs view
@@ -37,6 +37,7 @@   | CouldNotReadFromStdin String   | CouldNotDataize   | CouldNotPrintExpressionInXMIR+  | EmptySubstsOnMatch   deriving (Exception)  instance Show CmdException where@@ -44,6 +45,7 @@   show (CouldNotReadFromStdin msg) = printf "Could not read input from stdin\nReason: %s" msg   show CouldNotDataize = "Could not dataize given program"   show CouldNotPrintExpressionInXMIR = "Could not print expression with --output=xmir, only program printing is allowed"+  show EmptySubstsOnMatch = "Provided pattern was not matched, no substitutions are built"  data Command   = CmdRewrite OptsRewrite@@ -131,6 +133,7 @@   , _expression :: Maybe String   , _label :: Maybe String   , _meetPrefix :: Maybe String+  , _breakpoint :: Maybe String   , _targetFile :: Maybe FilePath   , _stepsDir :: Maybe FilePath   , _inputFile :: Maybe FilePath
src/Dataize.hs view
@@ -50,6 +50,7 @@     _depthSensitive     _buildTerm     MtDisabled+    Nothing     _saveStep  maybeBinding :: (Binding -> Bool) -> [Binding] -> (Maybe Binding, [Binding])
src/LaTeX.hs view
@@ -22,7 +22,7 @@ import AST import CST import Data.List (intercalate, nub)-import Data.Maybe (fromMaybe, isJust)+import Data.Maybe (isJust) import Encoding import Lining import Locator (locatedExpression)@@ -320,7 +320,7 @@ explainRule rule =   intercalate     "\n  "-    [ "\\trrule{" ++ fromMaybe "unknown" (Y.name rule) ++ "}"+    [ "\\trrule{" ++ Y.name rule ++ "}"     , braced (renderToLatex (expressionToCST (Y.pattern rule)) defaultLatexContext)     , braced (renderToLatex (expressionToCST (Y.result rule)) defaultLatexContext)     , conditionToLatex (joinedConditions (Y.when rule) (Y.having rule))
src/Rewriter.hs view
@@ -15,7 +15,6 @@ import Control.Exception (Exception, throwIO) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE-import Data.Maybe (fromMaybe) import qualified Data.Set as Set import Deps import Locator (locatedExpression, withLocatedExpression)@@ -29,7 +28,7 @@ import Text.Printf (printf) import qualified Yaml as Y -type RewriteState = (NonEmpty Rewritten, Set.Set Expression)+type RewriteState = (NonEmpty Rewritten, Set.Set Expression, Bool)  type Rewritten = (Program, Maybe String) @@ -46,6 +45,7 @@   , _depthSensitive :: Bool   , _buildTerm :: BuildTermFunc   , _must :: Must+  , _breakpoint :: Maybe String   , _saveStep :: SaveStepFunc   } @@ -129,19 +129,23 @@     hasMetaBindings = foldl (\acc bd -> acc || isMetaBinding bd) False tryBuildAndReplaceFast state _ = buildAndReplace' state replaceExpression --- The function returns tuple (X, Y) where+-- The function returns tuple (X, Y, Z) where -- - X is sequence of programs; -- - Y is Set of unique programs after each rule application. It allows to stop the rewriting if we're getting --   into loop and get back to program which we've already got before+-- - Z is boolean flag which tells us if we reach breakpoint. If unmatched rule is equal to breakpoint rule - entire+--   rewriting must be stopped and original program must be returned rewrite' :: RewriteState -> [Y.Rule] -> Int -> RewriteContext -> IO RewriteState rewrite' state [] _ _ = pure state rewrite' state (rule : rest) iteration ctx@RewriteContext{..} = do   state' <- _rewrite state 1-  rewrite' state' rest iteration ctx+  case state' of+    (_, _, True) -> pure state'+    _ -> rewrite' state' rest iteration ctx   where     _rewrite :: RewriteState -> Int -> IO RewriteState-    _rewrite (_rewrittens@((program, _) :| _), _unique) _count =-      let ruleName = fromMaybe "unknown" (Y.name rule)+    _rewrite (_rewrittens@((program, _) :| _), _unique, _) _count =+      let ruleName = Y.name rule           ptn = Y.pattern rule           res = Y.result rule        in if _count - 1 == _maxDepth@@ -149,22 +153,25 @@               logDebug (printf "Max amount of rewriting cycles (%d) for rule '%s' has been reached, rewriting is stopped" _maxDepth ruleName)               if _depthSensitive                 then throwIO (StoppedOnLimit "max-depth" _maxDepth)-                else pure (_rewrittens, _unique)+                else pure (_rewrittens, _unique, False)             else do               logDebug (printf "Starting rewriting cycle for rule '%s': %d out of %d" ruleName _count _maxDepth)               expression <- locatedExpression _locator program-              matched <- R.matchExpressionWithRule expression rule (RuleContext _buildTerm)-              if null matched-                then do+              R.matchExpressionWithRule expression rule (RuleContext _buildTerm) >>= \case+                [] -> do                   logDebug (printf "Rule '%s' does not match, rewriting is stopped" ruleName)-                  pure (_rewrittens, _unique)-                else do+                  if _breakpoint == Just ruleName+                    then do+                      logDebug (printf "Rule '%s' is a breakpoint, dropping down all the previous rewritings..." ruleName)+                      pure (_rewrittens, _unique, True)+                    else pure (_rewrittens, _unique, False)+                matched -> do                   logDebug (printf "Rule '%s' has been matched, applying..." ruleName)                   expr <- tryBuildAndReplaceFast (expression, ptn, res, matched) (ReplaceCtx _maxDepth)                   if expression == expr                     then do                       logDebug (printf "Applied '%s', no changes made" ruleName)-                      pure (_rewrittens, _unique)+                      pure (_rewrittens, _unique, False)                     else                       if Set.member expr _unique                         then throwIO (LoopingRewriting (printExpression expr) ruleName _count)@@ -179,21 +186,21 @@                             )                           prog <- withLocatedExpression _locator expr program                           _saveStep prog (((iteration - 1) * _maxDepth) + _count)-                          _rewrite (leadsTo prog, Set.insert expr _unique) (_count + 1)+                          _rewrite (leadsTo prog, Set.insert expr _unique, False) (_count + 1)       where         leadsTo :: Program -> NonEmpty Rewritten         leadsTo _prog =           let (program, _) :| rest = _rewrittens-           in (_prog, Nothing) :| (program, Just (fromMaybe "unknown" (Y.name rule))) : rest+           in (_prog, Nothing) :| (program, Just (Y.name rule)) : rest  -- Rewrite program by provided locator from RewriteContext rewrite :: Program -> [Y.Rule] -> RewriteContext -> IO Rewrittens rewrite prog rules ctx@RewriteContext{..} = do-  (rewrittens, exceeded) <- _rewrite ((prog, Nothing) :| [], Set.empty) 0+  (rewrittens, exceeded) <- _rewrite ((prog, Nothing) :| [], Set.empty, False) 0   pure (NE.reverse rewrittens, exceeded)   where     _rewrite :: RewriteState -> Int -> IO Rewrittens-    _rewrite state@(rewrittens@((program, _) :| _), _) count+    _rewrite state@(rewrittens@((program, _) :| _), _, _) count       | not (inRange _must count) && count > 0 && exceedsUpperBound _must count = throwIO (MustStopBefore _must count)       | count == _maxCycles = do           logDebug (printf "Max amount of rewriting cycles for all rules (%d) has been reached, rewriting is stopped" _maxCycles)@@ -202,11 +209,13 @@             else pure (rewrittens, True)       | otherwise = do           logDebug (printf "Starting rewriting cycle for all rules: %d out of %d" count _maxCycles)-          state'@(rewrittens'@((program', _) :| _), _) <- rewrite' state rules count ctx-          if program' == program-            then do-              logDebug "Rewriting is stopped since it has no effect"-              if not (inRange _must count)-                then throwIO (MustBeGoing _must count)-                else pure (rewrittens', False)-            else _rewrite state' (count + 1)+          rewrite' state rules count ctx >>= \case+            (_, _, True) -> pure ((prog, Nothing) :| [], False) -- breakpoint, return original program+            state'@(rewrittens'@((program', _) :| _), _, False) ->+              if program' == program+                then do+                  logDebug "Rewriting is stopped since it has no effect"+                  if not (inRange _must count)+                    then throwIO (MustBeGoing _must count)+                    else pure (rewrittens', False)+                else _rewrite state' (count + 1)
src/Rule.hs view
@@ -19,7 +19,7 @@ import qualified Data.ByteString.Char8 as B import Data.Foldable (foldlM) import qualified Data.Map.Strict as M-import Data.Maybe (catMaybes, fromMaybe)+import Data.Maybe (catMaybes) import Deps (BuildTermFunc, Term (..)) import GHC.IO (unsafePerformIO) import Logger (logDebug)@@ -280,7 +280,7 @@ matchExpressionWithRule expr rule ctx =   let ptn = Y.pattern rule       matched = matchExpression ptn expr-      name = fromMaybe "unknown" (Y.name rule)+      name = Y.name rule    in if null matched         then do           logDebug (printf "Pattern from rule '%s' was not matched:\n%s" name (printExpression' ptn logPrintConfig))
src/Yaml.hs view
@@ -171,7 +171,7 @@   deriving (Generic, Show)  data Rule = Rule-  { name :: Maybe String+  { name :: String   , description :: Maybe String   , pattern :: Expression   , result :: Expression
test/CLISpec.hs view
@@ -277,6 +277,12 @@             ["rewrite", "--margin=-1"]             ["[ERROR]"] +      it "with --breakpoint which does not exist across the rules" $+        withStdin "" $+          testCLIFailed+            ["rewrite", "--breakpoint=hello", "--normalize"]+            ["[ERROR]"]+     it "prints help" $       testCLISucceeded         ["rewrite", "--help"]@@ -755,6 +761,15 @@           ["rewrite", "--sweet", "--flat", "--locator=Q.ex", "--normalize"]           ["{⟦ ex ↦ ⟦ x ↦ 5 ⟧, abc ↦ ⟦ x ↦ ∅ ⟧( x ↦ 5 ) ⟧}"] +    it "returns original program on --breakpoint" $+      withStdin "{[[ x -> ?, y -> $.x ]](x -> [[ D> 42- ]]).y}" $+        testCLISucceeded+          ["rewrite", "--sweet", "--flat", "--normalize", "--breakpoint=stop", "--log-level=debug"]+          [ "Applied 'copy' (30 nodes -> 25 nodes)"+          , "Rule 'stop' is a breakpoint, dropping down all the previous rewritings..."+          , "{⟦ x ↦ ∅, y ↦ x ⟧( x ↦ ⟦ Δ ⤍ 42- ⟧ ).y}"+          ]+   describe "dataize" $ do     it "prints help" $       testCLISucceeded ["dataize", "--help"] ["Dataize the 𝜑-program"]@@ -1012,3 +1027,9 @@         testCLIFailed           ["match", "--pattern=[[!B]]", "--when=hello"]           ["[ERROR]: Couldn't parse given condition"]++    it "fails on empty substitutions" $+      withStdin "{Q.x.y}" $+        testCLIFailed+          ["match", "--pattern=$.!a"]+          ["[ERROR]"]
test/RewriterSpec.hs view
@@ -111,6 +111,7 @@                       False                       buildTerm                       must'+                      Nothing                       dontSaveStep                   )               let (program, _) = NE.last rewrittens