packages feed

improve (empty) → 0.0.0

raw patch · 4 files changed

+521/−0 lines, 4 filesdep +basedep +mtldep +processsetup-changed

Dependencies added: base, mtl, process

Files

+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) Tom Hawkins 2010++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ Language/ImProve.hs view
@@ -0,0 +1,450 @@+module Language.ImProve+  (+  -- * Types+    E+  , V+  , AllE+  , NumE+  , Name+  -- * Expressions+  -- ** Constants+  , true+  , false+  , constant+  -- ** Variable Reference+  , ref+  -- ** Logical Operations+  , not_+  , (&&.)+  , (||.)+  , and_+  , or_+  , any_+  , all_+  , imply+  -- ** Equality and Comparison+  , (==.)+  , (/=.)+  , (<.)+  , (<=.)+  , (>.)+  , (>=.)+  -- ** Min, max, and limiting.+  , min_+  , minimum_+  , max_+  , maximum_+  , limit+  -- ** Arithmetic Operations+  , (*.)+  , (/.)+  , mod_+  -- ** Conditional Operator+  , mux+  -- ** Lookups+  , linear+  -- * Hierarchical Scope+  , scope+  -- * Variable Declarations+  , bool+  , bool'+  , int+  , int'+  , float+  , float'+  , input+  -- * Statements+  , Stmt+  -- ** Variable Assignment+  , (<==)+  -- ** Conditional Execution+  , ifelse+  , if_+  -- ** Incrementing and decrementing.+  , incr+  , decr+  -- ** Assertions and  Assumptions+  , assert+  , assume+  -- * Compilation+  , compile+  ) where++import Control.Monad+import Data.List+import Data.Ratio++infixl 7 *., /., `mod_`+infix  4 ==., /=., <., <=., >., >=.+infixl 3 &&.+infixl 2 ||.+infixr 1 <==++type Name = String++-- | Variables.+data V a+  = V   [Name] a+  | VIn [Name]++-- | All types.+class AllE a where+  showConst :: a -> String+  showType  :: a -> String++instance AllE Bool where+  showConst a = case a of+    True  -> "1"+    False -> "0"++  showType _ = "int"++instance AllE Int where+  showConst = show+  showType _ = "int"+  +instance AllE Float where+  showConst = show+  showType _ = "float"++-- | Number types.+class    AllE a => NumE a+instance NumE Int+instance NumE Float++-- | Core expressions.+data E a where+  Ref   :: V a -> E a+  Const :: AllE a => a -> E a+  Add   :: NumE a => E a -> E a -> E a+  Sub   :: NumE a => E a -> E a -> E a+  Mul   :: NumE a => E a -> a -> E a+  Div   :: NumE a => E a -> a -> E a+  Mod   :: E Int -> Int -> E Int+  Not   :: E Bool -> E Bool+  And   :: E Bool -> E Bool -> E Bool+  Or    :: E Bool -> E Bool -> E Bool+  Eq    :: AllE a => E a -> E a -> E Bool+  Lt    :: NumE a => E a -> E a -> E Bool+  Gt    :: NumE a => E a -> E a -> E Bool+  Le    :: NumE a => E a -> E a -> E Bool+  Ge    :: NumE a => E a -> E a -> E Bool+  Mux   :: E Bool -> E a -> E a -> E a++instance Show (E a) where show = undefined +instance Eq   (E a) where (==) = undefined++instance (Num a, AllE a, NumE a) => Num (E a) where+  (+) = Add+  (-) = Sub+  (*) = error "general multiplication not supported, use (*.)"+  negate a = 0 - a+  abs a = mux (a <. 0) (negate a) a+  signum a = mux (a ==. 0) 0 $ mux (a <. 0) (-1) 1+  fromInteger = Const . fromInteger++instance Fractional (E Float) where+  (/) = error "general division not supported, use (/.)"+  recip a = 1 / a+  fromRational r = Const $ fromInteger (numerator r) / fromInteger (denominator r)++-- | True term.+true :: E Bool+true = Const True++-- | False term.+false :: E Bool+false = Const False++-- | Arbitrary constants.+constant :: AllE a => a -> E a+constant = Const++-- | Logical negation.+not_ :: E Bool -> E Bool+not_ = Not++-- | Logical AND.+(&&.) :: E Bool -> E Bool -> E Bool+(&&.) = And++-- | Logical OR.+(||.) :: E Bool -> E Bool -> E Bool+(||.) = Or++-- | The conjunction of a E Bool list.+and_ :: [E Bool] -> E Bool+and_ = foldl (&&.) true++-- | The disjunction of a E Bool list.+or_ :: [E Bool] -> E Bool+or_ = foldl (||.) false++-- | True iff the predicate is true for all elements.+all_ :: (a -> E Bool) -> [a] -> E Bool+all_ f a = and_ $ map f a++-- | True iff the predicate is true for any element.+any_ :: (a -> E Bool) -> [a] -> E Bool+any_ f a = or_ $ map f a++-- Logical implication (if a then b).+imply :: E Bool -> E Bool -> E Bool +imply a b = not_ a ||. b++-- | Equal.+(==.) :: AllE a => E a -> E a -> E Bool+(==.) = Eq++-- | Not equal.+(/=.) :: AllE a => E a -> E a -> E Bool+a /=. b = not_ (a ==. b)++-- | Less than.+(<.) :: NumE a => E a -> E a -> E Bool+(<.) = Lt++-- | Greater than.+(>.) :: NumE a => E a -> E a -> E Bool+(>.) = Gt++-- | Less than or equal.+(<=.) :: NumE a => E a -> E a -> E Bool+(<=.) = Le++-- | Greater than or equal.+(>=.) :: NumE a => E a -> E a -> E Bool+(>=.) = Ge++-- | Returns the minimum of two numbers.+min_ :: NumE a => E a -> E a -> E a+min_ a b = mux (a <=. b) a b++-- | Returns the minimum of a list of numbers.+minimum_ :: NumE a => [E a] -> E a+minimum_ = foldl1 min_++-- | Returns the maximum of two numbers.+max_ :: NumE a => E a -> E a -> E a+max_ a b = mux (a >=. b) a b++-- | Returns the maximum of a list of numbers.+maximum_ :: NumE a => [E a] -> E a+maximum_ = foldl1 max_++-- | Limits between min and max.+limit :: NumE a => E a -> E a -> E a -> E a+limit a b i = max_ min $ min_ max i+  where+  min = min_ a b+  max = max_ a b++-- | Multiplication.+(*.) :: NumE a => E a -> a -> E a+(*.) = Mul++-- | Division.+(/.) :: NumE a => E a -> a -> E a+(/.) = Div++-- | Modulo.+mod_ :: E Int -> Int -> E Int+mod_ = Mod++-- | Linear interpolation and extrapolation between two points.+linear :: (Float, Float) -> (Float, Float) -> E Float -> E Float+linear (x1, y1) (x2, y2) a = a *. slope + constant inter+  where+  slope = (y2 - y1) / (x2 - x1)+  inter = y1 - slope * x1++-- | References a variable.+ref :: V a -> E a+ref = Ref++-- | Conditional expression.+--+-- > mux test onTrue onFalse+mux :: E Bool -> E a -> E a -> E a+mux = Mux++-- | Creates a hierarchical scope.+scope :: Name -> Stmt a -> Stmt a+scope name (Stmt f0) = Stmt f1+  where+  f1 (scope, statement) = (a, (scope, statement1))+    where+    (a, (_, statement1)) = f0 (scope ++ [name], statement)+  +getScope :: Stmt [Name]+getScope = Stmt $ \ (scope, statement) -> (scope, (scope, statement))++var :: AllE a => Name -> a -> Stmt (V a)+var name init = do+  scope <- getScope+  return $ V (scope ++ [name]) init++-- | Input variable declaration.  Input variables are initialized to 0.+input  :: (Name -> a -> Stmt (V a)) -> Name -> Stmt (E a)+input _ name = do+  scope <- getScope+  return $ ref $ VIn (scope ++ [name])++-- | Boolean variable declaration.+bool :: Name -> Bool -> Stmt (V Bool)+bool = var++-- | Boolean variable declaration and immediate assignment.+bool' :: Name -> E Bool -> Stmt (E Bool)+bool' name value = do+  a <- bool name False+  a <== value+  return $ ref a++-- | Int variable declaration.+int :: Name -> Int -> Stmt (V Int)+int = var++-- | Int variable declaration and immediate assignment.+int' :: Name -> E Int -> Stmt (E Int)+int' name value = do+  a <- int name 0+  a <== value+  return $ ref a++-- | Float variable declaration.+float :: Name -> Float -> Stmt (V Float)+float = var++-- | Float variable declaration and immediate assignment.+float' :: Name -> E Float -> Stmt (E Float)+float' name value = do+  a <- float name 0+  a <== value+  return $ ref a++-- | Increments an E Int.+incr :: V Int -> Stmt ()+incr a = a <== ref a + 1++-- | Decrements an E Int.+decr :: V Int -> Stmt ()+decr a = a <== ref a - 1++data Statement+  = AssignBool  (V Bool ) (E Bool )+  | AssignInt   (V Int  ) (E Int  )+  | AssignFloat (V Float) (E Float)+  | Branch (E Bool) Statement Statement+  | Sequence Statement Statement+  | Assert [Name] (E Bool)+  | Assume [Name] (E Bool)+  | Null++-- | The Stmt monad holds variable declarations and statements.+data Stmt a = Stmt (([Name], Statement) -> (a, ([Name], Statement)))++instance Monad Stmt where+  return a = Stmt $ \ s -> (a, s)+  (Stmt f1) >>= f2 = Stmt f3+    where+    f3 s1 = f4 s2+      where+      (a, s2) = f1 s1+      Stmt f4 = f2 a++statement :: Statement -> Stmt ()+statement a = Stmt $ \ (scope, statement) -> ((), (scope, Sequence statement a))++evalStmt :: [Name] -> Stmt () -> Statement+evalStmt scope (Stmt f) = snd $ snd $ f (scope, Null)++class    Assign a     where (<==) :: V a -> E a -> Stmt ()+instance Assign Bool  where a <== b = statement $ AssignBool  a b+instance Assign Int   where a <== b = statement $ AssignInt   a b+instance Assign Float where a <== b = statement $ AssignFloat a b++-- | Assert that a condition is true.+assert :: Name -> E Bool -> Stmt ()+assert a b = do+  scope <- getScope+  statement $ Assert (scope ++ [a]) b++-- | Declare an assumption condition is true.+assume :: Name -> E Bool -> Stmt ()+assume a b = do+  scope <- getScope+  statement $ Assume (scope ++ [a]) b++-- | Conditional if-else.+ifelse :: E Bool -> Stmt () -> Stmt () -> Stmt ()+ifelse cond onTrue onFalse = do+  scope <- getScope+  statement $ Branch cond (evalStmt scope onTrue) (evalStmt scope onFalse)++-- | Conditional without the else.+if_ :: E Bool -> Stmt () -> Stmt()+if_ cond stmt = ifelse cond stmt $ return ()++-- | Generate C code.+compile :: Name -> Stmt () -> IO ()+compile name program = do+  writeFile (name ++ ".c") $+       "// Generated by ImProve.\n\n"+    ++ "#include <assert.h>\n\n"+    ++ "// XXX Need to build state struct.\n\n"+    ++ "void " ++ name ++ "() {\n"+    ++ indent (codeStmt stmt)+    ++ "}\n\n"+  writeFile (name ++ ".h") $+       "// Generated by ImProve.\n\n"+    ++ "// XXX Need to build state struct.\n\n"+    ++ "void " ++ name ++ "(void);\n\n"+  where+  stmt = evalStmt [] program++  varName :: V a -> String+  varName a = intercalate "." $ (name ++ "Variables") : names+    where+    names = case a of+      V names _ -> names+      VIn names -> names+  +  codeStmt :: Statement -> String+  codeStmt a = case a of+    AssignBool  a b -> varName a ++ " = " ++ codeExpr b ++ ";\n"+    AssignInt   a b -> varName a ++ " = " ++ codeExpr b ++ ";\n"+    AssignFloat a b -> varName a ++ " = " ++ codeExpr b ++ ";\n"+    Branch a b Null -> "if (" ++ codeExpr a ++ ") {\n" ++ indent (codeStmt b) ++ "}\n"+    Branch a b c    -> "if (" ++ codeExpr a ++ ") {\n" ++ indent (codeStmt b) ++ "}\nelse {\n" ++ indent (codeStmt c) ++ "}\n"+    Sequence a b -> codeStmt a ++ codeStmt b+    Assert names a -> "// assert " ++ intercalate "." names ++ "\nassert(" ++ codeExpr a ++ ");\n"+    Assume names a -> "// assume " ++ intercalate "." names ++ "\nassert(" ++ codeExpr a ++ ");\n"+    Null -> ""+  +  codeExpr :: E a -> String+  codeExpr a = case a of+    Ref a -> varName a+    Const a -> showConst a+    Add a b -> group [codeExpr a, "+", codeExpr b]+    Sub a b -> group [codeExpr a, "-", codeExpr b]+    Mul a b -> group [codeExpr a, "*", showConst b]+    Div a b -> group [codeExpr a, "/", showConst b]+    Mod a b -> group [codeExpr a, "%", showConst 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 ("  " ++) . lines+
+ Setup.hs view
@@ -0,0 +1,6 @@+#! /usr/bin/env runhaskell++import Distribution.Simple (defaultMain)++main :: IO ()+main = defaultMain
+ improve.cabal view
@@ -0,0 +1,38 @@+name:    improve+version: 0.0.0++category: Language++synopsis: A simple imperative, provable programming language for embedded applications.++description:+    TODO++author:     Tom Hawkins <tomahawkins@gmail.com>+maintainer: Tom Hawkins <tomahawkins@gmail.com>++license:      BSD3+license-file: LICENSE++homepage: http://tomahawkins.org++build-type:    Simple+cabal-version: >= 1.6++library+    build-depends:+        base       >= 4.2     && < 5,+        mtl        >= 1.1.0.1 && < 1.2,+        process    >= 1.0.1.1 && < 1.2++    exposed-modules:+        Language.ImProve++    extensions: GADTs, FlexibleInstances++    ghc-options: -W++source-repository head+    type:     git+    location: git://github.com/tomahawkins/atom.git+