hoq-0.3: src/Syntax/Parser.hs
module Syntax.Parser
( pDefs, pExpr
, fixFixity, fixFixityDef
) where
import Data.Maybe
import Control.Monad.State
import qualified Data.ByteString as B
import Syntax
import Syntax.ErrorDoc
import Syntax.Parser.Lexer
import qualified Syntax.Parser.Parser as P
import TypeChecking.Monad.Warn
import TypeChecking.Expressions.Utils
pDefs :: Monad m => B.ByteString -> WarnT [Error] m [Def]
pDefs = liftM reverse . runParser P.pDefs
pExpr :: Monad m => [(Name,Fixity)] -> B.ByteString -> WarnT [Error] m RawExpr
pExpr tab str = runParser P.pExpr str >>= fixFixity tab
runParser :: Monad m => Parser a -> B.ByteString -> WarnT [Error] m a
runParser p s = case evalState (runWarnT $ p ((1, 1), s)) [Layout 1] of
(errs, Nothing) -> throwError (mapErrs errs)
(errs, Just a) -> warn (mapErrs errs) >> return a
where
mapErrs = map $ \(pos, err) -> Error Other $ emsgLC pos err enull
data Tree p a = Branch Fixity Name Syntax (Tree p a) (Tree p a) | Leaf (Term (p, Syntax) a)
fixFixity :: Monad m => [(Name,Fixity)] -> Term (Posn, Syntax) a -> WarnT [Error] m (Term (Posn, Syntax) a)
fixFixity tab = go
where
go :: Monad m => Term (Posn, Syntax) a -> WarnT [Error] m (Term (Posn, Syntax) a)
go = liftM treeToExpr . exprToTree
exprToTree :: Monad m => Term (Posn, Syntax) a -> WarnT [Error] m (Tree Posn a)
exprToTree (Var a ts) = liftM (Leaf . Var a) (mapM go ts)
exprToTree (Lambda t) = liftM (Leaf . Lambda) (go t)
exprToTree (Apply (_, Name Infix{} s) [t1, t2]) = do
t1' <- exprToTree t1
t2' <- go t2
let ft = fromMaybe (Infix InfixL 90) (lookup s tab)
branch ft s (Name ft s) t1' (Leaf t2')
exprToTree (Apply (_, At) [t1,t2]) = do
t1' <- exprToTree t1
t2' <- go t2
branch (Infix InfixL 90) (Operator "@") At t1' (Leaf t2')
exprToTree (Apply (_, Null) (t:ts)) = liftM Leaf $ go (apps t ts)
exprToTree (Apply s ts) = liftM (Leaf . Apply s) (mapM go ts)
treeToExpr :: Tree Posn a -> Term (Posn, Syntax) a
treeToExpr (Leaf t) = t
treeToExpr (Branch ft _ s t1 t2) =
let t1' = treeToExpr t1
in Apply (termPos t1', s) [t1', treeToExpr t2]
branch :: Monad m => Fixity -> Name -> Syntax -> Tree Posn a -> Tree Posn a -> WarnT [Error] m (Tree Posn a)
branch ft@(Infix ia p) n s (Branch ft'@(Infix ia' p') n' s' a1 a2) b | p' < p || p == p' && ia == InfixR && ia' == InfixR = do
a2' <- branch ft n s a2 b
return (Branch ft' n' s' a1 a2')
branch ft@(Infix ia p) n s a@(Branch ft'@(Infix ia' p') n' _ _ _) b | p == p' && not (ia == InfixL && ia' == InfixL) = do
let showOp ft'' s'' = nameToInfix s'' ++ " [" ++ show ft'' ++ "]"
msg = "Precedence parsing error: cannot mix " ++ showOp ft n ++
" and " ++ showOp ft' n' ++ " in the same infix expression"
warn [Error Other $ emsgLC (termPos $ treeToExpr a) msg enull]
return (Branch ft n s a b)
branch ft name syn a b = return (Branch ft name syn a b)
fixFixityDef :: Monad m => [(Name,Fixity)] -> Def -> WarnT [Error] m Def
fixFixityDef tab (DefType name expr) = liftM (DefType name) (fixFixity tab expr)
fixFixityDef tab (DefFun name pats (Just expr)) = liftM (DefFun name pats . Just) (fixFixity tab expr)
fixFixityDef _ d@DefFun{} = return d
fixFixityDef tab (DefData name params cons clauses) = do
params' <- forM params (fixFixityTele tab)
cons' <- forM cons $ \(ConDef con teles) -> liftM (ConDef con) $ forM teles (fixFixityTele tab)
clauses' <- forM clauses $ \(Clause name pats expr) -> liftM (Clause name pats) (fixFixity tab expr)
return (DefData name params' cons' clauses')
fixFixityDef tab (DefRecord name params mcon fields clauses) = do
params' <- forM params (fixFixityTele tab)
fields' <- forM fields $ \(Field name expr) -> liftM (Field name) (fixFixity tab expr)
clauses' <- forM clauses $ \(Clause name pats expr) -> liftM (Clause name pats) (fixFixity tab expr)
return (DefRecord name params' mcon fields' clauses')
fixFixityDef _ d@DefImport{} = return d
fixFixityDef _ d@DefFixity{} = return d
fixFixityTele :: Monad m => [(Name,Fixity)] -> Tele -> WarnT [Error] m Tele
fixFixityTele tab (VarsTele e vars expr) = liftM (VarsTele e vars) (fixFixity tab expr)
fixFixityTele tab (TypeTele e expr) = liftM (TypeTele e ) (fixFixity tab expr)