----------------------------------------------------------------------------
-- |
-- Module      :  CSPM.Interpreter.PrepareAST
-- Copyright   :  (c) Fontaine 2008-2011
-- License     :  BSD
-- 
-- Maintainer  :  Fontaine@cs.uni-duesseldorf.de
-- Stability   :  experimental
-- Portability :  GHC-only
--
-- These are preprocessing steps which are specific for the interpreter.
-- Those steps of general use are in the CSPM-Frontend-package
--
----------------------------------------------------------------------------
{-# LANGUAGE ViewPatterns #-}
module CSPM.Interpreter.PrepareAST
(
  prepareAST
)
where

import Language.CSPM.AST as AST
import qualified Language.CSPM.Frontend as Frontend
import CSPM.Interpreter.Types (INT)
import CSPM.Interpreter.PatternCompiler (compilePattern)

import Data.Generics.Schemes (everywhere)
import Data.Generics.Aliases (mkT)
import Data.Generics.Basics (Data)

type IModule = Frontend.ModuleFromRenaming

prepareAST :: Frontend.ModuleFromRenaming -> Module INT
prepareAST = compilePattern . replaceFunCase . addFreeNames
{-
ReplaceFunCase with funCaseNew.
This is a quickfix
In CSPM Syntax we have tree cases: fun(x)(y) fun(x,y) and fun((x,y))
we want to map them to : fun x y and fun (x,y) in Haskell-Syntax.
-}
replaceFunCase :: IModule -> IModule
replaceFunCase ast = everywhere (mkT compFC) ast
  where
    compFC :: FunCase -> FunCase
    compFC (FunCase args expr)= FunCaseI (concat args) expr
    compFC (FunCaseI _ _) 
      = error "Internal Error : Did not expect FunCaseI in parse result"
{-
    flatArgs args = case args of
      [x] -> x
      _     -> map wrapTuple args

    wrapTuple [a] = a  -- one-element lists are not Tuples ?
    wrapTuple x   =(AST.labeled . TuplePat) x
-}


-- | Perform a freename analyzis for the body of prefixOperations
-- | and expressions that can become process-closures.
-- | This is ugly !!.
addFreeNames :: IModule -> IModule
addFreeNames ast = everywhere trans ast
  where
    trans :: Data a => a-> a
    trans = mkT mkExp -- . mkT mkFunBind

    fn :: LExp -> LExp
    fn expr = setNode expr
        $ ExprWithFreeNames (Frontend.computeFreeNames expr) expr

{-
    mkFunBind :: Decl -> Decl
    mkFunBind (FunBind i c) = FunBindI i (Frontend.computeFreeNames c) c
    mkFunBind o = o
-}

    mkExp :: Exp -> Exp
    mkExp expr = case expr of
      Let decls e
        -> LetI decls (Frontend.computeFreeNames (decls,expr)) e
      Lambda p e
        -> LambdaI (Frontend.computeFreeNames (p,e)) p  e
      PrefixExp c f p
        -> PrefixI (Frontend.computeFreeNames (c,f,p) ) c f p
      ProcSharing s a b
        -> ProcSharing s (fn a) (fn b)
      ProcAParallel l r a b
        -> ProcAParallel l r (fn a) (fn b)
      ProcLinkParallel l a b
        -> ProcLinkParallel l (fn a) (fn b)
      ProcRenaming r gen p
        -> ProcRenaming r gen $ fn p
      ProcRepSequence l p 
        -> ProcRepSequence l $ fn p
      ProcRepInternalChoice l p
        -> ProcRepInternalChoice l $ fn p
      ProcRepInterleave l p
        -> ProcRepInterleave l $ fn p
      ProcRepExternalChoice l p
        -> ProcRepExternalChoice l $ fn p
      ProcRepAParallel l a p
        -> ProcRepAParallel l a $ fn p
      ProcRepLinkParallel l e p
        -> ProcRepLinkParallel l e $ fn p
      ProcRepSharing l e p
        -> ProcRepSharing l e $ fn p
-- this is really ugly
      CallBuiltIn x@(unLabel -> BuiltIn bi) [[a,b]]
          -> let constr = CallBuiltIn x in case bi of
        F_Sequential -> constr [[fn a,fn b]]
        F_Interrupt -> constr [[fn a,fn b]]
        F_ExtChoice -> constr [[fn a,fn b]]
        F_Timeout -> constr [[fn a,fn b]]
        F_IntChoice -> constr [[fn a,fn b]]
        F_Interleave -> constr [[fn a,fn b]]
        F_Hiding -> constr [[fn a,b]]
        _ -> constr [[a,b]]
      Fun2  x@(unLabel -> BuiltIn bi) a b
          -> let constr = Fun2 x in case bi of
        F_Sequential -> constr (fn a) (fn b)
        F_Interrupt -> constr (fn a) (fn b)
        F_ExtChoice -> constr (fn a) (fn b)
        F_Timeout -> constr (fn a) (fn b)
        F_IntChoice -> constr (fn a) (fn b)
        F_Interleave -> constr (fn a) (fn b)
        F_Hiding -> constr (fn a) b
        F_Guard -> constr a (fn b)
        _ -> constr a b
      other -> other