packages feed

cnc-spec-compiler-0.2.0.0: Intel/Cnc/Spec/AST.hs

{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables  #-}
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}

module Intel.Cnc.Spec.AST where 

import StringTable.Atom
import Data.Data
import Data.Char
import Text.PrettyPrint.HughesPJClass
--import Data.Generics.Serialization.SExp
--import Data.Generics.Serialization.Streams
import Intel.Cnc.Spec.Util
import Intel.Cnc.Spec.SrcLoc

-- For now there is exactly one predefined step collection:
isBuiltin e | e == special_environment_name = True
isBuiltin _     = False

-- Oops, I don't know how to compose type constructors in a "curried" way:
--instance Decorated t => Decorated ([] . t) where 
--  stripDecor = map stripDecor
--  getDecor = 

--------------------------------------------------------------------------------
-- Expressions and Literals
--------------------------------------------------------------------------------

-- Expressions are the code used inside step skeletons.

data Lit = 
   LitInt Int 
 | LitFloat Float
 deriving (Eq, Ord, Show, Data, Typeable)

-- Expressions are decorated with values of an arbitrary type:
data Exp dec = 
   Lit dec Lit
 | Var dec Atom
 | App dec (Exp dec) [Exp dec]
 | If  dec (Exp dec) (Exp dec) (Exp dec) 
 deriving (Eq, Ord, Show, Data, Typeable)


instance Pretty Lit where 
 pPrint (LitInt i)   = pPrint i
 pPrint (LitFloat f) = pPrint f

instance Pretty (Exp dec) where 
 pPrint (Lit _ l) = pPrint l
 pPrint (Var _ s) = text (fromAtom s)
 pPrint (App _ rator rands) = 
     case (rator,rands) of 
       -- If it's a binop we should print appropriately.
       (Var _ name, [left,right]) | (not $ isAlpha (head (fromAtom name))) -> 
	     -- Sep can actually yield some very wierd behavior:
--	     pPrint left `sep2` text name `sep2` pPrint right
	     parens (pp left <+> text (fromAtom name) <+> pp right)
       _ ->  pPrint rator <> (parens $ commasep rands)

 pPrint (If _ a b c) = 
     sep [text "if (" <> pPrint a <> text ")",
          nest 5 $ pPrint b, 
	  text "else " <> pPrint c]

instance Decorated Exp where 
  mapDecor f e = 
   case e of 
    Lit s l        -> Lit (f s) l
    Var s v        -> Var (f s) v
    App s r d      -> App (f s) (mapDecor f r) (map (mapDecor f) d)
    If  s a b c    -> If  (f s) (mapDecor f a) (mapDecor f b) (mapDecor f c)

  -- This is the price of tagging the source locations (and other
  -- decorations) right on the Exprs rather than the even/odd
  -- alternating expression/decoration types.
  getDecor e = 
   case e of 
    Lit s _        -> s
    Var s _        -> s
    App s _ _      -> s
    If  s _ _ _    -> s

--------------------------------------------------------------------------------
-- Types
--------------------------------------------------------------------------------

data Type =
   TInt
 | TFloat | TDouble
 | TChar
 -- An abstract type not intpreted by CnC:
 | TSym Atom
 | TPtr Type
 | TRef   Type -- quite annoying, used for C++
 | TConst Type -- quite annoying, used for C++
 | TDense Type -- Density annotations.
 | TTuple [Type]
 deriving (Eq,Ord,Show,Data,Typeable)

instance Pretty (Type) where
  pPrint = cppType
 -- pPrint (TInt)      = text "int"
 -- pPrint (TFloat)    = text "float"
 -- pPrint (TDouble)   = text "double"
 -- pPrint (TSym str)  = text (fromAtom str)
 -- pPrint (TPtr ty)   = pPrint ty <> text "*"
 -- pPrint (TRef ty)   = pPrint ty <> text "&"
 -- pPrint (TDense ty) = text "dense" <+> pPrint ty 
 -- pPrint (TConst ty) = text "const" <+> pPrint ty 
 -- pPrint (TTuple ty) = text "(" <> commacat ty <> text ")"

-- A literal text description of a type.  
litType x = TSym (toAtom x)

-- For now I'm not exposing type constructors as a separate variant:
tyConstructor :: Doc -> Type -> Type
tyConstructor doc ty = 
  TSym (toAtom$ doc <> angles (pPrint ty))

voidTy = TSym (toAtom "void")

-- Converting types to C++ concrete syntax.
cppType :: Type -> Doc
cppType ty = case ty of 
  TInt    -> t "int"
  TFloat  -> t "float"
  TDouble -> t "double"
  TChar   -> t "char"
  TSym s  -> textAtom s
  TPtr ty -> cppType ty <> t "*"
  TRef ty -> cppType ty <> t " &"
  TConst ty -> t"const" <+> cppType ty 

  -- This doesn't affect the C-type, any influence has already taken place.
  TDense ty -> cppType ty 

-- Here is the convention for representing tuples in C++.
  --TTuple [a,b]   -> t "Pair"   <> angles (hcat$ punctuate commspc (map cppType [a,b]))
  --TTuple [a,b,c] -> t "Triple" <> angles (hcat$ punctuate commspc (map cppType [a,b,c]))
  TTuple ls -> t "cnctup::tuple" <> angles (hcat$ punctuate commspc$ map cppType ls)
  --TTuple ls -> error$ "CppOld codegen: Tuple types of length "++ show (length ls) ++" not standardized yet!"


----------------------------------------------------------------------------------------------------
-- Abstract Syntax for Top level Statements in a .cnc file:
----------------------------------------------------------------------------------------------------

-- These are the statements produced by parsing (hence 'P')
-- They get converted to a different format post-parsing
data PStatement dec = 
   -- When we parse a file we allow statements to be arbitrarily long chains of relations:
   -- We represent this as a starting instance(s) followed by an arbitrary number of links.
   Chain [CollectionInstance dec] [RelLink dec]
 | DeclareTags       dec Atom (Maybe Type)
 | DeclareItems      dec Atom (Maybe (Type, Type))
 | DeclareReductions dec Atom Atom (Exp dec) (Maybe (Type, Type))
 | DeclareSteps      dec Atom 

 -- Type synonyms are of kind * for now...
 | TypeDef dec Atom Type

 | Function
 | DeclareExtern
 | Constraints  dec (CollectionInstance dec) [Exp dec]

 deriving (Eq,Ord,Show,Data,Typeable)

instance Pretty (PStatement dec) where 
 pPrint (Chain first rest) = 
     commacat first <+>
     hsep (map pPrint rest) <> text ";\n"
 pPrint (DeclareTags _ name Nothing)   = text "tags " <> text (fromAtom name) <> text ";\n"
 pPrint (DeclareTags _ name (Just ty)) = text "tags<" <> pPrint ty <> text "> " <> text (fromAtom name) <> t";\n"
 pPrint (DeclareItems _ name Nothing)  = text "items" <+> text (fromAtom name) <> t";\n"
 pPrint (DeclareItems _ name (Just (ty1,ty2))) = 
     t"items<" <> pp ty1 <> comma <+> pp ty2 <> t"> " <> toDoc name <> t";\n"

 pPrint (DeclareReductions _ name op exp Nothing)  = 
     t"reductions" <+> (toDoc name) <> parens (toDoc op <> t", " <> pPrint exp) <> t";\n"
-- pPrint (DeclareReductions _ name op (Just (ty1,ty2))) = 
 pPrint (DeclareReductions _ name op exp (Just ty1)) = 
     t"reductions<" <> pp ty1 <> t"> " <> toDoc name <> parens (toDoc op <> t", " <> pPrint exp) <> t";\n"

 pPrint (DeclareSteps _ name) =  text "steps " <> text (fromAtom name) <> text ";\n"
 pPrint (Constraints _ inst exps) = text "constrain " <> pp inst <+> 
				    hcat (punctuate (text ", ") $ map pp exps) <> text ";\n"

 pPrint (TypeDef _ nm ty) = text "type"<+> pPrint nm <+> char '=' <+> pPrint ty <> text ";\n"

 pPrint (Function )     = text "FUNCTION NOT WORKING YET"
 pPrint (DeclareExtern) = text "DECLARE EXTERN NOT WORKING YET"


--instance Pretty [PStatement dec] where 
-- pPrint ls = vcat (map pPrint ls)

instance Decorated PStatement where 
  mapDecor f stmt = 
   case stmt of 
     Chain insts links -> Chain (map (mapDecor f) insts) (map (mapDecor f) links)
     DeclareTags  s name ty -> DeclareTags  (f s) name ty
     DeclareItems s name ty -> DeclareItems (f s) name ty
     DeclareReductions s name op exp ty -> DeclareReductions (f s) name op (mapDecor f exp) ty
--     DeclareReductions s name op exp ty -> DeclareReductions (f s) name op exp ty
     DeclareSteps s name    -> DeclareSteps (f s) name
     Constraints  s inst ls -> Constraints  (f s) (mapDecor f inst) (map (mapDecor f) ls)

     Function -> Function 
     DeclareExtern -> DeclareExtern 
     TypeDef      s name ty -> TypeDef      (f s) name ty


  getDecor stmt = 
   case stmt of 
     Chain (hd:_) _  -> getDecor hd
     Chain [] (hd:_) -> getDecor hd
     Chain [] []     -> error "getDecor: cannot get decoration from an empty 'Chain'.  Shouldn't have such a thing anyway."
     DeclareTags       s _ _   -> s
     DeclareItems      s _ _   -> s
     DeclareReductions s _ _ _ _ -> s
     DeclareSteps      s _   -> s
     Constraints       s _ _ -> s
     TypeDef           s _ _ -> s
     Function      -> error "getDecor: not implemented yet"
     DeclareExtern -> error "getDecor: not implemented yet"


------------------------------------------------------------
data RelLink dec = 
   ProduceLink    dec [CollectionInstance dec]
 | PrescribeLink  dec [CollectionInstance dec]
 | RevProduceLink dec [CollectionInstance dec]
 deriving (Eq,Ord,Show,Data,Typeable)

instance Pretty (RelLink dec) where
 pPrint (ProduceLink    _ ls) = text "->" <+> commacat ls 
 pPrint (PrescribeLink  _ ls) = text "::" <+> commacat ls 
 pPrint (RevProduceLink _ ls) = text "<-" <+> commacat ls 

instance Decorated RelLink where 
  mapDecor f link = 
    case link of 
     ProduceLink    s ls -> ProduceLink    (f s) (map (mapDecor f) ls)
     PrescribeLink  s ls -> PrescribeLink  (f s) (map (mapDecor f) ls)
     RevProduceLink s ls -> RevProduceLink (f s) (map (mapDecor f) ls)  
  getDecor link = 
    case link of 
     ProduceLink    s _ -> s
     PrescribeLink  s _ -> s
     RevProduceLink s _ -> s

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

-- These are references to collections in the
-- prescribe/produce/consume constructions of the .cnc file.
data CollectionInstance dec = 
   InstName dec String
   -- TEMP: until the syntax has been figured out we sometimes know
   -- that an instance is a Step OR a Tag collection, but not which.
 | InstStepOrTags dec String [Exp dec]
 | InstTagCol       dec String [Exp dec]
 | InstItemCol      dec String [Exp dec]
 | InstReductionCol dec String [Exp dec]
 | InstStepCol      dec String [Exp dec]

 deriving (Eq,Ord,Show,Data,Typeable)

instance Pretty (CollectionInstance dec) where 
  pPrint (InstName _ s) = text s
--  pPrint (InstItemCol    s exps) = text s <> pPrint exps -- WEIRD indent behaviour, commasep is ALSO weird
  pPrint (InstStepOrTags _ s exps) = text s <> parens   (commacat exps)
  pPrint (InstItemCol    _ s exps) = text s <> brackets (commacat exps)
  pPrint (InstStepCol    _ s exps) = text s <> parens   (commacat exps)
  pPrint (InstTagCol     _ s exps) = text s <> angles   (commacat exps)


instance Decorated CollectionInstance where 
  mapDecor f inst = 
    case inst of 
      InstName       s n    -> InstName       (f s) n 
      InstStepOrTags s n ls -> InstStepOrTags (f s) n (map (mapDecor f) ls)
      InstItemCol    s n ls -> InstItemCol    (f s) n (map (mapDecor f) ls)
      InstStepCol    s n ls -> InstStepCol    (f s) n (map (mapDecor f) ls)
      InstTagCol     s n ls -> InstTagCol     (f s) n (map (mapDecor f) ls)
  -- We follow a "left hand rule" for data structures that are not decorated but have decorated children.
  -- That is, pick the left-most child that has a decoration.
  getDecor inst = 
    case inst of 
      InstName       s _   -> s
      InstStepOrTags s _ _ -> s
      InstItemCol    s _ _ -> s
      InstStepCol    s _ _ -> s
      InstTagCol     s _ _ -> s


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