module Language.Egison.Parser.Pattern.Mode.Haskell
(
Expr
, parseExpr
, parseExprWithFixities
, ParseMode
, ParseFixity
, Fixity
, makeHaskellMode
, makeFixity
, makeParseFixity
, makeParseFixities
)
where
import Data.Functor ( void )
import Data.Maybe ( mapMaybe )
import Control.Monad.Except ( MonadError )
import Language.Haskell.Exts.Syntax ( QName(..)
, Exp(..)
, Name(..)
, ModuleName(..)
, Exp
)
import Language.Haskell.Exts.SrcLoc ( SrcSpanInfo )
import qualified Language.Haskell.Exts.Fixity as Haskell
( Fixity(..) )
import qualified Language.Haskell.Exts.Syntax as Haskell
( Assoc(..) )
import qualified Language.Haskell.Exts.Parser as Haskell
( parseExpWithMode
, ParseMode(..)
, ParseResult(..)
)
import qualified Language.Egison.Syntax.Pattern
as Egison
( Expr )
import qualified Language.Egison.Parser.Pattern
as Egison
( ParseMode(..)
, ParseFixity(..)
, Fixity(..)
, Associativity(..)
, parseExpr
)
import Language.Egison.Parser.Pattern ( Precedence(..)
, Errors
)
type Expr = Egison.Expr (QName ()) (Name ()) (Exp SrcSpanInfo)
type ParseMode = Egison.ParseMode (QName ()) (Name ()) (Exp SrcSpanInfo) String
type Fixity = Egison.Fixity (QName ())
type ParseFixity = Egison.ParseFixity (QName ()) String
resultToEither :: Haskell.ParseResult a -> Either String a
resultToEither (Haskell.ParseOk a ) = Right a
resultToEither (Haskell.ParseFailed _ e) = Left e
parseVarNameWithMode :: Haskell.ParseMode -> String -> Either String (Name ())
parseVarNameWithMode mode content =
case resultToEither $ Haskell.parseExpWithMode mode content of
Right (Var _ (UnQual _ name)) -> Right $ void name
Right e -> Left (show e ++ " is not a variable")
Left err -> Left err
parseNameWithMode :: Haskell.ParseMode -> String -> Either String (QName ())
parseNameWithMode mode content =
case resultToEither $ Haskell.parseExpWithMode mode content of
Right (Var _ name) -> Right $ void name
Right (Con _ name) -> Right $ void name
Right e -> Left (show e ++ " is not a name")
Left err -> Left err
makeFixity :: Haskell.Fixity -> Fixity
makeFixity (Haskell.Fixity assoc prec name) = fixity
where
fixity = Egison.Fixity (makeAssoc assoc) (Precedence prec) name
makeAssoc (Haskell.AssocRight ()) = Egison.AssocRight
makeAssoc (Haskell.AssocLeft ()) = Egison.AssocLeft
makeAssoc (Haskell.AssocNone ()) = Egison.AssocNone
makeParseFixity :: Fixity -> Maybe ParseFixity
makeParseFixity fixity = Egison.ParseFixity fixity <$> makeNameParser symbol
where
Egison.Fixity { Egison.symbol } = fixity
makeNameParser (UnQual () (Ident () n)) = Just $ makeIdentOpParser Nothing n
makeNameParser (UnQual () (Symbol () n)) =
Just $ makeSymbolOpParser Nothing n
makeNameParser (Qual () (ModuleName () m) (Ident () n)) =
Just $ makeIdentOpParser (Just m) n
makeNameParser (Qual () (ModuleName () m) (Symbol () n)) =
Just $ makeSymbolOpParser (Just m) n
makeNameParser (Special () _) = Nothing
makeIdentOpParser mModName ident content
| content == printed = Right ()
| otherwise = Left "not an operator name"
where printed = '`' : maybe ident (++ '.' : ident) mModName ++ "`"
makeSymbolOpParser mModName sym content
| content == printed = Right ()
| otherwise = Left "not an operator name"
where printed = maybe sym (++ '.' : sym) mModName
makeParseFixities :: [Haskell.Fixity] -> [ParseFixity]
makeParseFixities = mapMaybe $ makeParseFixity . makeFixity
makeHaskellMode :: Haskell.ParseMode -> ParseMode
makeHaskellMode mode@Haskell.ParseMode { Haskell.fixities } = Egison.ParseMode
{ Egison.fixities = maybe [] makeParseFixities fixities
, Egison.blockComment = Just ("{-", "-}")
, Egison.lineComment = Just "--"
, Egison.varNameParser = parseVarNameWithMode mode
, Egison.nameParser = parseNameWithMode mode
, Egison.valueExprParser = resultToEither . Haskell.parseExpWithMode mode
}
parseExpr
:: MonadError (Errors String) m => Haskell.ParseMode -> String -> m Expr
parseExpr mode@Haskell.ParseMode { Haskell.parseFilename } =
Egison.parseExpr (makeHaskellMode mode) parseFilename
parseExprWithFixities
:: MonadError (Errors String) m
=> Haskell.ParseMode
-> [Fixity]
-> String
-> m Expr
parseExprWithFixities mode@Haskell.ParseMode { Haskell.parseFilename } fixities
= Egison.parseExpr hsModeWithFixities parseFilename
where
hsMode = makeHaskellMode mode
hsModeWithFixities =
hsMode { Egison.fixities = mapMaybe makeParseFixity fixities }