packages feed

purescript-0.6.4.1: psci/Parser.hs

-----------------------------------------------------------------------------
--
-- Module      :  Parser
-- Copyright   :  (c) Phil Freeman 2014
-- License     :  MIT
--
-- Maintainer  :  Phil Freeman <paf31@cantab.net>
-- Stability   :  experimental
-- Portability :
--
-- |
-- Parser for PSCI.
--
-----------------------------------------------------------------------------

module Parser (
    parseCommand
  ) where

import Prelude hiding (lex)

import Commands

import Data.Char (isSpace)

import Control.Applicative hiding (many)

import Text.Parsec hiding ((<|>))

import qualified Language.PureScript as P
import qualified Language.PureScript.Parser.Common as C (mark, same)

-- |
-- Parses PSCI metacommands or expressions input from the user.
--
parseCommand :: String -> Either String Command
parseCommand cmdString =
  case splitCommand cmdString of
    Just ('?', _) -> return Help
    Just ('q', _) -> return Quit
    Just ('r', _) -> return Reset
    Just ('i', moduleName) -> Import <$> parseRest P.moduleName moduleName
    Just ('b', moduleName) -> Browse <$> parseRest P.moduleName moduleName
    Just ('m', filename) -> return $ LoadFile (trimEnd filename)
    Just ('s', command) -> return $ Show (trimEnd command)
    Just ('t', expr) -> TypeOf <$> parseRest P.parseValue expr
    Just ('k', ty) -> KindOf <$> parseRest P.parseType ty
    Just _ -> Left $ "Unrecognized command. Type :? for help."
    Nothing -> parseRest (psciLet <|> psciExpression) cmdString
  where
  parseRest :: P.TokenParser a -> String -> Either String a
  parseRest p s = either (Left . show) Right $ do
    ts <- P.lex "" s
    P.runTokenParser "" (p <* eof) ts

  trimEnd :: String -> String
  trimEnd = reverse . dropWhile isSpace . reverse

  -- |
  -- Split a command into a command char and the trailing string
  --
  splitCommand :: String -> Maybe (Char, String)
  splitCommand (':' : c : s) = Just (c, dropWhile isSpace s)
  splitCommand _ = Nothing

  -- |
  -- Parses expressions entered at the PSCI repl.
  --
  psciExpression :: P.TokenParser Command
  psciExpression = Expression <$> P.parseValue

  -- |
  -- PSCI version of @let@.
  -- This is essentially let from do-notation.
  -- However, since we don't support the @Eff@ monad,
  -- we actually want the normal @let@.
  --
  psciLet :: P.TokenParser Command
  psciLet = Let <$> (P.Let <$> (P.reserved "let" *> P.indented *> manyDecls))
    where
    manyDecls :: P.TokenParser [P.Declaration]
    manyDecls = C.mark (many1 (C.same *> P.parseDeclaration))