copilot-3.19.1/0000755000000000000000000000000014616626101011447 5ustar0000000000000000copilot-3.19.1/copilot.cabal0000644000000000000000000001466614616626101014121 0ustar0000000000000000name: copilot version: 3.19.1 cabal-version: >= 1.10 license: BSD3 license-file: LICENSE author: Frank Dedden, Nis Nordby Wegmann, Lee Pike, Robin Morisset, Sebastian Niller, Alwyn Goodloe, Ivan Perez synopsis: A stream DSL for writing embedded C programs. build-type: Simple maintainer: Ivan Perez category: Language, Embedded homepage: https://copilot-language.github.io bug-reports: https://github.com/Copilot-Language/copilot/issues stability: Experimental description: Copilot is a stream-based runtime verification framework implemented as an embedded domain-specific language (EDSL) in Haskell. Programs can be interpreted for testing, or translated into C99 code to be incorporated in a project, or as a standalone application. The C99 backend output is constant in memory and time, making it suitable for systems with hard realtime requirements. . This package is the main entry-point for using Copilot. . A tutorial, examples, and other information are available at . x-curation: uncurated extra-source-files: README.md CHANGELOG source-repository head type: git location: https://github.com/Copilot-Language/copilot.git subdir: copilot flag examples description: Enable examples default: False manual: True library hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall -fno-warn-orphans build-depends: base >= 4.9 && < 5 , optparse-applicative >= 0.14 && < 0.19 , directory >= 1.3 && < 1.4 , filepath >= 1.4 && < 1.5 , copilot-core >= 3.19.1 && < 3.20 , copilot-theorem >= 3.19.1 && < 3.20 , copilot-language >= 3.19.1 && < 3.20 , copilot-libraries >= 3.19.1 && < 3.20 , copilot-c99 >= 3.19.1 && < 3.20 , copilot-prettyprinter >= 3.19.1 && < 3.20 exposed-modules: Language.Copilot, Language.Copilot.Main executable what4-propositional main-is: Propositional.hs hs-source-dirs: examples/what4 build-depends: base , copilot , copilot-theorem default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable what4-arithmetic main-is: Arithmetic.hs hs-source-dirs: examples/what4 build-depends: base , copilot , copilot-theorem default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable what4-structs main-is: Structs.hs hs-source-dirs: examples/what4 build-depends: base , copilot , copilot-theorem default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable wcv main-is: WCV.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot , copilot-core , copilot-theorem default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable addmult main-is: AddMult.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot , copilot-core , copilot-theorem default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable array main-is: Array.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable cast main-is: Cast.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable clock main-is: Clock.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot , copilot-libraries , copilot-core , copilot-theorem default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable counter main-is: Counter.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot , copilot-c99 default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable engine main-is: Engine.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable heater main-is: Heater.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot , copilot-c99 default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable structs main-is: Structs.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot , copilot-c99 default-language: Haskell2010 if flag(examples) buildable: True else buildable: False executable voting main-is: Voting.hs hs-source-dirs: examples build-depends: base >= 4.9 && < 5 , copilot default-language: Haskell2010 if flag(examples) buildable: True else buildable: False copilot-3.19.1/README.md0000644000000000000000000002516514616626101012737 0ustar0000000000000000
# Copilot [![Build Status](https://travis-ci.com/Copilot-Language/copilot.svg?branch=master)](https://app.travis-ci.com/github/Copilot-Language/copilot) [![Version on Hackage](https://img.shields.io/hackage/v/copilot.svg)](https://hackage.haskell.org/package/copilot) Copilot is a runtime verification framework for hard real-time systems. Programs can be interpreted for testing, or translated into C99 code to be incorporated in a project or standalone application. The C99 code generated is constant in memory and time, making it suitable for systems with hard real-time requirements. [Installation](#installation) • [Examples](#examples) • [Related projects](#related-projects) • [Documentation](#documentation) • [Contributions](#contributions) • [Acknowledgements](#acknowledgements)
## Features - Write simple, high-level specifications using a stream-based language. - Produce hard real-time C99 runtime monitors that run in constant memory and time. - Catch errors in specifications early using expressive static type system. - Prove properties about specifications using theorem proving extensions. - Interpret specifications for testing and debugging purposes. - Obtain proofs of correctness of the generated code. ## Table of Contents - [Installation](#installation) - [Linux installation](#linux-installation) - [Mac installation](#mac-installation) - [Troubleshooting](#troubleshooting) - [Examples](#examples) - [Related projects](#related-projects) - [Documentation](#documentation) - [API documentation and tutorials](#api-documentation-and-tutorials) - [Publications](#publications) - [Website](#website) - [Contributions](#contributions) - [Acknowledgements](#acknowledgements) - [The Copilot team](#the-copilot-team) - [Institutional support](#institutional-support) # Installation [(Back to top)](#table-of-contents) ## Linux installation [(Back to top)](#table-of-contents) ### Debian Bookworm / Ubuntu 23.04 On Debian Bookworm / Ubuntu 23.04 or newer, Copilot can be installed directly from the package repositories with: ```sh $ sudo apt-get install libghc-copilot-dev ``` To test that Copilot is available, execute the following: ```sh $ ghci <<< 'import Language.Copilot' ``` It should end with a line like the following and not print any error messages: ```sh ghci> ghci> Leaving GHCi. ``` ### Other Linux distributions On other Linux distributions or older Debian-based distributions, to use Copilot you must install a Haskell compiler (GHC) and the package manager Cabal. We currently support all versions of GHC from 8.6.5 to modern versions (9.6 as of this writing). You can install the toolchain using [ghcup](https://www.haskell.org/ghcup/) or, if you are on Debian/Ubuntu, directly with `apt-get`: ```sh $ sudo apt-get install ghc cabal-install ``` Once the compiler is installed, install Copilot from [Hackage](https://hackage.haskell.org/package/copilot) with: ```sh cabal v2-install --lib copilot ``` To test that Copilot is available, execute the following: ```sh $ ghci <<< 'import Language.Copilot' ``` It should end with a line like the following and not print any error messages: ```sh ghci> ghci> Leaving GHCi. ``` ## Mac installation [(Back to top)](#table-of-contents) To use Copilot you must have a Haskell compiler (GHC) and the package manager Cabal. We currently support all versions of GHC from 8.6.5 to modern versions (9.6 as of this writing). You can install the toolchain using [ghcup](https://www.haskell.org/ghcup/), as well as with Homebrew: ```sh $ brew install ghc cabal-install ``` Once the compiler is installed, install Copilot from [Hackage](https://hackage.haskell.org/package/copilot) with: ```sh $ cabal v2-install --lib copilot ``` To test that Copilot is available, execute the following: ```sh $ ghci <<< 'import Language.Copilot' ``` It should end with a line like the following and not print any error messages: ```sh ghci> ghci> Leaving GHCi. ``` ## Troubleshooting [(Back to top)](#table-of-contents) Feel free to open an issue if you are unable to install Copilot following these instructions. There is a TravisCI file at the root of the repository that may help with troubleshooting the installation. Our issues often include comments with Dockerfiles listing the steps necessary to install Copilot from scratch. ## Examples [(Back to top)](#table-of-contents) Here follows a simple example of a heating system. More examples can be found in the [examples directory](https://github.com/Copilot-Language/copilot/tree/master/copilot/examples) of the main repository. ```haskell -- This example implements a simple home heating system. The system heats -- when the temperature gets too low, and stops when it is high enough. It read -- temperature as a byte (range -50C to 100C) and translates this to Celsius. module Heater where import Language.Copilot import Copilot.Compile.C99 import Prelude hiding ((>), (<), div) -- External temperature as a byte, ranging from -50C to 100C. temp :: Stream Word8 temp = extern "temperature" Nothing -- Temperature in Celsius. -- -- We need to cast the Word8 to a Float. This is an unsafeCast, as there -- is no direct relation between Word8 and Float. ctemp :: Stream Float ctemp = (unsafeCast temp) * (150.0 / 255.0) - 50.0 spec = do -- Triggers that fire when the ctemp is too low or too high, -- pass the current ctemp as an argument. trigger "heaton" (ctemp < 18.0) [arg ctemp] trigger "heatoff" (ctemp > 21.0) [arg ctemp] -- Compile the spec main = reify spec >>= compile "heater" ``` If you save this example in a file `Heater.hs` and run: ```sh $ runhaskell Heater.hs ``` it will produce the files `heater.c`, `heater.h` and `heater_types.h`, containing, respectively, the implementation of the monitors, the interface, and a declaration of any types declared in the specification (empty in this case). If you clone the repository, the examples in the `examples/` directory can be run from the root of the project. As a rule of thumb, each example is named after the filename (without extension) in lowercase letters, and directory separators replaced with a '-'. For example: ```sh $ cabal run addmult -f examples $ cabal run counter -f examples $ cabal run what4-arithmetic -f examples ``` # Related projects [(Back to top)](#table-of-contents) _Disclaimer: The following projects are not part of Copilot. Their mention here does not constitute any form of endorsement._ - [Ogma](https://github.com/nasa/ogma) is a NASA tool to facilitate the integration of safe runtime monitors into other systems, including those built using NASA's Core Flight System or the Robot Operating System (ROS 2). - [arduino-copilot](https://hackage.haskell.org/package/arduino-copilot) facilitates building copilot applications that run on Arduino. - [sketch-frp-copilot](https://hackage.haskell.org/package/sketch-frp-copilot) extends Copilot with an FRP-like interface. - [zephyr-copilot](https://hackage.haskell.org/package/zephyr-copilot) facilitates building copilot applications that run on boards supported by the Zephyr project. # Documentation [(Back to top)](#table-of-contents) ## API documentation and tutorials [(Back to top)](#table-of-contents) A tutorial on Copilot can be found [here](https://copilot-language.github.io/downloads/copilot_tutorial.pdf). The API is documented throughout the different libraries and published on Hackage: - [copilot](https://hackage.haskell.org/package/copilot) - [copilot-c99](https://hackage.haskell.org/package/copilot-c99) - [copilot-core](https://hackage.haskell.org/package/copilot-core) - [copilot-interpreter](https://hackage.haskell.org/package/copilot-interpreter) - [copilot-language](https://hackage.haskell.org/package/copilot-language) - [copilot-libraries](https://hackage.haskell.org/package/copilot-libraries) - [copilot-prettyprinter](https://hackage.haskell.org/package/copilot-prettyprinter) - [copilot-theorem](https://hackage.haskell.org/package/copilot-theorem) ## Publications [(Back to top)](#table-of-contents) The best introduction to the fundamentals of Copilot apart from the tutorial is: - [Copilot 3](https://ntrs.nasa.gov/citations/20200003164) Other relevant papers include: - [Automated Translation of Natural Language Requirements to Runtime Monitors](https://link.springer.com/chapter/10.1007/978-3-030-99524-9_21) - [Copilot: A Hard Real-Time Runtime Monitor](https://link.springer.com/chapter/10.1007/978-3-642-16612-9_26) - [Copilot: monitoring embedded systems](https://link.springer.com/article/10.1007/s11334-013-0223-x) - [From Requirements to Autonomous Flight: An Overview of the Monitoring ICAROUS Project](https://arxiv.org/abs/2012.03745) - [Integrating FRET with Copilot: Automated Translation of Natural Language Requirements to Runtime Monitors](https://ntrs.nasa.gov/citations/20220000049) - [Monitoring Distributed Real-Time Systems: A Survey and Future Directions](https://ntrs.nasa.gov/citations/20100027427) - [Monitoring ROS2: from Requirements to Autonomous Robots](https://arxiv.org/abs/2209.14030) ## Website [(Back to top)](#table-of-contents) For further information, including links to more documentation and the tutorial, please visit the Copilot website: [https://copilot-language.github.io](https://copilot-language.github.io). # Contributions [(Back to top)](#table-of-contents) Copilot cannot accept pull requests or code contributions from developers outside the development team at this point. If you have a question, find a bug, or would like to request a change, please file an issue adding as much information as you can to help us reproduce the error or identify the use case. Please file the issue with no labels. # Acknowledgements [(Back to top)](#table-of-contents) ## The Copilot team [(Back to top)](#table-of-contents) Copilot is currently maintained by: * Alwyn Goodloe * Ivan Perez Past and current team members also include (in alphabetical order): * Macallan Cruff * Frank Dedden * Chris Hathhorn * Georges-Axel Jolayan * Jonathan Laurent * Eli Mendelson * Robin Morisset * Sebastian Niller * Lauren Pick * Lee Pike * Will Pogge * Ryan Spring * Laura Titolo * Nis Wegmann For a complete list of contributors, including external contributors, see: https://github.com/Copilot-Language/copilot/graphs/contributors ## Institutional support [(Back to top)](#table-of-contents) We are grateful for NASA Contract NNL08AD13T to Galois, Inc. and the National Institute of Aerospace, which partially supported this work. Additionally NASA Langley contracts 80LARC17C0004 and NNL09AA00A supported further development of Copilot. copilot-3.19.1/LICENSE0000644000000000000000000000263614616626101012463 0ustar00000000000000002009 BSD3 License terms Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. Neither the name of the developers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. copilot-3.19.1/Setup.hs0000644000000000000000000000005614616626101013104 0ustar0000000000000000import Distribution.Simple main = defaultMain copilot-3.19.1/CHANGELOG0000644000000000000000000000734014616626101012665 0ustar00000000000000002024-05-07 * Version bump (3.19.1). (#512) 2024-03-07 * Version bump (3.19). (#504) 2024-01-07 * Version bump (3.18.1). (#493) * Update README to reflect support for GHC 9.6. (#491) 2024-01-07 * Version bump (3.18). (#487) * Enable tests for copilot-theorem in CI script. (#474) * Enable tests for copilot-libraries in CI script. (#475) * Replace uses of forall with forAll. (#470) * Update CI job to check for MISRA compliance with cppcheck. (#472) * Relax version constraint on optparse-applicative. (#488) 2023-11-07 * Version bump (3.17). (#466) * Replace uses of deprecated functions. (#457) 2023-11-03 * Fix typo in README. (#459) 2023-09-07 * Version bump (3.16.1). (#455) 2023-07-07 * Version bump (3.16). (#448) 2023-05-07 * Version bump (3.15). (#438) 2023-03-07 * Version bump (3.14). (#422) * Replace import of Copilot.Language.prettyPrint. (#412) * Re-structure README. (#415) * Update README to reflect support for GHC 9.4. (#423) 2023-01-07 * Version bump (3.13). (#406) 2022-11-07 * Version bump (3.12). (#389) 2022-09-07 * Version bump (3.11). (#376) 2022-07-07 * Version bump (3.10). (#356) * Run tests in CI. (#329) * Remove duplicated compiler option. (#328) * Fix typos in README and Heater example. (#352) * 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) * Add support for GHC 9.0. (#294) 2022-03-07 * Version bump (3.8). (#298) * Mark package as uncurated to avoid modification. (#288) 2022-01-07 * Version bump (3.7). (#287) * Add example with nested structs. (#275) 2021-11-07 * Version bump (3.6). (#264) * Fix missing dependency in example executable. (#252) * Fix outdated/broken links. (#252) * Update installation instructions in README to match new repo structure. (#248) 2021-08-19 * Version bump (3.5). (#247) * Update travis domain in README. (#222) * Remove commented code. (#15) * Update official maintainer. (#236) * Fix typo in description. (#240) * Fix reset in counter example. (#54) * Remove unnecessary files from repo. (#244) * Add I. Perez to author list. (#243) 2021-07-07 * Version bump (3.4). (#231) 2021-05-07 * Version bump (3.3). (#217) * Document installation process without git submodules. (#214) * Bump upper constraint on what4 version number. (#90) * Remove support for GHC <= 8.4 from CI. (#89) 2021-03-07 * Version bump (3.2.1). (#85) * Renamed Examples directory to examples. (#44) * Remove version bounds for copilot package in examples. (#86) * Remove unnecessary duplicates from field in cabal file. (#87) * Added how to run examples to README. (#48) * Added flag to prevent examples from being built by default. (#48) * Fix typo in README. (#49) * Completed the documentation. (#67) * Merged and updated examples from benjaminselfridge:feature/what4-updates. (#63) 2020-12-06 * Update optparse-applicative dependency version for newer base versions. (#61). * Add Ivan Perez as co-maintainer (#51). * Update description in cabal file to match copilot-core (#50). 2019-11-22 Ivan Perez * Version bump (3.1). * Update multiple examples (#41). * Update instructions to match new repositry name (#45). copilot-3.19.1/examples/0000755000000000000000000000000014616626101013265 5ustar0000000000000000copilot-3.19.1/examples/Array.hs0000644000000000000000000000165614616626101014707 0ustar0000000000000000-- Copyright © 2019 National Institute of Aerospace / Galois, Inc. -- | This is a simple example for arrays. As a program, it does not make much -- sense, however it shows of the features of arrays nicely. -- | Enable compiler extension for type-level data, necesary for the array -- length. {-# LANGUAGE DataKinds #-} {-# LANGUAGE RebindableSyntax #-} module Main where import Language.Copilot -- Lets define an array of length 2. -- Make the buffer of the streams 3 elements long. arr :: Stream (Array 2 Bool) arr = [ array [True, False] , array [True, True] , array [False, False]] ++ arr spec :: Spec spec = do -- A trigger that fires 'func' when the first element of 'arr' is True. -- It passes the current value of arr as an argument. -- The prototype of 'func' would be: -- void func (int8_t arg[3]); trigger "func" (arr .!! 0) [arg arr] -- Compile the spec main :: IO () main = interpret 30 spec copilot-3.19.1/examples/Structs.hs0000644000000000000000000000410114616626101015264 0ustar0000000000000000-- | An example showing how specifications involving structs (in particular, -- nested structs) are compiled to C using copilot-c99. {-# LANGUAGE DataKinds #-} module Main where import qualified Prelude as P import Control.Monad (void, forM_) import Language.Copilot import Copilot.Compile.C99 -- | Definition for `Volts`. data Volts = Volts { numVolts :: Field "numVolts" Word16 , flag :: Field "flag" Bool } -- | `Struct` instance for `Volts`. instance Struct Volts where typeName _ = "volts" toValues volts = [ Value Word16 (numVolts volts) , Value Bool (flag volts) ] -- | `Volts` instance for `Typed`. instance Typed Volts where typeOf = Struct (Volts (Field 0) (Field False)) data Battery = Battery { temp :: Field "temp" Word16 , volts :: Field "volts" (Array 10 Volts) , other :: Field "other" (Array 10 (Array 5 Word32)) } -- | `Battery` instance for `Struct`. instance Struct Battery where typeName _ = "battery" toValues battery = [ Value typeOf (temp battery) , Value typeOf (volts battery) , Value typeOf (other battery) ] -- | `Battery` instance for `Typed`. Note that `undefined` is used as an -- argument to `Field`. This argument is never used, so `undefined` will never -- throw an error. instance Typed Battery where typeOf = Struct (Battery (Field 0) (Field undefined) (Field undefined)) spec :: Spec spec = do let battery :: Stream Battery battery = extern "battery" Nothing -- Check equality, indexing into nested structs and arrays. Note that this is -- trivial by equality. trigger "equalitySameIndex" ((((battery#volts) .!! 0)#numVolts) == (((battery#volts) .!! 0)#numVolts)) [arg battery] -- Same as previous example, but get a different array index (so should be -- false). trigger "equalityDifferentIndices" ((((battery#other) .!! 2) .!! 3) == (((battery#other) .!! 2) .!! 4)) [arg battery] main :: IO () main = do spec' <- reify spec -- Compile the specific to C. compile "structs" spec' copilot-3.19.1/examples/Voting.hs0000644000000000000000000000230514616626101015067 0ustar0000000000000000-- Copyright © 2019 National Institute of Aerospace / Galois, Inc. -- | Fault-tolerant voting examples. {-# LANGUAGE RebindableSyntax #-} module Main where import Language.Copilot vote :: Spec vote = do -- majority selects element with the biggest occurance. trigger "maj" true [arg maj] -- aMajority checks if the selected element has a majority. trigger "aMaj" true [arg $ aMajority inputs maj] where maj = majority inputs -- 26 input streams to vote on inputs :: [Stream Word32] inputs = [ a, b, c, d, e, f, g, h, i, j, k, l, m , n, o, p, q, r, s, t, u, v, w, x, y, z ] a = [0] ++ a + 1 b = [0] ++ b + 1 c = [0] ++ c + 1 d = [0] ++ d + 1 e = [1] ++ e + 1 f = [1] ++ f + 1 g = [1] ++ g + 1 h = [1] ++ h + 1 i = [1] ++ i + 1 j = [1] ++ j + 1 k = [1] ++ k + 1 l = [1] ++ l + 1 m = [1] ++ m + 1 n = [1] ++ n + 1 o = [1] ++ o + 1 p = [1] ++ p + 1 q = [1] ++ q + 1 r = [1] ++ r + 1 s = [1] ++ s + 1 t = [1] ++ t + 1 u = [1] ++ u + 1 v = [1] ++ v + 1 w = [1] ++ w + 1 x = [1] ++ x + 1 y = [1] ++ y + 1 z = [1] ++ z + 1 main :: IO () main = interpret 30 vote copilot-3.19.1/examples/Cast.hs0000644000000000000000000000064114616626101014514 0ustar0000000000000000-- Copyright © 2019 National Institute of Aerospace / Galois, Inc. -- | Examples of casting types. {-# LANGUAGE RebindableSyntax #-} module Main where import Language.Copilot b :: Stream Bool b = [True] ++ not b i :: Stream Int8 i = cast b x :: Stream Word16 x = [0] ++ x + 1 y :: Stream Int32 y = 1 + cast x spec :: Spec spec = trigger "trigger" true [arg y, arg i] main :: IO () main = interpret 30 spec copilot-3.19.1/examples/AddMult.hs0000644000000000000000000000061414616626101015154 0ustar0000000000000000-- Copyright © 2019 National Institute of Aerospace / Galois, Inc. -- | Another small example that calculates a constant value using a recursive -- function. module Main where import Language.Copilot spec :: Spec spec = trigger "f" true [ arg $ mult 5 ] where mult :: Word64 -> Stream Word64 mult 0 = 1 mult i = constant i * mult (i-1) main :: IO () main = interpret 100 spec copilot-3.19.1/examples/Clock.hs0000644000000000000000000000114614616626101014656 0ustar0000000000000000-- Copyright © 2019 National Institute of Aerospace / Galois, Inc. -- | Example showing usage of clocks to generate periodically recurring truth -- values. module Main where import Language.Copilot import Copilot.Library.Clocks -- | We need to force a type for the argument of `period`. p :: Word8 p = 5 -- | Both have the same period, but a different phase. clkStream :: Stream Bool clkStream = clk (period p) (phase 0) clkStream' :: Stream Bool clkStream' = clk (period p) (phase 2) spec :: Spec spec = do observer "clk" clkStream observer "clk'" clkStream' main :: IO () main = interpret 30 spec copilot-3.19.1/examples/Heater.hs0000644000000000000000000000203614616626101015032 0ustar0000000000000000-- Copyright 2019 National Institute of Aerospace / Galois, Inc. -- This is a simple example with basic usage. It implements a simple home -- heating system: It heats when temp gets too low, and stops when it is high -- enough. It read temperature as a byte (range -50C to 100C) and translates -- this to Celsius. module Main where import Language.Copilot import Copilot.Compile.C99 import Prelude hiding ((>), (<), div) -- External temperature as a byte, range of -50C to 100C temp :: Stream Word8 temp = extern "temperature" Nothing -- Calculate temperature in Celsius. -- We need to cast the Word8 to a Float. Note that it is an unsafeCast, as there -- is no direct relation between Word8 and Float. ctemp :: Stream Float ctemp = (unsafeCast temp) * (150.0 / 255.0) - 50.0 spec = do -- Triggers that fire when the ctemp is too low or too high, -- pass the current ctemp as an argument. trigger "heaton" (ctemp < 18.0) [arg ctemp] trigger "heatoff" (ctemp > 21.0) [arg ctemp] -- Compile the spec main = reify spec >>= compile "heater" copilot-3.19.1/examples/WCV.hs0000644000000000000000000001216414616626101014264 0ustar0000000000000000-- | This example shows an implementation of the Well-Clear Violation -- algorithm, it follows the implementation described in 'Analysis of -- Well-Clear Bounday Models for the Integration of UAS in the NAS', -- https://ntrs.nasa.gov/citations/20140010078. {-# LANGUAGE DataKinds #-} {-# LANGUAGE RebindableSyntax #-} module Main where import Language.Copilot import qualified Copilot.Theorem.What4 as CT import qualified Prelude as P import Data.Foldable (forM_) import qualified Control.Monad as Monad -- | `dthr` is the horizontal distance threshold. dthr :: Stream Double dthr = extern "dthr" Nothing -- | `tthr` is the horizontal time threshold. tthr :: Stream Double tthr = extern "tthr" Nothing -- | `zthr` is the vertical distance / altitude threshold. zthr :: Stream Double zthr = extern "zthr" Nothing -- | `tcoathr` is the vertical time threshold. tcoathr :: Stream Double tcoathr = extern "tcoathr" Nothing type Vect2 = (Stream Double, Stream Double) -- External streams for relative position and velocity. -- | The relative x velocity between ownship and the intruder. vx :: Stream Double vx = extern "relative_velocity_x" Nothing -- | The relative y velocity between ownship and the intruder. vy :: Stream Double vy = extern "relative_velocity_y" Nothing -- | The relative z velocity between ownship and the intruder. vz :: Stream Double vz = extern "relative_velocity_z" Nothing -- | The relative velocity as a 2D vector. v :: (Stream Double, Stream Double) v = (vx, vy) -- | The relative x position between ownship and the intruder. sx :: Stream Double sx = extern "relative_position_x" Nothing -- | The relative y position between ownship and the intruder. sy :: Stream Double sy = extern "relative_position_y" Nothing -- | The relative z position between ownship and the intruder. sz :: Stream Double sz = extern "relative_position_z" Nothing -- | The relative position as a 2D vector. s :: (Stream Double, Stream Double) s = (sx, sy) -- The following section contains basic libraries for working with vectors. -- | Multiply two Vectors. (|*|) :: Vect2 -> Vect2 -> Stream Double (|*|) (x1, y1) (x2, y2) = (x1 * x2) + (y1 * y2) -- | Calculate the square of a vector. sq :: Vect2 -> Stream Double sq x = x |*| x -- | Calculate the length of a vector. norm :: Vect2 -> Stream Double norm = sqrt . sq -- | Calculate the determinant of two vectors. det :: Vect2 -> Vect2 -> Stream Double det (x1, y1) (x2, y2) = (x1 * y2) - (x2 * y1) -- | Compare two vectors, taking into account the small error that is -- introduced by the usage of `Double`s. (~=) :: Stream Double -> Stream Double -> Stream Bool a ~= b = (abs (a - b)) < 0.001 -- | Negate a vector. neg :: Vect2 -> Vect2 neg (x, y) = (negate x, negate y) -- From here on the algorithm, as described by the paper mentioned on the top -- of this file, is implemented. Please refer to the paper for details. tau :: Vect2 -> Vect2 -> Stream Double tau s v = if s |*| v < 0 then (-(sq s)) / (s |*| v) else -1 tcpa :: Vect2 -> Vect2 -> Stream Double tcpa s v@(vx, vy) = if vx ~= 0 && vy ~= 0 then 0 else -(s |*| v)/(sq v) taumod :: Vect2 -> Vect2 -> Stream Double taumod s v = if s |*| v < 0 then (dthr * dthr - (sq s))/(s |*| v) else -1 tep :: Vect2 -> Vect2 -> Stream Double tep s v = if (s |*| v < 0) && ((delta s v dthr) >= 0) then theta s v dthr (-1) else -1 delta :: Vect2 -> Vect2 -> Stream Double -> Stream Double delta s v d = (d*d) * (sq v) - ((det s v)*(det s v)) -- Here the formula says : (s . orth v)^2 which is the same as det(s,v)^2 theta :: Vect2 -> Vect2 -> Stream Double -> Stream Double -> Stream Double theta s v d e = (-(s |*| v) + e * (sqrt $ delta s v d)) / (sq v) tcoa :: Stream Double -> Stream Double -> Stream Double tcoa sz vz = if (sz * vz) < 0 then (-sz) / vz else -1 dcpa :: Vect2 -> Vect2 -> Stream Double dcpa s@(sx, sy) v@(vx, vy) = norm (sx + (tcpa s v) * vx, sy + (tcpa s v) * vy) -- Well clear Violation -- -- | Determines if the well clear property is violated or not. wcv :: (Vect2 -> Vect2 -> Stream Double) -> Vect2 -> Stream Double -> Vect2 -> Stream Double -> Stream Bool wcv tvar s sz v vz = (horizontalWCV tvar s v) && (verticalWCV sz vz) verticalWCV :: Stream Double -> Stream Double -> Stream Bool verticalWCV sz vz = ((abs $ sz) <= zthr) || (0 <= (tcoa sz vz) && (tcoa sz vz) <= tcoathr) horizontalWCV :: (Vect2 -> Vect2 -> Stream Double) -> Vect2 -> Vect2 -> Stream Bool horizontalWCV tvar s v = (norm s <= dthr) || (((dcpa s v) <= dthr) && (0 <= (tvar s v)) && ((tvar s v) <= tthr)) spec = do Monad.void $ prop "1a" (forAll $ (tau s v) ~= (tau (neg s) (neg v))) -- Monad.void $ prop "3d" (forAll $ (wcv tep s sz v vz) == (wcv tep (neg s) (-sz) (neg v) (-vz))) main :: IO () main = do spec' <- reify spec -- Use Z3 to prove the properties. results <- CT.prove CT.Z3 spec' -- Print the results. forM_ results $ \(nm, res) -> do putStr $ nm <> ": " case res of CT.Valid -> putStrLn "valid" CT.Invalid -> putStrLn "invalid" CT.Unknown -> putStrLn "unknown" copilot-3.19.1/examples/Engine.hs0000644000000000000000000000206514616626101015031 0ustar0000000000000000-- Copyright © 2011 National Institute of Aerospace / Galois, Inc. -- | Example implementing an engine cooling control system. {-# LANGUAGE RebindableSyntax #-} module Main where import Language.Copilot import qualified Prelude as P -- If the majority of the engine temperature probes exeeds 250 degrees, then -- the cooler is engaged and remains engaged until the majority of the engine -- temperature probes drop to 250 or below. Otherwise, trigger an immediate -- shutdown of the engine. engineMonitor :: Spec engineMonitor = do trigger "shutoff" (not ok) [arg maj] where vals = [ externW8 "tmp_probe_0" two51 , externW8 "tmp_probe_1" two51 , externW8 "tmp_probe_2" zero] exceed = map (> 250) vals maj = majority exceed checkMaj = aMajority exceed maj ok = alwaysBeen ((maj && checkMaj) ==> extern "cooler" cooler) two51 = Just $ [251, 251] P.++ repeat (250 :: Word8) zero = Just $ repeat (0 :: Word8) cooler = Just $ [True, True] P.++ repeat False main :: IO () main = interpret 10 engineMonitor copilot-3.19.1/examples/Counter.hs0000644000000000000000000000136614616626101015246 0ustar0000000000000000-- Copyright © 2019 National Institute of Aerospace / Galois, Inc. -- | Example showing an implementation of a resettable counter. {-# LANGUAGE RebindableSyntax #-} module Main where import Language.Copilot import Copilot.Compile.C99 -- A resettable counter counter :: Stream Bool -> Stream Bool -> Stream Int32 counter inc reset = cnt where cnt = if reset then 0 else if inc then z + 1 else z z = [0] ++ cnt -- Counter that resets when it reaches 256 bytecounter :: Stream Int32 bytecounter = counter true reset where reset = counter true false `mod` 256 == 0 spec :: Spec spec = trigger "counter" true [arg $ bytecounter] main :: IO () -- main = interpret 1280 spec main = reify spec >>= compile "counter" copilot-3.19.1/examples/what4/0000755000000000000000000000000014616626101014314 5ustar0000000000000000copilot-3.19.1/examples/what4/Propositional.hs0000644000000000000000000000342714616626101017520 0ustar0000000000000000-- | An example showing the usage of the What4 backend in copilot-theorem for -- propositional logic on boolean streams. module Main where import qualified Prelude as P import Control.Monad (void, forM_) import Language.Copilot import Copilot.Theorem.What4 spec :: Spec spec = do -- The constant value true, which is translated as the corresponding SMT -- boolean literal. void $ prop "Example 1" (forAll true) -- The constant value false, which is translated as the corresponding SMT -- boolean literal. void $ prop "Example 2" (forAll false) -- An inductively defined flavor of true, which requires induction to prove, -- and hence is found to be invalid by the SMT solver (since no inductive -- hypothesis is made). let a = [True] ++ a void $ prop "Example 3" (forAll a) -- An inductively defined "a or not a" proposition, which is unprovable by -- the SMT solver. let a = [False] ++ b b = [True] ++ a void $ prop "Example 4" (forAll (a || b)) -- A version of "a or not a" proposition which does not require any sort of -- inductive argument, and hence is provable. let a = [False] ++ b b = not a void $ prop "Example 5" (forAll (a || b)) -- A bit more convoluted version of Example 5, which is provable. let a = [True, False] ++ b b = [False] ++ not (drop 1 a) void $ prop "Example 6" (forAll (a || b)) -- An example using external streams. let a = extern "a" Nothing void $ prop "Example 7" (forAll (a || not a)) main :: IO () main = do spec' <- reify spec -- Use Z3 to prove the properties. results <- prove Z3 spec' -- Print the results. forM_ results $ \(nm, res) -> do putStr $ nm <> ": " case res of Valid -> putStrLn "valid" Invalid -> putStrLn "invalid" Unknown -> putStrLn "unknown" copilot-3.19.1/examples/what4/Structs.hs0000644000000000000000000000450514616626101016323 0ustar0000000000000000-- | An example showing the usage of the What4 backend in copilot-theorem for -- structs and arrays. Particular focus is on nested structs. -- For general usage of structs, refer to the general structs example. {-# LANGUAGE DataKinds #-} module Main where import qualified Prelude as P import Control.Monad (void, forM_) import Language.Copilot import Copilot.Theorem.What4 -- | Definition for `Volts`. data Volts = Volts { numVolts :: Field "numVolts" Word16 , flag :: Field "flag" Bool } -- | `Struct` instance for `Volts`. instance Struct Volts where typeName _ = "volts" toValues volts = [ Value Word16 (numVolts volts) , Value Bool (flag volts) ] -- | `Volts` instance for `Typed`. instance Typed Volts where typeOf = Struct (Volts (Field 0) (Field False)) data Battery = Battery { temp :: Field "temp" Word16 , volts :: Field "volts" (Array 10 Volts) , other :: Field "other" (Array 10 (Array 5 Word32)) } -- | `Battery` instance for `Struct`. instance Struct Battery where typeName _ = "battery" toValues battery = [ Value typeOf (temp battery) , Value typeOf (volts battery) , Value typeOf (other battery) ] -- | `Battery` instance for `Typed`. Note that `undefined` is used as an -- argument to `Field`. This argument is never used, so `undefined` will never -- throw an error. instance Typed Battery where typeOf = Struct (Battery (Field 0) (Field undefined) (Field undefined)) spec :: Spec spec = do let battery :: Stream Battery battery = extern "battery" Nothing -- Check equality, indexing into nested structs and arrays. Note that this is -- trivial by equality. void $ prop "Example 1" $ forAll $ (((battery#volts) .!! 0)#numVolts) == (((battery#volts) .!! 0)#numVolts) -- Same as previous example, but get a different array index (so should be -- false). void $ prop "Example 2" $ forAll $ (((battery#other) .!! 2) .!! 3) == (((battery#other) .!! 2) .!! 4) main :: IO () main = do spec' <- reify spec -- Use Z3 to prove the properties. results <- prove Z3 spec' -- Print the results. forM_ results $ \(nm, res) -> do putStr $ nm <> ": " case res of Valid -> putStrLn "valid" Invalid -> putStrLn "invalid" Unknown -> putStrLn "unknown" copilot-3.19.1/examples/what4/Arithmetic.hs0000644000000000000000000000321114616626101016736 0ustar0000000000000000-- | An example showing the usage of the What4 backend in copilot-theorem for -- simple arithmetic. module Main where import qualified Prelude as P import Control.Monad (void, forM_) import Language.Copilot import Copilot.Theorem.What4 spec :: Spec spec = do -- Define some external streams. Their values are not important, so external -- streams suffice. let eint8 :: Stream Int8 eint8 = extern "eint8" Nothing eword8 :: Stream Word8 eword8 = extern "eword8" Nothing efloat :: Stream Float efloat = extern "efloat" Nothing -- The simplest example involving numbers: equality on constant values. void $ prop "Example 1" (forAll ((constant (1 :: Int8)) == (constant 1))) -- Testing "a < a + 1". This should fail, because it isn't true. void $ prop "Example 2" (forAll (eint8 < (eint8 + 1))) -- Adding another condition to the above property to make it true. void $ prop "Example 3" (forAll ((eint8 < (eint8 + 1)) || (eint8 == 127))) -- Just like the previous example, but with words. void $ prop "Example 4" (forAll ((eword8 < (eword8 + 1)) || (eword8 == 255))) -- An example with floats. void $ prop "Example 5" (forAll ((2 * efloat) == (efloat + efloat))) -- Another example with floats. This fails, because it isn't true. void $ prop "Example 6" (forAll ((efloat + 1) /= efloat)) main :: IO () main = do spec' <- reify spec -- Use Z3 to prove the properties. results <- prove Z3 spec' -- Print the results. forM_ results $ \(nm, res) -> do putStr $ nm <> ": " case res of Valid -> putStrLn "valid" Invalid -> putStrLn "invalid" Unknown -> putStrLn "unknown" copilot-3.19.1/src/0000755000000000000000000000000014616626101012236 5ustar0000000000000000copilot-3.19.1/src/Language/0000755000000000000000000000000014616626101013761 5ustar0000000000000000copilot-3.19.1/src/Language/Copilot.hs0000644000000000000000000000177614616626101015741 0ustar0000000000000000-- | Copilot is a stream-based runtime verification framework. Programs can be -- interpreted for testing, or translated into C99 code to be incorporated in a -- project, or as a standalone application. The C99 backend output is constant -- in memory and time, making it suitable for systems with hard realtime -- requirements. -- -- This module is the main entry point for the Copilot language. The -- expectation is that most Copilot users will only need to import this module, -- together with one of the backend modules (at present, only -- 'Copilot.Compile.C99' from the -- library is -- available). module Language.Copilot ( module Copilot.Language , module Copilot.Language.Prelude , module Copilot.Language.Reify , module Copilot.Library.Libraries , copilotMain , defaultMain ) where import Copilot.Language import Copilot.Language.Prelude import Copilot.Language.Reify import Copilot.Library.Libraries import Language.Copilot.Main copilot-3.19.1/src/Language/Copilot/0000755000000000000000000000000014616626101015372 5ustar0000000000000000copilot-3.19.1/src/Language/Copilot/Main.hs0000644000000000000000000000703014616626101016612 0ustar0000000000000000-- | Create Copilot executables that generate code or interpret streams and -- print the results to stdout. module Language.Copilot.Main ( copilotMain, defaultMain ) where import qualified Copilot.Core as C (Spec) import Copilot.Language (interpret) import Copilot.Language.Reify (reify) import Copilot.Language (Spec) import qualified Copilot.PrettyPrint as PP import Options.Applicative import Data.Semigroup ((<>)) import Control.Monad (when) -- | An interpreter of Copilot specifications for a given -- number of simulation steps. type Interpreter = Integer -> Spec -> IO () -- | A compiler from -- -- specifications. type Compiler = FilePath -> C.Spec -> IO () -- | A pretty printer of Copilot specifications. type Printer = Spec -> IO () -- | Command line arguments supported by all commands in 'cmdargs'. data CmdArgs = CmdArgs { aoutput :: String , acompile :: Bool , apretty :: Bool , ainterpret :: Int } -- | Command line arguments handled by the Copilot main function. cmdargs :: Parser CmdArgs cmdargs = CmdArgs <$> strOption (long "output" <> short 'o' <> value "." <> help "Output directory of C files") <*> switch (long "justrun" <> short 'c' <> help "Do NOT produce *.c and *.h files as output") <*> switch (long "print" <> short 'p' <> help "Pretty print the specification") <*> option auto (long "interpret" <> short 'i' <> value 0 <> metavar "INT" <> showDefault <> help "Interpret specification and write result to output") -- | Create a main to either compile or interpret a copilot specification. -- -- This function must be provided an auxiliary function capable of compiling -- -- specifications for some target. -- -- The command line program supports four main commands: -- -- * @--output/-o@: use the given compiler to produce C code. -- -- * @--justrun/-c@: execute a dry-run, which parses and converts the -- specification to core but does not produce any output. -- -- * @--print/-p@: pretty print the specification. -- -- * @--interpret/-i NUM@: interpret the specification for a given number -- of steps. copilotMain :: Interpreter -> Printer -> Compiler -> Spec -> IO () copilotMain interp pretty comp spec = main =<< execParser opts where opts = info (cmdargs <**> helper) fullDesc main :: CmdArgs -> IO () main args = do let iters = ainterpret args when (apretty args) $ pretty spec when (iters Prelude.> 0) $ interp (fromIntegral iters) spec when (not $ acompile args) $ do spec' <- reify spec comp (aoutput args) spec' -- | Create a main function with a default interpreter and pretty printer. -- -- This function must be provided an auxiliary function capable of compiling -- -- specifications for some target. -- -- This function relies on 'copilotMain', please refer to that function for the -- command line options. defaultMain :: Compiler -> Spec -> IO () defaultMain = copilotMain interpret prettyPrint where -- Transform a high-level Copilot Language specification into a low-level -- Copilot Core specification and pretty-print it to stdout. prettyPrint :: Spec -> IO () prettyPrint e = fmap PP.prettyPrint (reify e) >>= putStr