-- | Generate C code from the mangled AST. module GenerateC where import Data.Char import Data.List import Data.Maybe import Control.Monad.Writer import Control.Monad.Error import Control.Monad.State import Numeric import Text.Printf import qualified AST as A import CompState import EvalConstants import EvalLiterals import Metadata import Pass import Errors import TLP import Types import Utils --{{{ monad definition type CGen = WriterT [String] PassM instance Die CGen where die = throwError --}}} --{{{ top-level generateC :: A.Process -> PassM String generateC ast = do (a, w) <- runWriterT (genTopLevel ast) return $ concat w genTLPChannel :: TLPChannel -> CGen () genTLPChannel TLPIn = tell ["in"] genTLPChannel TLPOut = tell ["out"] genTLPChannel TLPError = tell ["err"] genTopLevel :: A.Process -> CGen () genTopLevel p = do tell ["#include \n"] genProcess p (name, chans) <- tlpInterface tell ["void tock_main (Process *me, Channel *in, Channel *out, Channel *err) {\n"] genName name tell [" (me"] sequence_ [tell [", "] >> genTLPChannel c | c <- chans] tell [");\n"] tell ["}\n"] --}}} --{{{ utilities missing :: String -> CGen () missing s = tell ["\n#error Unimplemented: ", s, "\n"] --{{{ simple punctuation genComma :: CGen () genComma = tell [", "] seqComma :: [CGen ()] -> CGen () seqComma ps = sequence_ $ intersperse genComma ps genLeftB :: CGen () genLeftB = tell ["{ "] genRightB :: CGen () genRightB = tell [" }"] --}}} -- | A function that applies a subscript to a variable. type SubscripterFunction = A.Variable -> A.Variable -- | Map an operation over every item of an occam array. overArray :: Meta -> A.Variable -> (SubscripterFunction -> Maybe (CGen ())) -> CGen () overArray m var func = do A.Array ds _ <- typeOfVariable var specs <- sequence [makeNonceVariable "i" m A.Int A.VariableName A.Original | _ <- ds] let indices = [A.Variable m n | A.Specification _ n _ <- specs] let arg = (\var -> foldl (\v s -> A.SubscriptedVariable m s v) var [A.Subscript m $ A.ExprVariable m i | i <- indices]) case func arg of Just p -> do sequence_ [do tell ["for (int "] genVariable i tell [" = 0; "] genVariable i tell [" < "] genVariable var tell ["_sizes[", show v, "]; "] genVariable i tell ["++) {\n"] | (v, i) <- zip [0..] indices] p sequence_ [tell ["}\n"] | _ <- indices] Nothing -> return () -- | Generate code for one of the Structured types. genStructured :: A.Structured -> (A.Structured -> CGen ()) -> CGen () genStructured (A.Rep _ rep s) def = genReplicator rep (genStructured s def) genStructured (A.Spec _ spec s) def = genSpec spec (genStructured s def) genStructured (A.ProcThen _ p s) def = genProcess p >> genStructured s def genStructured (A.Several _ ss) def = sequence_ [genStructured s def | s <- ss] genStructured s def = def s data InputType = ITTimerRead | ITTimerAfter | ITOther -- | Given an input mode, figure out what sort of input it's actually doing. inputType :: A.Variable -> A.InputMode -> CGen InputType inputType c im = do t <- typeOfVariable c return $ case t of A.Timer -> case im of A.InputSimple _ _ -> ITTimerRead A.InputAfter _ _ -> ITTimerAfter _ -> ITOther --}}} --{{{ metadata -- | Turn a Meta into a string literal that can be passed to a function -- expecting a const char * argument. genMeta :: Meta -> CGen () genMeta m = tell ["\"", show m, "\""] --}}} --{{{ names genName :: A.Name -> CGen () genName n = tell [[if c == '.' then '_' else c | c <- A.nameName n]] --}}} --{{{ types -- | If a type maps to a simple C type, return Just that; else return Nothing. scalarType :: A.Type -> Maybe String scalarType A.Bool = Just "bool" scalarType A.Byte = Just "uint8_t" scalarType A.Int = Just "int" scalarType A.Int16 = Just "int16_t" scalarType A.Int32 = Just "int32_t" scalarType A.Int64 = Just "int64_t" scalarType A.Real32 = Just "float" scalarType A.Real64 = Just "double" scalarType A.Timer = Just "Time" scalarType _ = Nothing genType :: A.Type -> CGen () genType (A.Array _ t) = do genType t tell ["*"] genType (A.Record n) = genName n -- UserProtocol -- not used genType (A.Chan t) = tell ["Channel *"] -- Counted -- not used -- Any -- not used --genType (A.Port t) = genType t = case scalarType t of Just s -> tell [s] Nothing -> missing $ "genType " ++ show t -- | Generate the number of bytes in a type that must have a fixed size. genBytesIn :: A.Type -> Maybe A.Variable -> CGen () genBytesIn t v = do free <- genBytesIn' t v case free of Nothing -> return () Just _ -> die "genBytesIn type with unknown dimension" -- | Generate the number of bytes in a type that may have one free dimension. genBytesIn' :: A.Type -> Maybe A.Variable -> CGen (Maybe Int) genBytesIn' (A.Array ds t) v = do free <- genBytesInArray ds 0 genBytesIn' t v return free where genBytesInArray [] _ = return Nothing genBytesInArray ((A.Dimension n):ds) i = do free <- genBytesInArray ds (i + 1) tell [show n, " * "] return free genBytesInArray (A.UnknownDimension:ds) i = case v of Just rv -> do free <- genBytesInArray ds (i + 1) genVariable rv tell ["_sizes[", show i, "] * "] return free Nothing -> do free <- genBytesInArray ds (i + 1) case free of Nothing -> return $ Just i Just _ -> die "genBytesIn' type with more than one free dimension" genBytesIn' (A.Record n) _ = do tell ["sizeof ("] genName n tell [")"] return Nothing -- This is so that we can do RETYPES checks on channels; we don't actually -- allow retyping between channels and other things. genBytesIn' (A.Chan _) _ = do tell ["sizeof (Channel *)"] return Nothing genBytesIn' t _ = case scalarType t of Just s -> tell ["sizeof (", s, ")"] >> return Nothing Nothing -> die $ "genBytesIn' " ++ show t --}}} --{{{ declarations genDeclType :: A.AbbrevMode -> A.Type -> CGen () genDeclType am t = do when (am == A.ValAbbrev) $ tell ["const "] genType t case t of A.Array _ _ -> return () A.Chan _ -> return () A.Record _ -> tell [" *"] _ -> when (am == A.Abbrev) $ tell [" *"] genDecl :: A.AbbrevMode -> A.Type -> A.Name -> CGen () genDecl am t n = do genDeclType am t tell [" "] genName n --}}} --{{{ conversions genCheckedConversion :: Meta -> A.Type -> A.Type -> CGen () -> CGen () genCheckedConversion m fromT toT exp = do tell ["(("] genType toT tell [") "] if isSafeConversion fromT toT then exp else do genTypeSymbol "range_check" fromT tell [" ("] genTypeSymbol "mostneg" toT tell [", "] genTypeSymbol "mostpos" toT tell [", "] exp tell [", "] genMeta m tell [")"] tell [")"] genConversion :: Meta -> A.ConversionMode -> A.Type -> A.Expression -> CGen () genConversion m A.DefaultConversion toT e = do fromT <- typeOfExpression e genCheckedConversion m fromT toT (genExpression e) genConversion m cm toT e = do fromT <- typeOfExpression e case (isSafeConversion fromT toT, isRealType fromT, isRealType toT) of (True, _, _) -> -- A safe conversion -- no need for a check. genCheckedConversion m fromT toT (genExpression e) (_, True, True) -> -- Real to real. do genConversionSymbol fromT toT cm tell [" ("] genExpression e tell [", "] genMeta m tell [")"] (_, True, False) -> -- Real to integer -- do real -> int64_t -> int. do let exp = do genConversionSymbol fromT A.Int64 cm tell [" ("] genExpression e tell [", "] genMeta m tell [")"] genCheckedConversion m A.Int64 toT exp (_, False, True) -> -- Integer to real -- do int -> int64_t -> real. do genConversionSymbol A.Int64 toT cm tell [" ("] genCheckedConversion m fromT A.Int64 (genExpression e) tell [", "] genMeta m tell [")"] _ -> missing $ "genConversion " ++ show cm genConversionSymbol :: A.Type -> A.Type -> A.ConversionMode -> CGen () genConversionSymbol fromT toT cm = do tell ["occam_convert_"] genType fromT tell ["_"] genType toT tell ["_"] case cm of A.Round -> tell ["round"] A.Trunc -> tell ["trunc"] --}}} --{{{ literals genLiteral :: A.LiteralRepr -> CGen () genLiteral lr = if isStringLiteral lr then do tell ["\""] let A.ArrayLiteral _ aes = lr sequence_ [genByteLiteral s | A.ArrayElemExpr (A.Literal _ _ (A.ByteLiteral _ s)) <- aes] tell ["\""] else genLiteralRepr lr -- | Does a LiteralRepr represent something that can be a plain string literal? isStringLiteral :: A.LiteralRepr -> Bool isStringLiteral (A.ArrayLiteral _ aes) = and [case ae of A.ArrayElemExpr (A.Literal _ _ (A.ByteLiteral _ _)) -> True _ -> False | ae <- aes] isStringLiteral _ = False genLiteralRepr :: A.LiteralRepr -> CGen () genLiteralRepr (A.RealLiteral m s) = tell [s] genLiteralRepr (A.IntLiteral m s) = genDecimal s genLiteralRepr (A.HexLiteral m s) = tell ["0x", s] genLiteralRepr (A.ByteLiteral m s) = tell ["'"] >> genByteLiteral s >> tell ["'"] genLiteralRepr (A.ArrayLiteral m aes) = do genLeftB genArrayLiteralElems aes genRightB genLiteralRepr (A.RecordLiteral _ es) = do genLeftB seqComma $ map genUnfoldedExpression es genRightB -- | Generate an expression inside a record literal. -- -- This is awkward: the sort of literal that this produces when there's a -- variable in here cannot always be compiled at the top level of a C99 program -- -- because in C99, an array subscript is not a constant, even if it's a -- constant subscript of a constant array. So we need to be sure that when we -- use this at the top level, the thing we're unfolding only contains literals. -- Yuck! genUnfoldedExpression :: A.Expression -> CGen () genUnfoldedExpression (A.Literal _ t lr) = do genLiteralRepr lr case t of A.Array ds _ -> do genComma genLeftB genArraySizesLiteral ds genRightB _ -> return () genUnfoldedExpression (A.ExprVariable m var) = genUnfoldedVariable m var genUnfoldedExpression e = genExpression e -- | Generate a variable inside a record literal. genUnfoldedVariable :: Meta -> A.Variable -> CGen () genUnfoldedVariable m var = do t <- typeOfVariable var case t of A.Array ds _ -> do genLeftB unfoldArray ds var genRightB genComma genLeftB genArraySizesLiteral ds genRightB A.Record _ -> do genLeftB fs <- recordFields m t seqComma [genUnfoldedVariable m (A.SubscriptedVariable m (A.SubscriptField m n) var) | (n, t) <- fs] genRightB -- We can defeat the usage check here because we know it's safe; *we're* -- generating the subscripts. -- FIXME Is that actually true for something like [a[x]]? _ -> genVariable' False var where unfoldArray :: [A.Dimension] -> A.Variable -> CGen () unfoldArray [] v = genUnfoldedVariable m v unfoldArray (A.Dimension n:ds) v = seqComma $ [unfoldArray ds (A.SubscriptedVariable m (A.Subscript m $ makeConstant m i) v) | i <- [0..(n - 1)]] unfoldArray _ _ = dieP m "trying to unfold array with unknown dimension" -- | Generate a decimal literal -- removing leading zeroes to avoid producing -- an octal literal! genDecimal :: String -> CGen () genDecimal "0" = tell ["0"] genDecimal ('0':s) = genDecimal s genDecimal ('-':s) = tell ["-"] >> genDecimal s genDecimal s = tell [s] genArrayLiteralElems :: [A.ArrayElem] -> CGen () genArrayLiteralElems aes = seqComma $ map genElem aes where genElem :: A.ArrayElem -> CGen () genElem (A.ArrayElemArray aes) = genArrayLiteralElems aes genElem (A.ArrayElemExpr e) = genUnfoldedExpression e genByteLiteral :: String -> CGen () genByteLiteral s = do c <- evalByte s tell [convByte c] convByte :: Char -> String convByte '\'' = "\\'" convByte '"' = "\\\"" convByte '\\' = "\\\\" convByte '\r' = "\\r" convByte '\n' = "\\n" convByte '\t' = "\\t" convByte c | o == 0 = "\\0" | (o < 32 || o > 127) = printf "\\%03o" o | otherwise = [c] where o = ord c --}}} --{{{ variables {- The various types are generated like this: ================= Use ================= Original ValAbbrev Abbrev -------------------------------------- INT x: int x; int x; int *x; x x x *x [10]INT xs: int xs[10]; int *xs; int *xs; xs xs xs xs xs[i] xs[i] xs[i] xs[i] [20][10]INT xss: int xss[20*10]; int *xss; int *xss; xss xss xss xss xss[i] &xss[i*10] &xss[i*10] &xss[i*10] (where 10 = xss_sizes[1]) xss[i][j] xss[i*10+j] xss[i*10+j] xss[i*10+j] [6][4][2]INT xsss: int xsss[6*4*2]; int *xsss; xsss xsss (as left) xsss[i] &xsss[i*4*2] xsss[i][j] &xsss[i*4*2+j*2] xsss[i][j][k] xsss[i*4*2+j*2+k] MYREC r: MYREC r; MYREC *r; MYREC *r; r &r r r r[F] (&r)->F (r)->F (r)->F [10]MYREC rs: MYREC rs[10]; MYREC *rs; MYREC *rs; rs rs rs rs rs[i] &rs[i] &rs[i] &rs[i] rs[i][F] (&rs[i])->F (&rs[i])->F (&rs[i])->F -- depending on what F is -- if it's another record... CHAN OF INT c: Channel c; Channel *c; c &c c [10]CHAN OF INT cs: Channel **cs; Channel **cs; cs cs cs cs[i] cs[i] cs[i] I suspect there's probably a nicer way of doing this, but as a translation of the above table this isn't too horrible... -} -- | Generate C code for a variable. genVariable :: A.Variable -> CGen () genVariable = genVariable' True -- | Generate C code for a variable without doing any range checks. genVariableUnchecked :: A.Variable -> CGen () genVariableUnchecked = genVariable' False -- FIXME This needs to detect when we've "gone through" a record and revert to -- the Original prefixing behaviour. (Can do the same for arrays?) -- Best way to do this is probably to make inner return a reference and a prefix, -- so that we can pass prefixes upwards... genVariable' :: Bool -> A.Variable -> CGen () genVariable' checkValid v = do am <- accessAbbrevMode v t <- typeOfVariable v let isSub = case v of A.Variable _ _ -> False A.SubscriptedVariable _ _ _ -> True let prefix = case (am, t) of (_, A.Array _ _) -> "" (A.Original, A.Chan _) -> if isSub then "" else "&" (A.Abbrev, A.Chan _) -> "" (A.Original, A.Record _) -> "&" (A.Abbrev, A.Record _) -> "" (A.Abbrev, _) -> "*" _ -> "" when (prefix /= "") $ tell ["(", prefix] inner v when (prefix /= "") $ tell [")"] where -- | Find the effective abbreviation mode for the variable we're looking at. -- This differs from abbrevModeOfVariable in that it will return Original -- for array and record elements (because when we're generating C, we can -- treat c->x as if it's just x). accessAbbrevMode :: A.Variable -> CGen A.AbbrevMode accessAbbrevMode (A.Variable _ n) = abbrevModeOfName n accessAbbrevMode (A.SubscriptedVariable _ sub v) = do am <- accessAbbrevMode v return $ case (am, sub) of (_, A.Subscript _ _) -> A.Original (_, A.SubscriptField _ _) -> A.Original _ -> am inner :: A.Variable -> CGen () inner (A.Variable _ n) = genName n inner sv@(A.SubscriptedVariable _ (A.Subscript _ _) _) = do let (es, v) = collectSubs sv genVariable v genArraySubscript checkValid v es inner (A.SubscriptedVariable _ (A.SubscriptField m n) v) = do genVariable v tell ["->"] genName n inner (A.SubscriptedVariable m (A.SubscriptFromFor m' start _) v) = inner (A.SubscriptedVariable m (A.Subscript m' start) v) inner (A.SubscriptedVariable m (A.SubscriptFrom m' start) v) = inner (A.SubscriptedVariable m (A.Subscript m' start) v) inner (A.SubscriptedVariable m (A.SubscriptFor m' _) v) = inner (A.SubscriptedVariable m (A.Subscript m' (makeConstant m' 0)) v) -- | Collect all the plain subscripts on a variable, so we can combine them. collectSubs :: A.Variable -> ([A.Expression], A.Variable) collectSubs (A.SubscriptedVariable _ (A.Subscript _ e) v) = (es' ++ [e], v') where (es', v') = collectSubs v collectSubs v = ([], v) genArraySubscript :: Bool -> A.Variable -> [A.Expression] -> CGen () genArraySubscript checkValid v es = do t <- typeOfVariable v let numDims = case t of A.Array ds _ -> length ds tell ["["] sequence_ $ intersperse (tell [" + "]) $ genPlainSub v es [0..(numDims - 1)] tell ["]"] where -- | Generate the individual offsets that need adding together to find the -- right place in the array. -- FIXME This is obviously not the best way to factor this, but I figure a -- smart C compiler should be able to work it out... genPlainSub :: A.Variable -> [A.Expression] -> [Int] -> [CGen ()] genPlainSub _ [] _ = [] genPlainSub v (e:es) (sub:subs) = gen : genPlainSub v es subs where gen = sequence_ $ intersperse (tell [" * "]) $ genSub : genChunks genSub = if checkValid then do tell ["occam_check_index ("] genExpression e tell [", "] genVariable v tell ["_sizes[", show sub, "], "] genMeta (findMeta e) tell [")"] else genExpression e genChunks = [genVariable v >> tell ["_sizes[", show i, "]"] | i <- subs] --}}} --{{{ expressions genExpression :: A.Expression -> CGen () genExpression (A.Monadic m op e) = genMonadic m op e genExpression (A.Dyadic m op e f) = genDyadic m op e f genExpression (A.MostPos m t) = genTypeSymbol "mostpos" t genExpression (A.MostNeg m t) = genTypeSymbol "mostneg" t --genExpression (A.SizeType m t) genExpression (A.SizeExpr m e) = do genExpression e tell ["_sizes[0]"] genExpression (A.SizeVariable m v) = do genVariable v tell ["_sizes[0]"] genExpression (A.Conversion m cm t e) = genConversion m cm t e genExpression (A.ExprVariable m v) = genVariable v genExpression (A.Literal _ _ lr) = genLiteral lr genExpression (A.True m) = tell ["true"] genExpression (A.False m) = tell ["false"] --genExpression (A.FunctionCall m n es) genExpression (A.IntrinsicFunctionCall m s es) = genIntrinsicFunction m s es --genExpression (A.SubscriptedExpr m s e) --genExpression (A.BytesInExpr m e) genExpression (A.BytesInType m t) = genBytesIn t Nothing --genExpression (A.OffsetOf m t n) genExpression t = missing $ "genExpression " ++ show t genTypeSymbol :: String -> A.Type -> CGen () genTypeSymbol s t = case scalarType t of Just ct -> tell ["occam_", s, "_", ct] Nothing -> missing $ "genTypeSymbol " ++ show t genIntrinsicFunction :: Meta -> String -> [A.Expression] -> CGen () genIntrinsicFunction m s es = do tell ["occam_", s, " ("] sequence [genExpression e >> genComma | e <- es] genMeta m tell [")"] --}}} --{{{ operators genSimpleMonadic :: String -> A.Expression -> CGen () genSimpleMonadic s e = do tell ["(", s] genExpression e tell [")"] genMonadic :: Meta -> A.MonadicOp -> A.Expression -> CGen () genMonadic _ A.MonadicSubtr e = genSimpleMonadic "-" e genMonadic _ A.MonadicBitNot e = genSimpleMonadic "~" e genMonadic _ A.MonadicNot e = genSimpleMonadic "!" e genSimpleDyadic :: String -> A.Expression -> A.Expression -> CGen () genSimpleDyadic s e f = do tell ["("] genExpression e tell [" ", s, " "] genExpression f tell [")"] genFuncDyadic :: Meta -> String -> A.Expression -> A.Expression -> CGen () genFuncDyadic m s e f = do t <- typeOfExpression e genTypeSymbol s t tell [" ("] genExpression e tell [", "] genExpression f tell [", "] genMeta m tell [")"] genDyadic :: Meta -> A.DyadicOp -> A.Expression -> A.Expression -> CGen () genDyadic m A.Add e f = genFuncDyadic m "add" e f genDyadic m A.Subtr e f = genFuncDyadic m "subtr" e f genDyadic m A.Mul e f = genFuncDyadic m "mul" e f genDyadic m A.Div e f = genFuncDyadic m "div" e f genDyadic m A.Rem e f = genFuncDyadic m "rem" e f genDyadic _ A.Plus e f = genSimpleDyadic "+" e f genDyadic _ A.Minus e f = genSimpleDyadic "-" e f genDyadic _ A.Times e f = genSimpleDyadic "*" e f genDyadic _ A.LeftShift e f = genSimpleDyadic "<<" e f genDyadic _ A.RightShift e f = genSimpleDyadic ">>" e f genDyadic _ A.BitAnd e f = genSimpleDyadic "&" e f genDyadic _ A.BitOr e f = genSimpleDyadic "|" e f genDyadic _ A.BitXor e f = genSimpleDyadic "^" e f genDyadic _ A.And e f = genSimpleDyadic "&&" e f genDyadic _ A.Or e f = genSimpleDyadic "||" e f genDyadic _ A.Eq e f = genSimpleDyadic "==" e f genDyadic _ A.NotEq e f = genSimpleDyadic "!=" e f genDyadic _ A.Less e f = genSimpleDyadic "<" e f genDyadic _ A.More e f = genSimpleDyadic ">" e f genDyadic _ A.LessEq e f = genSimpleDyadic "<=" e f genDyadic _ A.MoreEq e f = genSimpleDyadic ">=" e f --}}} --{{{ input/output items genInputItem :: A.Variable -> A.InputItem -> CGen () genInputItem c (A.InCounted m cv av) = do genInputItem c (A.InVariable m cv) t <- typeOfVariable av tell ["ChanIn ("] genVariable c tell [", "] fst $ abbrevVariable A.Abbrev t av tell [", "] subT <- trivialSubscriptType t genVariable cv tell [" * "] genBytesIn subT (Just av) tell [");\n"] genInputItem c (A.InVariable m v) = do t <- typeOfVariable v let rhs = fst $ abbrevVariable A.Abbrev t v case t of A.Int -> do tell ["ChanInInt ("] genVariable c tell [", "] rhs tell [");\n"] _ -> do tell ["ChanIn ("] genVariable c tell [", "] rhs tell [", "] genBytesIn t (Just v) tell [");\n"] genOutputItem :: A.Variable -> A.OutputItem -> CGen () genOutputItem c (A.OutCounted m ce ae) = do genOutputItem c (A.OutExpression m ce) t <- typeOfExpression ae case ae of A.ExprVariable m v -> do tell ["ChanOut ("] genVariable c tell [", "] fst $ abbrevVariable A.Abbrev t v tell [", "] subT <- trivialSubscriptType t genExpression ce tell [" * "] genBytesIn subT (Just v) tell [");\n"] genOutputItem c (A.OutExpression m e) = do t <- typeOfExpression e case (t, e) of (A.Int, _) -> do tell ["ChanOutInt ("] genVariable c tell [", "] genExpression e tell [");\n"] (_, A.ExprVariable _ v) -> do tell ["ChanOut ("] genVariable c tell [", "] fst $ abbrevVariable A.Abbrev t v tell [", "] genBytesIn t (Just v) tell [");\n"] _ -> do n <- makeNonce "output_item" tell ["const "] genType t tell [" ", n, " = "] genExpression e tell [";\n"] tell ["ChanOut ("] genVariable c tell [", &", n, ", "] genBytesIn t Nothing tell [");\n"] --}}} --{{{ replicators genReplicator :: A.Replicator -> CGen () -> CGen () genReplicator rep body = do tell ["for ("] genReplicatorLoop rep tell [") {\n"] body tell ["}\n"] isZero :: A.Expression -> Bool isZero (A.Literal _ A.Int (A.IntLiteral _ "0")) = True isZero _ = False genReplicatorLoop :: A.Replicator -> CGen () genReplicatorLoop (A.For m index base count) = if isZero base then genSimpleReplicatorLoop index count else genGeneralReplicatorLoop index base count genSimpleReplicatorLoop :: A.Name -> A.Expression -> CGen () genSimpleReplicatorLoop index count = do tell ["int "] genName index tell [" = 0; "] genName index tell [" < "] genExpression count tell ["; "] genName index tell ["++"] genGeneralReplicatorLoop :: A.Name -> A.Expression -> A.Expression -> CGen () genGeneralReplicatorLoop index base count = do counter <- makeNonce "replicator_count" tell ["int ", counter, " = "] genExpression count tell [", "] genName index tell [" = "] genExpression base tell ["; ", counter, " > 0; ", counter, "--, "] genName index tell ["++"] genReplicatorSize :: A.Replicator -> CGen () genReplicatorSize rep = genExpression (sizeOfReplicator rep) --}}} --{{{ abbreviations -- FIXME: This code is horrible, and I can't easily convince myself that it's correct. genSlice :: A.Variable -> A.Variable -> A.Expression -> A.Expression -> [A.Dimension] -> (CGen (), A.Name -> CGen ()) genSlice v (A.Variable _ on) start count ds -- We need to disable the index check here because we might be taking -- element 0 of a 0-length array -- which is valid. = (tell ["&"] >> genVariableUnchecked v, genArraySize False (do tell ["occam_check_slice ("] genExpression start tell [", "] genExpression count tell [", "] genName on tell ["_sizes[0], "] genMeta (findMeta count) tell [")"] sequence_ [do tell [", "] genName on tell ["_sizes[", show i, "]"] | i <- [1..(length ds - 1)]])) genArrayAbbrev :: A.Variable -> (CGen (), A.Name -> CGen ()) genArrayAbbrev v = (tell ["&"] >> genVariable v, genAASize v 0) where genAASize (A.SubscriptedVariable _ (A.Subscript _ _) v) arg = genAASize v (arg + 1) genAASize (A.Variable _ on) arg = genArraySize True (tell ["&"] >> genName on >> tell ["_sizes[", show arg, "]"]) genArraySize :: Bool -> CGen () -> A.Name -> CGen () genArraySize isPtr size n = if isPtr then do tell ["const int *"] genName n tell ["_sizes = "] size tell [";\n"] else do tell ["const int "] genName n tell ["_sizes[] = { "] size tell [" };\n"] noSize :: A.Name -> CGen () noSize n = return () genVariableAM :: A.Variable -> A.AbbrevMode -> CGen () genVariableAM v am = do when (am == A.Abbrev) $ tell ["&"] genVariable v -- | Generate the right-hand side of an abbreviation of a variable. abbrevVariable :: A.AbbrevMode -> A.Type -> A.Variable -> (CGen (), A.Name -> CGen ()) abbrevVariable am (A.Array _ _) v@(A.SubscriptedVariable _ (A.Subscript _ _) _) = genArrayAbbrev v abbrevVariable am (A.Array ds _) v@(A.SubscriptedVariable _ (A.SubscriptFromFor _ start count) v') = genSlice v v' start count ds abbrevVariable am (A.Array ds _) v@(A.SubscriptedVariable m (A.SubscriptFrom _ start) v') = genSlice v v' start (A.Dyadic m A.Minus (A.SizeExpr m (A.ExprVariable m v')) start) ds abbrevVariable am (A.Array ds _) v@(A.SubscriptedVariable m (A.SubscriptFor _ count) v') = genSlice v v' (makeConstant m 0) count ds abbrevVariable am (A.Array _ _) v = (genVariable v, genArraySize True (genVariable v >> tell ["_sizes"])) abbrevVariable am (A.Chan _) v = (genVariable v, noSize) abbrevVariable am (A.Record _) v = (genVariable v, noSize) abbrevVariable am t v = (genVariableAM v am, noSize) -- | Generate the size part of a RETYPES/RESHAPES abbrevation of a variable. genRetypeSizes :: Meta -> A.AbbrevMode -> A.Type -> A.Name -> A.Type -> A.Variable -> CGen () genRetypeSizes m am destT destN srcT srcV = do size <- makeNonce "retype_size" tell ["int ", size, " = occam_check_retype ("] genBytesIn srcT (Just srcV) tell [", "] free <- genBytesIn' destT Nothing tell [", "] genMeta m tell [");\n"] case destT of -- An array -- figure out the missing dimension, if there is one. A.Array destDS _ -> do case free of -- No free dimensions; check the complete array matches in size. Nothing -> do tell ["if (", size, " != 1) {\n"] genStop m "array size mismatch in RETYPES" tell ["}\n"] _ -> return () let dims = [case d of A.UnknownDimension -> -- Unknown dimension -- insert it. case free of Just _ -> tell [size] Nothing -> die "genRetypeSizes expecting free dimension" A.Dimension n -> tell [show n] | d <- destDS] genArraySize False (seqComma dims) destN -- Not array; just check the size is 1. _ -> do tell ["if (", size, " != 1) {\n"] genStop m "size mismatch in RETYPES" tell ["}\n"] -- | Generate the right-hand side of an abbreviation of an expression. abbrevExpression :: A.AbbrevMode -> A.Type -> A.Expression -> (CGen (), A.Name -> CGen ()) abbrevExpression am t@(A.Array _ _) e = case e of A.ExprVariable _ v -> abbrevVariable am t v A.Literal _ (A.Array ds _) r -> (genExpression e, declareArraySizes ds) _ -> bad where bad = (missing "array expression abbreviation", noSize) abbrevExpression am _ e = (genExpression e, noSize) --}}} --{{{ specifications genSpec :: A.Specification -> CGen () -> CGen () genSpec spec body = do introduceSpec spec body removeSpec spec -- | Generate the C type corresponding to a variable being declared. -- It must be possible to use this in arrays. declareType :: A.Type -> CGen () declareType (A.Chan _) = tell ["Channel *"] declareType t = genType t -- | Generate a declaration of a new variable. genDeclaration :: A.Type -> A.Name -> CGen () genDeclaration (A.Chan _) n = do tell ["Channel "] genName n tell [";\n"] genDeclaration (A.Array ds t) n = do declareType t tell [" "] genName n genFlatArraySize ds tell [";\n"] declareArraySizes ds n genDeclaration t n = do declareType t tell [" "] genName n tell [";\n"] -- | Generate the size of the C array that an occam array of the given -- dimensions maps to. genFlatArraySize :: [A.Dimension] -> CGen () genFlatArraySize ds = do tell ["["] sequence $ intersperse (tell [" * "]) [case d of A.Dimension n -> tell [show n] | d <- ds] tell ["]"] -- | Generate the size of the _sizes C array for an occam array. genArraySizesSize :: [A.Dimension] -> CGen () genArraySizesSize ds = do tell ["["] tell [show $ length ds] tell ["]"] -- | Declare an _sizes array for a variable. declareArraySizes :: [A.Dimension] -> A.Name -> CGen () declareArraySizes ds name = genArraySize False (genArraySizesLiteral ds) name -- | Generate a C literal to initialise an _sizes array with, where all the -- dimensions are fixed. genArraySizesLiteral :: [A.Dimension] -> CGen () genArraySizesLiteral ds = seqComma dims where dims :: [CGen ()] dims = [case d of A.Dimension n -> tell [show n] _ -> die "unknown dimension in array type" | d <- ds] -- | Initialise an item being declared. declareInit :: Meta -> A.Type -> A.Variable -> Maybe (CGen ()) declareInit _ (A.Chan _) var = Just $ do tell ["ChanInit ("] genVariable var tell [");\n"] declareInit m t@(A.Array ds t') var = Just $ do init <- case t' of A.Chan _ -> do A.Specification _ store _ <- makeNonceVariable "storage" m (A.Array ds A.Int) A.VariableName A.Original let storeV = A.Variable m store tell ["Channel "] genName store genFlatArraySize ds tell [";\n"] declareArraySizes ds store return (\sub -> Just $ do genVariable (sub var) tell [" = &"] genVariable (sub storeV) tell [";\n"] doMaybe $ declareInit m t' (sub var)) _ -> return (\sub -> declareInit m t' (sub var)) overArray m var init declareInit m rt@(A.Record _) var = Just $ do fs <- recordFields m rt sequence_ [initField t (A.SubscriptedVariable m (A.SubscriptField m n) var) | (n, t) <- fs] where initField :: A.Type -> A.Variable -> CGen () -- An array as a record field; we must initialise the sizes. initField t@(A.Array ds _) v = do sequence_ [do genVariable v tell ["_sizes[", show i, "] = ", show n, ";\n"] | (i, A.Dimension n) <- zip [0..(length ds - 1)] ds] doMaybe $ declareInit m t v initField t v = doMaybe $ declareInit m t v declareInit _ _ _ = Nothing -- | Free a declared item that's going out of scope. declareFree :: Meta -> A.Type -> A.Variable -> Maybe (CGen ()) declareFree _ _ _ = Nothing {- Original Abbrev INT x IS y: int *x = &y; int *x = &(*y); []INT xs IS ys: int *xs = ys; int *xs = ys; const int xs_sizes[] = ys_sizes; CHAN OF INT c IS d: Channel *c = d; [10]CHAN OF INT cs: Channel tmp[10]; Channel *cs[10]; for (...) { cs[i] = &tmp[i]; ChanInit(cs[i]); } const int cs_sizes[] = { 10 }; []CHAN OF INT ds IS cs: Channel **ds = cs; const int *ds_sizes = cs_sizes; -} introduceSpec :: A.Specification -> CGen () introduceSpec (A.Specification m n (A.Declaration _ t)) = do genDeclaration t n case declareInit m t (A.Variable m n) of Just p -> p Nothing -> return () introduceSpec (A.Specification _ n (A.Is _ am t v)) = do let (rhs, rhsSizes) = abbrevVariable am t v genDecl am t n tell [" = "] rhs tell [";\n"] rhsSizes n introduceSpec (A.Specification _ n (A.IsExpr _ am t e)) = do let (rhs, rhsSizes) = abbrevExpression am t e case (am, t, e) of (A.ValAbbrev, A.Array _ ts, A.Literal _ _ _) -> -- For "VAL []T a IS [vs]:", we have to use [] rather than * in the -- declaration, since you can't say "int *foo = {vs};" in C. do tell ["const "] genType ts tell [" "] genName n tell ["[] = "] rhs tell [";\n"] rhsSizes n (A.ValAbbrev, A.Record _, A.Literal _ _ _) -> -- Record literals are even trickier, because there's no way of -- directly writing a struct literal in C that you can use -> on. do tmp <- makeNonce "record_literal" tell ["const "] genType t tell [" ", tmp, " = "] rhs tell [";\n"] genDecl am t n tell [" = &", tmp, ";\n"] rhsSizes n _ -> do genDecl am t n tell [" = "] rhs tell [";\n"] rhsSizes n introduceSpec (A.Specification _ n (A.IsChannelArray _ t cs)) = do tell ["Channel *"] genName n tell ["[] = {"] seqComma (map genVariable cs) tell ["};\n"] declareArraySizes [A.Dimension $ length cs] n introduceSpec (A.Specification _ _ (A.DataType _ _)) = return () introduceSpec (A.Specification _ n (A.RecordType _ b fs)) = do tell ["typedef struct {\n"] sequence_ [case t of -- Arrays need the corresponding _sizes array. A.Array ds t' -> do genType t' tell [" "] genName n genFlatArraySize ds tell [";\n"] tell ["int "] genName n tell ["_sizes"] genArraySizesSize ds tell [";\n"] _ -> genDeclaration t n | (n, t) <- fs] tell ["} "] when b $ tell ["occam_struct_packed "] genName n tell [";\n"] introduceSpec (A.Specification _ n (A.Protocol _ _)) = return () introduceSpec (A.Specification _ n (A.ProtocolCase _ ts)) = do tell ["typedef enum {\n"] seqComma [genName tag >> tell ["_"] >> genName n | (tag, _) <- ts] -- You aren't allowed to have an empty enum. when (ts == []) $ tell ["empty_protocol_"] >> genName n tell ["\n"] tell ["} "] genName n tell [";\n"] introduceSpec (A.Specification _ n (A.Proc _ sm fs p)) = do genSpecMode sm tell ["void "] genName n tell [" (Process *me"] genFormals fs tell [") {\n"] genProcess p tell ["}\n"] introduceSpec (A.Specification _ n (A.Retypes m am t v)) = do origT <- typeOfVariable v let (rhs, rhsSizes) = abbrevVariable A.Abbrev origT v genDecl am t n tell [" = "] -- For scalar types that are VAL abbreviations (e.g. VAL INT64), -- we need to dereference the pointer that abbrevVariable gives us. let deref = case (am, t) of (_, A.Array _ _) -> False (_, A.Chan _) -> False (A.ValAbbrev, _) -> True _ -> False when deref $ tell ["*"] tell ["("] genDeclType am t when deref $ tell [" *"] tell [") "] rhs tell [";\n"] genRetypeSizes m am t n origT v --introduceSpec (A.Specification _ n (A.RetypesExpr _ am t e)) introduceSpec n = missing $ "introduceSpec " ++ show n removeSpec :: A.Specification -> CGen () removeSpec (A.Specification m n (A.Declaration _ t)) = case t of A.Array _ t' -> overArray m var (\sub -> declareFree m t' (sub var)) _ -> do case declareFree m t var of Just p -> p Nothing -> return () where var = A.Variable m n removeSpec _ = return () genSpecMode :: A.SpecMode -> CGen () genSpecMode A.PlainSpec = return () genSpecMode A.InlineSpec = tell ["inline "] --}}} --{{{ actuals/formals prefixComma :: [CGen ()] -> CGen () prefixComma cs = sequence_ [genComma >> c | c <- cs] genActuals :: [A.Actual] -> CGen () genActuals as = prefixComma (map genActual as) genActual :: A.Actual -> CGen () genActual actual = case actual of A.ActualExpression t e -> case (t, e) of (A.Array _ _, A.ExprVariable _ v) -> do genVariable v tell [", "] genVariable v tell ["_sizes"] _ -> genExpression e A.ActualVariable am t v -> case t of A.Array _ _ -> do genVariable v tell [", "] genVariable v tell ["_sizes"] _ -> fst $ abbrevVariable am t v numCArgs :: [A.Actual] -> Int numCArgs [] = 0 numCArgs (A.ActualVariable _ (A.Array _ _) _:fs) = 2 + numCArgs fs numCArgs (A.ActualExpression (A.Array _ _) _:fs) = 2 + numCArgs fs numCArgs (_:fs) = 1 + numCArgs fs genFormals :: [A.Formal] -> CGen () genFormals fs = prefixComma (map genFormal fs) genFormal :: A.Formal -> CGen () genFormal (A.Formal am t n) = case t of A.Array _ t' -> do genDecl am t n tell [", const int *"] genName n tell ["_sizes"] _ -> genDecl am t n --}}} --{{{ processes genProcess :: A.Process -> CGen () genProcess p = case p of A.Assign m vs es -> genAssign m vs es A.Input m c im -> genInput c im A.Output m c ois -> genOutput c ois A.OutputCase m c t ois -> genOutputCase c t ois A.Skip m -> tell ["/* skip */\n"] A.Stop m -> genStop m "STOP process" A.Main m -> tell ["/* main */\n"] A.Seq _ s -> genSeqBody s A.If m s -> genIf m s A.Case m e s -> genCase m e s A.While m e p -> genWhile e p A.Par m pm s -> genPar pm s -- PROCESSOR does nothing special. A.Processor m e p -> genProcess p A.Alt m b s -> genAlt b s A.ProcCall m n as -> genProcCall n as A.IntrinsicProcCall m s as -> genIntrinsicProc m s as --{{{ assignment genAssign :: Meta -> [A.Variable] -> A.ExpressionList -> CGen () genAssign m [v] el = case el of A.FunctionCallList _ _ _ -> missing "function call" A.ExpressionList _ [e] -> do t <- typeOfVariable v doAssign t v e where doAssign :: A.Type -> A.Variable -> A.Expression -> CGen () doAssign t@(A.Array _ subT) toV (A.ExprVariable m fromV) = overArray m fromV (\sub -> Just $ doAssign subT (sub toV) (A.ExprVariable m (sub fromV))) doAssign rt@(A.Record _) toV (A.ExprVariable m fromV) = do fs <- recordFields m rt sequence_ [let subV v = A.SubscriptedVariable m (A.SubscriptField m n) v in doAssign t (subV toV) (A.ExprVariable m $ subV fromV) | (n, t) <- fs] doAssign t v e = case scalarType t of Just _ -> do genVariable v tell [" = "] genExpression e tell [";\n"] Nothing -> missing $ "assignment of type " ++ show t --}}} --{{{ input genInput :: A.Variable -> A.InputMode -> CGen () genInput c im = do t <- typeOfVariable c case t of A.Timer -> case im of A.InputSimple m [A.InVariable m' v] -> genTimerRead c v A.InputAfter m e -> genTimerWait e _ -> case im of A.InputSimple m is -> sequence_ $ map (genInputItem c) is A.InputCase m s -> genInputCase m c s _ -> missing $ "genInput " ++ show im genInputCase :: Meta -> A.Variable -> A.Structured -> CGen () genInputCase m c s = do t <- typeOfVariable c let proto = case t of A.Chan (A.UserProtocol n) -> n tag <- makeNonce "case_tag" genName proto tell [" ", tag, ";\n"] tell ["ChanInInt ("] genVariable c tell [", &", tag, ");\n"] tell ["switch (", tag, ") {\n"] genInputCaseBody proto c (return ()) s tell ["default:\n"] genStop m "unhandled variant in CASE input" tell ["}\n"] -- This handles specs in a slightly odd way, because we can't insert specs into -- the body of a switch. genInputCaseBody :: A.Name -> A.Variable -> CGen () -> A.Structured -> CGen () genInputCaseBody proto c coll (A.Spec _ spec s) = genInputCaseBody proto c (genSpec spec coll) s genInputCaseBody proto c coll (A.OnlyV _ (A.Variant _ n iis p)) = do tell ["case "] genName n tell ["_"] genName proto tell [": {\n"] coll sequence_ $ map (genInputItem c) iis genProcess p tell ["break;\n"] tell ["}\n"] genInputCaseBody proto c coll (A.Several _ ss) = sequence_ $ map (genInputCaseBody proto c coll) ss genTimerRead :: A.Variable -> A.Variable -> CGen () genTimerRead c v = do tell ["ProcTime (&"] genVariable c tell [");\n"] genVariable v tell [" = "] genVariable c tell [";\n"] genTimerWait :: A.Expression -> CGen () genTimerWait e = do tell ["ProcTimeAfter ("] genExpression e tell [");\n"] --}}} --{{{ output genOutput :: A.Variable -> [A.OutputItem] -> CGen () genOutput c ois = sequence_ $ map (genOutputItem c) ois genOutputCase :: A.Variable -> A.Name -> [A.OutputItem] -> CGen () genOutputCase c tag ois = do t <- typeOfVariable c let proto = case t of A.Chan (A.UserProtocol n) -> n tell ["ChanOutInt ("] genVariable c tell [", "] genName tag tell ["_"] genName proto tell [");\n"] genOutput c ois --}}} --{{{ stop genStop :: Meta -> String -> CGen () genStop m s = do tell ["occam_stop ("] genMeta m tell [", \"", s, "\");\n"] --}}} --{{{ seq genSeqBody :: A.Structured -> CGen () genSeqBody s = genStructured s doP where doP (A.OnlyP _ p) = genProcess p --}}} --{{{ if genIf :: Meta -> A.Structured -> CGen () genIf m s = do label <- makeNonce "if_end" genIfBody label s genStop m "no choice matched in IF process" tell [label, ":\n;\n"] genIfBody :: String -> A.Structured -> CGen () genIfBody label s = genStructured s doC where doC (A.OnlyC m (A.Choice m' e p)) = do tell ["if ("] genExpression e tell [") {\n"] genProcess p tell ["goto ", label, ";\n"] tell ["}\n"] --}}} --{{{ case genCase :: Meta -> A.Expression -> A.Structured -> CGen () genCase m e s = do tell ["switch ("] genExpression e tell [") {\n"] seenDefault <- genCaseBody (return ()) s when (not seenDefault) $ do tell ["default:\n"] genStop m "no option matched in CASE process" tell ["}\n"] -- FIXME -- can this be made common with genInputCaseBody above? genCaseBody :: CGen () -> A.Structured -> CGen Bool genCaseBody coll (A.Spec _ spec s) = genCaseBody (genSpec spec coll) s genCaseBody coll (A.OnlyO _ (A.Option _ es p)) = do sequence_ [tell ["case "] >> genExpression e >> tell [":\n"] | e <- es] tell ["{\n"] coll genProcess p tell ["break;\n"] tell ["}\n"] return False genCaseBody coll (A.OnlyO _ (A.Else _ p)) = do tell ["default:\n"] tell ["{\n"] coll genProcess p tell ["}\n"] return True genCaseBody coll (A.Several _ ss) = do seens <- mapM (genCaseBody coll) ss return $ or seens --}}} --{{{ while genWhile :: A.Expression -> A.Process -> CGen () genWhile e p = do tell ["while ("] genExpression e tell [") {\n"] genProcess p tell ["}\n"] --}}} --{{{ par genPar :: A.ParMode -> A.Structured -> CGen () genPar pm s = do (size, _, _) <- constantFold $ addOne (sizeOfStructured s) pids <- makeNonce "pids" pris <- makeNonce "priorities" index <- makeNonce "i" when (pm == A.PriPar) $ do tell ["int ", pris, "["] genExpression size tell ["];\n"] tell ["Process *", pids, "["] genExpression size tell ["];\n"] tell ["int ", index, " = 0;\n"] genStructured s (createP pids pris index) tell [pids, "[", index, "] = NULL;\n"] case pm of A.PriPar -> tell ["ProcPriParList (", pids, ", ", pris, ");\n"] _ -> tell ["ProcParList (", pids, ");\n"] tell [index, " = 0;\n"] genStructured s (freeP pids index) where createP pids pris index (A.OnlyP _ p) = do when (pm == A.PriPar) $ tell [pris, "[", index, "] = ", index, ";\n"] tell [pids, "[", index, "++] = "] genProcAlloc p tell [";\n"] freeP pids index (A.OnlyP _ _) = do tell ["ProcAllocClean (", pids, "[", index, "++]);\n"] genProcAlloc :: A.Process -> CGen () genProcAlloc (A.ProcCall m n as) = do tell ["ProcAlloc ("] genName n -- FIXME stack size fixed here let stackSize = 65536 tell [", ", show stackSize, ", ", show $ numCArgs as] genActuals as tell [")"] genProcAlloc p = missing $ "genProcAlloc " ++ show p --}}} --{{{ alt genAlt :: Bool -> A.Structured -> CGen () genAlt isPri s = do tell ["AltStart ();\n"] tell ["{\n"] genAltEnable s tell ["}\n"] -- Like occ21, this is always a PRI ALT, so we can use it for both. tell ["AltWait ();\n"] id <- makeNonce "alt_id" tell ["int ", id, " = 0;\n"] tell ["{\n"] genAltDisable id s tell ["}\n"] fired <- makeNonce "alt_fired" tell ["int ", fired, " = AltEnd ();\n"] tell [id, " = 0;\n"] label <- makeNonce "alt_end" tell ["{\n"] genAltProcesses id fired label s tell ["}\n"] tell [label, ":\n;\n"] withIf :: A.Expression -> CGen () -> CGen () withIf cond body = do tell ["if ("] genExpression cond tell [") {\n"] body tell ["}\n"] genAltEnable :: A.Structured -> CGen () genAltEnable s = genStructured s doA where doA (A.OnlyA _ alt) = case alt of A.Alternative _ c im _ -> doIn c im A.AlternativeCond _ e c im _ -> withIf e $ doIn c im A.AlternativeSkip _ e _ -> withIf e $ tell ["AltEnableSkip ();\n"] doIn c im = do t <- inputType c im case t of ITTimerRead -> missing "timer read in ALT" ITTimerAfter -> do let time = case im of A.InputAfter _ e -> e tell ["AltEnableTimer ("] genExpression time tell [");\n"] ITOther -> do tell ["AltEnableChannel ("] genVariable c tell [");\n"] genAltDisable :: String -> A.Structured -> CGen () genAltDisable id s = genStructured s doA where doA (A.OnlyA _ alt) = case alt of A.Alternative _ c im _ -> doIn c im A.AlternativeCond _ e c im _ -> withIf e $ doIn c im A.AlternativeSkip _ e _ -> withIf e $ tell ["AltDisableSkip (", id, "++);\n"] doIn c im = do t <- inputType c im case t of ITTimerRead -> missing "timer read in ALT" ITTimerAfter -> do let time = case im of A.InputAfter _ e -> e tell ["AltDisableTimer (", id, "++, "] genExpression time tell [");\n"] ITOther -> do tell ["AltDisableChannel (", id, "++, "] genVariable c tell [");\n"] genAltProcesses :: String -> String -> String -> A.Structured -> CGen () genAltProcesses id fired label s = genStructured s doA where doA (A.OnlyA _ alt) = case alt of A.Alternative _ c im p -> doIn c im p A.AlternativeCond _ e c im p -> withIf e $ doIn c im p A.AlternativeSkip _ e p -> withIf e $ doCheck (genProcess p) doIn c im p = do t <- inputType c im case t of ITTimerRead -> missing "timer read in ALT" ITTimerAfter -> doCheck (genProcess p) ITOther -> doCheck (genInput c im >> genProcess p) doCheck body = do tell ["if (", id, "++ == ", fired, ") {\n"] body tell ["goto ", label, ";\n"] tell ["}\n"] --}}} --{{{ proc call genProcCall :: A.Name -> [A.Actual] -> CGen () genProcCall n as = do genName n tell [" (me"] genActuals as tell [");\n"] --}}} --{{{ intrinsic procs genIntrinsicProc :: Meta -> String -> [A.Actual] -> CGen () genIntrinsicProc m "ASSERT" [A.ActualExpression A.Bool e] = genAssert m e genIntrinsicProc _ s _ = missing $ "intrinsic PROC " ++ s genAssert :: Meta -> A.Expression -> CGen () genAssert m e = do tell ["if (!"] genExpression e tell [") {\n"] genStop m "assertion failed" tell ["}\n"] --}}} --}}}