module Language.Clafer.IG.CommandLineParser (Command(..), UnsatCoreMinimization(..), parseCommandLine, parseCommandLineAutoComplete, commandStrings, expectedMessage, unexpectedMessage, errorMessages) where
import Control.Monad
import Data.List
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Error
import Text.Parsec.Prim hiding (try)
import Data.Functor.Identity
data Command = Next |
IncreaseGlobalScope Integer |
IncreaseScope String Integer |
SetGlobalScope Integer |
SetScope String Integer |
SetBitwidth Integer |
SetMaxInt Integer |
Save |
Quit |
Reload |
Help |
Find String |
ShowScopes |
SaveScopes |
LoadScopes |
ShowClaferModel |
ShowAlloyModel |
ShowAlloyInstance |
SetUnsatCoreMinimization UnsatCoreMinimization deriving Show
data UnsatCoreMinimization = Fastest | Medium | Best deriving Show
unexpectedMessage :: Message -> Maybe String
unexpectedMessage (SysUnExpect x) = Just x
unexpectedMessage (UnExpect x) = Just x
unexpectedMessage _ = Nothing
expectedMessage :: Message -> Maybe String
expectedMessage (Expect x) = Just x
expectedMessage _ = Nothing
parseCommandLine :: String -> Either ParseError Command
parseCommandLine input =
if null input then Right Next
else parse doParse "ClaferAlloyIG" input
where
doParse =
do
skipMany (space <?> "")
c <- commandLine
skipMany (space <?> "")
eof
return c
parseCommandLineAutoComplete :: String -> ParseError
parseCommandLineAutoComplete input =
case parse doParse "ClaferAlloyIG autocomplete" input of
Left e -> e
Right _ -> error "Failed at failing."
where
doParse =
do
skipMany (space <?> "")
_ <-commandLine
fail "reached end"
commandLine :: Parser Command
commandLine =
do
name <- command
case lookup name commandMap of
Just x -> x
Nothing ->
fail $ "Unknown command \"" ++ name ++ "\"" ++ hint didYouMean
where
quote x = '"' : x ++ "\""
didYouMean = filter (name `isPrefixOf`) commandStrings
hint [] = ""
hint _ = ", did you mean " ++ intercalate " or " (map quote didYouMean) ++ "?"
command :: Parser String
command = many1 (letter <?> "command")
commandStrings :: [String]
commandStrings = map fst commandMap
commandMap :: [(String, Parser Command)]
commandMap =
("h", helpCommand):
("i", increaseCommand):
("s", setCommand):
("b", setBitwidthCommand):
("m", setMaxIntCommand):
("maxint", setMaxIntCommand):
("n", nextCommand):
("f", findCommand):
("q", quitCommand):
("v", saveCommand):
("r", reloadCommand):
("scope", showScopesCommand):
("saveScopes", saveScopesCommand):
("loadScopes", loadScopesCommand):
("claferModel", claferModelCommand):
("c", claferModelCommand):
("alloyModel", alloyModelCommand):
("a", alloyModelCommand):
("alloyInstance", alloyInstanceCommand):
("setUnsatCoreMinimization", setUnsatCoreMinimization):
[]
helpCommand :: ParsecT String () Identity Command
helpCommand = return Help
increaseCommand :: Parser Command
increaseCommand = increaseGlobalScope
setCommand :: Parser Command
setCommand = setGlobalScope
setBitwidthCommand :: Parser Command
setBitwidthCommand = setBitwidth
setMaxIntCommand :: Parser Command
setMaxIntCommand = setMaxInt
nextCommand :: ParsecT String () Identity Command
nextCommand = return Next
quitCommand :: ParsecT String () Identity Command
quitCommand = return Quit
saveCommand :: ParsecT String () Identity Command
saveCommand = return Save
reloadCommand :: ParsecT String () Identity Command
reloadCommand = return Reload
findCommand :: ParsecT String () Identity Command
findCommand = Find `liftM` (gap >> claferInstance)
showScopesCommand :: ParsecT String () Identity Command
showScopesCommand = return ShowScopes
saveScopesCommand :: ParsecT String () Identity Command
saveScopesCommand = return SaveScopes
loadScopesCommand :: ParsecT String () Identity Command
loadScopesCommand = return LoadScopes
claferModelCommand :: ParsecT String () Identity Command
claferModelCommand = return ShowClaferModel
alloyModelCommand :: ParsecT String () Identity Command
alloyModelCommand = return ShowAlloyModel
alloyInstanceCommand :: ParsecT String () Identity Command
alloyInstanceCommand = return ShowAlloyInstance
setUnsatCoreMinimization :: ParsecT String () Identity Command
setUnsatCoreMinimization = SetUnsatCoreMinimization `liftM` (gap >> unsatCoreMinimization)
gap :: ParsecT String () Identity ()
gap = skipMany1 space
increaseGlobalScope :: Parser Command
increaseGlobalScope =
do
try (gap >> explicitIncreaseGlobalScope)
<|>
return (IncreaseGlobalScope 1)
setGlobalScope :: Parser Command
setGlobalScope =
do
try (gap >> explicitSetGlobalScope)
<|>
do
try (gap >> explicitSetScope)
explicitIncreaseGlobalScope :: Parser Command
explicitIncreaseGlobalScope =
fmap IncreaseGlobalScope signedNumber
<|>
increaseScope
explicitSetGlobalScope :: Parser Command
explicitSetGlobalScope = fmap SetGlobalScope number
increaseScope :: Parser Command
increaseScope =
do
name <- clafer
do
try (gap >> explicitIncreaseScope name)
<|>
return (IncreaseScope name 1)
explicitIncreaseScope :: String -> Parser Command
explicitIncreaseScope name = fmap (IncreaseScope name) signedNumber
explicitSetScope :: Parser Command
explicitSetScope =
do
name <- clafer
gap
i <- number
return (SetScope name i)
setBitwidth :: Parser Command
setBitwidth =
do
gap
b <- number
return $ SetBitwidth b
setMaxInt :: Parser Command
setMaxInt =
do
gap
b <- number
return $ SetMaxInt b
number :: Parser Integer
number = do
n <- many1 digit
return $ read n
signedNumber :: Parser Integer
signedNumber = do
s <- option "" $ string "-"
n <- many1 digit
return $ read $ s ++ n
clafer :: Parser String
clafer = many1 ((alphaNum <|> char ':' <|> char '_') <?> "clafer")
claferInstance :: Parser String
claferInstance = many1 (alphaNum <?> "claferInstance")
unsatCoreMinimization :: Parser UnsatCoreMinimization
unsatCoreMinimization =
do
level <- many1 (letter <?> "Unsat core minimization level")
case level of
"fastest" -> return Fastest
"medium" -> return Medium
"best" -> return Best
x -> fail $ x ++ " is not a valid unsat core minimization level"