-- Datentyp für While-Programme gemäß Übung 6 CB (WS03)

module ProgType where

import List(transpose)

data Program = Prog String     [Var]       [Stmt]
--                  Name   Deklarationen Anweisungen

type Var = String 

data Stmt = Print Var
	  | Assign Var Expr
	  | If Cond [Stmt]
	  | While Cond [Stmt]

data Cond = Rel RelOp Expr Expr

data RelOp = Eq | NEq | LE | LEq | GR | GEq 
--           =    !=    <    <=     >   >=

data Expr = V Var 
	  | N Int 
	  | Op Char Expr Expr

------------------------ Show ---------------------------------

instance Show Program where
	 showsPrec _ (Prog name vars stmts) = showString ("program "++name ++ "\n vars: ") .
					      shows vars . showString "\n" .
					      shows stmts

instance Show Stmt where
    showsPrec _ stmt x = show_stmts "" [stmt] ++ x
    showList stmts x = show_stmts "" stmts ++ x

instance Show Cond where
    showsPrec _ (Rel op e1 e2) = shows e1 . shows op . shows e2

instance Show RelOp where
    showsPrec _ Eq = showString " = "
    showsPrec _ NEq = showString " != "
    showsPrec _ LE = showString " < "
    showsPrec _ LEq = showString " <= "
    showsPrec _ GR = showString " > "
    showsPrec _ GEq = showString " >= "

instance Show Expr where 
    showsPrec _ (V var) = showString var
    showsPrec _ (N int) = shows int
    showsPrec _ (Op c e1 e2) = showString "(" . 
			       shows e1 . showString (' ':c:" ") . shows e2 .
			       showString ")"

-- indentation function:
show_stmts :: String -> [Stmt] -> String
show_stmts _ [] = ""
show_stmts ind ((Print var ):ss)    = ind ++ "print " ++ var ++ rest
  where rest = "\n" ++ show_stmts ind ss
show_stmts ind ((Assign st e):ss)    = ind ++ st ++ " := " ++ (show e) ++ rest
  where rest = "\n" ++ show_stmts ind ss
show_stmts ind ((If e s1 ):ss) = ind ++ "if "++(show e)++" then \n" ++
                               (show_stmts ('\t':ind) s1) ++ rest
  where rest = "\n" ++ show_stmts ind ss
show_stmts ind ((While c st):ss) = ind ++ "while "++(show c)++" do\n"++
                                   (show_stmts ('\t':ind) st)++rest
  where rest = "\n" ++ show_stmts ind ss

-- Testdaten -----------------------------
stmts = take 20 $ drop 40 stmts'

shuffle :: [[a]] -> [a]
shuffle = concat . transpose 

stmts' =  
     shuffle [ [Assign var exp |  var <- vars , exp <- exps ],
	       cycle [Print var | var <- vars ],
	       [ If c [While c [s1,s2]] |
 		 s1 <- stmts', s2 <- stmts',c <- conds ] ,
	       [ While c [If c [s1,s2]] | 
		s1 <- stmts', s2 <- stmts',c <- conds ] 
	     ]

vars  = ["a","b","c"]
exps  = take 3 exps'
exps' = (map V vars) ++ map N [1..3] ++ 
	[ Op op e1 e2 | op <- "+*",e1 <- exps', e2 <- exps' ]
conds = [ Rel op e1 (exps'!!13) |  e1 <- exps, op <- [Eq,LE,GEq]] 

sampleprogram = Prog "Testprogramm" vars stmts

