packages feed

maude 0.3.0 → 0.6.1

raw patch · 7 files changed

+448/−307 lines, 7 filesdep +filepathdep +process-extrasdep +temporarydep −parsecPVP ok

version bump matches the API change (PVP)

Dependencies added: filepath, process-extras, temporary, xml

Dependencies removed: parsec

API changes (from Hackage documentation)

- Foreign.Maude: MaudeConf :: FilePath -> [FilePath] -> Bool -> MaudeConf
- Foreign.Maude: Rewrite :: Term -> MaudeCommand
- Foreign.Maude: RewriteResult :: Text -> Text -> Text -> RewriteResult
- Foreign.Maude: Search :: Term -> Pattern -> MaudeCommand
- Foreign.Maude: SearchResult :: Integer -> Text -> Text -> SearchResult
- Foreign.Maude: data MaudeCommand
- Foreign.Maude: data MaudeConf
- Foreign.Maude: data RewriteResult
- Foreign.Maude: data SearchResult
- Foreign.Maude: defaultConf :: MaudeConf
- Foreign.Maude: instance Eq MaudeConf
- Foreign.Maude: instance Show MaudeCommand
- Foreign.Maude: instance Show MaudeConf
- Foreign.Maude: instance Show RewriteResult
- Foreign.Maude: instance Show SearchResult
- Foreign.Maude: loadFiles :: MaudeConf -> [FilePath]
- Foreign.Maude: maudeCmd :: MaudeConf -> FilePath
- Foreign.Maude: parseRewriteResult :: Text -> Maybe RewriteResult
- Foreign.Maude: parseSearchResults :: Text -> Maybe [SearchResult]
- Foreign.Maude: printParens :: MaudeConf -> Bool
- Foreign.Maude: resultSort :: RewriteResult -> Text
- Foreign.Maude: resultTerm :: RewriteResult -> Text
- Foreign.Maude: rewrite :: [FilePath] -> Term -> IO (Maybe RewriteResult)
- Foreign.Maude: runMaude :: MaudeConf -> MaudeCommand -> IO Text
- Foreign.Maude: search :: [FilePath] -> Term -> Pattern -> IO (Maybe [SearchResult])
- Foreign.Maude: searchResultState :: SearchResult -> Integer
- Foreign.Maude: searchResultTerm :: SearchResult -> Text
- Foreign.Maude: searchStatistics :: SearchResult -> Text
- Foreign.Maude: statistics :: RewriteResult -> Text
- Foreign.Maude: type Pattern = Text
- Foreign.Maude: type Term = Text
+ Language.Maude.Exec: defaultConf :: MaudeConf
+ Language.Maude.Exec: rewrite :: [FilePath] -> Text -> IO RewriteResult
+ Language.Maude.Exec: runMaude :: MaudeConf -> MaudeCommand -> IO MaudeResult
+ Language.Maude.Exec: search :: [FilePath] -> Text -> Text -> IO SearchResults
+ Language.Maude.Exec.Types: Erewrite :: Text -> MaudeCommand
+ Language.Maude.Exec.Types: LogToXmlFailure :: MaudeException
+ Language.Maude.Exec.Types: MaudeConf :: FilePath -> [FilePath] -> MaudeConf
+ Language.Maude.Exec.Types: MaudeFailure :: ExitCode -> Text -> Text -> MaudeException
+ Language.Maude.Exec.Types: MaudeResult :: Text -> Text -> MaudeResult
+ Language.Maude.Exec.Types: MaudeStatistics :: Integer -> Integer -> Integer -> MaudeStatistics
+ Language.Maude.Exec.Types: Rewrite :: Text -> MaudeCommand
+ Language.Maude.Exec.Types: RewriteResult :: Term -> MaudeStatistics -> RewriteResult
+ Language.Maude.Exec.Types: Search :: Text -> Text -> MaudeCommand
+ Language.Maude.Exec.Types: SearchResult :: Integer -> MaudeStatistics -> Substitution -> SearchResult
+ Language.Maude.Exec.Types: Substitution :: Term -> Term -> Substitution
+ Language.Maude.Exec.Types: XmlToResultFailure :: String -> Element -> MaudeException
+ Language.Maude.Exec.Types: cpuTime :: MaudeStatistics -> Integer
+ Language.Maude.Exec.Types: data MaudeCommand
+ Language.Maude.Exec.Types: data MaudeConf
+ Language.Maude.Exec.Types: data MaudeException
+ Language.Maude.Exec.Types: data MaudeResult
+ Language.Maude.Exec.Types: data MaudeStatistics
+ Language.Maude.Exec.Types: data RewriteResult
+ Language.Maude.Exec.Types: data SearchResult
+ Language.Maude.Exec.Types: data Substitution
+ Language.Maude.Exec.Types: instance Data MaudeCommand
+ Language.Maude.Exec.Types: instance Data MaudeConf
+ Language.Maude.Exec.Types: instance Data MaudeResult
+ Language.Maude.Exec.Types: instance Data MaudeStatistics
+ Language.Maude.Exec.Types: instance Data RewriteResult
+ Language.Maude.Exec.Types: instance Data SearchResult
+ Language.Maude.Exec.Types: instance Data Substitution
+ Language.Maude.Exec.Types: instance Eq MaudeCommand
+ Language.Maude.Exec.Types: instance Eq MaudeConf
+ Language.Maude.Exec.Types: instance Eq MaudeResult
+ Language.Maude.Exec.Types: instance Eq MaudeStatistics
+ Language.Maude.Exec.Types: instance Eq RewriteResult
+ Language.Maude.Exec.Types: instance Eq SearchResult
+ Language.Maude.Exec.Types: instance Eq Substitution
+ Language.Maude.Exec.Types: instance Exception MaudeException
+ Language.Maude.Exec.Types: instance Ord MaudeCommand
+ Language.Maude.Exec.Types: instance Ord MaudeConf
+ Language.Maude.Exec.Types: instance Ord MaudeResult
+ Language.Maude.Exec.Types: instance Ord MaudeStatistics
+ Language.Maude.Exec.Types: instance Ord RewriteResult
+ Language.Maude.Exec.Types: instance Ord SearchResult
+ Language.Maude.Exec.Types: instance Ord Substitution
+ Language.Maude.Exec.Types: instance Show MaudeCommand
+ Language.Maude.Exec.Types: instance Show MaudeConf
+ Language.Maude.Exec.Types: instance Show MaudeException
+ Language.Maude.Exec.Types: instance Show MaudeResult
+ Language.Maude.Exec.Types: instance Show MaudeStatistics
+ Language.Maude.Exec.Types: instance Show RewriteResult
+ Language.Maude.Exec.Types: instance Show SearchResult
+ Language.Maude.Exec.Types: instance Show Substitution
+ Language.Maude.Exec.Types: instance Typeable MaudeCommand
+ Language.Maude.Exec.Types: instance Typeable MaudeConf
+ Language.Maude.Exec.Types: instance Typeable MaudeException
+ Language.Maude.Exec.Types: instance Typeable MaudeResult
+ Language.Maude.Exec.Types: instance Typeable MaudeStatistics
+ Language.Maude.Exec.Types: instance Typeable RewriteResult
+ Language.Maude.Exec.Types: instance Typeable SearchResult
+ Language.Maude.Exec.Types: instance Typeable Substitution
+ Language.Maude.Exec.Types: loadFiles :: MaudeConf -> [FilePath]
+ Language.Maude.Exec.Types: maudeCmd :: MaudeConf -> FilePath
+ Language.Maude.Exec.Types: maudeFailureExitCode :: MaudeException -> ExitCode
+ Language.Maude.Exec.Types: maudeFailureStderr :: MaudeException -> Text
+ Language.Maude.Exec.Types: maudeFailureStdout :: MaudeException -> Text
+ Language.Maude.Exec.Types: maudeStdout :: MaudeResult -> Text
+ Language.Maude.Exec.Types: maudeXmlLog :: MaudeResult -> Text
+ Language.Maude.Exec.Types: realTime :: MaudeStatistics -> Integer
+ Language.Maude.Exec.Types: resultTerm :: RewriteResult -> Term
+ Language.Maude.Exec.Types: rewriteStatistics :: RewriteResult -> MaudeStatistics
+ Language.Maude.Exec.Types: searchResult :: SearchResult -> Substitution
+ Language.Maude.Exec.Types: searchSolutionNumber :: SearchResult -> Integer
+ Language.Maude.Exec.Types: searchStatistics :: SearchResult -> MaudeStatistics
+ Language.Maude.Exec.Types: totalRewrites :: MaudeStatistics -> Integer
+ Language.Maude.Exec.Types: type SearchResults = [SearchResult]
+ Language.Maude.Syntax: IterTerm :: String -> String -> [Term] -> Integer -> Term
+ Language.Maude.Syntax: Term :: String -> String -> [Term] -> Term
+ Language.Maude.Syntax: data Term
+ Language.Maude.Syntax: instance Data Term
+ Language.Maude.Syntax: instance Eq Term
+ Language.Maude.Syntax: instance Ord Term
+ Language.Maude.Syntax: instance Show Term
+ Language.Maude.Syntax: instance Typeable Term
+ Language.Maude.Syntax: iterations :: Term -> Integer
+ Language.Maude.Syntax: termChildren :: Term -> [Term]
+ Language.Maude.Syntax: termOp :: Term -> String
+ Language.Maude.Syntax: termSort :: Term -> String

Files

+ README.md view
@@ -0,0 +1,10 @@+# About++This package provides a simple interface for doing [Maude](http://maude.cs.uiuc.edu/) rewrites from within Haskell.+See the [Haddock documentation](http://hackage.haskell.org/packages/archive/maude/latest/doc/html/Foreign-Maude.html) for examples.++# Contributing++This project is available on [GitHub](https://github.com/davidlazar/maude-hs) and [Bitbucket](https://bitbucket.org/davidlazar/maude-hs/). You may contribute changes using either.++Please report bugs and feature requests using the [GitHub issue tracker](https://github.com/davidlazar/maude-hs/issues).
maude.cabal view
@@ -1,5 +1,5 @@ Name:               maude-Version:            0.3.0+Version:            0.6.1 Synopsis:           An interface to the Maude rewriting system. Description:        This package provides a simple interface for doing Maude                     rewrites from within Haskell.@@ -8,15 +8,35 @@ License-file:       LICENSE Author:             David Lazar Maintainer:         David Lazar <lazar6@illinois.edu>-Category:           Foreign+Category:           Language Build-type:         Simple Cabal-version:      >=1.6+Extra-source-files:+  README.md  source-repository head   Type:             git   Location:         https://github.com/davidlazar/maude-hs  Library+  ghc-options:      -Wall+   Hs-source-dirs:   src-  Exposed-modules:  Foreign.Maude-  Build-depends:    base >= 4 && < 5, process, directory, text, parsec >= 3.1.2++  Exposed-modules:+    Language.Maude.Exec+    Language.Maude.Exec.Types+    Language.Maude.Syntax++  Other-modules:+    Language.Maude.Exec.XML++  Build-depends:+    base >= 4 && < 5,+    process,+    process-extras,+    filepath,+    directory,+    temporary,+    text,+    xml
− src/Foreign/Maude.hs
@@ -1,303 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--------------------------------------------------------------------------------- |--- Module      :  Foreign.Maude--- Copyright   :  (c) David Lazar, 2011--- License     :  MIT------ Maintainer  :  lazar6@illinois.edu--- Stability   :  experimental--- Portability :  unknown------ This package provides a simple interface (via the 'rewrite' and 'search'--- functions) for doing Maude rewrites from within Haskell.  The following--- steps are performed every time Maude is executed by this library:------ 1. A temporary file is created that contains the necessary commands.------ 2. The temporary file (with any other input files) is executed by Maude.------ 3. The temporary file is removed.------ 4. The output from step 2 is parsed and returned.------ This is a simple way to perform a single rewrite command, but it is--- inefficient for performing many rewrite commands.  See /Future Work/--- below.--------------------------------------------------------------------------------module Foreign.Maude-    (-    -- * Configuration-      MaudeConf(..)-    , defaultConf--    -- * Maude commands-    , Term-    , Pattern-    , MaudeCommand(..)--    -- * Invoking Maude-    , RewriteResult(..)-    , SearchResult(..)-    , rewrite-    , search-    , runMaude--    -- * Parsing Maude's output-    , parseRewriteResult-    , parseSearchResults--    -- * Examples-    -- $examples--    -- * Future Work-    -- $future-    ) where--import Control.Applicative ((<$>))-import Control.Monad (when)-import Data.Char (digitToInt)-import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.IO as T-import System.IO (hPutStr, hPutStrLn, hClose, openTempFile)-import System.Directory (getCurrentDirectory, removeFile)-import System.Process (readProcess)-import Text.Parsec-import Text.Parsec.Text---- | Configuration of Maude's execution.-data MaudeConf = MaudeConf-    { maudeCmd    :: FilePath   -- ^ Path to the Maude executable.-    , loadFiles   :: [FilePath] -- ^ Files to load before running a command.-    , printParens :: Bool       -- ^ Whether Maude should print with parentheses.-    } deriving (Eq, Show)---- | The default Maude configuration.-defaultConf :: MaudeConf-defaultConf = MaudeConf-    { maudeCmd    = "maude"-    , loadFiles   = []-    , printParens = False-    }---- | Maude option flags which force Maude's output to be as relevant as--- possible.-maudeArgs :: [String]-maudeArgs =-    [ "-no-banner"-    , "-no-advise"-    , "-no-wrap"-    , "-no-ansi-color"-    ]---- | Synonym for text to be manipulated by Maude.-type Term = Text---- | Synonym for text representing a search pattern; see 'search'.-type Pattern = Text---- Commands used in Maude.-data MaudeCommand-    = Rewrite Term-    | Search Term Pattern-    deriving (Show)---- | The result of a Maude rewrite.-data RewriteResult = RewriteResult-    { resultSort :: Text  -- ^ The sort of the rewritten term.-    , resultTerm :: Text  -- ^ The rewritten term.-    , statistics :: Text  -- ^ Statistics printed by Maude.-    } deriving (Show)---- | A single Maude search result.-data SearchResult = SearchResult-    { searchResultState :: Integer-    , searchStatistics  :: Text-    , searchResultTerm  :: Text-    } deriving (Show)---- | @rewrite files term@ performs a single Maude rewrite command on--- @term@ with @files@ loaded.-rewrite :: [FilePath] -> Term -> IO (Maybe RewriteResult)-rewrite files term = parseRewriteResult-                 <$> runMaude defaultConf{ loadFiles = files } (Rewrite term)---- | @search files term pattern@ uses Maude to search for all reachable--- states starting from @term@ and matching the given @pattern@. Note that--- @pattern@ should also include the search type. For example,------ >>> search [] term "=>! N:Nat"----search :: [FilePath] -> Term -> Pattern -> IO (Maybe [SearchResult])-search files term pattern = parseSearchResults-                        <$> runMaude defaultConf{ loadFiles = files } cmd-    where cmd = Search term pattern---- | @runMaude conf cmd@ runs the Maude using the configuration @conf@--- and performs the command @cmd@.-runMaude :: MaudeConf -> MaudeCommand -> IO Text-runMaude conf cmd = do-    runner <- newRunnerFile conf cmd-    let args = maudeArgs ++ [runner]-    out <- readProcess (maudeCmd conf) args []-    removeFile runner-    return $ T.pack out---- | Parse Maude's output into a RewriteResult.  The current implementation--- does very little sanity checking and can not parse Maude failures.-parseRewriteResult :: Text -> Maybe RewriteResult-parseRewriteResult txt =-    case parse pRewriteResult "" txt of-        Left _ -> Nothing-        Right r -> Just r---- | Parse the output of a successful @search@ command.-parseSearchResults :: Text -> Maybe [SearchResult]-parseSearchResults txt =-    case parse pSearchResults "" txt of-        Left _ -> Nothing-        Right r -> Just r---- | Parsec parser that parses the output of a successful Maude--- rewrite command.-pRewriteResult :: Parser RewriteResult-pRewriteResult = do-    optional (string "Maude>")-    spaces-    stats <- pLine-    string "result"-    spaces-    sort <- many1 (satisfy (/= ':'))-    char ':'-    spaces-    lines <- many1 pLine-    let term = T.concat . filter (/= "Bye.") $ lines-    return $ RewriteResult-        { resultSort = T.pack sort-        , resultTerm = term-        , statistics = stats-        }---- | Parsec parser that parses the output of a successful Maude--- search command.-pSearchResults :: Parser [SearchResult]-pSearchResults = do-    optional (symbol "Maude>")-    spaces-    pSearchResult `endBy1` newline---- | Parsec parser that parses a single search result.-pSearchResult :: Parser SearchResult-pSearchResult = do-    symbol "Solution"-    integer-    spaces-    state <- parens (symbol "state" >> integer)-    newline-    stats <- pLine-    var <- many1 (satisfy (/= ' '))-    spaces-    symbol "-->"-    lines <- many1 pLine-    let term = T.concat lines-    return $ SearchResult-        { searchResultState = state-        , searchStatistics = stats-        , searchResultTerm = term-        }---- | Parse a single line.-pLine :: Parser Text-pLine = do-    x <- many1 (satisfy (/= '\n'))-    newline-    return $ T.pack x---- | Create a temporary file which contains the commands Maude should run at--- startup: load file commands, formatting commands, the command to execute,--- and the quit command.-newRunnerFile :: MaudeConf -> MaudeCommand -> IO FilePath-newRunnerFile conf cmd = do-    currDir <- getCurrentDirectory-    (tmpf, tmph) <- openTempFile currDir "runner.maude"-    mapM_ (\f -> T.hPutStr tmph "load " >> hPutStrLn tmph f) (loadFiles conf)-    when (printParens conf) $-        T.hPutStrLn tmph "set print with parentheses on ."-    T.hPutStrLn tmph "set show command off ."-    T.hPutStr tmph (toTxt cmd)-    T.hPutStrLn tmph " ."-    T.hPutStrLn tmph "quit"-    hClose tmph-    return tmpf-    where toTxt (Rewrite term) = T.append "rewrite " term-          toTxt (Search term pat) = T.intercalate " " ["search", term, pat]----- Lexers:--integer = number 10 digit--parens = between (char '(') (char ')')--symbol s = do { x <- string s; spaces; return x }---- copied from Parsec:-number base baseDigit-    = do { digits <- many1 baseDigit-         ; let n = foldl (\x d -> base * x + toInteger (digitToInt d)) 0 digits-         ; seq n (return n)-         }--{- $examples--Maude's standard prelude is loaded by default, even when no input files are-specified:-->>> rewrite [] "not (A:Bool or B:Bool) implies (not A:Bool) and (not B:Bool)"-Just (RewriteResult-    { resultSort = "Bool"-    , resultTerm = "true"-    , statistics = "rewrites: 13 in 0ms cpu (0ms real) (~ rewrites/second)"-    })--The name of the module in which to reduce a term can be given explicitly:-->>> rewrite [] "in NAT-LIST : reverse(1 2 3 4)"-Just (RewriteResult-    { resultSort = "NeNatList"-    , resultTerm = "4 3 2 1"-    , statistics = "rewrites: 6 in 0ms cpu (0ms real) (~ rewrites/second)"-    })--Using a naive implementation of primes in Maude:-->>> rewrite ["primes.maude"] "2 .. 20"-Just (RewriteResult-    { resultSort = "PrimeSet"-    , resultTerm = "2 3 5 7 11 13 17 19"-    , statistics = "rewrites: 185 in 0ms cpu (0ms real) (~ rewrites/second)"-    })--If we are only interested in the statistics:-->>> liftM statistics <$> rewrite ["primes.maude"] "2 .. 1000"-Just "rewrites: 409905 in 839ms cpu (856ms real) (488014 rewrites/second)"--}--{- $future--This Maude interface is very minimal first step.  It could be extended in the-following ways:--* Better handling of Maude failures.  Failure messages should be parsed and-  returned to the user.--* Support for other Maude commands besides @rewrite@. --* A Maude monad that handles failure and multiple Maude commands efficiently-  is a long-term goal for this package.--* Consider taking of advantage of Maude's -xml-log option.--}
+ src/Language/Maude/Exec.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Language.Maude.Exec+-- Copyright   :  (c) David Lazar, 2012+-- License     :  MIT+--+-- Maintainer  :  lazar6@illinois.edu+-- Stability   :  experimental+-- Portability :  unknown+--+-- This package provides a simple interface to the Maude executable for+-- doing Maude rewrites from within Haskell.+--+-- Note: Maude is considered to have failed if it ever prints to stderr.+-----------------------------------------------------------------------------++module Language.Maude.Exec+    (+      module Language.Maude.Exec.Types++    -- * High-level interface+    , rewrite+    , search++    -- * Low-level interface+    , runMaude+    , defaultConf+    ) where++import Control.Exception+import Control.Monad (when)+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import System.IO (hClose)+import System.IO.Temp+import System.Directory (getCurrentDirectory)+import System.Exit+import System.Process.Text (readProcessWithExitCode)+import Text.XML.Light (parseXMLDoc)++import Language.Maude.Exec.Types+import Language.Maude.Exec.XML++-- | @rewrite files term@ rewrites @term@ using Maude (with @files@ loaded).+--+-- This function may throw a 'MaudeException'.+rewrite :: [FilePath] -> Text -> IO RewriteResult+rewrite files term = do+    let cmd = Rewrite term+    maudeResult <- runMaude defaultConf{ loadFiles = files } cmd+    let maybeXml = parseXMLDoc $ maudeXmlLog maudeResult+    xml <- maybe (throwIO LogToXmlFailure) return maybeXml+    case parseRewriteResult xml of+        ParseError e s -> throwIO $ XmlToResultFailure s e+        Ok a -> return a++-- | @search files term pattern@ uses Maude (with @files@ loaded) to search+-- for all reachable states starting from @term@ and matching the given+-- @pattern@. Note that @pattern@ should also include the search type.+-- For example,+--+-- >>> search [] term "=>! N:Nat"+--+-- runs the Maude command @search term =>! N:Nat@.+--+-- This function may throw a 'MaudeException'.+search :: [FilePath] -> Text -> Text -> IO SearchResults+search files term pattern = do+    let cmd = Search term pattern+    maudeResult <- runMaude defaultConf{ loadFiles = files } cmd+    let maybeXml = parseXMLDoc $ maudeXmlLog maudeResult+    xml <- maybe (throwIO LogToXmlFailure) return maybeXml+    case parseSearchResults xml of+        ParseError e s -> throwIO $ XmlToResultFailure s e+        Ok a -> return a++-- | @runMaude conf cmd@ performs the Maude command @cmd@ using the+-- configuration @conf@.+--+-- This function may throw a 'MaudeException'.+runMaude :: MaudeConf -> MaudeCommand -> IO MaudeResult+runMaude conf cmd = do+    currDir <- getCurrentDirectory+    withTempFile currDir "maudelog.xml" $ \xmlFile xmlHandle -> do+        hClose xmlHandle -- we don't need it+        let exe = maudeCmd conf+        let args = maudeArgs xmlFile ++ (loadFiles conf)+        let input = mkMaudeInput cmd+        (exitCode, out, err) <- readProcessWithExitCode exe args input+        when (not (T.null err) || exitCode /= ExitSuccess) $+            throwIO $ MaudeFailure+                { maudeFailureExitCode = exitCode+                , maudeFailureStderr = err+                , maudeFailureStdout = out+                }+        xmlText <- T.readFile xmlFile+        return $ MaudeResult+            { maudeStdout = out+            , maudeXmlLog = xmlText+            }++-- | Default Maude configuration+defaultConf :: MaudeConf+defaultConf = MaudeConf+    { maudeCmd  = "maude"+    , loadFiles = []+    }++-- | Maude flags which force its output to be as relevant as possible+maudeArgs :: FilePath -> [String]+maudeArgs xmlFile =+    [ "-no-banner"+    , "-no-advise"+    , "-no-wrap"+    , "-no-ansi-color"+    , "-xml-log=" ++ xmlFile+    ]++-- | Constructs the text that is sent to Maude.+mkMaudeInput :: MaudeCommand -> Text+mkMaudeInput cmd = T.unlines $+    [ "set show command off ."+    , showCommand cmd+    , " ."+    , "quit"+    ]++showCommand :: MaudeCommand -> Text+showCommand (Rewrite term) = "rewrite " `T.append` term+showCommand (Erewrite term) = "erewrite " `T.append` term+showCommand (Search term pattern) = T.concat ["search ", term, " ", pattern]
+ src/Language/Maude/Exec/Types.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE DeriveDataTypeable #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Language.Maude.Exec.Types+-- Copyright   :  (c) David Lazar, 2012+-- License     :  MIT+--+-- Maintainer  :  lazar6@illinois.edu+-- Stability   :  experimental+-- Portability :  unknown+--+-- Types shared between modules in the Language.Maude.Exec namespace+-----------------------------------------------------------------------------+module Language.Maude.Exec.Types+    (+    -- * Error handling+      MaudeException(..)++    -- * Configuring Maude's execution+    , MaudeCommand(..)+    , MaudeConf(..)++    -- * Result types+    , MaudeResult(..)+    , RewriteResult(..)+    , SearchResult(..)+    , SearchResults+    , Substitution(..)+    , MaudeStatistics(..)+    ) where++import Control.Exception+import Data.Data+import Data.Text (Text)+import System.Exit (ExitCode)+import qualified Text.XML.Light as XML++import Language.Maude.Syntax++data MaudeException+    = MaudeFailure+        { maudeFailureExitCode :: ExitCode+        , maudeFailureStderr   :: Text+        , maudeFailureStdout   :: Text+        }+    -- ^ Thrown when the @maude@ executable fails+    | LogToXmlFailure+    -- ^ Thrown when the log produced by Maude is not parseable as XML+    | XmlToResultFailure String XML.Element+    -- ^ Thrown when the XML can't be parsed/translated to+    -- one of the result types below+    deriving (Typeable)++instance Exception MaudeException++instance Show MaudeException where+    showsPrec _ (MaudeFailure e err out)+        = showString "MaudeFailure (exitCode = " . showsPrec 0 e+        . showString ") (stderr = " . showsPrec 0 err+        . showString ") (stdout = " . showsPrec 0 out . showChar ')'+    showsPrec _ LogToXmlFailure = showString "LogToXmlFailure"+    showsPrec _ (XmlToResultFailure s e)+        = showString "XmlToResultFailure " . showsPrec 0 s+        . showString "\n" . showString (take n xml)+        . showString (if length xml > n then "..." else "")+      where+        n = 100+        xml = XML.showElement e++-- | Commands performed by Maude+data MaudeCommand+    = Rewrite Text+    | Erewrite Text+    | Search Text Text+    deriving (Eq, Ord, Show, Data, Typeable)++-- | Configuration of Maude's execution+data MaudeConf = MaudeConf+    { maudeCmd    :: FilePath+    -- ^ Path to the Maude executable+    , loadFiles   :: [FilePath]+    -- ^ Files to load before running a command+    } deriving (Eq, Ord, Show, Data, Typeable)++-- | Low-level Maude result+data MaudeResult+    = MaudeResult+        { maudeStdout :: Text+        -- ^ Text printed to standard out during execution+        , maudeXmlLog :: Text+        -- ^ XML log obtained via Maude's @--xml-log@ option+        }+    deriving (Eq, Ord, Show, Data, Typeable)++-- | High-level (e)rewrite result+data RewriteResult = RewriteResult+    { resultTerm        :: Term+    -- ^ The rewritten term+    , rewriteStatistics :: MaudeStatistics+    -- ^ Statistics about the rewrite performed+    } deriving (Eq, Ord, Show, Data, Typeable)++-- | High-level search result+data SearchResult = SearchResult+    { searchSolutionNumber :: Integer+    , searchStatistics     :: MaudeStatistics+    , searchResult         :: Substitution+    } deriving (Eq, Ord, Show, Data, Typeable)++-- | Several search results+type SearchResults = [SearchResult]++-- | Search result substitution+data Substitution = Substitution Term Term+    deriving (Eq, Ord, Show, Data, Typeable)++-- | Statistics returned by Maude after a successful command+data MaudeStatistics = MaudeStatistics+    { totalRewrites :: Integer+    -- ^ Total rewrites performed+    , realTime      :: Integer+    -- ^ Real time (milliseconds)+    , cpuTime       :: Integer+    -- ^ CPU time (milliseconds)+    } deriving (Eq, Ord, Show, Data, Typeable)
+ src/Language/Maude/Exec/XML.hs view
@@ -0,0 +1,119 @@+module Language.Maude.Exec.XML+    ( Parser(..)+    , parseRewriteResult+    , parseSearchResults+    ) where++import Control.Monad+import Text.XML.Light++import Language.Maude.Syntax+import Language.Maude.Exec.Types++data Parser a+    = ParseError Element String+    | Ok a+    deriving (Show)++instance Functor Parser where+    fmap _ (ParseError e s) = ParseError e s+    fmap f (Ok r) = Ok (f r)++instance Monad Parser where+    return = Ok+    ParseError e s >>= _ = ParseError e s+    Ok r >>= k = k r++-- <maudeml> (root)+parseRewriteResult :: Element -> Parser RewriteResult+parseRewriteResult e = parseRewriteResult' =<< child "result" e++-- <maudeml> (root)+parseSearchResults :: Element -> Parser SearchResults+parseSearchResults e = case results of+    [] -> ParseError e "no search results found"+    _  -> mapM parseSearchResult =<< actualResults+  where+    results = findChildren (unqual "search-result") e+    actualResults = filterM notNone results+    notNone e' = attr "solution-number" e' >>= return . (/= "NONE")++-- <result>+parseRewriteResult' :: Element -> Parser RewriteResult+parseRewriteResult' e = do+    stats <- parseStatistics e+    term <- case elChildren e of+        [e'] -> parseTerm e'+        _ -> ParseError e "expecting exactly one result child"+    return $ RewriteResult+        { resultTerm = term+        , rewriteStatistics = stats+        }++-- <result>+parseStatistics :: Element -> Parser MaudeStatistics+parseStatistics e = do+    rews <- readattr "total-rewrites" e+    real <- readattr "real-time-ms" e+    cpu  <- readattr "cpu-time-ms" e+    return $ MaudeStatistics rews real cpu++-- <search-result>+parseSearchResult :: Element -> Parser SearchResult+parseSearchResult e = do+    solution <- readattr "solution-number" e+    stats <- parseStatistics e+    subst <- parseSubstitution =<< child "substitution" e+    return $ SearchResult+        { searchSolutionNumber = solution+        , searchStatistics = stats+        , searchResult = subst+        }++-- <substitution>+parseSubstitution :: Element -> Parser Substitution+parseSubstitution e = do+    assignment <- child "assignment" e+    -- TODO: better error handling+    [s, t] <- mapM parseTerm (elChildren assignment)+    return $ Substitution s t++-- <term>+parseTerm :: Element -> Parser Term+parseTerm e = do+    sort <- parseSort e+    op <- attr "op" e+    children <- mapM parseTerm (elChildren e)+    case findAttr (unqual "number") e of+        Nothing -> return $ Term sort op children+        Just i -> return $ IterTerm sort op children (read i)++-- <term>+parseSort :: Element -> Parser String+parseSort e = fromMaybeM err $ sort `mplus` synt+  where+    sort = findAttr (unqual "sort") e+    synt = findAttr (unqual "syntactic-sort") e+    err = ParseError e "key 'sort' or 'syntactic-sort' not found"++{- utility functions -}++child :: String -> Element -> Parser Element+child tag e = fromMaybeM err $ findChild (unqual tag) e+  where+    err = ParseError e $ "child not found: <" ++ tag ++ ">"++attr :: String -> Element -> Parser String+attr key e = fromMaybeM err $ findAttr (unqual key) e+  where+    err = ParseError e $ "key not found: " ++ key++readattr :: Read a => String -> Element -> Parser a+readattr key e = do+    s <- attr key e+    case reads s of+        [(a, "")] -> return a+        _ -> ParseError e $ "failed to read value of key: " ++ key++fromMaybeM :: Monad m => m a -> Maybe a -> m a+fromMaybeM err = maybe err return
+ src/Language/Maude/Syntax.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE DeriveDataTypeable #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Language.Maude.Syntax+-- Copyright   :  (c) David Lazar, 2012+-- License     :  MIT+--+-- Maintainer  :  lazar6@illinois.edu+-- Stability   :  experimental+-- Portability :  unknown+--+-- Types representing Maude syntax and terms+-----------------------------------------------------------------------------+module Language.Maude.Syntax+    ( Term(..)+    ) where++import Data.Data++-- TODO: handle kinds++data Term+    = Term+        { termSort     :: String+        , termOp       :: String+        , termChildren :: [Term]+        }+    -- ^ Generic representation of terms in Maude+    | IterTerm+        { termSort     :: String+        , termOp       :: String+        , termChildren :: [Term]+        , iterations   :: Integer+        }+    -- ^ Term constructed from an iterated (@iter@) operator,+    -- for example, the @s_@ constructor for Nats+    deriving (Eq, Ord, Show, Data, Typeable)