packages feed

improve 0.3.2 → 0.3.3

raw patch · 11 files changed

+735/−466 lines, 11 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Language.ImProve.Code: instance Show Mdl
- Language.ImProve.Code: instance Show Statement
+ Language.ImProve: C :: Target
+ Language.ImProve: Modelica :: Target
+ Language.ImProve: Simulink :: Target
+ Language.ImProve: analyze :: (Statement -> IO a) -> Stmt () -> IO a
+ Language.ImProve: data Target
+ Language.ImProve.Code: C :: Target
+ Language.ImProve.Code: Modelica :: Target
+ Language.ImProve.Code: Simulink :: Target
+ Language.ImProve.Code: data Target
+ Language.ImProve.Code: instance Eq Target
+ Language.ImProve.Code.C: codeC :: Name -> Statement -> IO ()
+ Language.ImProve.Code.C: instance Show Statement
+ Language.ImProve.Code.Common: indent :: String -> String
+ Language.ImProve.Code.Modelica: codeModelica :: Name -> Statement -> IO ()
+ Language.ImProve.Code.Simulink: Add' :: Block
+ Language.ImProve.Code.Simulink: And' :: Block
+ Language.ImProve.Code.Simulink: Assertion :: Block
+ Language.ImProve.Code.Simulink: Cast :: String -> Block
+ Language.ImProve.Code.Simulink: Const' :: Const -> Block
+ Language.ImProve.Code.Simulink: Div' :: Block
+ Language.ImProve.Code.Simulink: Eq' :: Block
+ Language.ImProve.Code.Simulink: Ge' :: Block
+ Language.ImProve.Code.Simulink: Gt' :: Block
+ Language.ImProve.Code.Simulink: Inport :: Const -> Block
+ Language.ImProve.Code.Simulink: Le' :: Block
+ Language.ImProve.Code.Simulink: Lt' :: Block
+ Language.ImProve.Code.Simulink: Mod' :: Block
+ Language.ImProve.Code.Simulink: Mul' :: Block
+ Language.ImProve.Code.Simulink: Mux' :: Block
+ Language.ImProve.Code.Simulink: Netlist :: Int -> Path -> [Path] -> [Name] -> [(Name, Block)] -> [(Name, (Name, Int))] -> Netlist
+ Language.ImProve.Code.Simulink: Not' :: Block
+ Language.ImProve.Code.Simulink: Or' :: Block
+ Language.ImProve.Code.Simulink: Outport :: Const -> Block
+ Language.ImProve.Code.Simulink: Sub' :: Block
+ Language.ImProve.Code.Simulink: UnitDelay :: Const -> Block
+ Language.ImProve.Code.Simulink: blocks :: Netlist -> [(Name, Block)]
+ Language.ImProve.Code.Simulink: codeSimulink :: Name -> Statement -> IO ()
+ Language.ImProve.Code.Simulink: data Block
+ Language.ImProve.Code.Simulink: data Netlist
+ Language.ImProve.Code.Simulink: env :: Netlist -> [Name]
+ Language.ImProve.Code.Simulink: instance Show Mdl
+ Language.ImProve.Code.Simulink: netlist :: Statement -> IO Netlist
+ Language.ImProve.Code.Simulink: nets :: Netlist -> [(Name, (Name, Int))]
+ Language.ImProve.Code.Simulink: nextId :: Netlist -> Int
+ Language.ImProve.Code.Simulink: path :: Netlist -> Path
+ Language.ImProve.Code.Simulink: vars :: Netlist -> [Path]
+ Language.ImProve.Path: totalPaths :: Name -> Statement -> IO ()
- Language.ImProve: assume :: Name -> E Bool -> Stmt ()
+ Language.ImProve: assume :: Name -> E Bool -> Stmt Theorem
- Language.ImProve: code :: Name -> Stmt () -> IO ()
+ Language.ImProve: code :: Target -> Name -> Stmt () -> IO ()
- Language.ImProve.Code: code :: Name -> Statement -> IO ()
+ Language.ImProve.Code: code :: Target -> Name -> Statement -> IO ()
- Language.ImProve.Core: Assume :: E Bool -> Statement
+ Language.ImProve.Core: Assume :: Int -> E Bool -> Statement

Files

Language/ImProve.hs view
@@ -216,7 +216,10 @@   -- * Verification   , verify   -- * Code Generation+  , C.Target (..)   , code+  -- * General Analysis+  , analyze   ) where  import Control.Monad@@ -360,17 +363,8 @@ mux :: AllE a => E Bool -> E a -> E a -> E a mux = Mux --- | Array index to a variable.---(!) :: AllE a => A a -> E Int -> V a---(!) a i = VArray a i---- | Array index to an expression.---(!.) :: AllE a => A a -> E Int -> E a---(!.) a i = ref $ a ! i---- | Labels a statement and creates a variable scope.---   Labels are used in counter examples to trace the program execution.---   And assertion names, and hence counter example trace file names, are produce from labels.+-- | Labels a statement and creates a new variable scope.+--   Labels are used in counter examples to help trace the program execution. (-|) :: Name -> Stmt a -> Stmt a name -| stmt = do   (id, path0, stmt0) <- get@@ -470,15 +464,17 @@ instance Assign Int   where a <== b = statement $ Assign a b instance Assign Float where a <== b = statement $ Assign a b --- | Declare an assumption condition is true.---   Assumptions expressions must contain variables directly or indirectly related---   to the assertion under verification, otherwise they will be ignored.-assume :: Name -> E Bool -> Stmt ()-assume name a = statement $ Label name $ Assume a- -- | Theorem to be proven or used as lemmas to assist proofs of other theorems. data Theorem = Theorem' Int +-- | Assume a condition is true.+--   Assumptions are used as lemmas to other theorems.+assume :: Name -> E Bool -> Stmt Theorem+assume name a = do+  (id, path, stmt) <- get+  put (id + 1, path, Sequence stmt $ Label name $ Assume id a)+  return $ Theorem' id+ -- | Defines a new theorem. -- -- > theorem name k lemmas proposition@@ -520,13 +516,15 @@ -- -- > verify pathToYices program verify :: FilePath -> Stmt () -> IO ()-verify yices program = V.verify yices stmt-  where-  (_, _, stmt) = evalStmt 0 [] program+verify yices program = analyze (V.verify yices) program --- | Generate C and Simulink code.-code :: Name -> Stmt () -> IO ()-code name program = C.code name stmt+-- | Generate code.+code :: C.Target -> Name -> Stmt () -> IO ()+code target name program = analyze (C.code target name) program++-- | Generic program analysis.+analyze :: (Statement -> IO a) -> Stmt () -> IO a+analyze f program = f stmt   where   (_, _, stmt) = evalStmt 0 [] program 
Language/ImProve/Code.hs view
@@ -1,436 +1,26 @@-module Language.ImProve.Code (code) where--import Control.Monad.State-import Data.List-import Data.Maybe-import Text.Printf+module Language.ImProve.Code+  ( Target (..)+  , code+  ) where +import Language.ImProve.Code.C+import Language.ImProve.Code.Modelica+import Language.ImProve.Code.Simulink import Language.ImProve.Core-import Language.ImProve.Tree hiding (Branch)-import qualified Language.ImProve.Tree as T -infixr 0 :-, :=---- | Generate C and Simulink code.-code :: Name -> Statement -> IO ()-code name stmt = do-  writeFile (name ++ ".c") $-       "/* Generated by ImProve. */\n\n"-    ++ "#include <assert.h>\n\n"-    ++ codeVariables True scope ++ "\n"-    ++ "void " ++ name ++ "()\n{\n"-    ++ indent (codeStmt name [] stmt)-    ++ "}\n\n"-  writeFile (name ++ ".h") $-       "/* Generated by ImProve. */\n\n"-    ++ codeVariables False scope ++ "\n"-    ++ "void " ++ name ++ "(void);\n\n"-  codeMdl name stmt-  where-  scope = case tree (\ (_, path, _) -> path) $ stmtVars stmt of-    [] -> error "program contains no useful statements"-    a  -> T.Branch (name ++ "_variables") a--instance Show Statement where show = codeStmt "none" []--codeStmt :: Name -> [Name] -> Statement -> String-codeStmt name path a = case a of-  Assign a b -> name ++ "_variables." ++ pathName a ++ " = " ++ codeExpr b ++ ";\n"-  Branch a b Null -> "if (" ++ codeExpr a ++ ") {\n" ++ indent (codeStmt name path b) ++ "}\n"-  Branch a b c    -> "if (" ++ codeExpr a ++ ") {\n" ++ indent (codeStmt name path b) ++ "}\nelse {\n" ++ indent (codeStmt name path c) ++ "}\n"-  Sequence a b -> codeStmt name path a ++ codeStmt name path b-  Theorem _ _ _ a -> "assert((" ++ show (pathName path) ++ ", " ++ codeExpr a ++ "));\n"-  Assume a -> "assert((" ++ show (pathName path) ++ ", " ++ codeExpr a ++ "));\n"-  Label name' a -> "/*" ++ name' ++ "*/\n" ++ indent (codeStmt name (path ++ [name']) a)-  Null -> ""-  where--  codeExpr :: E a -> String-  codeExpr a = case a of-    Ref a     -> name ++ "_variables." ++ pathName a-    Const a   -> showConst $ const' a-    Add a b   -> group [codeExpr a, "+", codeExpr b]-    Sub a b   -> group [codeExpr a, "-", codeExpr b]-    Mul a b   -> group [codeExpr a, "*", showConst (const' b)]-    Div a b   -> group [codeExpr a, "/", showConst (const' b)]-    Mod a b   -> group [codeExpr a, "%", showConst (const' b)]-    Not a     -> group ["!", codeExpr a]-    And a b   -> group [codeExpr a, "&&",  codeExpr b]-    Or  a b   -> group [codeExpr a, "||",  codeExpr b]-    Eq  a b   -> group [codeExpr a, "==",  codeExpr b]-    Lt  a b   -> group [codeExpr a, "<",   codeExpr b]-    Gt  a b   -> group [codeExpr a, ">",   codeExpr b]-    Le  a b   -> group [codeExpr a, "<=",  codeExpr b]-    Ge  a b   -> group [codeExpr a, ">=",  codeExpr b]-    Mux a b c -> group [codeExpr a, "?", codeExpr b, ":", codeExpr c] -    where-    group :: [String] -> String-    group a = "(" ++ intercalate " " a ++ ")"--indent :: String -> String-indent = unlines . map ("\t" ++) . lines--indent' :: String -> String-indent' a = case lines a of-  [] -> []-  (a:b) -> a ++ "\n" ++ indent (unlines b)--codeVariables :: Bool -> (Tree Name (Bool, Path, Const)) -> String-codeVariables define a = (if define then "" else "extern ") ++ init (init (f1 a)) ++ (if define then " =\n    " ++ f2 a else "") ++ ";\n"-  where-  f1 a = case a of-    T.Branch name items -> "struct {  /* " ++ name ++ " */\n" ++ indent (concatMap f1 items) ++ "} " ++ name ++ ";\n"-    Leaf name (input, _, init) -> printf "%-5s %-25s;%s\n" (showConstType init) name (if input then "  /* input */" else "")--  f2 a = case a of-    T.Branch name items -> indent' $ "{   " ++ (intercalate ",   " $ map f2 items) ++ "}  /* " ++ name ++ " */\n"-    Leaf name (_, _, init) -> printf "%-15s  /* %s */\n" (showConst init) name--showConst :: Const -> String-showConst a = case a of-  Bool  True  -> "1"-  Bool  False -> "0"-  Int   a     -> show a-  Float a     -> show a--showConstType :: Const -> String-showConstType a = case a of-  Bool  _ -> "int"-  Int   _ -> "int"-  Float _ -> "float"---type Net = StateT Netlist IO--data Block-  = Inport  Const-  | Outport Const-  | UnitDelay Const-  | Cast String-  | Assertion-  | Const' Const-  | Add'-  | Sub'-  | Mul'-  | Div'-  | Mod'-  | Not'-  | And'-  | Or'-  | Eq'-  | Lt'-  | Gt'-  | Le'-  | Ge'-  | Mux'--data Netlist = Netlist-  { nextId :: Int-  , path   :: Path-  , vars   :: [Path]-  , env    :: [Name]-  , blocks :: [(Name, Block)]-  , nets   :: [(Name, (Name, Int))]-  }---- Simulink generation.-codeMdl :: Name -> Statement -> IO ()-codeMdl name stmt = do-  net <- execStateT all (Netlist 0 [] paths env [] []) >>= return . removeNullEffect-  writeFile (name ++ ".mdl") $ show $ mdl name $ (mdlBlocks $ blocks net) ++ (mdlLines $ nets net)-  where-  vars = stmtVars stmt-  paths = [ path | (_, path, _) <- vars ]-  env = [ error $ "variable " ++ pathName a ++ " does not have a source" | a <- vars ]--  all :: Net ()-  all = do-    inputs <- mapM input vars-    elaborate stmt-    mapM_ output $ zip vars inputs--  input :: VarInfo -> Net Name-  input (input, path, const) = if input-    then do-      a <- block' (pathName path) (Inport const)-      updateEnv path a-      return a-    else do-      a <- block $ UnitDelay const-      b <- block $ Cast $ constType const-      net a (b, 0)-      updateEnv path b-      return a-  -  output :: (VarInfo, Name) -> Net ()-  output ((True, _, _), _) = return ()-  output ((False, path, const), delay) = do-    a <- block' (pathName path) $ Outport const-    src <- getNet path-    net src (a, 0)-    net src (delay, 0)--newName :: Net Name-newName = do-  net <- get-  put net { nextId = nextId net + 1 }-  return $ "b" ++ show (nextId net)---- New unnamed block.-block :: Block -> Net Name-block a = do-  name <- newName-  modify $ \ net -> net { blocks = (name, a) : blocks net }-  return name---- New named block.-block' :: Name -> Block -> Net Name-block' name a = do-  modify $ \ net -> net { blocks = (name, a) : blocks net }-  return name---- New net.-net :: Name -> (Name, Int) -> Net ()-net src (dest, port) = modify $ \ net -> net { nets = (src, (dest, port)) : nets net }--updateEnv :: Path -> Name -> Net ()-updateEnv path name = do-  net <- get-  let i = fromJust $ elemIndex path $ vars net-      pre = take i $ env net-      post = drop (i + 1) $ env net-  put net { env = pre ++ [name] ++ post }--getNet :: Path -> Net Name-getNet path = do-  net <- get-  return $ env net !! (fromJust $ elemIndex path $ vars net)--getPathName :: Net Name-getPathName = do-  net <- get-  return $ pathName $ path net---- Elaborate netlist.-elaborate :: Statement -> Net ()-elaborate a = case a of --  Assign (V _ path _) b -> do-    b <- evalExpr b-    updateEnv path b--  Branch a b c -> do-    cond <- evalExpr a-    net0 <- get--    elaborate b-    net1 <- get-    modify $ \ net -> net { env = env net0 }--    elaborate c-    net2 <- get-    modify $ \ net -> net { env = env net0 }--    names <- mergeEnvs cond (env net1) (env net2)-    modify $ \ net -> net { env = names }--    where--    mergeEnvs :: Name -> [Name] -> [Name] -> Net [Name]-    mergeEnvs _ [] [] = return []-    mergeEnvs cond (a : as) (b : bs) = do-      names <- mergeEnvs cond as bs-      name <- if a == b then return a else do-        switch <- block Mux'-        net a    (switch, 0)-        net cond (switch, 1)-        net b    (switch, 2)-        return switch-      return $ name : names-    mergeEnvs _ _ _ = error "unbalanced environments"--  Sequence a b    -> elaborate a >> elaborate b--  Theorem _ _ _ a -> do-    a <- evalExpr a-    name <- getPathName-    assert <- block' name Assertion-    net a (assert, 0)--  Assume a -> do-    a <- evalExpr a-    name <- getPathName-    assert <- block' name Assertion-    net a (assert, 0)--  Label name a -> do-    modify $ \ net -> net { path = path net ++ [name] }-    elaborate a-    modify $ \ net -> net { path = init $ path net }--  Null            -> return ()--evalExpr :: E a -> Net Name-evalExpr a = case a of-  Ref (V _ path _) -> getNet path-  Const a   -> block $ Const' $ const' a-  Add a b   -> f2 Add' a b-  Sub a b   -> f2 Sub' a b-  Mul a b   -> do-    b <- block $ Const' $ const' b-    f2' Mul' a b-  Div a b   -> do-    b <- block $ Const' $ const' b-    f2' Div' a b-  Mod a b   -> do-    b <- block $ Const' $ const' b-    f2' Mod' a b-  Not a     -> f1 Not' a-  And a b   -> f2 And' a b-  Or  a b   -> f2 Or'  a b-  Eq  a b   -> f2 Eq'  a b-  Lt  a b   -> f2 Lt'  a b-  Gt  a b   -> f2 Gt'  a b-  Le  a b   -> f2 Le'  a b-  Ge  a b   -> f2 Ge'  a b-  Mux a b c -> f3 Mux' b a c-  where-  f1 :: Block -> E a -> Net Name-  f1 b a1 = do-    a1 <- evalExpr a1-    b  <- block b-    net a1 (b, 0)-    return b--  f2 :: Block -> E a -> E b -> Net Name-  f2 b a1 a2 = do-    a1 <- evalExpr a1-    a2 <- evalExpr a2-    b  <- block b-    net a1 (b, 0)-    net a2 (b, 1)-    return b--  f2' :: Block -> E a -> Name -> Net Name-  f2' b a1 a2 = do-    a1 <- evalExpr a1-    b  <- block b-    net a1 (b, 0)-    net a2 (b, 1)-    return b--  f3 :: Block -> E a -> E b -> E c -> Net Name-  f3 b a1 a2 a3 = do-    a1 <- evalExpr a1-    a2 <- evalExpr a2-    a3 <- evalExpr a3-    b  <- block b-    net a1 (b, 0)-    net a2 (b, 1)-    net a3 (b, 2)-    return b--data Mdl-  = String :- String-  | String := [Mdl]--instance Show Mdl where-  show a = case a of-    name :- value -> name ++ "\t" ++ show value ++ "\n"-    name := items -> name ++ " {\n" ++ indent (concatMap show items) ++ "}\n"-    where-    indent = unlines . map ('\t' :) . lines--mdl :: Name -> [Mdl] -> Mdl-mdl name blocks = "Library" :=-  [ "Name" :- name-  , "System" :=-    [ "Name" :- name-    , "Block" :=-      [ "BlockType" :- "SubSystem"-      , "Name" :- name-      , "TreatAsAtomicUnit" :- "on"-      , "System" := ("Name" :- name) : blocks-      ]-    ]-  ]--mdlLines :: [(Name, (Name, Int))] -> [Mdl]-mdlLines nets = map branch branches-  where-  branches :: [(Name, [(Name, Int)])]-  branches = [ (src, [ dest | (src', dest) <- nets, src == src' ]) | src <- nub $ fst $ unzip nets ]-  branch :: (Name, [(Name, Int)]) -> Mdl-  branch (src, dests) = "Line" :=-    [ "SrcBlock" :- src-    , "SrcPort"  :- "1"-    ] ++ (if length dests == 1 then head dests' else map ("Branch" :=) dests')-    where-    dests' = [ ["DstBlock" :- dest, "DstPort" :- show $ port + 1] | (dest, port) <- dests ]--mdlBlocks :: [(Name, Block)] -> [Mdl]-mdlBlocks blocks = map (port "Inport") inputs ++ map blk others ++ map (port "Outport") outputs-  where-  inputs  = zip [1 ..] $ sortBy (\ (a, _) (b, _) -> compare a b) [ (name, constType init) | (name, Inport  init) <- blocks ]-  outputs = zip [1 ..] $ sortBy (\ (a, _) (b, _) -> compare a b) [ (name, constType init) | (name, Outport init) <- blocks ]-  others  = [ (name, block) | (name, block) <- blocks, not $ isPort block ]-  port :: String -> (Int, (Name, String)) -> Mdl-  port direction (port, (name, typ)) = mdlBlock direction name-    [ "Port" :- show port-    , "DataType" :- typ-    ]-  isPort :: Block -> Bool-  isPort (Inport  _) = True-  isPort (Outport _) = True-  isPort _           = False--mdlBlock :: String -> Name -> [Mdl] -> Mdl-mdlBlock blockType name fields = "Block" :=-  [ "BlockType" :- blockType-  , "Name"      :- name-  ] ++ fields--constType :: Const -> String-constType a = case a of-  Bool  _ -> "boolean"-  Int   _ -> "int32"-  Float _ -> "single"--blk :: (Name, Block) -> Mdl-blk (name, a) = case a of-  Inport  _ -> undefined-  Outport _ -> undefined-  UnitDelay init -> f "UnitDelay"          ["X0" :- showConst init, "SampleTime" :- "-1"]-  Cast t         -> f "DataTypeConversion" ["OutDataTypeMode" :- t]-  Assertion      -> f "Assertion"          ["StopWhenAssertionFail" :- "off", "SampleTime" :- "-1", "Enabled" :- "on"]-  Const' c       -> f "Constant"           ["Value" :- showConst c, "OutDataTypeMode" :- constType c]-  Add'           -> f "Sum"                ["Inputs" :- "++"]-  Sub'           -> f "Sum"                ["Inputs" :- "+-"]-  Mul'           -> f "Product"            ["Inputs" :- "**"]-  Div'           -> f "Product"            ["Inputs" :- "*/"]-  Mod'           -> f "Math"               ["Operator" :- "mod"]-  Not'           -> f "Logic"              ["Operator" :- "NOT", "Inputs" :- "1"]-  And'           -> f "Logic"              ["Operator" :- "AND", "Inputs" :- "2"]-  Or'            -> f "Logic"              ["Operator" :- "OR",  "Inputs" :- "2"]-  Eq'            -> f "RelationalOperator" ["Operator" :- "==", "LogicOutDataTypeMode" :- "boolean"]-  Lt'            -> f "RelationalOperator" ["Operator" :- "<" , "LogicOutDataTypeMode" :- "boolean"]-  Gt'            -> f "RelationalOperator" ["Operator" :- ">" , "LogicOutDataTypeMode" :- "boolean"]-  Le'            -> f "RelationalOperator" ["Operator" :- "<=", "LogicOutDataTypeMode" :- "boolean"]-  Ge'            -> f "RelationalOperator" ["Operator" :- ">=", "LogicOutDataTypeMode" :- "boolean"]-  Mux'           -> f "Switch"             ["Criteria" :- "u2 ~= 0"]-  where-  f typ args = mdlBlock typ name args--isSrc :: Block -> Bool-isSrc a = case a of-  Outport _ -> False-  Assertion -> False-  _         -> True+-- | Code generation targets.+data Target+  = C+  | Modelica+  | Simulink+  deriving Eq -removeNullEffect :: Netlist -> Netlist-removeNullEffect net = if null unused then net else removeNullEffect net { blocks = blocks', nets = nets' }+-- | Generate target code.+code :: Target -> Name -> Statement -> IO ()+code target name stmt = f name stmt   where-  unused = [ name | (name, block) <- blocks net, isSrc block, not $ any (\ (n, _) -> name == n) $ nets net ]-  blocks' = [ (name, block) | (name, block) <- blocks net, not $ elem name unused ]-  nets' = [ (src, (dest, port)) | (src, (dest, port)) <- nets net, not $ elem dest unused ]+  f = case target of+    C        -> codeC+    Modelica -> codeModelica+    Simulink -> codeSimulink 
+ Language/ImProve/Code/C.hs view
@@ -0,0 +1,100 @@+module Language.ImProve.Code.C (codeC) where++import Data.List+import Text.Printf++import Language.ImProve.Code.Common+import Language.ImProve.Core+import Language.ImProve.Tree hiding (Branch)+import qualified Language.ImProve.Tree as T++-- | Generate C.+codeC :: Name -> Statement -> IO ()+codeC name stmt = do+  writeFile (name ++ ".c") $+       "/* Generated by ImProve. */\n\n"+    ++ "#include <assert.h>\n\n"+    ++ codeVariables True scope ++ "\n"+    ++ "void " ++ name ++ "()\n{\n"+    ++ indent (codeStmt name [] stmt)+    ++ "}\n\n"+  writeFile (name ++ ".h") $+       "/* Generated by ImProve. */\n\n"+    ++ "#ifdef __cplusplus\n"+    ++ "extern \"C\" {\n"+    ++ "#endif\n\n"+    ++ codeVariables False scope ++ "\n"+    ++ "void " ++ name ++ "(void);\n\n"+    ++ "#ifdef __cplusplus\n"+    ++ "}\n"+    ++ "#endif\n"+  where+  scope = case tree (\ (_, path, _) -> path) $ stmtVars stmt of+    [] -> error "program contains no useful statements"+    a  -> T.Branch (name ++ "_variables") a++instance Show Statement where show = codeStmt "none" []++codeStmt :: Name -> [Name] -> Statement -> String+codeStmt name path a = case a of+  Assign a b -> name ++ "_variables." ++ pathName a ++ " = " ++ codeExpr b ++ ";\n"+  Branch a b Null -> "if (" ++ codeExpr a ++ ") {\n" ++ indent (codeStmt name path b) ++ "}\n"+  Branch a b c    -> "if (" ++ codeExpr a ++ ") {\n" ++ indent (codeStmt name path b) ++ "}\nelse {\n" ++ indent (codeStmt name path c) ++ "}\n"+  Sequence a b -> codeStmt name path a ++ codeStmt name path b+  Theorem _ _ _ a -> "assert((" ++ show (pathName path) ++ ", " ++ codeExpr a ++ "));\n"+  Assume _ a -> "assert((" ++ show (pathName path) ++ ", " ++ codeExpr a ++ "));\n"+  Label name' a -> "/*" ++ name' ++ "*/\n" ++ indent (codeStmt name (path ++ [name']) a)+  Null -> ""+  where++  codeExpr :: E a -> String+  codeExpr a = case a of+    Ref a     -> name ++ "_variables." ++ pathName a+    Const a   -> showConst $ const' a+    Add a b   -> group [codeExpr a, "+", codeExpr b]+    Sub a b   -> group [codeExpr a, "-", codeExpr b]+    Mul a b   -> group [codeExpr a, "*", showConst (const' b)]+    Div a b   -> group [codeExpr a, "/", showConst (const' b)]+    Mod a b   -> group [codeExpr a, "%", showConst (const' b)]+    Not a     -> group ["!", codeExpr a]+    And a b   -> group [codeExpr a, "&&",  codeExpr b]+    Or  a b   -> group [codeExpr a, "||",  codeExpr b]+    Eq  a b   -> group [codeExpr a, "==",  codeExpr b]+    Lt  a b   -> group [codeExpr a, "<",   codeExpr b]+    Gt  a b   -> group [codeExpr a, ">",   codeExpr b]+    Le  a b   -> group [codeExpr a, "<=",  codeExpr b]+    Ge  a b   -> group [codeExpr a, ">=",  codeExpr b]+    Mux a b c -> group [codeExpr a, "?", codeExpr b, ":", codeExpr c] +    where+    group :: [String] -> String+    group a = "(" ++ intercalate " " a ++ ")"++indent' :: String -> String+indent' a = case lines a of+  [] -> []+  (a:b) -> a ++ "\n" ++ indent (unlines b)++codeVariables :: Bool -> (Tree Name (Bool, Path, Const)) -> String+codeVariables define a = (if define then "" else "extern ") ++ init (init (f1 a)) ++ (if define then " =\n\t" ++ f2 a else "") ++ ";\n"+  where+  f1 a = case a of+    T.Branch name items -> "struct {  /* " ++ name ++ " */\n" ++ indent (concatMap f1 items) ++ "} " ++ name ++ ";\n"+    Leaf name (input, _, init) -> printf "%-5s %-25s;%s\n" (showConstType init) name (if input then "  /* input */" else "")++  f2 a = case a of+    T.Branch name items -> indent' $ "{   " ++ (intercalate ",   " $ map f2 items) ++ "}  /* " ++ name ++ " */\n"+    Leaf name (_, _, init) -> printf "%-15s  /* %s */\n" (showConst init) name++showConst :: Const -> String+showConst a = case a of+  Bool  True  -> "1"+  Bool  False -> "0"+  Int   a     -> show a+  Float a     -> show a++showConstType :: Const -> String+showConstType a = case a of+  Bool  _ -> "int"+  Int   _ -> "int"+  Float _ -> "float"+
+ Language/ImProve/Code/Common.hs view
@@ -0,0 +1,7 @@+module Language.ImProve.Code.Common+  ( indent+  ) where++indent :: String -> String+indent = unlines . map ("\t" ++) . lines+
+ Language/ImProve/Code/Modelica.hs view
@@ -0,0 +1,154 @@+module Language.ImProve.Code.Modelica (codeModelica) where++import Data.Function+import Data.List+import Data.Maybe+import Text.Printf++import Language.ImProve.Code.Simulink+import Language.ImProve.Core++-- Modelica generation.+codeModelica :: Name -> Statement -> IO ()+codeModelica name stmt = do+  net <- netlist stmt >>= return . moRename+  writeFile (name ++ ".mo") $ unlines $+    [ "// Generated by ImProve."+    , ""+    , "block " ++ name+    , "\tparameter Real Period=0.001;"+    ] +++    inputs net +++    outputs net +++    [ "protected" ] +++    states net +++    internals net +++    [ "equation"+    , "\twhen sample(0, Period) then"+    ] +++    equations net +++    [ "\tend when;"+    , "end " ++ name ++ ";"+    ]+  where+  inputs    net = [ printf "\tinput %s %s;"                 (constType a) name               | (name, Inport a)    <- sortedBlocks net ]+  outputs   net = [ printf "\tdiscrete output %s %s;"       (constType a) name               | (name, Outport a)   <- sortedBlocks net ]+  states    net = [ printf "\tdiscrete %s %s (start = %s);" (constType a) name (showConst a) | (name, UnitDelay a) <- sortedBlocks net ]+  internals net = [ printf "\tdiscrete %s %s;"           (constType $ netType net name) name | (name, block) <- sortedBlocks net, isInternal block ]+  equations net = mapMaybe (equation net) $ blocks net+  sortedBlocks net = sortBy (compare `on` fst) $ blocks net++equation :: Netlist -> (Name, Block) -> Maybe String+equation net (name, block) = case block of+  Inport  _      -> Nothing+  Outport _      -> f $ arg 0+  UnitDelay _    -> f $ arg 0+  Cast _         -> f $ printf "pre(%s)" $ arg 0+  Assertion      -> Just $ printf "\tassert(%s, \"%s\");" (arg 0) name+  Const' c       -> f $ showConst c+  Add'           -> f $ printf "%s + %s" (arg 0) (arg 1)+  Sub'           -> f $ printf "%s - %s" (arg 0) (arg 1)+  Mul'           -> f $ printf "%s * %s" (arg 0) (arg 1)+  Div'           -> case netType net name of+		      Bool  _ -> error "Modelica.equation: invalid netlist (1)"+                      Int   _ -> f $ printf "div(%s, %s)" (arg 0) (arg 1)+		      Float _ -> f $ printf "%s / %s"     (arg 0) (arg 1)+  Mod'           -> f $ printf "mod(%s, %s)" (arg 0) (arg 1)+  Not'           -> f $ printf "not %s" $ arg 0+  And'           -> f $ printf "%s and %s" (arg 0) (arg 1)+  Or'            -> f $ printf "%s or %s" (arg 0) (arg 1)+  Eq'            -> f $ printf "%s == %s" (arg 0) (arg 1)+  Lt'            -> f $ printf "%s < %s" (arg 0) (arg 1)+  Gt'            -> f $ printf "%s > %s" (arg 0) (arg 1)+  Le'            -> f $ printf "%s <= %s" (arg 0) (arg 1)+  Ge'            -> f $ printf "%s >= %s" (arg 0) (arg 1)+  Mux'           -> f $ printf "if %s then %s else %s" (arg 0) (arg 1) (arg 2)+  where+  f :: String -> Maybe String+  f a = Just $ printf "\t%s = %s;" name a+  arg i = case [ n | (n, (n1, p1)) <- nets net, n1 == name, p1 == i ] of+    [n] -> n+    _ -> error "Modelica.equation: invalid netlist (2)"++isInternal :: Block -> Bool+isInternal a = case a of+  Inport    _ -> False+  Outport   _ -> False+  UnitDelay _ -> False+  Assertion   -> False+  _           -> True++moRename :: Netlist -> Netlist+moRename net = net { env = map f $ env net, blocks = [ (f n, b) | (n, b) <- blocks net ], nets = [ (f a, (f b, i)) | (a, (b, i)) <- nets net ] }+  where+  f n = "`" ++ n ++ "`"++showConst :: Const -> String+showConst a = case a of+  Bool  True  -> "true"+  Bool  False -> "false"+  Int   a     -> show a+  Float a     -> show a++constType :: Const -> String+constType a = case a of+  Bool  _ -> "Boolean"+  Int   _ -> "Integer"+  Float _ -> "Real   "++netType :: Netlist -> Name -> Const+netType net name = case fromJust $ lookup name $ blocks net of+  Inport    a -> a+  UnitDelay a -> a+  Const'    a -> a+  Outport _ -> error "Modelica.netType: not expecting Outport"+  Assertion -> error "Modelica.netType: not expecting Assertion"+  Mod' -> Int 0+  Not' -> Bool False+  And' -> Bool False+  Or'  -> Bool False+  Eq'  -> Bool False+  Lt'  -> Bool False+  Gt'  -> Bool False+  Le'  -> Bool False+  Ge'  -> Bool False+  Mux' -> follow 1+  _    -> follow 0+  where+  follow :: Int -> Const+  follow p = case [ n | (n, (n1, p1)) <- nets net, n1 == name, p1 == p ] of+    [n] -> netType net n+    _   -> error "Modelica.netType: invalid netlist"++{-+data Block+  = Inport  Const+  | Outport Const+  | UnitDelay Const+  | Cast String+  | Assertion+  | Const' Const+  | Add'+  | Sub'+  | Mul'+  | Div'+  | Mod'+  | Not'+  | And'+  | Or'+  | Eq'+  | Lt'+  | Gt'+  | Le'+  | Ge'+  | Mux'++data Netlist = Netlist+  { nextId :: Int+  , path   :: Path+  , vars   :: [Path]+  , env    :: [Name]+  , blocks :: [(Name, Block)]+  , nets   :: [(Name, (Name, Int))]+  }+-}
+ Language/ImProve/Code/Simulink.hs view
@@ -0,0 +1,371 @@+module Language.ImProve.Code.Simulink+  ( codeSimulink+  , Netlist (..)+  , Block   (..)+  , netlist+  ) where++import Control.Monad.State+import Data.List+import Data.Maybe++import Language.ImProve.Code.Common+import Language.ImProve.Core++infixr 0 :-, :=++showConst :: Const -> String+showConst a = case a of+  Bool  True  -> "1"+  Bool  False -> "0"+  Int   a     -> show a+  Float a     -> show a++type Net = StateT Netlist IO++data Block+  = Inport  Const+  | Outport Const+  | UnitDelay Const+  | Cast String+  | Assertion+  | Const' Const+  | Add'+  | Sub'+  | Mul'+  | Div'+  | Mod'+  | Not'+  | And'+  | Or'+  | Eq'+  | Lt'+  | Gt'+  | Le'+  | Ge'+  | Mux'++data Netlist = Netlist+  { nextId :: Int+  , path   :: Path+  , vars   :: [Path]+  , env    :: [Name]+  , blocks :: [(Name, Block)]+  , nets   :: [(Name, (Name, Int))]+  }++-- Simulink generation.+codeSimulink :: Name -> Statement -> IO ()+codeSimulink name stmt = do+  net <- netlist stmt+  writeFile (name ++ ".mdl") $ show $ mdl name $ (mdlBlocks $ blocks net) ++ (mdlLines $ nets net)++-- | Builds a netlist.+netlist :: Statement -> IO Netlist+netlist stmt' = execStateT all (Netlist 0 [] paths env [] []) >>= return . removeNullEffect+  where+  stmt = lowerConditionals (Const True) stmt'+  vars = stmtVars stmt+  paths = [ path | (_, path, _) <- vars ]+  env = [ error $ "variable " ++ pathName a ++ " does not have a source" | a <- vars ]++  all :: Net ()+  all = do+    inputs <- mapM input vars+    evalStmt stmt+    mapM_ output $ zip vars inputs++  input :: VarInfo -> Net Name+  input (input, path, const) = if input+    then do+      a <- block' (pathName path) (Inport const)+      updateEnv path a+      return a+    else do+      a <- block $ UnitDelay const+      b <- block $ Cast $ constType const+      net a (b, 0)+      updateEnv path b+      return a+  +  output :: (VarInfo, Name) -> Net ()+  output ((True, _, _), _) = return ()+  output ((False, path, const), delay) = do+    a <- block' (pathName path) $ Outport const+    src <- getNet path+    net src (a, 0)+    net src (delay, 0)++-- Pushes conditionals down to theorems and assumptions.+lowerConditionals :: E Bool -> Statement -> Statement+lowerConditionals cond a = case a of+  Assign   a b     -> Assign a b+  Branch   a b c   -> Branch a (lowerConditionals (And cond a) b) (lowerConditionals (And cond $ Not a) c)+  Sequence a b     -> Sequence (lowerConditionals cond a) (lowerConditionals cond b)+  Theorem  a b c d -> Theorem a b c $ Or (Not cond) d+  Assume   i a     -> Assume i $ Or (Not cond) a+  Label    a b     -> Label a $ lowerConditionals cond b+  Null             -> Null++newName :: Net Name+newName = do+  net <- get+  put net { nextId = nextId net + 1 }+  return $ "b" ++ show (nextId net)++-- New unnamed block.+block :: Block -> Net Name+block a = do+  name <- newName+  modify $ \ net -> net { blocks = (name, a) : blocks net }+  return name++-- New named block.+block' :: Name -> Block -> Net Name+block' name a = do+  modify $ \ net -> net { blocks = (name, a) : blocks net }+  return name++-- New net.+net :: Name -> (Name, Int) -> Net ()+net src (dest, port) = modify $ \ net -> net { nets = (src, (dest, port)) : nets net }++updateEnv :: Path -> Name -> Net ()+updateEnv path name = do+  net <- get+  let i = fromJust $ elemIndex path $ vars net+      pre = take i $ env net+      post = drop (i + 1) $ env net+  put net { env = pre ++ [name] ++ post }++getNet :: Path -> Net Name+getNet path = do+  net <- get+  return $ env net !! (fromJust $ elemIndex path $ vars net)++getPathName :: Net Name+getPathName = do+  net <- get+  return $ pathName $ path net++-- Elaborate netlist.+evalStmt :: Statement -> Net ()+evalStmt a = case a of ++  Assign (V _ path _) b -> do+    b <- evalExpr b+    updateEnv path b++  Branch a b c -> do+    cond <- evalExpr a+    net0 <- get++    evalStmt b+    net1 <- get+    modify $ \ net -> net { env = env net0 }++    evalStmt c+    net2 <- get+    modify $ \ net -> net { env = env net0 }++    names <- mergeEnvs cond (env net1) (env net2)+    modify $ \ net -> net { env = names }++    where++    mergeEnvs :: Name -> [Name] -> [Name] -> Net [Name]+    mergeEnvs _ [] [] = return []+    mergeEnvs cond (a : as) (b : bs) = do+      names <- mergeEnvs cond as bs+      name <- if a == b then return a else do+        switch <- block Mux'+        net a    (switch, 0)+        net cond (switch, 1)+        net b    (switch, 2)+        return switch+      return $ name : names+    mergeEnvs _ _ _ = error "unbalanced environments"++  Sequence a b    -> evalStmt a >> evalStmt b++  Theorem _ _ _ a -> do+    a <- evalExpr a+    name <- getPathName+    assert <- block' name Assertion+    net a (assert, 0)++  Assume _ a -> do+    a <- evalExpr a+    name <- getPathName+    assert <- block' name Assertion+    net a (assert, 0)++  Label name a -> do+    modify $ \ net -> net { path = path net ++ [name] }+    evalStmt a+    modify $ \ net -> net { path = init $ path net }++  Null            -> return ()++evalExpr :: E a -> Net Name+evalExpr a = case a of+  Ref (V _ path _) -> getNet path+  Const a   -> block $ Const' $ const' a+  Add a b   -> f2 Add' a b+  Sub a b   -> f2 Sub' a b+  Mul a b   -> do+    b <- block $ Const' $ const' b+    f2' Mul' a b+  Div a b   -> do+    b <- block $ Const' $ const' b+    f2' Div' a b+  Mod a b   -> do+    b <- block $ Const' $ const' b+    f2' Mod' a b+  Not a     -> f1 Not' a+  And a b   -> f2 And' a b+  Or  a b   -> f2 Or'  a b+  Eq  a b   -> f2 Eq'  a b+  Lt  a b   -> f2 Lt'  a b+  Gt  a b   -> f2 Gt'  a b+  Le  a b   -> f2 Le'  a b+  Ge  a b   -> f2 Ge'  a b+  Mux a b c -> f3 Mux' b a c+  where+  f1 :: Block -> E a -> Net Name+  f1 b a1 = do+    a1 <- evalExpr a1+    b  <- block b+    net a1 (b, 0)+    return b++  f2 :: Block -> E a -> E b -> Net Name+  f2 b a1 a2 = do+    a1 <- evalExpr a1+    a2 <- evalExpr a2+    b  <- block b+    net a1 (b, 0)+    net a2 (b, 1)+    return b++  f2' :: Block -> E a -> Name -> Net Name+  f2' b a1 a2 = do+    a1 <- evalExpr a1+    b  <- block b+    net a1 (b, 0)+    net a2 (b, 1)+    return b++  f3 :: Block -> E a -> E b -> E c -> Net Name+  f3 b a1 a2 a3 = do+    a1 <- evalExpr a1+    a2 <- evalExpr a2+    a3 <- evalExpr a3+    b  <- block b+    net a1 (b, 0)+    net a2 (b, 1)+    net a3 (b, 2)+    return b++data Mdl+  = String :- String+  | String := [Mdl]++instance Show Mdl where+  show a = case a of+    name :- value -> name ++ "\t" ++ show value ++ "\n"+    name := items -> name ++ " {\n" ++ indent (concatMap show items) ++ "}\n"++mdl :: Name -> [Mdl] -> Mdl+mdl name blocks = "Library" :=+  [ "Name" :- name+  , "System" :=+    [ "Name" :- name+    , "Block" :=+      [ "BlockType" :- "SubSystem"+      , "Name" :- name+      , "TreatAsAtomicUnit" :- "on"+      , "System" := ("Name" :- name) : blocks+      ]+    ]+  ]++mdlLines :: [(Name, (Name, Int))] -> [Mdl]+mdlLines nets = map branch branches+  where+  branches :: [(Name, [(Name, Int)])]+  branches = [ (src, [ dest | (src', dest) <- nets, src == src' ]) | src <- nub $ fst $ unzip nets ]+  branch :: (Name, [(Name, Int)]) -> Mdl+  branch (src, dests) = "Line" :=+    [ "SrcBlock" :- src+    , "SrcPort"  :- "1"+    ] ++ (if length dests == 1 then head dests' else map ("Branch" :=) dests')+    where+    dests' = [ ["DstBlock" :- dest, "DstPort" :- show $ port + 1] | (dest, port) <- dests ]++mdlBlocks :: [(Name, Block)] -> [Mdl]+mdlBlocks blocks = map (port "Inport") inputs ++ map blk others ++ map (port "Outport") outputs+  where+  inputs  = zip [1 ..] $ sortBy (\ (a, _) (b, _) -> compare a b) [ (name, constType init) | (name, Inport  init) <- blocks ]+  outputs = zip [1 ..] $ sortBy (\ (a, _) (b, _) -> compare a b) [ (name, constType init) | (name, Outport init) <- blocks ]+  others  = [ (name, block) | (name, block) <- blocks, not $ isPort block ]+  port :: String -> (Int, (Name, String)) -> Mdl+  port direction (port, (name, typ)) = mdlBlock direction name+    [ "Port" :- show port+    , "DataType" :- typ+    ]+  isPort :: Block -> Bool+  isPort (Inport  _) = True+  isPort (Outport _) = True+  isPort _           = False++mdlBlock :: String -> Name -> [Mdl] -> Mdl+mdlBlock blockType name fields = "Block" :=+  [ "BlockType" :- blockType+  , "Name"      :- name+  ] ++ fields++constType :: Const -> String+constType a = case a of+  Bool  _ -> "boolean"+  Int   _ -> "int32"+  Float _ -> "single"++blk :: (Name, Block) -> Mdl+blk (name, a) = case a of+  Inport  _ -> undefined+  Outport _ -> undefined+  UnitDelay init -> f "UnitDelay"          ["X0" :- showConst init, "SampleTime" :- "-1"]+  Cast t         -> f "DataTypeConversion" ["OutDataTypeMode" :- t]+  Assertion      -> f "Assertion"          ["StopWhenAssertionFail" :- "off", "SampleTime" :- "-1", "Enabled" :- "on"]+  Const' c       -> f "Constant"           ["Value" :- showConst c, "OutDataTypeMode" :- constType c]+  Add'           -> f "Sum"                ["Inputs" :- "++"]+  Sub'           -> f "Sum"                ["Inputs" :- "+-"]+  Mul'           -> f "Product"            ["Inputs" :- "**"]+  Div'           -> f "Product"            ["Inputs" :- "*/"]+  Mod'           -> f "Math"               ["Operator" :- "mod"]+  Not'           -> f "Logic"              ["Operator" :- "NOT", "Inputs" :- "1"]+  And'           -> f "Logic"              ["Operator" :- "AND", "Inputs" :- "2"]+  Or'            -> f "Logic"              ["Operator" :- "OR",  "Inputs" :- "2"]+  Eq'            -> f "RelationalOperator" ["Operator" :- "==", "LogicOutDataTypeMode" :- "boolean"]+  Lt'            -> f "RelationalOperator" ["Operator" :- "<" , "LogicOutDataTypeMode" :- "boolean"]+  Gt'            -> f "RelationalOperator" ["Operator" :- ">" , "LogicOutDataTypeMode" :- "boolean"]+  Le'            -> f "RelationalOperator" ["Operator" :- "<=", "LogicOutDataTypeMode" :- "boolean"]+  Ge'            -> f "RelationalOperator" ["Operator" :- ">=", "LogicOutDataTypeMode" :- "boolean"]+  Mux'           -> f "Switch"             ["Criteria" :- "u2 ~= 0"]+  where+  f typ args = mdlBlock typ name args++isSrc :: Block -> Bool+isSrc a = case a of+  Outport _ -> False+  Assertion -> False+  _         -> True++removeNullEffect :: Netlist -> Netlist+removeNullEffect net = if null unused then net else removeNullEffect net { blocks = blocks', nets = nets' }+  where+  unused = [ name | (name, block) <- blocks net, isSrc block, not $ any (\ (n, _) -> name == n) $ nets net ]+  blocks' = [ (name, block) | (name, block) <- blocks net, not $ elem name unused ]+  nets' = [ (src, (dest, port)) | (src, (dest, port)) <- nets net, not $ elem dest unused ]+
Language/ImProve/Core.hs view
@@ -108,7 +108,7 @@   Branch   :: E Bool -> Statement -> Statement -> Statement   Sequence :: Statement -> Statement -> Statement   Theorem  :: Int -> Int -> [Int] -> E Bool -> Statement -- Theorem id k lemmas expr-  Assume   :: E Bool -> Statement+  Assume   :: Int -> E Bool -> Statement                 -- Assume id expr   Label    :: Name -> Statement -> Statement   Null     :: Statement @@ -131,7 +131,7 @@   Branch a b c -> nub $ exprVars a ++ stmtVars b ++ stmtVars c   Sequence a b -> nub $ stmtVars a ++ stmtVars b   Theorem _ _ _ a -> exprVars a-  Assume a     -> exprVars a+  Assume  _ a     -> exprVars a   Label  _ a   -> stmtVars a   Null         -> [] @@ -162,7 +162,7 @@   Assign _ _   -> []   Branch _ a b -> theorems a ++ theorems b   Sequence a b -> theorems a ++ theorems b-  Assume _     -> []+  Assume _ _   -> []   Label  _ a   -> theorems a   Null         -> [] 
Language/ImProve/Examples.hs view
@@ -60,7 +60,7 @@  -- | Build the gcdMain code (i.e. gcd.c, gcd.h). buildGCD :: IO ()-buildGCD = code "gcd" gcdMain+buildGCD = code C "gcd" gcdMain   @@ -176,13 +176,13 @@ buildArbiters :: IO () buildArbiters = do   putStrLn "\nBuilding arbiter1 (arbiter1.c/h) ..."-  code "arbiter1" $ arbiter "arbiter1" arbiter1+  code C "arbiter1" $ arbiter "arbiter1" arbiter1    putStrLn "\nBuilding arbiter2 (arbiter2.c/h) ..."-  code "arbiter2" $ arbiter "arbiter2" arbiter2+  code C "arbiter2" $ arbiter "arbiter2" arbiter2    putStrLn "\nBuilding arbiter3 (arbiter3.c/h) ..."-  code "arbiter3" $ arbiter "arbiter3" arbiter3+  code C "arbiter3" $ arbiter "arbiter3" arbiter3  -- | Run all examples. runAll :: IO ()
+ Language/ImProve/Path.hs view
@@ -0,0 +1,42 @@+module Language.ImProve.Path+  ( totalPaths+  ) where++import Language.ImProve.Core++totalPaths :: Name -> Statement -> IO ()+totalPaths name stmt = do+  putStrLn $ "total paths: " ++ show (paths stmt)+  writeFile (name ++ ".dot") (dot stmt)++paths :: Statement -> Integer+paths a = case a of+  Assign _ _      -> 1+  Branch _ a b    -> paths a + paths b+  Sequence a b    -> paths a * paths b+  Theorem _ _ _ _ -> 1+  Assume  _ _     -> 1+  Label  _ a      -> paths a+  Null            -> 1++dot :: Statement -> String+dot stmt = unlines $ ["digraph {"] ++ links ++ ["}"]+  where+  (_, _, links) = d 0 1 stmt++d :: Int -> Int -> Statement -> (Int, Int, [String])+d src id a = case a of+  Branch _ a b -> (id2, id2 + 1, link src id ++ a' ++ b' ++ link srcA id2 ++ link srcB id2)+    where+    (srcA, id1, a') = d id (id + 1)  a+    (srcB, id2, b') = d id  id1      b+  Sequence a b -> (srcB, id2, a' ++ b')+    where+    (srcA, id1, a') = d src id  a+    (srcB, id2, b') = d srcA id1 b+  Label  _ a -> d src id a+  _ -> (src, id, [])+  where+  link :: Int -> Int -> [String]+  link a b = ["  " ++ show a ++ " -> " ++ show b]+
Language/ImProve/Verify.hs view
@@ -122,9 +122,11 @@       put env { asserts = VarE b : asserts env }       addTrace $ Assert' b     | otherwise -> return ()-  Assume a -> do-    a <- evalExpr a-    addCmd $ ASSERT (enabled :=> a)+  Assume id a+    | elem id lemmas -> do+      a <- evalExpr a+      addCmd $ ASSERT (enabled :=> a)+    | otherwise -> return ()   Branch a onTrue onFalse -> do     a <- evalExpr a     b <- newBoolVar
improve.cabal view
@@ -1,5 +1,5 @@ name:    improve-version: 0.3.2+version: 0.3.3  category: Language, Formal Methods, Embedded @@ -9,7 +9,7 @@   ImProve is an imperative programming language for high assurance applications.   ImProve uses infinite state, unbounded model checking to verify programs adhere   to specifications.  Yices (required) is the backend SMT solver.-  ImProve compiles to C and Simulink.+  ImProve compiles to C, Simulink, and Modelica.  author:     Tom Hawkins <tomahawkins@gmail.com> maintainer: Tom Hawkins <tomahawkins@gmail.com>@@ -17,7 +17,7 @@ license:      BSD3 license-file: LICENSE -homepage: http://tomahawkins.org+homepage: http://github.com/tomahawkins/improve/wiki/ImProve  build-type:    Simple cabal-version: >= 1.6@@ -31,8 +31,13 @@     exposed-modules:         Language.ImProve         Language.ImProve.Code+        Language.ImProve.Code.C+        Language.ImProve.Code.Common+        Language.ImProve.Code.Modelica+        Language.ImProve.Code.Simulink         Language.ImProve.Core         Language.ImProve.Examples+        Language.ImProve.Path         Language.ImProve.Tree         Language.ImProve.Verify