copilot-4.3/0000755000000000000000000000000014762717312011231 5ustar0000000000000000copilot-4.3/copilot.cabal0000644000000000000000000001621514762717312013673 0ustar0000000000000000name: copilot version: 4.3 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.6 , copilot-core >= 4.3 && < 4.4 , copilot-theorem >= 4.3 && < 4.4 , copilot-language >= 4.3 && < 4.4 , copilot-libraries >= 4.3 && < 4.4 , copilot-c99 >= 4.3 && < 4.4 , copilot-prettyprinter >= 4.3 && < 4.4 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-arithmetic-counterexamples main-is: ArithmeticCounterExamples.hs hs-source-dirs: examples/what4 build-depends: base , containers , 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 structs-update-field main-is: StructsUpdateField.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-4.3/README.md0000644000000000000000000003326214762717312012516 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. ``` ### Fedora 40 On Fedora 40 or newer, Copilot can be installed directly from the package repositories with: ```sh $ sudo dnf install ghc-copilot-devel ``` 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.10 as of this writing). You can install the toolchain using [ghcup](https://www.haskell.org/ghcup/) or, if you are on Debian/Ubuntu, you can use `apt-get` to install all dependencies as follows: ```sh $ sudo apt-get install ghc cabal-install alex happy pkg-config libz-dev ``` Once the compiler is installed, install Copilot from [Hackage](https://hackage.haskell.org/package/copilot) with: ```sh cabal v2-install --lib copilot copilot-core copilot-c99 copilot-language \ copilot-theorem copilot-libraries copilot-interpreter copilot-prettyprinter ``` 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 copilot-core copilot-c99 copilot-language \ copilot-theorem copilot-libraries copilot-interpreter copilot-prettyprinter ``` 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: - [Runtime Verification in Real-Time with the Copilot Language: A Tutorial](https://link.springer.com/chapter/10.1007/978-3-031-71177-0_27) - [Trustworthy Runtime Verification via Bisimulation (Experience Report)](https://dl.acm.org/doi/abs/10.1145/3607841) - [An Introduction to Copilot](https://copilot-language.github.io/downloads/copilot_tutorial.pdf) - [Assuring the Guardians](https://link.springer.com/chapter/10.1007/978-3-319-23820-3_6) - [Experience report: a do-it-yourself high-assurance compiler](https://dl.acm.org/doi/abs/10.1145/2364527.2364553) - [Compiling an Haskell EDSL to C: A new C back-end for the Copilot runtime verification framework](https://studenttheses.uu.nl/handle/20.500.12932/29176) - [Challenges in High-Assurance Runtime Verification](https://link.springer.com/chapter/10.1007/978-3-319-47166-2_31) - [Runtime Monitoring On Hard Real-Time Operating Systems](http://hdl.handle.net/10342/4999) - [Design and Testing of an Approach to Automated In-Flight Safety Risk Management for sUAS Operations](https://ntrs.nasa.gov/citations/20220005948) - [The Essence of Reactivity](https://dl.acm.org/doi/10.1145/3609026.3609727) - [Types that Change: The Extensible Type Design Pattern](https://dl.acm.org/doi/abs/10.1145/3609025.3609475) - [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) We'd love to receive your contributions, be it code fixes, new features, bug reports, discussions, or anything else that can help the Copilot project. If you have any comments, questions, ideas, or other topics that you think may be of interest, start a new discussion [here](https://github.com/Copilot-Language/copilot/discussions). If you would like to contribute a fix for an issue, please comment on the issue indicating that you want to fix it so that we can assign it to you and track the status on our end. If the issue does not exist, create it first or ask that an existing discussion be promoted to an issue. If you are unsure about whether your submission should be filed as an issue or as a discussion, file it as a discussion. We can always move it later. To facilitate merging any pull requests that you send, please: - Reference the issue you are addressing with the text `Refs #.` at the end of the subject line of each commit message, in *every commit*. Replace `` with the number of the specific issue that your pull request is addressing. - Describe what each commit does individually *in the commit's message*. It's best to err on the side of being more descriptive than less. - Update the CHANGELOGs in the *last commit(s)*. You can take a look at the repository's [commit history](https://github.com/Copilot-Language/copilot/commits/master/) to better understand the process we follow. Click on each commit to see how we write commit messages. # 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-4.3/LICENSE0000644000000000000000000000263614762717312012245 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-4.3/Setup.hs0000644000000000000000000000005614762717312012666 0ustar0000000000000000import Distribution.Simple main = defaultMain copilot-4.3/CHANGELOG0000644000000000000000000001162114762717312012444 0ustar00000000000000002025-03-07 * Version bump (4.3). (#604) * Include missing dependencies in installation instructions. (#591) * Update version of GHC in README. (#590) * Add example of how to use proveWithCounterExample. (#589) * List all Copilot packages in installation command in README. (#597) 2025-01-07 * Version bump (4.2). (#577) * Bump upper version constraint on filepath. (#570) * Update struct examples to use generic method implementations. (#564) 2024-11-07 * Version bump (4.1). (#561) * Update contribution guidelines. (#476) * Update README with missing publications. (#544) * Make the what4-propositional example's comments match results. (#535) * Add example describing how to implement updateField. (#525) * Standardize changelog format. (#550) * Add installation instructions for Fedora 40 and up. (#542) 2024-09-07 * Version bump (4.0). (#532) * Update example to demonstrate struct update support. (#524) * Update example to demonstrate array update support. (#36) 2024-07-07 * Version bump (3.20). (#522) * Update README to reflect support for GHC 9.8. (#518) 2024-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 * Version bump (3.1). (#46) * Update multiple examples. (#41) * Update instructions to match new repositry name. (#45) copilot-4.3/examples/0000755000000000000000000000000014762717312013047 5ustar0000000000000000copilot-4.3/examples/Array.hs0000644000000000000000000000274214762717312014466 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] -- A trigger that fires 'func2' every time. -- It passes the current value of arr as an argument, but updating the first -- element of the array to always be True. -- The prototype of 'func2' would be: -- void func2 (int8_t arg[3]); trigger "func2" true [arg (arr !! 0 =: true)] -- A trigger that fires 'func2' every time. -- It passes the current value of arr as an argument, but negating the second -- element of the array. -- The prototype of 'func3' would be: -- void func3 (int8_t arg[3]); trigger "func3" true [arg (arr !! 1 =$ not)] -- Compile the spec main :: IO () main = interpret 30 spec copilot-4.3/examples/Structs.hs0000644000000000000000000000423614762717312015057 0ustar0000000000000000-- | An example showing how specifications involving structs (in particular, -- nested structs) are compiled to C using copilot-c99. {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} module Main where import qualified Prelude as P import Control.Monad (void, forM_) import GHC.Generics (Generic) import Language.Copilot import Copilot.Compile.C99 -- | Definition for `Volts`. data Volts = Volts { numVolts :: Field "numVolts" Word16 , flag :: Field "flag" Bool } deriving Generic -- | `Struct` instance for `Volts`. instance Struct Volts where typeName = typeNameDefault toValues = toValuesDefault -- Note that we do not implement `updateField` here. `updateField` is only -- needed to make updates to structs work in the Copilot interpreter, and we -- do not use the interpreter in this example. (See -- `examples/StructsUpdateField.hs` for an example that does implement -- `updateField`.) -- | `Volts` instance for `Typed`. instance Typed Volts where typeOf = typeOfDefault data Battery = Battery { temp :: Field "temp" Word16 , volts :: Field "volts" (Array 10 Volts) , other :: Field "other" (Array 10 (Array 5 Word32)) } deriving Generic -- | `Battery` instance for `Struct`. instance Struct Battery where typeName = typeNameDefault toValues = toValuesDefault -- Note that we do not implement `updateField` here for the same reasons as in -- the `Struct Volts` instance above. -- | `Battery` instance for `Typed`. instance Typed Battery where typeOf = typeOfDefault 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-4.3/examples/Voting.hs0000644000000000000000000000230514762717312014651 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-4.3/examples/Cast.hs0000644000000000000000000000064114762717312014276 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-4.3/examples/AddMult.hs0000644000000000000000000000061414762717312014736 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-4.3/examples/Clock.hs0000644000000000000000000000114614762717312014440 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-4.3/examples/Heater.hs0000644000000000000000000000203614762717312014614 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-4.3/examples/StructsUpdateField.hs0000644000000000000000000001354014762717312017164 0ustar0000000000000000-- | An example showing how specifications involving structs (in particular, -- nested structs) are interpreted and how they are compiled to C using -- copilot-c99. {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} module Main where import qualified Prelude as P import Control.Monad (void, forM_) import Data.Proxy (Proxy(..)) import Data.Type.Equality (TestEquality(..), (:~:)(..)) import GHC.Generics (Generic) import GHC.TypeLits (sameSymbol) import Language.Copilot import Copilot.Compile.C99 -- | Definition for `Volts`. data Volts = Volts { numVolts :: Field "numVolts" Word16 , flag :: Field "flag" Bool } deriving Generic -- | `Struct` instance for `Volts`. instance Struct Volts where typeName = typeNameDefault toValues = toValuesDefault -- In order to run struct updates (as used in the "equalityStructUpdate" -- trigger below) in the Copilot interpreter, we must implement the -- `updateField` method. To do so, we must check to see if the supplied -- `Value` has a `Field` with the same name and type as a field in `Volts`. -- (Alternatively, we could define this as @updateField = updateFieldDefault@, -- but we demonstrate how to manually implement it below for educational -- purposes.) updateField volts (Value fieldTy (field :: Field fieldName a)) -- For each field in `Volts`, we must: -- -- 1. Check that the field names match using `sameSymbol`. Here, -- "numVolts" is the expected name, and `fieldName` is the actual name -- that is supplied as an argument to `updateField`. If the check -- succeeds, then the `sameSymbol` function will return `Just p`, where -- `p` is proof that the two names are the same. | Just Refl <- sameSymbol (Proxy @"numVolts") (Proxy @fieldName) -- 2. Check that the field types match using `testEquality`. Here, -- `Word16` is the expected type, and `fieldTy` is the actual type that -- is supplied as an argument. Again, `testEquality` will return `Just -- p` (where `p` is a proof) if the two are the same. , Just Refl <- testEquality Word16 fieldTy -- 3. If both of the checks above succeed, then we can update the field's -- value using a record update. = volts { numVolts = field } -- It is possible that the `Value` passed as an argument could correspond -- to any of the fields in `Volts`, so we must repeat this process for -- the `flag` field as well. | Just Refl <- sameSymbol (Proxy @fieldName) (Proxy @"flag") , Just Refl <- testEquality fieldTy Bool = volts { flag = field } -- If the supplied `Value` does not correspond to any field in `Volts`, -- then something went wrong in the Copilot interpreter. This case reports -- this as an error. | otherwise = error $ "Unexpected field: " P.++ show field -- | `Volts` instance for `Typed`. instance Typed Volts where typeOf = typeOfDefault data Battery = Battery { temp :: Field "temp" Word16 , volts :: Field "volts" (Array 10 Volts) , other :: Field "other" (Array 10 (Array 5 Word32)) } deriving Generic -- | `Battery` instance for `Struct`. instance Struct Battery where typeName = typeNameDefault toValues = toValuesDefault -- We implement `updateField` similarly to how we implement it in the -- `Struct Volts` instance above. (Alternatively, we could define this as -- @updateField = updateFieldDefault@, but we demonstrate how to manually -- implement it below for educational purposes.) updateField battery (Value fieldTy (field :: Field fieldName a)) | Just Refl <- sameSymbol (Proxy @fieldName) (Proxy @"temp") , Just Refl <- testEquality fieldTy Word16 = battery { temp = field } | Just Refl <- sameSymbol (Proxy @fieldName) (Proxy @"volts") -- Note that writing out the full `Type` for `Volts` is somewhat verbose, -- so we make use of the `Typed Volts` instance and write `typeOf @Volts` -- instead. , Just Refl <- testEquality fieldTy (Array @10 (typeOf @Volts)) = battery { volts = field } | Just Refl <- sameSymbol (Proxy @fieldName) (Proxy @"other") , Just Refl <- testEquality fieldTy (Array @10 (Array @5 Word32)) = battery { other = field } | otherwise = error $ "Unexpected field: " P.++ show field -- | `Battery` instance for `Typed`. instance Typed Battery where typeOf = typeOfDefault spec :: Spec spec = do let voltsValue :: Volts voltsValue = Volts { numVolts = Field 42 , flag = Field True } batteryValue :: Battery batteryValue = Battery { temp = Field 0 , volts = Field (array (replicate 10 voltsValue)) , other = Field (array (replicate 10 (array (replicate 5 0)))) } battery :: Stream Battery battery = extern "battery" (Just [batteryValue]) -- 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] -- Update a struct field, then check it for equality. let batteryTemp1, batteryTemp2 :: Stream Word16 batteryTemp1 = (battery ## temp =$ (+1))#temp batteryTemp2 = battery#temp + 1 trigger "equalityStructUpdate" (batteryTemp1 == batteryTemp2) [arg battery, arg batteryTemp1, arg batteryTemp2] main :: IO () main = do -- Run the specification using the Copilot interpreter. interpret 1 spec -- Compile the specification to C. spec' <- reify spec compile "structs" spec' copilot-4.3/examples/WCV.hs0000644000000000000000000001216414762717312014046 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-4.3/examples/Engine.hs0000644000000000000000000000206514762717312014613 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-4.3/examples/Counter.hs0000644000000000000000000000136614762717312015030 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-4.3/examples/what4/0000755000000000000000000000000014762717312014076 5ustar0000000000000000copilot-4.3/examples/what4/Propositional.hs0000644000000000000000000000551714762717312017304 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 -- * Non-inductive propositions -- The constant value true, which is translated as the corresponding SMT -- boolean literal (and is therefore provable). void $ prop "Example 1" (forAll true) -- The constant value false, which is translated as the corresponding SMT -- boolean literal (and is therefore not provable). void $ prop "Example 2" (forAll false) -- An "a or not a" proposition which does not require any sort of inductive -- argument (but see examples 5 and 6 below for versions that do require -- induction to solve). This is easily proven. let a = [False] ++ b b = not a void $ prop "Example 3" (forAll (a || b)) -- An "a or not a" proposition using external streams, which is also provable. let a = extern "a" Nothing void $ prop "Example 4" (forAll (a || not a)) -- * Simple inductive propositions -- -- While Copilot.Theorem.What4 is not able to solve all inductive propositions -- in general (see the "Complex inductive propositions" section below), the -- following inductive propositions are simple enough that the heuristics in -- Copilot.Theorem.What4 can solve them without issue. -- An inductively defined flavor of true. let a = [True] ++ a void $ prop "Example 5" (forAll a) -- An inductively defined "a or not a" proposition (i.e., a more complex -- version of example 3 above). let a = [False] ++ b b = [True] ++ a void $ prop "Example 6" (forAll (a || b)) -- A bit more convoluted version of example 6. let a = [True, False] ++ b b = [False] ++ not (drop 1 a) void $ prop "Example 7" (forAll (a || b)) -- * Complex induction propositions -- -- The heuristics in Copilot.Theorem.What4 are not able to prove these -- inductive propositions, so these will be reported as unprovable, even -- though each proposition is actually provable. -- An inductively defined flavor of true (i.e., a more complex version of -- example 5 above). let a = [True] ++ ([True] ++ ([True] ++ a)) void $ prop "Example 8" (forAll a) -- An inductively defined "a or not a" proposition (i.e., a more complex -- version of example 6 above). let a = [False] ++ ([False] ++ ([False] ++ b)) b = [True] ++ ([True] ++ ([True] ++ a)) void $ prop "Example 9" (forAll (a || b)) 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-4.3/examples/what4/Structs.hs0000644000000000000000000000507314762717312016106 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 #-} {-# LANGUAGE DeriveGeneric #-} module Main where import qualified Prelude as P import Control.Monad (void, forM_) import GHC.Generics (Generic) import Language.Copilot import Copilot.Theorem.What4 -- | Definition for `Volts`. data Volts = Volts { numVolts :: Field "numVolts" Word16 , flag :: Field "flag" Bool } deriving Generic -- | `Struct` instance for `Volts`. instance Struct Volts where typeName = typeNameDefault toValues = toValuesDefault -- Note that we do not implement `updateField` here. `updateField` is only -- needed to make updates to structs work in the Copilot interpreter, and we -- do not use the interpreter in this example. (See -- `examples/StructsUpdateField.hs` for an example that does implement -- `updateField`.) -- | `Volts` instance for `Typed`. instance Typed Volts where typeOf = typeOfDefault data Battery = Battery { temp :: Field "temp" Word16 , volts :: Field "volts" (Array 10 Volts) , other :: Field "other" (Array 10 (Array 5 Word32)) } deriving Generic -- | `Battery` instance for `Struct`. instance Struct Battery where typeName = typeNameDefault toValues = toValuesDefault -- Note that we do not implement `updateField` here for the same reasons as in -- the `Struct Volts` instance above. -- | `Battery` instance for `Typed`. instance Typed Battery where typeOf = typeOfDefault 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) -- Update a struct field, then check it for equality. void $ prop "Example 3" $ forAll $ ((battery ## temp =$ (+1))#temp == (battery#temp + 1)) 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-4.3/examples/what4/ArithmeticCounterExamples.hs0000644000000000000000000000667014762717312021573 0ustar0000000000000000-- | An example showing the usage of the What4 backend in copilot-theorem for -- simple arithmetic. This example uses the 'proveWithCounterExamples' function -- to demonstrate counterexamples in the event of invalid properties. module Main where import qualified Prelude as P import Control.Monad (void, forM_) import qualified Data.Map as Map 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 <- proveWithCounterExample Z3 spec' -- Print the results. forM_ results $ \(nm, res) -> do putStr $ nm <> ": " case res of ValidCex -> putStrLn "valid" InvalidCex cex -> do putStrLn "invalid" putStrLn $ ppCounterExample cex UnknownCex -> putStrLn "unknown" -- | Pretty-print a counterexample for user display. ppCounterExample :: CounterExample -> String ppCounterExample cex | any P.not (baseCases cex) = if Map.null baseCaseVals then " All possible extern values during the base case(s) " P.++ "constitute a counterexample." else unlines $ " The base cases failed with the following extern values:" : map (\((name, _), val) -> " " P.++ name P.++ ": " P.++ show val) (Map.toList baseCaseVals) | P.not (inductionStep cex) = if Map.null inductionStepVals then " All possible extern values during the induction step " P.++ "constitute a counterexample." else unlines $ " The induction step failed with the following extern values:" : map (\((name, _), val) -> " " P.++ name P.++ ": " P.++ show val) (Map.toList inductionStepVals) | otherwise = error $ "ppCounterExample: " P.++ "Counterexample without failing base cases or induction step" where allExternVals = concreteExternValues cex baseCaseVals = Map.filterWithKey (\(_, offset) _ -> case offset of AbsoluteOffset {} -> True RelativeOffset {} -> False ) allExternVals inductionStepVals = Map.filterWithKey (\(_, offset) _ -> case offset of AbsoluteOffset {} -> False RelativeOffset {} -> True ) allExternVals copilot-4.3/examples/what4/Arithmetic.hs0000644000000000000000000000321114762717312016520 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-4.3/src/0000755000000000000000000000000014762717312012020 5ustar0000000000000000copilot-4.3/src/Language/0000755000000000000000000000000014762717312013543 5ustar0000000000000000copilot-4.3/src/Language/Copilot.hs0000644000000000000000000000177614762717312015523 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-4.3/src/Language/Copilot/0000755000000000000000000000000014762717312015154 5ustar0000000000000000copilot-4.3/src/Language/Copilot/Main.hs0000644000000000000000000000703014762717312016374 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