elm-repl-0.2.1: src/Parse.hs
module Parse where
import Data.Functor ((<$), (<$>))
import Text.Parsec
import qualified Data.Char as Char
import qualified Data.List as List
import Action
type Parser = Parsec String ()
input :: String -> Action
input inp = case parse result "" inp of
Left err -> Command . Help . Just . show $ err
Right act -> act
result :: Parser Action
result = do
spaces
skip <|> cmd <|> term
where
skip = Skip <$ eof
cmd = char ':' >> Command <$> command
term = Code . mkTerm <$> many anyChar
command :: Parser Command
command = do
flag <- many1 notSpace
spaces
case flag of
"exit" -> basicCommand Exit
"reset" -> basicCommand Reset
"help" -> basicCommand $ Help Nothing
"flags" -> basicCommand (InfoFlags Nothing) <|> flags
_ -> return $ Help . Just $ flag
where basicCommand cmd = cmd <$ eof
flags :: Parser Command
flags = do
flag <- many1 notSpace
case flag of
"add" -> srcDirFlag AddFlag
"remove" -> srcDirFlag RemoveFlag
"list" -> return ListFlags
"clear" -> return ClearFlags
_ -> return $ InfoFlags . Just $ flag
where srcDirFlag ctor = do
many1 space
ctor <$> srcDir
notSpace :: Parser Char
notSpace = satisfy $ not . Char.isSpace
srcDir :: Parser String
srcDir = do
string "--src-dir="
dir <- manyTill anyChar (choice [ space >> return (), eof ])
return $ "--src-dir=" ++ dir
mkTerm :: String -> Term
mkTerm src = (src, mkCode src)
mkCode :: String -> Maybe Def
mkCode src
| List.isPrefixOf "import " src =
let name = getFirstCap . words $ src
getFirstCap (tok@(c:_):rest) = if Char.isUpper c
then tok
else getFirstCap rest
getFirstCap _ = src
in Just $ Import name
| List.isPrefixOf "data " src =
let name = takeWhile (/=' ') . drop 5 $ src
in Just $ DataDef name
| otherwise = case break (=='=') src of
(_,"") -> Nothing
(beforeEquals, _:c:_)
| Char.isSymbol c || hasLet beforeEquals || hasBrace beforeEquals ->
Nothing
| otherwise -> Just . VarDef $ declName beforeEquals
_ -> error "Parse.hs: Case error. Please submit bug report to https://github.com/elm-lang/elm-repl/issues."
where
declName pattern =
case takeWhile Char.isSymbol . dropWhile (not . Char.isSymbol) $ pattern of
"" -> takeWhile (/=' ') pattern
op -> op
hasLet = elem "let" . map token . words
where
isVarChar c = Char.isAlpha c || Char.isDigit c || elem c "_'"
token = takeWhile isVarChar . dropWhile (not . Char.isAlpha)
hasBrace = elem '{'