packages feed

copilot-c99 4.6.1 → 4.7

raw patch · 6 files changed

+110/−13 lines, 6 filesdep ~copilot-corePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: copilot-core

API changes (from Hackage documentation)

Files

CHANGELOG view
@@ -1,3 +1,7 @@+2026-03-07+        * Version bump (4.7). (#714)+        * Raise error when compiling empty arrays or structs. (#695)+ 2026-01-07         * Version bump (4.6.1). (#705) 
copilot-c99.cabal view
@@ -1,6 +1,6 @@ cabal-version             : >= 1.10 name                      : copilot-c99-version                   : 4.6.1+version                   : 4.7 synopsis                  : A compiler for Copilot targeting C99. description               :   This package is a back-end from Copilot to C.@@ -45,7 +45,7 @@                           , mtl                 >= 2.2 && < 2.4                           , pretty              >= 1.1 && < 1.2 -                          , copilot-core        >= 4.6.1 && < 4.7+                          , copilot-core        >= 4.7   && < 4.8                           , language-c99        >= 0.2.0 && < 0.3                           , language-c99-simple >= 0.3   && < 0.4 
src/Copilot/Compile/C99/Error.hs view
@@ -5,7 +5,10 @@ -- -- Custom functions to report error messages to users. module Copilot.Compile.C99.Error-    ( impossible )+    ( impossible+    , errorEmptyStruct+    , errorZeroLengthArray+    )   where  -- | Report an error due to a bug in Copilot.@@ -18,3 +21,17 @@     ++ ". Please file an issue at "     ++ "https://github.com/Copilot-Language/copilot/issues"     ++ " or email the maintainers at <ivan.perezdominguez@nasa.gov>"++-- | Report an error when attempting to compile a zero-length array to C99.+-- C99 does not support zero-length arrays, so Copilot cannot compile+-- specifications that use them.+errorZeroLengthArray :: a+errorZeroLengthArray =+  error "copilot-c99: Cannot compile zero-length arrays to C99.\n"++-- | Report an error when attempting to compile an empty struct to C99.+-- C99 does not support empty structs, so Copilot cannot compile+-- specifications that use them.+errorEmptyStruct :: a+errorEmptyStruct =+  error "copilot-c99: Cannot compile empty structs to C99.\n"
src/Copilot/Compile/C99/Expr.hs view
@@ -18,7 +18,7 @@                       arrayElems, toValues, typeLength, typeSize )  -- Internal imports-import Copilot.Compile.C99.Error ( impossible )+import Copilot.Compile.C99.Error ( impossible, errorEmptyStruct, errorZeroLengthArray ) import Copilot.Compile.C99.Name  ( exCpyName, streamAccessorName ) import Copilot.Compile.C99.Type  ( transLocalVarDeclType, transType,                                    transTypeName )@@ -371,14 +371,23 @@  -- | Transform a Copilot Struct, based on the struct fields, into a list of C99 -- initializer values.+--+-- Raises an error if the struct is empty, as C99 does not support structs with+-- no fields. constStruct :: [Value a] -> NonEmpty.NonEmpty C.InitItem-constStruct val = NonEmpty.fromList $ map constFieldInit val+constStruct val = case val of+  [] -> errorEmptyStruct+  _  -> NonEmpty.fromList $ map constFieldInit val  -- | Transform a Copilot Array, based on the element values and their type, -- into a list of C99 initializer values.+--+-- Raises an error if the array is empty, as C99 does not support zero-length+-- arrays. constArray :: Type a -> [a] -> NonEmpty.NonEmpty C.InitItem-constArray ty =-  NonEmpty.fromList . map (C.InitItem Nothing . constInit ty)+constArray ty xs = case xs of+  [] -> errorZeroLengthArray+  _  -> NonEmpty.fromList $ map (C.InitItem Nothing . constInit ty) xs  -- | Explicitly cast a C99 value to a type. explicitTy :: Type a -> C.Expr -> C.Expr
src/Copilot/Compile/C99/Type.hs view
@@ -12,7 +12,9 @@ import qualified Language.C99.Simple as C  -- Internal imports: Copilot-import Copilot.Core ( Type (..), typeLength, typeName )+import Copilot.Core              ( Struct (..), Type (..), typeLength,+                                   typeName )+import Copilot.Compile.C99.Error ( errorEmptyStruct, errorZeroLengthArray )  -- | Translate a Copilot type to a C99 type. transType :: Type a -> C.Type@@ -28,10 +30,12 @@   Word64    -> C.TypeSpec $ C.TypedefName "uint64_t"   Float     -> C.TypeSpec C.Float   Double    -> C.TypeSpec C.Double-  Array ty' -> C.Array (transType ty') len+  Array ty' | typeLength ty == 0 -> errorZeroLengthArray+            | otherwise          -> C.Array (transType ty') len     where       len = Just $ C.LitInt $ fromIntegral $ typeLength ty-  Struct s  -> C.TypeSpec $ C.Struct (typeName s)+  Struct s  | null (toValues s) -> errorEmptyStruct+            | otherwise         -> C.TypeSpec $ C.Struct (typeName s)  -- | Translate a Copilot type to a valid (local) variable declaration C99 type. --
tests/Test/Copilot/Compile/C99.hs view
@@ -8,10 +8,11 @@  -- External imports import Control.Arrow                        ((&&&))-import Control.Exception                    (IOException, catch)-import Control.Monad                        (when)+import Control.Exception                    (ErrorCall (..), IOException, catch,+                                             try)+import Control.Monad                        (unless, when) import Data.Bits                            (Bits, complement)-import Data.List                            (intercalate)+import Data.List                            (intercalate, isSubsequenceOf) import Data.Type.Equality                   (testEquality) import Data.Typeable                        (Proxy (..), (:~:) (Refl)) import GHC.TypeLits                         (KnownNat, natVal)@@ -24,7 +25,9 @@ import System.Process                       (callProcess, readProcess) import System.Random                        (Random) import Test.Framework                       (Test, testGroup)+import Test.Framework.Providers.HUnit       (testCase) import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.HUnit                           (Assertion, assertFailure) import Test.QuickCheck                      (Arbitrary, Gen, Property,                                              arbitrary, choose, elements,                                              forAll, forAllBlind, frequency,@@ -50,6 +53,7 @@     , testProperty "Compile specification in custom dir" testCompileCustomDir     , testProperty "Run specification"                   testRun     , testProperty "Run and compare results"             testRunCompare+    , testCase     "Reject empty arrays and structs"     testRejectEmpties     ]  -- * Individual tests@@ -136,6 +140,65 @@     guard = Const Bool True      args = []++data Empty = Empty++instance Struct Empty where+  typeName _ = ""+  toValues _ = []++instance Typed Empty where+  typeOf = Struct Empty++-- | Test that compiling a spec with an empty array or struct raises an error.+-- C99 does not support zero-length arrays or structs without fields, so Copilot+-- should report an error during compilation.+testRejectEmpties :: Assertion+testRejectEmpties = do+    tmpDir <- getTemporaryDirectory+    setCurrentDirectory tmpDir++    r1 <- try (compile "copilot_test" $ spec t1) :: IO (Either ErrorCall ())+    unless (isErrZeroArray r1) $ assertFailure "Const zero-length array"++    r2 <- try (compile "copilot_test" $ spec t2) :: IO (Either ErrorCall ())+    unless (isErrZeroArray r2) $ assertFailure "Extern zero-length array"++    r3 <- try (compile "copilot_test" $ spec t3) :: IO (Either ErrorCall ())+    unless (isErrEmptyStruct r3) $ assertFailure "Const empty struct"++    r4 <- try (compile "copilot_test" $ spec t4) :: IO (Either ErrorCall ())+    unless (isErrEmptyStruct r4) $ assertFailure "Extern empty struct"++  where++    spec a = Spec streams observers (triggers a) properties++    streams    = []+    observers  = []+    triggers a = [ Trigger "trig" (Const Bool True) a ]+    properties = []++    t1 = [ UExpr arrTy (Const arrTy (array [])) ]+    t2 = [ UExpr arrTy (ExternVar arrTy "arrs" Nothing) ]+    t3 = [ UExpr structTy (Const structTy Empty) ]+    t4 = [ UExpr structTy (ExternVar structTy "structs" Nothing) ]++    arrTy :: Type (Array 0 Bool)+    arrTy = Array Bool++    structTy :: Type Empty+    structTy = Struct Empty++    isErrZeroArray :: Either ErrorCall a -> Bool+    isErrZeroArray e = case e of+      Left (ErrorCall msg) -> "zero-length array" `isSubsequenceOf` msg+      _                    -> False++    isErrEmptyStruct :: Either ErrorCall a -> Bool+    isErrEmptyStruct e = case e of+      Left (ErrorCall msg) -> "empty struct" `isSubsequenceOf` msg+      _                    -> False  -- | Test compiling a spec and running the resulting program. --