packages feed

hgom-0.5.1: Gom/OOMappingGen.hs

-------------------------------------------------------------------
-- |
-- Module      : Gom.CodeGen
-- Copyright   : (c) Paul Brauner 2009
--               (c) Emilie Balland 2009
--               (c) INRIA 2009
-- Licence     : GPL (see COPYING)
--
-- Maintainer  : emilie.balland@inria.fr
-- Stability   : provisional
-- Portability : non-portable (requires generalized newtype deriving)
--
-- Generation of a file hierarchy from a symbol table.
-------------------------------------------------------------------- 

module Gom.OOMappingGen (st2oomapping) where

import Gom.Sig
import Gom.SymbolTable
import Gom.Config
import Gom.FileGen
import Gom.CodeGen.Common

import Text.PrettyPrint.Leijen
import Control.Arrow((***))
import Data.Char(toLower)

-- | Compiles a symbol table into OO Mapping
st2oomapping :: SymbolTable -> Config -> FileHierarchy
st2oomapping =  runGen compOOMapping

-- | Generates the @Mod.tom@ tom mapping file for module @Mod@ based
-- on OO mappings and the OOMapping interface class
compOOMapping :: Gen FileHierarchy
compOOMapping = do m <- askSt modName
                   let mn = map toLower m 
                   pr <- askConf package
                   ctrs  <- askSt simpleConstructorsIds
                   vctrs <- askSt variadicConstructorsIds
                   srts  <- askSt definedSortsIds
                   tyts  <- mapM compTypeTerm srts
                   ops   <- mapM compOp ctrs
                   vops  <- mapM compVOp vctrs
                   isig  <- compISignature ctrs vctrs 
                   let mapping = Tom m . vsep $ tyts++ops++vops
                   return . wrap pr $ Package mn [mapping,isig]
  where wrap Nothing  h = h
        wrap (Just l) h = foldr w h l
        w p h = Package p [h]
                 
-- | Given a sort @S@, generates
--
-- > %typeterm S {
-- >   implement { S }
-- >   is_sort(t) { ($t instanceof S) }
-- >   equals(t1,t2) { ($t1 == $t2) }
-- > }
--
-- generats @$t1.equals($t2)@ if @--noSharing@ has been
-- toggled
compTypeTerm :: SortId -> Gen Doc
compTypeTerm s = do 
  cs <- askSt (concreteTypeOf s)
  return $ rTypeterm (pretty s) (text (getClassName cs)) False 

-- | Given a non-variadic constructor @C(x1:T1,..,xn:Tn)@
-- of codomain @Co@, generates
--
-- > %op Co C(x1:T1,..,xn:Tn) {
-- >   is_fsym(t) { (getSignature().getMapping_C().isInstanceOf($t)) }
-- >   get_slot(x1,t) { getSignature().getMapping_f().get1($t) }
-- >   ...
-- >   get_slot(xn,t) { getSignature().getMapping_f().getn($t) }
-- >   make (t1,..,tn) { (getSignature().getMapping_f().make($s1, $s2)) }
-- > }
compOp :: CtorId -> Gen Doc
compOp c = do pfields <- map (pretty *** pretty) `fmap` askSt (fieldsOf c)
              co <- askSt (codomainOf c)
              let pfs = map fst pfields
              return $ rOp (pretty co) (pretty c) pfields
                           (vcat [isfsym, getters pfs, make pfs])
  where mapping = text "getSignature().getMapping_" <> pretty c <> text "()"
        isfsym  = text "is_fsym(t) {" <>  mapping <> text ".isInstanceOf($t) }"
        make fs = text "make" <> gen fs <+> (sbraces . parens $ body)
          where body = mapping <> text ".make" <> (gen $ map inline fs)
                gen  = parens . hcat . punctuate comma
        getters fs = vcat $ zipWith getter [0 :: Int ..] fs
        getter i s = text "get_slot(" <> pretty s <> 
                     text ",t) {" <> mapping <> text ".get" <> 
                     text (show i) <> text "($t) }"

-- | Given a variadic constructor @L(T*)@
-- of codomain @Co@, generates
-- %oplist Co L(T*) {
--  is_fsym(l)       { getSignature().getMapping_L().isInstanceOf($l) }
--  make_empty()     { getSignature().getMapping_L().makeEmpty() } 
--  make_insert(o,l) { getSignature().getMapping_L().makeInsert($o,$l) }
--  get_head(l)      { getSignature().getMapping_L().getHead($l) }
--  get_tail(l)      { getSignature().getMapping_L().getTail($l) }
--  is_empty(l)      { getSignature().getMapping_L().isEmpty($l) }
--}
compVOp :: CtorId -> Gen Doc
compVOp c = do 
  codom  <- askSt (codomainOf c)
  dom  <- askSt (fieldOf c)
  return $ text "%oplist" <+> pretty codom <+> pretty c <> 
           parens (pretty dom <> text "*") <+> ibraces (vcat $ map text 
             [" is_fsym(l)       { " ++ mapping ++ ".isInstanceOf($l) }",
              " make_empty()     { " ++ mapping ++ ".makeEmpty() }",
              " make_insert(o,l) { " ++ mapping ++ ".makeInsert($o,$l) }",
              " get_head(l)      { " ++ mapping ++ ".getHead($l) }",
              " get_tail(l)      { " ++ mapping ++ ".getTail($l) }",
              " is_empty(l)      { " ++ mapping ++ ".isEmpty($l) }"])
  where mapping = "getSignature().getMapping_" ++ show c ++ "()"


-- | Given a list of constructors @cs@ and a list of var constructors
-- @vcs@, generates the ISignature of new oo mappings.
compISignature :: [CtorId] -> [CtorId] -> Gen FileHierarchy
compISignature cs vcs = do 
  methDecls  <- mapM compMDecl cs
  vmethDecls <- mapM compMVDecl vcs
  let code = rInterface public (text "ISignature") 
                        (rBody (methDecls ++ vmethDecls))
  return $ Class "ISignature" code 

compMDecl :: CtorId -> Gen Doc
compMDecl c = do 
  cfields <- askSt (fieldsOf c)
  s       <- askSt (codomainOf c)
  cs      <- askSt (concreteTypeOf s) 
  let arity = length cfields
  classes <- mapM (prettyConcreteType . snd) cfields
  let types = gen (pretty cs:classes) 
  return $ text "tom.library.oomapping.Mapping" <> pretty arity <> 
           types <> text " getMapping_" <> pretty c <> text "()"
  where gen = angles . hcat . punctuate comma
        prettyConcreteType s = do cs <- askSt (concreteTypeOf s)
                                  return $ pretty cs

compMVDecl :: CtorId -> Gen Doc
compMVDecl c = do 
  dom    <- askSt (fieldOf c)
  codom  <- askSt (codomainOf c)
  cdom   <- askSt (concreteTypeOf dom) 
  ccodom <- askSt (concreteTypeOf codom) 
  return $ text "tom.library.oomapping.ListMapping<" <> pretty ccodom <> 
           text "," <> pretty cdom <> text ">" <+> text "getMapping_" <> 
           pretty c <> text "()"