packages feed

CPL-0.2.0: src/ExpParser.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  ExpParser
-- Copyright   :  (c) Masahiro Sakai 2009
-- License     :  BSD-style
--
-- Maintainer  :  masahiro.sakai@gmail.com
-- Stability   :  provisional
-- Portability :  portable
--
-----------------------------------------------------------------------------

module ExpParser
    ( Exp (..)
    , exp
    , def
    , evalExp
    , identityNames
    ) where

import qualified CDT
import qualified Exp as E
import ParserUtils

import Prelude hiding (exp)
import Control.Monad
import Control.Monad.Except
import Text.Parsec hiding (string')
import Text.Parsec.String (Parser)
import Data.List (find)
import Data.Maybe
import qualified Data.Map as Map
import Text.Printf

----------------------------------------------------------------------------

data Exp
    = Comp Exp Exp
    | Ident String [Exp]
    deriving (Show, Read)

exp :: Parser Exp
exp =
    do xs <- sepBy1 pident (tok (char '.' `mplus` char '\x2218'))
       return (foldr1 Comp xs)
    where pident =
              do s  <- ident
                 xs <- option [] $ between (char' '(') (char' ')')
                                 $ exp `sepBy` char' ','
                 spaces
                 return (Ident s xs)

def :: Parser (E.Id, [E.Id], Exp)
def = do
  spaces
  s <- ident
  ps <- option [] $ between (char' '(') (char' ')') $ ident `sepBy` char' ','
  spaces
  char' '='
  body <- exp
  spaces
  return (s, ps, body)

----------------------------------------------------------------------------

type CDTEnv = [CDT.CDT]

evalExp :: CDTEnv -> (Map.Map String Int) -> Exp -> Either String E.Exp
evalExp cenv env = f
  where
    f :: Exp -> Either String E.Exp
    f (Comp a b) = do
      a' <- f a
      b' <- f b
      return (E.Comp a' b')
    f (Ident s args) | s `elem` identityNames = do
      unless (length args == 0) $
        throwError $ printf "%s: wrong number of arguments (given %d, expected %d)" s (length args) (0 :: Int)
      return E.Identity
    f (Ident s args)  = do
      let arity = length args
      args' <- mapM f args
      case () of
        _ | Just o <- find (\o -> CDT.functName o  == s) cenv -> do
          unless (CDT.functArity o == arity) $
            throwError $ printf "%s: wrong number of arguments (given %d, expected %d)" s arity (CDT.functArity o)
          return (E.Funct o args')
        _ | Just o <- find (\o -> CDT.factName o  == s) cenv -> do
          unless (CDT.nNats o == arity) $
            throwError $ printf "%s: wrong number of arguments (given %d, expected %d)" s arity (CDT.nNats o)
          return (E.Fact o args')
        _ | Just n <- find (\n -> CDT.natName n == s) [n | o <- cenv, n <- CDT.nats o] -> do
          unless (arity == 0) $
            throwError $ printf "%s: wrong number of arguments (given %d, expected %d)" s arity (0 :: Int)
          return (E.Nat n)
        _ | Just arity' <- Map.lookup s env -> do
          unless (arity == arity') $
            throwError $ printf "%s: wrong number of arguments (given %d, expected %d)" s arity arity'
          return (E.Var s args')
        _ -> throwError ("unknown symbol: " ++ s)

identityNames :: [String]
identityNames = ["I", "id"]

----------------------------------------------------------------------------