packages feed

MiniAgda-0.2016.12.19: src/Concrete.hs

{-# LANGUAGE NamedFieldPuns #-}
-- concrete syntax
module Concrete where

import Prelude hiding (null)

import Util
import Abstract (Co,Sized,PiSigma(..),Decoration(..),Dec,Override(..),Measure(..),Bound(..),HasPred(..),LtLe(..),polarity)
import qualified Abstract as A
import Polarity

-- | Concrete names.
data Name = Name { theName :: String }
  deriving (Eq,Ord)

instance Show Name where
  show (Name n) = n

-- | Possibly qualified names.
data QName
  = Qual  { qual :: Name, name :: Name }  -- ^ @X.x@ e.g. qualified constructor.
  | QName { name :: Name }                -- ^ @x@.
  deriving (Eq,Ord)

unqual (QName n) = n

instance Show QName where
  show (Qual m n) = show m ++ "." ++ show n
  show (QName n)  = show n

set0 = Set Zero
ident n = Ident (QName n)

-- | Concrete expressions syntax.
data Expr
  = Set Expr                        -- ^ Universe @Set e@; @Set@ for @Set 0@.
  | CoSet Expr
  | Size                            -- ^ @Size@ type of sizes.
  | Succ Expr                       -- ^ @$e@.
  | Zero                            -- ^ @0@.
  | Infty                           -- ^ @#@.
  | Max                             -- ^ @max@.
  | Plus Expr Expr                  -- ^ @e + e'@.
  | RApp Expr Expr                  -- ^ @e |> f@.
  | App Expr [Expr]                 -- ^ @f e1 ... en@ or @f <| e@.
  | Lam Name Expr                   -- ^ @\ x -> e@.
  | Case Expr (Maybe Type) [Clause] -- ^ @case e : A { cls }@.
  | LLet LetDef Expr                -- ^ @let x = e in e'@ local let.
  | Quant PiSigma Telescope Expr    -- ^ @(x : A) -> B@, @[x : A] -> B@, @(x : A) & B@.
  | Pair Expr Expr                  -- ^ @e , e'@.
  | Record [([Name],Expr)]          -- ^ @record { x = e, x' y = e' }@.
  | Proj Name                       -- ^ @.x@.
  | Ident QName                     -- ^ @x@ or @D.c@.
  | Unknown                         -- ^ @_@.
  | Sing Expr Expr                  -- ^ @<e : A>@ singleton type.
--  | EBind TBind Expr                -- ^ @[x : A] B@
  deriving (Eq)

data LetDef = LetDef
  { letDefDec :: Dec
  , letDefName :: Name
  , letDefTel  ::  Telescope
  , letDefType :: (Maybe Type)
  , letDefExpr :: Expr
  } deriving (Eq, Show)

instance Show Expr where
    show = prettyExpr

instance HasPred Expr where
  predecessor (Succ e) = Just e
  predecessor _ = Nothing

data Declaration
  = DataDecl Name Sized Co Telescope Type [Constructor]
      [Name] -- list of field names
  | RecordDecl Name Telescope Type Constructor
      [Name] -- list of field names
  | FunDecl Co TypeSig [Clause]
  | LetDecl Bool LetDef -- True = if eval
--  | LetDecl Bool Name Telescope (Maybe Type) Expr -- True = if eval
  | PatternDecl Name [Name] Pattern
  | MutualDecl [Declaration]
  | OverrideDecl Override [Declaration] -- fail etc.
    deriving (Eq,Show)

data TypeSig = TypeSig Name Type
             deriving (Eq)

instance Show TypeSig where
  show (TypeSig n t) = show n ++ " : " ++ show t

type Type = Expr

data Constructor = Constructor
  { conName :: Name
  , conTel  :: Telescope
  , conType :: Maybe Type -- can be omitted *but* for families
  } deriving (Eq)

instance Show Constructor where
  show (Constructor n tel (Just t)) = show n ++ " " ++ show tel ++ " : " ++ show t
  show (Constructor n tel  Nothing) = show n ++ " " ++ show tel

type TBind = TBinding Type
type LBind = TBinding (Maybe Type)  -- possibly domain-free

data TBinding a = TBind
  { boundDec   :: Dec
  , boundNames :: [Name] -- [] if no name is given, then its a single bind
  , boundType  :: a
  }
  | TBounded  -- bounded quantification
  { boundDec   :: Dec
  , boundName  :: Name -- [] if no name is given, then its a single bind
  , ltle       :: LtLe
  , upperBound :: Expr
--  , boundMType :: Maybe Type -- type is inferred from upperBound
  }
  | TMeasure (Measure Expr)
  | TBound (Bound Expr)
--  | TSized { boundName :: Name } -- the size parameter of a sized record
    deriving (Eq,Show)

type Telescope = [TBind]

data DefClause = DefClause
   Name         -- function identifier
   [Elim]
   (Maybe Expr) -- Nothing for absurd pattern clause
 deriving (Eq,Show)

data Elim
  = EApp Pattern          -- application to a pattern
  | EProj Name [Pattern]  -- projection with arguments
    deriving (Eq,Show)

data Clause = Clause
                (Maybe Name) -- Just funId | Nothing for case clauses
                [Pattern]
                (Maybe Expr) -- Nothing for absurd pattern clause
            deriving (Eq,Show)

data Pattern
  = ConP Bool QName [Pattern] -- ^ @(c ps)@ if @False; @(.c ps)@ if @True@.
  | PairP Pattern Pattern     -- ^ @(p, p')@
  | SuccP Pattern             -- ^ @($ p)@
  | DotP Expr                 -- ^ @.e@
  | IdentP QName              -- ^ @x@ or @c@ or @D.c@.
  | SizeP Expr Name           -- ^ @(x > y)@ or @y < #@ or ...
  | AbsurdP                   -- ^ @()@
    deriving (Eq,Show)

type Case = (Pattern,Expr)

-- | Used in Parser.
patApp :: Pattern -> [Pattern] -> Pattern
patApp (IdentP c)         ps' = ConP False  c ps'
patApp (ConP dotted c ps) ps' = ConP dotted c (ps ++ ps')

-- * Pretty printing.

prettyLBind :: LBind -> String
-- prettyLBind (TSized x)                   = prettyTBind False (TSized x)
prettyLBind (TMeasure mu)                = prettyTBind False (TMeasure mu)
prettyLBind (TBound (Bound ltle mu mu')) = prettyTBind False (TBound (Bound ltle mu mu'))
prettyLBind (TBounded dec x ltle e)      = prettyTBind False (TBounded dec x ltle e)
prettyLBind (TBind dec xs (Just t))      = prettyTBind False (TBind dec xs t)
prettyLBind (TBind dec xs Nothing) =
  if erased dec then addPol False $ brackets binding
   else addPol True binding
  where binding = Util.showList " " show xs
        pol = polarity dec
        addPol b x = if pol==defaultPol
                      then x
                      else show pol ++ (if b then " " else "") ++ x


prettyTBind :: Bool -> TBind -> String
-- prettyTBind inPi (TSized x) = parens ("sized " ++ x)
prettyTBind inPi (TMeasure mu) = "|" ++
  (Util.showList ","  prettyExpr (measure mu)) ++ "|"
prettyTBind inPi (TBound (Bound ltle mu mu')) = "|" ++
  (Util.showList ","  prettyExpr (measure mu))  ++ "| " ++ show ltle ++ " |" ++
  (Util.showList ","  prettyExpr (measure mu')) ++ "|"
prettyTBind inPi (TBind dec xs t) =
  if erased dec then addPol False $ brackets binding
   else if (null xs) then addPol True s
   else addPol (not inPi) $ (if inPi then parens else id) binding
  where s = prettyExpr t
        binding = if null xs then s else
          foldr (\ x s -> show x ++ " " ++ s) (": " ++ s) xs
        pol = polarity dec
        addPol b x = if pol==defaultPol
                      then x
                      else show pol ++ (if b then " " else "") ++ x
prettyTBind inPi (TBounded dec x ltle e) =
  if erased dec then addPol False $ brackets binding
   else addPol (not inPi) $ (if inPi then parens else id) binding
  where binding = show x ++ " < " ++ prettyExpr e
        pol = polarity dec
        addPol b x = if pol==defaultPol
                      then x
                      else show pol ++ (if b then " " else "") ++ x
{-
prettyTBind :: Bool -> TBind -> String
prettyTBind inPi (TBind dec x t) =
  if erased dec then addPol False $ brackets binding
   else if x=="" then addPol True s
   else addPol (not inPi) $ (if inPi then parens else id) binding
  where s = prettyExpr t
        binding = if x == "" then s else x ++ " : " ++ s
        pol = polarity dec
        addPol b x = if pol==Mixed then x
                      else show pol ++ (if b then " " else "") ++ x
-}
prettyLetBody :: String -> Expr -> String
prettyLetBody s e = parens $ s ++ " in " ++ prettyExpr e

prettyLetAssign :: String -> Expr -> String
prettyLetAssign s e = "let " ++ s ++ " = " ++ prettyExpr e

prettyLetDef :: LetDef -> String
prettyLetDef (LetDef dec n [] mt e) = prettyLetAssign (prettyLBind tb) e
  where tb = TBind dec [n] mt
prettyLetDef (LetDef dec n tel mt e) = prettyLetAssign s e
  where s = prettyDecId dec n ++ " " ++ prettyTel False tel ++ prettyMaybeType mt

prettyDecId :: Dec -> Name -> String
prettyDecId dec x
  | erased dec = brackets $ show x
  | otherwise  =
     let pol = polarity dec
     in  if pol == defaultPol then show x else show pol ++ show x

prettyTel :: Bool -> Telescope -> String
prettyTel inPi = Util.showList " " (prettyTBind inPi)

prettyMaybeType = maybe "" $ \ t -> " : " ++ prettyExpr t

prettyExpr :: Expr -> String
prettyExpr e =
    case e of
      -- Type e          -> "Type " ++ prettyExpr e
      CoSet e         -> "CoSet " ++ prettyExpr e
      Set e         -> "CoSet " ++ prettyExpr e
      -- Set             -> "Set"
      Size            -> "Size"
      Max             -> "max"
      Succ e          -> "$ " ++ prettyExpr e -- ++ ")"
      Zero            -> "0"
      Infty           -> "#"
      Plus e1 e2      -> "(" ++ prettyExpr e1 ++ " + " ++  prettyExpr e2 ++ ")"
      Pair e1 e2      -> "(" ++ prettyExpr e1 ++ " , " ++  prettyExpr e2 ++ ")"
      App e1 el       -> "(" ++ prettyExprs (e1:el) ++ ")"
      Lam x e1        -> "(\\" ++ show x ++ " -> " ++ prettyExpr e1 ++ ")"
      Case e Nothing cs -> "case " ++ prettyExpr e ++ " { " ++ Util.showList "; " prettyCase cs ++ " } "
      Case e (Just t) cs -> "case " ++ prettyExpr e ++ " : " ++ prettyExpr t ++ " { " ++ Util.showList "; " prettyCase cs ++ " } "
      LLet letdef e -> prettyLetBody (prettyLetDef letdef) e
{-
      LLet tb e1 e2 -> "(let " ++ prettyLBind tb ++ " = " ++ prettyExpr e1 ++ " in " ++ prettyExpr e2 ++ ")"
-}
      Record rs       -> "record {" ++ Util.showList "; " prettyRecordLine rs ++ "}"
      Proj n          -> "." ++ show n
      Ident n         -> show n
      Unknown         -> "_"
      Sing e t        -> "<" ++ prettyExpr e ++ " : " ++ prettyExpr t ++ ">"
--      Quant pisig tb t2 -> parens $ prettyTBind True tb
      Quant pisig tel t2 -> parens $ prettyTel True tel
                                  ++ " " ++ show pisig ++ " " ++ prettyExpr t2

prettyRecordLine (xs, e) = Util.showList " " show xs ++ " = " ++ prettyExpr e

prettyCase (Clause Nothing [p] Nothing)  = prettyPattern p
prettyCase (Clause Nothing [p] (Just e)) = prettyPattern p ++ " -> " ++ prettyExpr e

prettyPattern :: Pattern -> String
prettyPattern (ConP dotted c ps) = parens $ foldl (\ acc p -> acc ++ " " ++ prettyPattern p) (if dotted then "." ++ show c else show c) ps
prettyPattern (PairP p1 p2) = parens $ prettyPattern p1 ++ ", " ++
                                prettyPattern p2
prettyPattern (SuccP p)   = parens $ "$ " ++ prettyPattern p
prettyPattern (DotP e)    = "." ++ prettyExpr e
prettyPattern (IdentP x)  = show x
prettyPattern (SizeP e y) = parens $ prettyExpr e ++ " > " ++ show y
prettyPattern (AbsurdP)   = parens ""

prettyExprs :: [Expr] -> String
prettyExprs = Util.showList " " prettyExpr

prettyDecl (PatternDecl n ns p) = "pattern " ++ (Util.showList " " show (n:ns)) ++ " = " ++ prettyPattern p

teleToType :: Telescope -> Type -> Type
teleToType [] t = t
teleToType (tb:tel) t2 = Quant Pi [tb] (teleToType tel t2)
--teleToType (PosTB dec n t:tel) t2 = Pi dec n t (teleToType tel t2)

typeToTele :: Type -> (Telescope, Type)
typeToTele (Quant Pi tel0 c) =
  let (tel, a) = typeToTele c in (tel0 ++ tel, a)
typeToTele a = ([],a)

{-
teleToType :: Telescope -> Type -> Type
teleToType [] t = t
teleToType (tb:tel) t2 = Quant Pi tb (teleToType tel t2)
--teleToType (PosTB dec n t:tel) t2 = Pi dec n t (teleToType tel t2)

typeToTele :: Type -> (Telescope, Type)
typeToTele = typeToTele' (-1)

typeToTele' :: Int -> Type -> (Telescope, Type)
typeToTele' k (Quant A.Pi tb c) | k /= 0 =
  let (tel, a) = typeToTele' (k-1) c in (tb:tel, a)
typeToTele' _ a = ([],a)
-}

teleNames :: Telescope -> [Name]
teleNames tel = concat $ map tbindNames tel

tbindNames :: TBind -> [Name]
tbindNames TBind{ boundNames }   = boundNames
tbindNames TBounded{ boundName } = [boundName]
-- tbindNames TSized{ boundName }   = [boundName]
tbindNames tb = error $ "tbindNames (" ++ show tb ++ ")"