copilot-c99 3.4 → 3.5
raw patch · 12 files changed
+242/−147 lines, 12 filesdep ~copilot-corePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: copilot-core
API changes (from Hackage documentation)
+ Copilot.Compile.C99: CSettings :: String -> CSettings
+ Copilot.Compile.C99: [cSettingsStepFunctionName] :: CSettings -> String
+ Copilot.Compile.C99: compileWith :: CSettings -> String -> Spec -> IO ()
+ Copilot.Compile.C99: data CSettings
+ Copilot.Compile.C99: mkDefaultCSettings :: CSettings
+ Copilot.Compile.C99.CodeGen: mkaccessdecln :: Id -> Type a -> [a] -> FunDef
+ Copilot.Compile.C99.Compile: CSettings :: String -> CSettings
+ Copilot.Compile.C99.Compile: [cSettingsStepFunctionName] :: CSettings -> String
+ Copilot.Compile.C99.Compile: compileWith :: CSettings -> String -> Spec -> IO ()
+ Copilot.Compile.C99.Compile: data CSettings
+ Copilot.Compile.C99.Compile: mkDefaultCSettings :: CSettings
+ Copilot.Compile.C99.Settings: CSettings :: String -> CSettings
+ Copilot.Compile.C99.Settings: [cSettingsStepFunctionName] :: CSettings -> String
+ Copilot.Compile.C99.Settings: data CSettings
+ Copilot.Compile.C99.Settings: mkDefaultCSettings :: CSettings
+ Copilot.Compile.C99.Util: streamaccessorname :: Id -> String
- Copilot.Compile.C99.CodeGen: mkstep :: [Stream] -> [Trigger] -> [External] -> FunDef
+ Copilot.Compile.C99.CodeGen: mkstep :: CSettings -> [Stream] -> [Trigger] -> [External] -> FunDef
- Copilot.Compile.C99.Util: type FunEnv = ([Decln], [Ident])
+ Copilot.Compile.C99.Util: type FunEnv = [Decln]
Files
- CHANGELOG +11/−0
- README.md +1/−1
- copilot-c99.cabal +16/−5
- src/Copilot/Compile/C99.hs +5/−1
- src/Copilot/Compile/C99/CodeGen.hs +20/−4
- src/Copilot/Compile/C99/Compile.hs +6/−125
- src/Copilot/Compile/C99/Compile/Internal.hs +146/−0
- src/Copilot/Compile/C99/External.hs +3/−1
- src/Copilot/Compile/C99/Settings.hs +8/−0
- src/Copilot/Compile/C99/Settings/Internal.hs +11/−0
- src/Copilot/Compile/C99/Translate.hs +7/−8
- src/Copilot/Compile/C99/Util.hs +8/−2
CHANGELOG view
@@ -1,3 +1,14 @@+2021-08-19+ * Version bump (3.5). (#247)+ * Update travis domain in README. (#222)+ * Remove second element of pair FunEnv. (#170)+ * Allow customizing name of step function. (#64)+ * Update official maintainer. (#236)+ * Deprecate internal modules. (#237, #242)+ * Update source repo location. (#241)+ * Fix out-of-bounds array access. (#238)+ * Add I. Perez to author list. (#243)+ 2021-07-07 * Version bump (3.4). (#231) * Remove broken test. (#232)
README.md view
@@ -1,4 +1,4 @@-[](https://travis-ci.org/Copilot-Language/copilot-core)+[](https://travis-ci.com/Copilot-Language/copilot-core) # Copilot: a stream DSL Copilot-c99 implements a C99 backend for Copilot, producing high quality code
copilot-c99.cabal view
@@ -1,6 +1,6 @@ cabal-version : >= 1.10 name : copilot-c99-version : 3.4+version : 3.5 synopsis : A compiler for Copilot targeting C99. description : This package is a back-end from Copilot to C.@@ -14,7 +14,7 @@ license : BSD3 license-file : LICENSE-maintainer : Frank Dedden <dev@dedden.net>+maintainer : Ivan Perez <ivan.perezdominguez@nasa.gov> homepage : https://copilot-language.github.io bug-reports : https://github.com/Copilot-Language/copilot/issues stability : Experimental@@ -25,15 +25,22 @@ author : Frank Dedden , Alwyn Goodloe+ , Ivan Perez source-repository head type: git- location: git://github.com/Copilot-Language/copilot-c99.git+ location: git://github.com/Copilot-Language/copilot.git+ subdir: lib/copilot-c99 library default-language : Haskell2010 hs-source-dirs : src- ghc-options : -Wall -fwarn-tabs++ -- The following -Wno-deprecations is temprary and related to issue+ -- https://github.com/Copilot-Language/copilot/issues/237+ -- It should be removed in a future version, when this library hides+ -- internal modules.+ ghc-options : -Wall -fwarn-tabs -Wno-deprecations build-depends : base >= 4.9 && < 5 , containers >= 0.4 && < 0.7 , directory >= 1.3 && < 1.4@@ -41,7 +48,7 @@ , mtl >= 2.2 && < 2.3 , pretty >= 1.1 && < 1.2 - , copilot-core >= 3.4 && < 3.5+ , copilot-core >= 3.5 && < 3.6 , language-c99 >= 0.1.1 && < 0.2 , language-c99-util >= 0.1.1 && < 0.2 , language-c99-simple >= 0.1.1 && < 0.2@@ -52,3 +59,7 @@ , Copilot.Compile.C99.CodeGen , Copilot.Compile.C99.External , Copilot.Compile.C99.Compile+ , Copilot.Compile.C99.Settings++ other-modules : Copilot.Compile.C99.Compile.Internal+ , Copilot.Compile.C99.Settings.Internal
src/Copilot/Compile/C99.hs view
@@ -1,6 +1,10 @@ -- | Compile Copilot specifications to C99 code. module Copilot.Compile.C99 ( compile+ , compileWith+ , CSettings(..)+ , mkDefaultCSettings ) where -import Copilot.Compile.C99.Compile+import Copilot.Compile.C99.Compile.Internal+import Copilot.Compile.C99.Settings.Internal
src/Copilot/Compile/C99/CodeGen.hs view
@@ -2,7 +2,9 @@ {-# LANGUAGE ScopedTypeVariables #-} -- | High-level translation of Copilot Core into C99.-module Copilot.Compile.C99.CodeGen where+module Copilot.Compile.C99.CodeGen+ {-# DEPRECATED "This module will be hidden in future versions." #-}+ where import Control.Monad.State (runState) import Data.List (union, unzip4)@@ -13,6 +15,7 @@ import Copilot.Core import Copilot.Compile.C99.Util import Copilot.Compile.C99.External+import Copilot.Compile.C99.Settings import Copilot.Compile.C99.Translate -- | Write a declaration for a generator function.@@ -24,7 +27,7 @@ genfun :: String -> Expr a -> Type a -> C.FunDef genfun name expr ty = C.FunDef cty name [] cvars [C.Return $ Just cexpr] where cty = C.decay $ transtype ty- (cexpr, (cvars, _)) = runState (transexpr expr) mempty+ (cexpr, cvars) = runState (transexpr expr) mempty -- | Make a extern declaration of a variable. mkextdecln :: External -> C.Decln@@ -53,9 +56,22 @@ cty = C.TypeSpec $ C.TypedefName "size_t" initval = Just $ C.InitExpr $ C.LitInt 0 +-- | Define an accessor functions for the ring buffer associated with a stream+mkaccessdecln :: Id -> Type a -> [a] -> C.FunDef+mkaccessdecln sid ty xs = C.FunDef cty name params [] [C.Return (Just expr)]+ where+ cty = C.decay $ transtype ty+ name = streamaccessorname sid+ bufflength = C.LitInt $ fromIntegral $ length xs+ params = [C.Param (C.TypeSpec $ C.TypedefName "size_t") "x"]+ index = (C.Ident (indexname sid) C..+ C.Ident "x") C..% bufflength+ expr = C.Index (C.Ident (streamname sid)) index+ -- | Writes the step function, that updates all streams.-mkstep :: [Stream] -> [Trigger] -> [External] -> C.FunDef-mkstep streams triggers exts = C.FunDef void "step" [] declns stmts where+mkstep :: CSettings -> [Stream] -> [Trigger] -> [External] -> C.FunDef+mkstep cSettings streams triggers exts =+ C.FunDef void (cSettingsStepFunctionName cSettings) [] declns stmts where+ void = C.TypeSpec C.Void stmts = map mkexcopy exts ++ map mktriggercheck triggers
src/Copilot/Compile/C99/Compile.hs view
@@ -1,130 +1,11 @@ -- | Compile Copilot specifications to C99 code. module Copilot.Compile.C99.Compile+ {-# DEPRECATED "This module will be hidden in future versions." #-} ( compile+ , compileWith+ , CSettings(..)+ , mkDefaultCSettings ) where -import Text.PrettyPrint (render)-import Data.List (nub)-import Data.Maybe (catMaybes)--import Language.C99.Pretty (pretty)-import qualified Language.C99.Simple as C--import Copilot.Core-import Copilot.Compile.C99.Util-import Copilot.Compile.C99.External-import Copilot.Compile.C99.Translate-import Copilot.Compile.C99.CodeGen---- | Compile a specification to a .h and a .c file.------ The first argument is used as prefix for the .h and .c files generated.-compile :: String -> Spec -> IO ()-compile prefix spec = do- let cfile = render $ pretty $ C.translate $ compilec spec- hfile = render $ pretty $ C.translate $ compileh spec-- -- TODO: find a nicer solution using annotated AST's- -- Should figure out exactly which headers are needed, based on what- -- is used.- cmacros = unlines [ "#include <stdint.h>"- , "#include <stdbool.h>"- , "#include <string.h>"- , "#include <stdlib.h>"- , "#include <math.h>"- , ""- , "#include \"" ++ prefix ++ ".h\""- , ""- ]-- writeFile (prefix ++ ".c") $ cmacros ++ cfile- writeFile (prefix ++ ".h") hfile---- | Generate the .c file from a 'Spec'.------ The generated C file has the following structure:------ * Include .h file.--- * Declarations of global buffers and indices.--- * Generator functions for streams, guards and trigger arguments.--- * Declaration of the @step()@ function.-compilec :: Spec -> C.TransUnit-compilec spec = C.TransUnit declns funs where- streams = specStreams spec- triggers = specTriggers spec- exts = gatherexts streams triggers- exprs = gatherexprs streams triggers-- declns = mkstructdeclns exprs ++ mkexts exts ++ mkglobals streams- funs = genfuns streams triggers ++ [mkstep streams triggers exts]-- -- Write struct datatypes- mkstructdeclns :: [UExpr] -> [C.Decln]- mkstructdeclns es = catMaybes $ map mkdecln utypes where- mkdecln (UType ty) = case ty of- Struct x -> Just $ mkstructdecln ty- _ -> Nothing-- utypes = nub $ concatMap (\(UExpr _ e) -> exprtypes e) es-- -- Make declarations for copies of external variables.- mkexts :: [External] -> [C.Decln]- mkexts exts = map mkextcpydecln exts-- -- Make buffer and index declarations for streams.- mkglobals :: [Stream] -> [C.Decln]- mkglobals streams = map buffdecln streams ++ map indexdecln streams where- buffdecln (Stream sid buff _ ty) = mkbuffdecln sid ty buff- indexdecln (Stream sid _ _ _ ) = mkindexdecln sid-- -- Make generator functions, including trigger arguments.- genfuns :: [Stream] -> [Trigger] -> [C.FunDef]- genfuns streams triggers = map streamgen streams- ++ concatMap triggergen triggers where- streamgen :: Stream -> C.FunDef- streamgen (Stream sid _ expr ty) = genfun (generatorname sid) expr ty-- triggergen :: Trigger -> [C.FunDef]- triggergen (Trigger name guard args) = guarddef : argdefs where- guarddef = genfun (guardname name) guard Bool- argdefs = map arggen (zip (argnames name) args)-- arggen :: (String, UExpr) -> C.FunDef- arggen (argname, UExpr ty expr) = genfun argname expr ty---- | Generate the .h file from a 'Spec'.-compileh :: Spec -> C.TransUnit-compileh spec = C.TransUnit declns [] where- streams = specStreams spec- triggers = specTriggers spec- exts = gatherexts streams triggers- exprs = gatherexprs streams triggers-- declns = mkstructforwdeclns exprs- ++ mkexts exts- ++ extfundeclns triggers- ++ [stepdecln]-- mkstructforwdeclns :: [UExpr] -> [C.Decln]- mkstructforwdeclns es = catMaybes $ map mkdecln utypes where- mkdecln (UType ty) = case ty of- Struct x -> Just $ mkstructforwdecln ty- _ -> Nothing-- utypes = nub $ concatMap (\(UExpr _ e) -> exprtypes e) es-- -- Make declarations for external variables.- mkexts :: [External] -> [C.Decln]- mkexts = map mkextdecln-- extfundeclns :: [Trigger] -> [C.Decln]- extfundeclns triggers = map extfundecln triggers where- extfundecln :: Trigger -> C.Decln- extfundecln (Trigger name _ args) = C.FunDecln Nothing cty name params where- cty = C.TypeSpec C.Void- params = map mkparam $ zip (argnames name) args- mkparam (name, UExpr ty _) = C.Param (transtype ty) name-- -- Declaration for the step function.- stepdecln :: C.Decln- stepdecln = C.FunDecln Nothing (C.TypeSpec C.Void) "step" []+import Copilot.Compile.C99.Compile.Internal+import Copilot.Compile.C99.Settings.Internal
+ src/Copilot/Compile/C99/Compile/Internal.hs view
@@ -0,0 +1,146 @@+-- | Compile Copilot specifications to C99 code.+module Copilot.Compile.C99.Compile.Internal+ ( compile+ , compileWith+ ) where++import Text.PrettyPrint (render)+import Data.List (nub)+import Data.Maybe (catMaybes)++import Language.C99.Pretty (pretty)+import qualified Language.C99.Simple as C++import Copilot.Core+import Copilot.Compile.C99.Util+import Copilot.Compile.C99.External+import Copilot.Compile.C99.Settings.Internal+import Copilot.Compile.C99.Translate+import Copilot.Compile.C99.CodeGen++-- | Compile a specification to a .h and a .c file.+--+-- The first argument is the settings for the C code generated.+--+-- The second argument is used as prefix for the .h and .c files generated.+compileWith :: CSettings -> String -> Spec -> IO ()+compileWith cSettings prefix spec = do+ let cfile = render $ pretty $ C.translate $ compilec cSettings spec+ hfile = render $ pretty $ C.translate $ compileh cSettings spec++ -- TODO: find a nicer solution using annotated AST's+ -- Should figure out exactly which headers are needed, based on what+ -- is used.+ cmacros = unlines [ "#include <stdint.h>"+ , "#include <stdbool.h>"+ , "#include <string.h>"+ , "#include <stdlib.h>"+ , "#include <math.h>"+ , ""+ , "#include \"" ++ prefix ++ ".h\""+ , ""+ ]++ writeFile (prefix ++ ".c") $ cmacros ++ cfile+ writeFile (prefix ++ ".h") hfile++-- | Compile a specification to a .h and a .c file.+--+-- The first argument is used as prefix for the .h and .c files generated.+compile :: String -> Spec -> IO ()+compile = compileWith mkDefaultCSettings++-- | Generate the .c file from a 'Spec'.+--+-- The generated C file has the following structure:+--+-- * Include .h file.+-- * Declarations of global buffers and indices.+-- * Generator functions for streams, guards and trigger arguments.+-- * Declaration of the @step()@ function.+compilec :: CSettings -> Spec -> C.TransUnit+compilec cSettings spec = C.TransUnit declns funs where+ streams = specStreams spec+ triggers = specTriggers spec+ exts = gatherexts streams triggers+ exprs = gatherexprs streams triggers++ declns = mkstructdeclns exprs ++ mkexts exts ++ mkglobals streams+ funs = genfuns streams triggers ++ [mkstep cSettings streams triggers exts]++ -- Write struct datatypes+ mkstructdeclns :: [UExpr] -> [C.Decln]+ mkstructdeclns es = catMaybes $ map mkdecln utypes where+ mkdecln (UType ty) = case ty of+ Struct x -> Just $ mkstructdecln ty+ _ -> Nothing++ utypes = nub $ concatMap (\(UExpr _ e) -> exprtypes e) es++ -- Make declarations for copies of external variables.+ mkexts :: [External] -> [C.Decln]+ mkexts exts = map mkextcpydecln exts++ -- Make buffer and index declarations for streams.+ mkglobals :: [Stream] -> [C.Decln]+ mkglobals streams = map buffdecln streams ++ map indexdecln streams where+ buffdecln (Stream sid buff _ ty) = mkbuffdecln sid ty buff+ indexdecln (Stream sid _ _ _ ) = mkindexdecln sid++ -- Make generator functions, including trigger arguments.+ genfuns :: [Stream] -> [Trigger] -> [C.FunDef]+ genfuns streams triggers = map accessdecln streams+ ++ map streamgen streams+ ++ concatMap triggergen triggers where++ accessdecln :: Stream -> C.FunDef+ accessdecln (Stream sid buff _ ty) = mkaccessdecln sid ty buff++ streamgen :: Stream -> C.FunDef+ streamgen (Stream sid _ expr ty) = genfun (generatorname sid) expr ty++ triggergen :: Trigger -> [C.FunDef]+ triggergen (Trigger name guard args) = guarddef : argdefs where+ guarddef = genfun (guardname name) guard Bool+ argdefs = map arggen (zip (argnames name) args)++ arggen :: (String, UExpr) -> C.FunDef+ arggen (argname, UExpr ty expr) = genfun argname expr ty++-- | Generate the .h file from a 'Spec'.+compileh :: CSettings -> Spec -> C.TransUnit+compileh cSettings spec = C.TransUnit declns [] where+ streams = specStreams spec+ triggers = specTriggers spec+ exts = gatherexts streams triggers+ exprs = gatherexprs streams triggers++ declns = mkstructforwdeclns exprs+ ++ mkexts exts+ ++ extfundeclns triggers+ ++ [stepdecln]++ mkstructforwdeclns :: [UExpr] -> [C.Decln]+ mkstructforwdeclns es = catMaybes $ map mkdecln utypes where+ mkdecln (UType ty) = case ty of+ Struct x -> Just $ mkstructforwdecln ty+ _ -> Nothing++ utypes = nub $ concatMap (\(UExpr _ e) -> exprtypes e) es++ -- Make declarations for external variables.+ mkexts :: [External] -> [C.Decln]+ mkexts = map mkextdecln++ extfundeclns :: [Trigger] -> [C.Decln]+ extfundeclns triggers = map extfundecln triggers where+ extfundecln :: Trigger -> C.Decln+ extfundecln (Trigger name _ args) = C.FunDecln Nothing cty name params where+ cty = C.TypeSpec C.Void+ params = map mkparam $ zip (argnames name) args+ mkparam (name, UExpr ty _) = C.Param (transtype ty) name++ -- Declaration for the step function.+ stepdecln :: C.Decln+ stepdecln = C.FunDecln Nothing (C.TypeSpec C.Void)+ (cSettingsStepFunctionName cSettings) []
src/Copilot/Compile/C99/External.hs view
@@ -2,7 +2,9 @@ -- | Represent information about externs needed in the generation of C99 code -- for stream declarations and triggers.-module Copilot.Compile.C99.External where+module Copilot.Compile.C99.External+ {-# DEPRECATED "This module will be hidden in future versions." #-}+ where import Data.List (unionBy)
+ src/Copilot/Compile/C99/Settings.hs view
@@ -0,0 +1,8 @@+-- | Settings used by the code generator to customize the code.+module Copilot.Compile.C99.Settings+ {-# DEPRECATED "This module will be hidden in future versions." #-}+ (module Copilot.Compile.C99.Settings.Internal)+ where++import Copilot.Compile.C99.Settings.Internal+
+ src/Copilot/Compile/C99/Settings/Internal.hs view
@@ -0,0 +1,11 @@+-- | Settings used by the code generator to customize the code.+module Copilot.Compile.C99.Settings.Internal where++-- | Settings used to customize the code generated.+data CSettings = CSettings+ { cSettingsStepFunctionName :: String+ }++-- | Default settings with a step function called @step@.+mkDefaultCSettings :: CSettings+mkDefaultCSettings = CSettings "step"
src/Copilot/Compile/C99/Translate.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE GADTs #-} -- | Translate Copilot Core expressions and operators to C99.-module Copilot.Compile.C99.Translate where+module Copilot.Compile.C99.Translate+ {-# DEPRECATED "This module will be hidden in future versions." #-}+ where import Control.Monad.State @@ -18,19 +20,16 @@ e1' <- transexpr e1 let cty1 = transtype ty1 init = Just $ C.InitExpr e1'- statetell ([C.VarDecln Nothing cty1 name init], [])+ statetell [C.VarDecln Nothing cty1 name init] transexpr e2 transexpr (Var _ n) = return $ C.Ident n transexpr (Drop _ amount sid) = do- let var = streamname sid- indexvar = indexname sid- index = case amount of- 0 -> C.Ident indexvar- n -> C.Ident indexvar C..+ C.LitInt (fromIntegral n)- return $ C.Index (C.Ident var) index+ let accessvar = streamaccessorname sid+ index = C.LitInt (fromIntegral amount)+ return $ funcall accessvar [index] transexpr (ExternVar _ name _) = return $ C.Ident (excpyname name)
src/Copilot/Compile/C99/Util.hs view
@@ -1,5 +1,7 @@ -- | Auxiliary helper functions to generate C99 code.-module Copilot.Compile.C99.Util where+module Copilot.Compile.C99.Util+ {-# DEPRECATED "This module will be hidden in future versions." #-}+ where import Control.Monad.State @@ -9,7 +11,7 @@ -- | Auxiliary type used to collect all the declarations of all the variables -- used in a function to be generated, since variable declarations are always -- listed first at the top of the function body.-type FunEnv = ([C.Decln], [C.Ident])+type FunEnv = [C.Decln] -- | `tell` equivalent for `State`. statetell :: Monoid m => m -> State m ()@@ -32,6 +34,10 @@ -- | Turn a stream id into the global varname for indices. indexname :: Id -> String indexname sid = streamname sid ++ "_idx"++-- | Turn a stream id into the name of its accessor function+streamaccessorname :: Id -> String+streamaccessorname sid = streamname sid ++ "_get" -- | Add a postfix for copies of external variables the name. excpyname :: String -> String