packages feed

Annotations-0.2.1: tests/MultiRec/ExprParser.hs

module MultiRec.ExprParser where

import Annotations.Bounds
import Annotations.BoundsParser
import MultiRec.ExprLexer
import MultiRec.Expr
import Annotations.MultiRec.ErrorAlg
import Annotations.MultiRec.ParserCombinators
import Annotations.Except
import Annotations.MultiRec.Annotated
import Annotations.MultiRec.Yield
import Annotations.MultiRec.Any

import qualified Text.Parsec as P

import Data.Maybe
import Control.Applicative
import Control.Monad.Identity

import Debug.Trace


type ExprParser = YP ExprToken Tuples Identity

pExpr :: ExprParser Expr
pExpr = do
  left <- getPos
  ex <- pAdd
  P.option ex $ do
    void (pToken TDoubleColon)
    ty <- pType
    mkBounded Expr left (ETyped ex ty)

pAdd :: ExprParser Expr
pAdd = chainl Expr pMul (EAdd <$ pToken TPlus)

pMul :: ExprParser Expr
pMul = chainl Expr pFactor (EAdd <$ pToken TStar)

pFactor :: ExprParser Expr
pFactor = pIntLit <|> pTupleVal

pIntLit :: ExprParser Expr
pIntLit = unit Expr $ (\(TIntLit n) -> EIntLit n) <$> satisfy isIntLit

pTupleVal :: ExprParser Expr
pTupleVal = pTuple Expr pExpr ETup

pType :: ExprParser Type
pType = pTyInt <|> pTyTuple

pTuple :: Tuples ix -> ExprParser ix -> (ix -> ix -> ix) -> ExprParser ix
pTuple w pEl f = do
  left <- getPos
  void (pToken TLParen)
  lhs <- pEl
  ty <- P.option lhs $ do
    void (pToken TComma)
    rhs <- pEl
    mkBounded w left (f lhs rhs)
  void (pToken TRParen)
  return ty

pTyTuple :: ExprParser Type
pTyTuple = pTuple Type pType TyTup

pTyInt :: ExprParser Type
pTyInt = unit Type $ TyInt <$ pToken TInt

readExpr :: String -> AnnFix Bounds Tuples Expr
readExpr input = case P.runParser pTokens () "" input of
  Left msg -> error (show msg)
  Right toks ->
    let toks' = trace (show toks) $ collapse isSpace toks
        leftmost = leftMargin $ snd $ head toks'
        p = P.runParserT (pExpr <* P.eof) leftmost "" toks'
     in case runYieldG p of
       (Left msg, _) -> error (show msg)
       (Right _, Just expr) -> fromJust (matchAnyF Expr expr)

inferExprType :: String -> Except [(String, Bounds)] Type
inferExprType = errorCata (mkErrorAlg inferType) Expr . readExpr