packages feed

copilot-c99 3.9 → 3.10

raw patch · 5 files changed

+115/−16 lines, 5 filesdep −containersdep −language-c99-utildep ~copilot-coredep ~mtlPVP ok

version bump matches the API change (PVP)

Dependencies removed: containers, language-c99-util

Dependency ranges changed: copilot-core, mtl

API changes (from Hackage documentation)

Files

CHANGELOG view
@@ -1,3 +1,11 @@+2022-07-07+        * Version bump (3.10). (#356)+        * Remove unnecessary dependencies from Cabal package. (#323)+        * Remove duplicated compiler option. (#328)+        * Pass structs by reference, not value, in handlers. (#305)+        * Relax version bounds of dependencies. (#335)+        * Update repo info in cabal file. (#333)+ 2022-05-06         * Version bump (3.9). (#320)         * Compliance with style guide (partial). (#316)
copilot-c99.cabal view
@@ -1,6 +1,6 @@ cabal-version             : >= 1.10 name                      : copilot-c99-version                   : 3.9+version                   : 3.10 synopsis                  : A compiler for Copilot targeting C99. description               :   This package is a back-end from Copilot to C.@@ -31,8 +31,8 @@  source-repository head     type:       git-    location:   git://github.com/Copilot-Language/copilot.git-    subdir:     lib/copilot-c99+    location:   https://github.com/Copilot-Language/copilot.git+    subdir:     copilot-c99  library   default-language        : Haskell2010@@ -42,17 +42,15 @@   -- 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+  ghc-options             : -Wall -Wno-deprecations   build-depends           : base                >= 4.9 && < 5-                          , containers          >= 0.4 && < 0.7                           , directory           >= 1.3 && < 1.4                           , filepath            >= 1.4 && < 1.5-                          , mtl                 >= 2.2 && < 2.3+                          , mtl                 >= 2.2 && < 2.4                           , pretty              >= 1.1 && < 1.2 -                          , copilot-core        >= 3.9   && < 3.10+                          , copilot-core        >= 3.10  && < 3.11                           , language-c99        >= 0.1.1 && < 0.2-                          , language-c99-util   >= 0.1.1 && < 0.2                           , language-c99-simple >= 0.1.1 && < 0.2    exposed-modules         : Copilot.Compile.C99
src/Copilot/Compile/C99/CodeGen.hs view
@@ -79,12 +79,16 @@      void = C.TypeSpec C.Void     stmts  =  map mkexcopy exts-           ++ map mktriggercheck triggers+           ++ triggerStmts            ++ tmpassigns            ++ bufferupdates            ++ indexupdates-    (declns, tmpassigns, bufferupdates, indexupdates) =+    declns =  streamDeclns+           ++ concat triggerDeclns+    (streamDeclns, tmpassigns, bufferupdates, indexupdates) =       unzip4 $ map mkupdateglobals streams+    (triggerDeclns, triggerStmts) =+      unzip $ map mktriggercheck triggers      -- Write code to update global stream buffers and index.     mkupdateglobals :: Stream -> (C.Decln, C.Stmt, C.Stmt, C.Stmt)@@ -129,13 +133,85 @@        _       -> C.Ident cpyname C..= C.Ident name -    -- Make if-statement to check the guard, call the trigger if necessary.-    mktriggercheck :: Trigger -> C.Stmt-    mktriggercheck (Trigger name guard args) = C.If guard' firetrigger+    -- Make if-statement to check the guard, call the handler if necessary.+    -- This returns two things:+    --+    -- * A list of Declns for temporary variables, one for each argument that+    --   the handler function accepts. For example, if a handler function takes+    --   three arguments, the list of Declns might look something like this:+    --+    --   @+    --   int8_t   handler_arg_temp0;+    --   int16_t  handler_arg_temp1;+    --   struct s handler_arg_temp2;+    --   @+    --+    -- * A Stmt representing the if-statement. Continuing the example above,+    --   the if-statement would look something like this:+    --+    --   @+    --   if (handler_guard()) {+    --     handler_arg_temp0 = handler_arg0();+    --     handler_arg_temp1 = handler_arg1();+    --     handler_arg_temp2 = handler_arg2();+    --     handler(handler_arg_temp0, handler_arg_temp1, &handler_arg_temp2);+    --   }+    --   @+    --+    -- We create temporary variables because:+    --+    -- 1. We want to pass structs by reference intead of by value. To this end,+    --    we use C's & operator to obtain a reference to a temporary variable+    --    of a struct type and pass that to the handler function.+    --+    -- 2. Assigning a struct to a temporary variable defensively ensures that+    --    any modifications that the handler called makes to the struct argument+    --    will not affect the internals of the monitoring code.+    mktriggercheck :: Trigger -> ([C.Decln], C.Stmt)+    mktriggercheck (Trigger name guard args) =+        (aTmpDeclns, ifStmt)       where-        guard'      = C.Funcall (C.Ident $ guardname name) []-        firetrigger = [C.Expr $ C.Funcall (C.Ident name) args']+        aTmpDeclns = zipWith (\tmpVar arg ->+                               C.VarDecln Nothing (tempType arg) tmpVar Nothing)+                             aTempNames+                             args           where+            tempType (UExpr { uExprType = ty }) =+              case ty of+                -- If a temporary variable is being used to store an array,+                -- declare the type of the temporary variable as a pointer, not+                -- an array. The problem with declaring it as an array is that+                -- the `arg` function will return a pointer, not an array, and+                -- C doesn't make it easy to cast directly from an array to a+                -- pointer.+                Array ty' -> C.Ptr $ transtype ty'+                _         -> transtype ty++        aTempNames = take (length args) (argTempNames name)++        ifStmt = C.If guard' firetrigger++        guard' = C.Funcall (C.Ident $ guardname name) []++        -- The body of the if-statement. This consists of statements that assign+        -- the values of the temporary variables, following by a final statement+        -- that passes the temporary variables to the handler function.+        firetrigger = map C.Expr argAssigns +++                      [C.Expr $ C.Funcall (C.Ident name)+                                          (zipWith passArg aTempNames args)]+          where+            passArg aTempName (UExpr { uExprType = ty }) =+              case ty of+                -- Special case for Struct to pass reference to temporary+                -- struct variable to handler. (See the comments for+                -- mktriggercheck for details.)+                Struct _ -> C.UnaryOp C.Ref $ C.Ident aTempName+                _        -> C.Ident aTempName++            argAssigns = zipWith (\aTempName arg ->+                                   C.AssignOp C.Assign (C.Ident aTempName) arg)+                                 aTempNames+                                 args'             args'        = take (length args) (map argcall (argnames name))             argcall name = C.Funcall (C.Ident name) [] 
src/Copilot/Compile/C99/Compile.hs view
@@ -157,7 +157,15 @@           where             cty    = C.TypeSpec C.Void             params = map mkparam $ zip (argnames name) args-            mkparam (name, UExpr ty _) = C.Param (transtype ty) name+            mkparam (name, UExpr ty _) = C.Param (mkParamTy ty) name++            -- Special case for Struct, to pass struct arguments by reference.+            -- Arrays are also passed by reference, but using C's array type+            -- does that automatically.+            mkParamTy ty =+              case ty of+                Struct _ -> C.Ptr (transtype ty)+                _        -> transtype ty      -- Declaration for the step function.     stepdecln :: C.Decln
src/Copilot/Compile/C99/Util.hs view
@@ -55,9 +55,18 @@ argname :: String -> Int -> String argname name n = name ++ "_arg" ++ show n +-- | Turn a handler function name into a name for a temporary variable for a+-- handler argument.+argTempName :: String -> Int -> String+argTempName name n = name ++ "_arg_temp" ++ show n+ -- | Enumerate all argument names based on trigger name. argnames :: String -> [String] argnames base = [aname | n <- [0..], let aname = argname base n]++-- | Enumerate all temporary variable names based on handler function name.+argTempNames :: String -> [String]+argTempNames base = map (argTempName base) [0..]  -- | Define a C expression that calls a function with arguments. funcall :: C.Ident -> [C.Expr] -> C.Expr