mirror of
https://github.com/GaloisInc/cryptol.git
synced 2024-10-03 17:07:41 +03:00
Merge branch 'master' into functors-merge
# Conflicts: # docs/RefMan/_build/doctrees/BasicSyntax.doctree # docs/RefMan/_build/doctrees/BasicTypes.doctree # docs/RefMan/_build/doctrees/Expressions.doctree # docs/RefMan/_build/doctrees/FFI.doctree # docs/RefMan/_build/doctrees/Modules.doctree # docs/RefMan/_build/doctrees/OverloadedOperations.doctree # docs/RefMan/_build/doctrees/RefMan.doctree # docs/RefMan/_build/doctrees/TypeDeclarations.doctree # docs/RefMan/_build/doctrees/environment.pickle # docs/RefMan/_build/html/.buildinfo # docs/RefMan/_build/html/BasicSyntax.html # docs/RefMan/_build/html/BasicTypes.html # docs/RefMan/_build/html/Expressions.html # docs/RefMan/_build/html/FFI.html # docs/RefMan/_build/html/Modules.html # docs/RefMan/_build/html/OverloadedOperations.html # docs/RefMan/_build/html/RefMan.html # docs/RefMan/_build/html/TypeDeclarations.html # docs/RefMan/_build/html/_static/doctools.js # docs/RefMan/_build/html/_static/fonts/Lato-Bold.ttf # docs/RefMan/_build/html/_static/fonts/Lato-Regular.ttf # docs/RefMan/_build/html/_static/js/modernizr.min.js # docs/RefMan/_build/html/_static/searchtools.js # docs/RefMan/_build/html/searchindex.js # src/Cryptol/ModuleSystem.hs # src/Cryptol/ModuleSystem/Base.hs # src/Cryptol/ModuleSystem/InstantiateModule.hs # src/Cryptol/Parser/AST.hs # src/Cryptol/Parser/ParserUtils.hs # src/Cryptol/REPL/Command.hs # src/Cryptol/Transform/AddModParams.hs # src/Cryptol/Transform/Specialize.hs # src/Cryptol/TypeCheck/Infer.hs # src/Cryptol/TypeCheck/InferTypes.hs # src/Cryptol/Utils/Ident.hs
This commit is contained in:
commit
441e163856
67
.github/workflows/ci.yml
vendored
67
.github/workflows/ci.yml
vendored
@ -9,7 +9,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
SOLVER_PKG_VERSION: "snapshot-20220721"
|
||||
SOLVER_PKG_VERSION: "snapshot-20220812"
|
||||
# The CACHE_VERSION can be updated to force the use of a new cache if
|
||||
# the current cache contents become corrupted/invalid. This can
|
||||
# sometimes happen when (for example) the OS version is changed but
|
||||
@ -20,7 +20,7 @@ env:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
name: ${{ steps.config.outputs.name }}
|
||||
version: ${{ steps.config.outputs.version }}
|
||||
@ -58,21 +58,18 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-12, windows-2019]
|
||||
ghc-version: ["8.8.4", "8.10.7", "9.0.2", "9.2.2"]
|
||||
os: [ubuntu-22.04, macos-12, windows-2019]
|
||||
ghc-version: ["8.10.7", "9.0.2", "9.2.4"]
|
||||
exclude:
|
||||
# https://gitlab.haskell.org/ghc/ghc/-/issues/18550
|
||||
- os: windows-2019
|
||||
ghc-version: 8.10.7
|
||||
- os: windows-2019
|
||||
ghc-version: 9.0.2
|
||||
- os: windows-2019
|
||||
ghc-version: 9.2.2
|
||||
ghc-version: 9.2.4
|
||||
include:
|
||||
# We include one job from an older Ubuntu LTS release to increase our
|
||||
# coverage of possible Linux configurations.
|
||||
- os: ubuntu-18.04
|
||||
ghc-version: 8.8.4
|
||||
- os: ubuntu-22.04
|
||||
ghc-version: 8.10.7
|
||||
outputs:
|
||||
test-lib-json: ${{ steps.test-lib.outputs.targets-json }}
|
||||
env:
|
||||
@ -96,6 +93,14 @@ jobs:
|
||||
with:
|
||||
ghc-version: ${{ matrix.ghc-version }}
|
||||
|
||||
- name: Post-GHC installation fixups on Windows
|
||||
shell: bash
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
# A workaround for https://github.com/Mistuke/CabalChoco/issues/5
|
||||
cabal user-config update -a "extra-include-dirs: \"\""
|
||||
cabal user-config update -a "extra-lib-dirs: \"\""
|
||||
|
||||
- uses: actions/cache@v2
|
||||
name: Cache cabal store
|
||||
with:
|
||||
@ -147,6 +152,8 @@ jobs:
|
||||
cmd="cat \$1.stdout"
|
||||
if ${{ runner.os == 'Windows' }}; then
|
||||
cmd="cat \$1.stdout.mingw32 2>/dev/null || $cmd"
|
||||
elif ${{ runner.os == 'macOS' }}; then
|
||||
cmd="cat \$1.stdout.darwin 2>/dev/null || $cmd"
|
||||
fi
|
||||
./bin/test-runner --ext=.icry -r ./output --exe=$(which bash) -F -c -F "$cmd" -F -- ./tests
|
||||
TARGETS_JSON=$(echo -n "$(ls -1 ./output/tests)" | jq -Rsc 'split("\n")')
|
||||
@ -158,7 +165,7 @@ jobs:
|
||||
- if: runner.os == 'Windows'
|
||||
run: .github/wix.ps1
|
||||
|
||||
- if: runner.os == 'Windows'
|
||||
- if: runner.os == 'Windows' && github.event.pull_request.head.repo.fork == false
|
||||
shell: bash
|
||||
env:
|
||||
SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
|
||||
@ -181,7 +188,8 @@ jobs:
|
||||
env:
|
||||
OS_TAG: ${{ matrix.os }}
|
||||
|
||||
- shell: bash
|
||||
- if: github.event.pull_request.head.repo.fork == false
|
||||
shell: bash
|
||||
env:
|
||||
SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
|
||||
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
|
||||
@ -203,13 +211,13 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: ${{ needs.config.outputs.retention-days }}
|
||||
|
||||
- if: matrix.ghc-version == '8.8.4'
|
||||
- if: matrix.ghc-version == '8.10.7'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: dist/bin
|
||||
name: ${{ runner.os }}-dist-bin
|
||||
|
||||
- if: matrix.ghc-version == '8.8.4'
|
||||
- if: matrix.ghc-version == '8.10.7'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: bin
|
||||
@ -231,12 +239,12 @@ jobs:
|
||||
matrix:
|
||||
suite: [test-lib]
|
||||
target: ${{ fromJson(needs.build.outputs.test-lib-json) }}
|
||||
os: [ubuntu-20.04, macos-12, windows-2019]
|
||||
os: [ubuntu-22.04, macos-12, windows-2019]
|
||||
continue-on-error: [false]
|
||||
include:
|
||||
- suite: rpc
|
||||
target: ''
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
continue-on-error: false
|
||||
#- suite: rpc
|
||||
# target: ''
|
||||
@ -255,6 +263,19 @@ jobs:
|
||||
with:
|
||||
ghc-version: '8.10.7'
|
||||
|
||||
- name: Install dependencies (Windows)
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
update: true
|
||||
msystem: MINGW64
|
||||
# These are needed for the ffi tests on Windows
|
||||
install: |
|
||||
diffutils
|
||||
make
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-gmp
|
||||
if: matrix.suite == 'test-lib' && runner.os == 'Windows'
|
||||
|
||||
- if: matrix.suite == 'rpc'
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
@ -293,7 +314,7 @@ jobs:
|
||||
cp cabal.GHC-"$ghc_ver".config cabal.project.freeze
|
||||
cabal v2-update
|
||||
|
||||
- if: matrix.suite == 'test-lib'
|
||||
- if: matrix.suite == 'test-lib' && runner.os != 'Windows'
|
||||
shell: bash
|
||||
continue-on-error: ${{ matrix.continue-on-error }}
|
||||
name: test-lib ${{ matrix.target }}
|
||||
@ -303,6 +324,16 @@ jobs:
|
||||
./bin/test-runner --ext=.icry -F -b --exe=dist/bin/cryptol ./tests/${{ matrix.target }}
|
||||
fi
|
||||
|
||||
- if: matrix.suite == 'test-lib' && runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
continue-on-error: ${{ matrix.continue-on-error }}
|
||||
name: test-lib ${{ matrix.target }}
|
||||
run: |
|
||||
export PATH=$PWD/bin:$PWD/dist/bin:$PATH
|
||||
if ${{ matrix.target != 'ffi' }} || dist/bin/cryptol -v | grep -q 'FFI enabled'; then
|
||||
./bin/test-runner --ext=.icry -F -b --exe=dist/bin/cryptol ./tests/${{ matrix.target }}
|
||||
fi
|
||||
|
||||
- if: matrix.suite == 'rpc'
|
||||
shell: bash
|
||||
continue-on-error: ${{ matrix.continue-on-error }}
|
||||
@ -311,7 +342,7 @@ jobs:
|
||||
cryptol-remote-api/run_rpc_tests.sh
|
||||
|
||||
build-push-image:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [config]
|
||||
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || needs.config.outputs.release == 'true'
|
||||
strategy:
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,6 +10,7 @@ dist-newstyle
|
||||
.ghc.environment.*
|
||||
cabal.project.freeze
|
||||
cabal.project.local*
|
||||
.vscode/
|
||||
|
||||
# don't check in generated documentation
|
||||
#docs/CryptolPrims.pdf
|
||||
@ -38,3 +39,6 @@ allfiles.wxs
|
||||
cryptol.msi
|
||||
cryptol.wixobj
|
||||
cryptol.wixpdb
|
||||
|
||||
# happy-generated files
|
||||
src/Cryptol/Parser.hs
|
26
CHANGES.md
26
CHANGES.md
@ -1,10 +1,36 @@
|
||||
# next
|
||||
|
||||
## Language changes
|
||||
|
||||
* Declarations may now use *numeric constraint guards*. This is a feature
|
||||
that allows a function to behave differently depending on its numeric
|
||||
type parameters. See the [manual section](https://galoisinc.github.io/cryptol/RefMan/_build/html/BasicSyntax.html#numeric-constraint-guards))
|
||||
for more information.
|
||||
|
||||
* The foreign function interface (FFI) has been added, which allows Cryptol to
|
||||
call functions written in C. See the [manual section](https://galoisinc.github.io/cryptol/RefMan/_build/html/FFI.html)
|
||||
for more information.
|
||||
|
||||
* The unary `-` operator now has the same precedence as binary `-`, meaning
|
||||
expressions like `-x^^2` will now parse as `-(x^^2)` instead of `(-x)^^2`.
|
||||
**This is a breaking change.** A warning has been added in cases where the
|
||||
behavior has changed, and can be disabled with `:set warnPrefixAssoc=off`.
|
||||
|
||||
* Infix operators are now allowed in import lists: `import M ((<+>))` will
|
||||
import only the operator `<+>` from module `M`.
|
||||
|
||||
## New features
|
||||
|
||||
* Add a `:time` command to benchmark the evaluation time of expressions.
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Fix a bug in the What4 backend that could cause applications of `(@)` with
|
||||
symbolic `Integer` indices to become out of bounds (#1359).
|
||||
|
||||
* Fix a bug that caused finite bitvector enumerations to panic when used in
|
||||
combination with `(#)` (e.g., `[0..1] # 0`).
|
||||
|
||||
# 2.13.0
|
||||
|
||||
## Language changes
|
||||
|
55
ConditionalConstraints.md
Normal file
55
ConditionalConstraints.md
Normal file
@ -0,0 +1,55 @@
|
||||
# Conditional Constraints
|
||||
|
||||
## Syntax
|
||||
|
||||
The front-end AST has a new constructor:
|
||||
|
||||
```hs
|
||||
data BindDef name = DPropGuards [([Prop name], Expr name)] | ...
|
||||
```
|
||||
|
||||
which is parsed from the following syntax:
|
||||
|
||||
```
|
||||
<name> : <signature>
|
||||
<name> <pats>
|
||||
[ | <props> => <expr> ]
|
||||
```
|
||||
|
||||
## Expanding PropGuards
|
||||
|
||||
- Before renaming, a `Bind` with a `bDef = DPropGuards ...` will be expanded into several `Bind`s, one for each guard case.
|
||||
- The generated `Bind`s will have fresh names, but the names will have the same location as the original function's name.
|
||||
- These generated `Bind`'s will have the same type as the original function, except that the list of type constraints will also include the `Prop name`s that appeared on the LHS of the originating ase of `DPropGuards`.
|
||||
- The original function will have the `Expr name` in each of the `DPropGuards` cases replaced with a function call the appropriate, generated function.
|
||||
|
||||
## Renaming
|
||||
|
||||
The new constructor of `BindDef` is traversed as normal during renaming. This ensures that a function with `DPropGuards` ends up in the same mutual-recursion group as the generated functions that it calls.
|
||||
|
||||
## Typechecking
|
||||
|
||||
The back-end AST has a new constructor:
|
||||
|
||||
```hs
|
||||
data Expr = EPropGuards [([Prop], Expr)] | ...
|
||||
```
|
||||
|
||||
During typechecking, a `BindDef` of the form
|
||||
|
||||
```
|
||||
DPropGuards [(props1, f1 x y), (prop2, f2 x y)]
|
||||
```
|
||||
|
||||
is processed into a `Decl` of the form
|
||||
|
||||
```
|
||||
Decl
|
||||
{ dDefinition =
|
||||
DExpr (EPropGuards
|
||||
[ (props1, f1 x y)
|
||||
, (props2, f2 x y) ])
|
||||
}
|
||||
```
|
||||
|
||||
Each case of an `EPropGuards` is typechecked by first asssuming the `props` and then typechecking the expression. However, this typechecking isn't really that important because by construction the expression is just a simple application that is ensured to be well-typed. But we can use this structure for more general purposes.
|
29
Dockerfile
29
Dockerfile
@ -1,21 +1,36 @@
|
||||
FROM haskell:8.8.4 AS build
|
||||
FROM ubuntu:22.04 AS build
|
||||
|
||||
RUN apt-get update && apt-get install -y libncurses-dev unzip
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
# ghcup requirements
|
||||
build-essential curl libffi-dev libffi8 libgmp-dev libgmp10 libncurses-dev libncurses6 libtinfo6 \
|
||||
# Cryptol dependencies
|
||||
zlib1g-dev \
|
||||
# Miscellaneous
|
||||
unzip
|
||||
RUN useradd -m cryptol
|
||||
COPY --chown=cryptol:cryptol . /cryptol
|
||||
USER cryptol
|
||||
WORKDIR /cryptol
|
||||
RUN mkdir -p rootfs/usr/local/bin
|
||||
WORKDIR /cryptol/rootfs/usr/local/bin
|
||||
RUN curl -o solvers.zip -sL "https://github.com/GaloisInc/what4-solvers/releases/download/snapshot-20220114/ubuntu-18.04-bin.zip"
|
||||
RUN curl -o solvers.zip -sL "https://github.com/GaloisInc/what4-solvers/releases/download/snapshot-20220812/ubuntu-22.04-bin.zip"
|
||||
RUN unzip solvers.zip && rm solvers.zip && chmod +x *
|
||||
WORKDIR /cryptol
|
||||
ENV PATH=/cryptol/rootfs/usr/local/bin:$PATH
|
||||
ENV PATH=/cryptol/rootfs/usr/local/bin:/home/cryptol/.local/bin:/home/cryptol/.ghcup/bin:$PATH
|
||||
RUN z3 --version
|
||||
ARG CRYPTOLPATH="/cryptol/.cryptol"
|
||||
ENV LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8
|
||||
COPY cabal.GHC-8.8.4.config cabal.project.freeze
|
||||
COPY cabal.GHC-8.10.7.config cabal.project.freeze
|
||||
RUN mkdir -p /home/cryptol/.local/bin && \
|
||||
curl -L https://downloads.haskell.org/~ghcup/0.1.17.7/x86_64-linux-ghcup-0.1.17.7 -o /home/cryptol/.local/bin/ghcup && \
|
||||
chmod +x /home/cryptol/.local/bin/ghcup
|
||||
RUN mkdir -p /home/cryptol/.ghcup && \
|
||||
ghcup --version && \
|
||||
ghcup install cabal 3.6.2.0 && \
|
||||
ghcup install ghc 8.10.7 && \
|
||||
ghcup set ghc 8.10.7
|
||||
RUN cabal v2-update && \
|
||||
cabal v2-build -j cryptol:exe:cryptol && \
|
||||
cp $(cabal v2-exec which cryptol) rootfs/usr/local/bin && \
|
||||
@ -33,9 +48,9 @@ RUN mkdir -p rootfs/"${CRYPTOLPATH}" \
|
||||
USER root
|
||||
RUN chown -R root:root /cryptol/rootfs
|
||||
|
||||
FROM debian:buster-20210511-slim
|
||||
FROM ubuntu:22.04
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libgmp10 libgomp1 libffi6 libncurses6 libtinfo6 libreadline7 \
|
||||
&& apt-get install -y libgmp10 libgomp1 libffi8 libncurses6 libtinfo6 libreadline8 \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
RUN useradd -m cryptol && chown -R cryptol:cryptol /home/cryptol
|
||||
COPY --from=build /cryptol/rootfs /
|
||||
|
@ -46,7 +46,7 @@ Cryptol currently uses Microsoft Research's [Z3 SMT
|
||||
solver](https://github.com/Z3Prover/z3) by default to solve constraints
|
||||
during type checking, and as the default solver for the `:sat` and
|
||||
`:prove` commands. Cryptol generally requires the most recent version
|
||||
of Z3, but you can see the specific version tested in CI by looking [here](https://github.com/GaloisInc/what4-solvers/releases/tag/snapshot-20220721).
|
||||
of Z3, but you can see the specific version tested in CI by looking [here](https://github.com/GaloisInc/what4-solvers/releases/tag/snapshot-20220812).
|
||||
|
||||
You can download Z3 binaries for a variety of platforms from their
|
||||
[releases page](https://github.com/Z3Prover/z3/releases). If you
|
||||
@ -75,15 +75,15 @@ Cryptol builds and runs on various flavors of Linux, Mac OS X, and
|
||||
Windows. We regularly build and test it in the following environments:
|
||||
|
||||
- macOS 12, 64-bit
|
||||
- Ubuntu 18.04, 64-bit
|
||||
- Ubuntu 20.04, 64-bit
|
||||
- Ubuntu 22.04, 64-bit
|
||||
- Windows Server 2019, 64-bit
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Cryptol is regularly built and tested with the three most recent
|
||||
versions of GHC, which at the time of this writing are 8.10.7, 9.0.2, and
|
||||
9.2.2. The easiest way to install an approporiate version of GHC is
|
||||
9.2.4. The easiest way to install an approporiate version of GHC is
|
||||
with [ghcup](https://www.haskell.org/ghcup/).
|
||||
|
||||
Some supporting non-Haskell libraries are required to build
|
||||
|
@ -11,10 +11,7 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.abstract-par ==0.3.3,
|
||||
any.adjunctions ==4.4,
|
||||
any.adjunctions ==4.4.2,
|
||||
any.aeson ==2.0.3.0,
|
||||
aeson -cffi +ordered-keymap,
|
||||
any.alex ==3.2.7.1,
|
||||
@ -23,7 +20,7 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.appar ==0.1.8,
|
||||
any.arithmoi ==0.12.0.1,
|
||||
any.arithmoi ==0.12.0.2,
|
||||
any.array ==0.5.4.0,
|
||||
any.asn1-encoding ==0.9.6,
|
||||
any.asn1-parse ==0.9.5,
|
||||
@ -35,16 +32,18 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.14.3.0,
|
||||
any.base-compat ==0.12.1,
|
||||
any.base-compat-batteries ==0.12.1,
|
||||
any.base-orphans ==0.8.6,
|
||||
any.base-compat ==0.12.2,
|
||||
any.base-compat-batteries ==0.12.2,
|
||||
any.base-orphans ==0.8.7,
|
||||
any.base64-bytestring ==1.2.1.0,
|
||||
any.basement ==0.0.14,
|
||||
any.bifunctors ==5.5.11,
|
||||
any.basement ==0.0.15,
|
||||
any.bifunctors ==5.5.13,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.bimap ==0.4.0,
|
||||
any.bimap ==0.5.0,
|
||||
any.binary ==0.8.8.0,
|
||||
any.binary-orphans ==1.0.2,
|
||||
any.binary-orphans ==1.0.3,
|
||||
any.bitvec ==1.1.3.0,
|
||||
bitvec -libgmp,
|
||||
any.bitwise ==1.0.0.1,
|
||||
any.blaze-builder ==0.4.2.2,
|
||||
any.blaze-html ==0.9.1.2,
|
||||
@ -56,9 +55,9 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.cabal-doctest ==1.0.9,
|
||||
any.call-stack ==0.4.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.cassava ==0.5.2.0,
|
||||
any.cassava ==0.5.3.0,
|
||||
cassava -bytestring--lt-0_10_4,
|
||||
any.cereal ==0.5.8.2,
|
||||
any.cereal ==0.5.8.3,
|
||||
cereal -bytestring-builder,
|
||||
any.chimera ==0.3.2.0,
|
||||
chimera +representable,
|
||||
@ -69,19 +68,19 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.concurrent-extra ==0.7.0.12,
|
||||
any.config-value ==0.8.2.1,
|
||||
any.constraints ==0.13.3,
|
||||
any.config-value ==0.8.3,
|
||||
any.constraints ==0.13.4,
|
||||
any.containers ==0.6.5.1,
|
||||
any.contravariant ==1.5.5,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cookie ==0.4.5,
|
||||
any.criterion ==1.5.13.0,
|
||||
any.criterion ==1.6.0.0,
|
||||
criterion -embed-data-files -fast,
|
||||
any.criterion-measurement ==0.1.3.0,
|
||||
any.criterion-measurement ==0.2.0.0,
|
||||
criterion-measurement -fast,
|
||||
any.cryptohash-md5 ==0.11.101.0,
|
||||
any.cryptohash-sha1 ==0.11.101.0,
|
||||
cryptol +relocatable -static,
|
||||
cryptol +ffi +relocatable -static,
|
||||
cryptol-remote-api -notthreaded -static,
|
||||
cryptol-test-runner -static,
|
||||
any.cryptonite ==0.30,
|
||||
@ -91,7 +90,7 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.data-fix ==0.3.2,
|
||||
any.deepseq ==1.4.4.0,
|
||||
any.dense-linear-algebra ==0.1.0.0,
|
||||
any.deriving-compat ==0.6,
|
||||
any.deriving-compat ==0.6.1,
|
||||
deriving-compat +base-4-9 +new-functor-classes +template-haskell-2-11,
|
||||
any.directory ==1.3.6.0,
|
||||
any.distributive ==0.6.2.1,
|
||||
@ -99,18 +98,18 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.easy-file ==0.2.2,
|
||||
any.entropy ==0.4.1.7,
|
||||
entropy -halvm,
|
||||
any.entropy ==0.4.1.10,
|
||||
entropy -donotgetentropy,
|
||||
any.exact-pi ==0.5.0.2,
|
||||
any.exceptions ==0.10.4,
|
||||
any.extensible-exceptions ==0.1.1.4,
|
||||
any.extra ==1.7.10,
|
||||
any.extra ==1.7.12,
|
||||
any.fail ==4.9.0.0,
|
||||
any.fast-logger ==3.1.1,
|
||||
any.filelock ==0.1.1.5,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.fingertree ==0.1.5.0,
|
||||
any.free ==5.1.7,
|
||||
any.free ==5.1.9,
|
||||
any.ghc-boot-th ==8.10.7,
|
||||
any.ghc-prim ==0.6.1,
|
||||
any.gitrev ==1.3.1,
|
||||
@ -121,6 +120,7 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
hashtables -bounds-checking -debug -detailed-profiling -portable -sse42 +unsafe-tricks,
|
||||
any.haskeline ==0.8.2,
|
||||
any.heredoc ==0.2.0.0,
|
||||
any.hgmp ==0.1.2.1,
|
||||
any.hostname ==1.0,
|
||||
any.hourglass ==0.2.12,
|
||||
any.hsc2hs ==0.68.8,
|
||||
@ -129,35 +129,38 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.http-types ==0.12.3,
|
||||
any.http2 ==3.0.3,
|
||||
http2 -devel -doc -h2spec,
|
||||
any.ieee754 ==0.8.0,
|
||||
any.indexed-traversable ==0.1.2,
|
||||
any.indexed-traversable-instances ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1.1.1,
|
||||
any.integer-gmp ==1.0.3.0,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.integer-roots ==1.0.2.0,
|
||||
any.invariant ==0.5.5,
|
||||
any.io-streams ==1.5.2.1,
|
||||
any.invariant ==0.6,
|
||||
any.io-streams ==1.5.2.2,
|
||||
io-streams +network -nointeractivetests +zlib,
|
||||
any.iproute ==1.7.12,
|
||||
any.js-chart ==2.9.4.1,
|
||||
any.kan-extensions ==5.2.3,
|
||||
any.lens ==5.1,
|
||||
any.kan-extensions ==5.2.5,
|
||||
any.language-c99 ==0.2.0,
|
||||
any.language-c99-simple ==0.2.2,
|
||||
any.language-c99-util ==0.2.0,
|
||||
any.lens ==5.1.1,
|
||||
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
|
||||
any.libBF ==0.6.3,
|
||||
any.libBF ==0.6.5.1,
|
||||
libBF -system-libbf,
|
||||
any.libffi ==0.2,
|
||||
libffi +ghc-bundled-libffi,
|
||||
any.math-functions ==0.3.4.2,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==9.2.0,
|
||||
any.megaparsec ==9.2.1,
|
||||
megaparsec -dev,
|
||||
any.memory ==0.17.0,
|
||||
any.memory ==0.18.0,
|
||||
memory +support_bytestring +support_deepseq,
|
||||
any.microstache ==1.0.2,
|
||||
any.microstache ==1.0.2.2,
|
||||
any.mod ==0.1.2.2,
|
||||
mod +semirings +vector,
|
||||
any.monad-control ==1.0.3.1,
|
||||
any.monad-par ==0.3.5,
|
||||
monad-par -chaselev -newgeneric,
|
||||
any.monad-par-extras ==0.3.3,
|
||||
any.monadLib ==3.10.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.mwc-random ==0.15.0.2,
|
||||
@ -167,7 +170,7 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
network -devel,
|
||||
any.network-byte-order ==0.1.6,
|
||||
any.network-info ==0.2.1,
|
||||
any.newtype-generics ==0.6.1,
|
||||
any.newtype-generics ==0.6.2,
|
||||
any.numtype-dk ==0.5.0.3,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
@ -184,20 +187,20 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.prettyprinter ==1.7.1,
|
||||
prettyprinter -buildreadme +text,
|
||||
any.primitive ==0.7.3.0,
|
||||
any.primitive ==0.7.4.0,
|
||||
any.process ==1.6.13.2,
|
||||
any.profunctors ==5.6.2,
|
||||
any.psqueues ==0.2.7.3,
|
||||
any.quickcheck-instances ==0.3.27,
|
||||
any.quickcheck-instances ==0.3.28,
|
||||
quickcheck-instances -bytestring-builder,
|
||||
any.random ==1.2.1,
|
||||
any.random ==1.2.1.1,
|
||||
any.reflection ==2.1.6,
|
||||
reflection -slow +template-haskell,
|
||||
any.regex-base ==0.94.0.2,
|
||||
any.regex-compat ==0.95.2.1,
|
||||
any.regex-posix ==0.96.0.1,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.3,
|
||||
any.resourcet ==1.2.6,
|
||||
any.rts ==1.0.1,
|
||||
any.safe ==0.3.19,
|
||||
any.sbv ==9.0,
|
||||
@ -212,23 +215,23 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||
any.semirings ==0.6,
|
||||
semirings +containers +unordered-containers,
|
||||
any.silently ==1.2.5.2,
|
||||
any.silently ==1.2.5.3,
|
||||
any.simple-get-opt ==0.4,
|
||||
any.simple-sendfile ==0.2.30,
|
||||
simple-sendfile +allow-bsd,
|
||||
any.simple-smt ==0.9.7,
|
||||
any.splitmix ==0.1.0.4,
|
||||
splitmix -optimised-mixer,
|
||||
any.statistics ==0.16.0.2,
|
||||
any.statistics ==0.16.1.0,
|
||||
any.stm ==2.5.0.1,
|
||||
any.streaming-commons ==0.2.2.4,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.syb ==0.7.2.1,
|
||||
any.syb ==0.7.2.2,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.tasty ==1.4.2.1,
|
||||
any.tasty ==1.4.2.3,
|
||||
tasty +clock +unix,
|
||||
any.tasty-hunit ==0.10.0.3,
|
||||
any.tasty-quickcheck ==0.10.2,
|
||||
@ -243,30 +246,30 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.text-short ==0.1.5,
|
||||
text-short -asserts,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.3.0,
|
||||
any.th-abstraction ==0.4.5.0,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.19,
|
||||
any.th-lift-instances ==0.1.20,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.6.1,
|
||||
time-compat -old-locale,
|
||||
any.time-manager ==0.0.0,
|
||||
any.tls ==1.5.7,
|
||||
any.tls ==1.6.0,
|
||||
tls +compat -hans +network,
|
||||
any.tls-session-manager ==0.0.4,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.6,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.7.1,
|
||||
any.transformers-compat ==0.7.2,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.type-equality ==1,
|
||||
any.unbounded-delays ==0.1.1.1,
|
||||
any.uniplate ==1.6.13,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-compat ==0.5.4,
|
||||
any.unix-compat ==0.6,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unix-time ==0.4.8,
|
||||
any.unliftio ==0.2.22.0,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.19.1,
|
||||
@ -278,7 +281,7 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
vault +useghc,
|
||||
any.vector ==0.12.3.1,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.4,
|
||||
any.vector-algorithms ==0.9.0.1,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.vector-binary-instances ==0.2.5.2,
|
||||
any.vector-th-unbox ==0.2.2,
|
||||
@ -286,19 +289,19 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.void ==0.7.3,
|
||||
void -safe,
|
||||
any.wai ==3.2.3,
|
||||
any.wai-extra ==3.1.10,
|
||||
any.wai-extra ==3.1.12.1,
|
||||
wai-extra -build-example,
|
||||
any.wai-logger ==2.4.0,
|
||||
any.warp ==3.3.20,
|
||||
any.warp ==3.3.22,
|
||||
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
||||
any.warp-tls ==3.3.2,
|
||||
any.warp-tls ==3.3.3,
|
||||
any.wcwidth ==0.0.2,
|
||||
wcwidth -cli +split-base,
|
||||
any.what4 ==1.3,
|
||||
what4 -drealtestdisable -solvertests -stptestdisable,
|
||||
any.witherable ==0.4.2,
|
||||
any.word8 ==0.1.3,
|
||||
any.x509 ==1.7.6,
|
||||
any.x509 ==1.7.7,
|
||||
any.x509-store ==1.6.9,
|
||||
any.x509-validation ==1.6.12,
|
||||
any.xml ==1.3.14,
|
||||
@ -306,4 +309,4 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.zlib ==0.6.3.0,
|
||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
index-state: hackage.haskell.org 2022-05-04T18:13:54Z
|
||||
index-state: hackage.haskell.org 2022-09-24T14:14:21Z
|
||||
|
@ -1,310 +0,0 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.0.1.0,
|
||||
any.Glob ==0.10.2,
|
||||
any.GraphSCC ==1.0.4,
|
||||
GraphSCC -use-maps,
|
||||
any.HUnit ==1.6.2.0,
|
||||
any.MemoTrie ==0.6.10,
|
||||
MemoTrie -examples,
|
||||
any.OneTuple ==0.3.1,
|
||||
any.Only ==0.1,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.abstract-par ==0.3.3,
|
||||
any.adjunctions ==4.4,
|
||||
any.aeson ==2.0.3.0,
|
||||
aeson -cffi +ordered-keymap,
|
||||
any.alex ==3.2.7.1,
|
||||
any.ansi-terminal ==0.11.3,
|
||||
ansi-terminal -example,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.appar ==0.1.8,
|
||||
any.arithmoi ==0.12.0.1,
|
||||
any.array ==0.5.4.0,
|
||||
any.asn1-encoding ==0.9.6,
|
||||
any.asn1-parse ==0.9.5,
|
||||
any.asn1-types ==0.3.4,
|
||||
any.assoc ==1.0.2,
|
||||
any.async ==2.2.4,
|
||||
async -bench,
|
||||
any.attoparsec ==0.14.4,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.13.0.0,
|
||||
any.base-compat ==0.12.1,
|
||||
any.base-compat-batteries ==0.12.1,
|
||||
any.base-orphans ==0.8.6,
|
||||
any.base64-bytestring ==1.2.1.0,
|
||||
any.basement ==0.0.14,
|
||||
any.bifunctors ==5.5.11,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.bimap ==0.4.0,
|
||||
any.binary ==0.8.7.0,
|
||||
any.binary-orphans ==1.0.2,
|
||||
any.bitwise ==1.0.0.1,
|
||||
any.blaze-builder ==0.4.2.2,
|
||||
any.blaze-html ==0.9.1.2,
|
||||
any.blaze-markup ==0.8.2.8,
|
||||
any.bsb-http-chunked ==0.0.0.4,
|
||||
any.bv-sized ==1.0.4,
|
||||
any.byteorder ==1.0.4,
|
||||
any.bytestring ==0.10.10.1,
|
||||
any.cabal-doctest ==1.0.9,
|
||||
any.call-stack ==0.4.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.cassava ==0.5.2.0,
|
||||
cassava -bytestring--lt-0_10_4,
|
||||
any.cereal ==0.5.8.2,
|
||||
cereal -bytestring-builder,
|
||||
any.chimera ==0.3.2.0,
|
||||
chimera +representable,
|
||||
any.clock ==0.8.3,
|
||||
clock -llvm,
|
||||
any.code-page ==0.2.1,
|
||||
any.colour ==2.3.6,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.concurrent-extra ==0.7.0.12,
|
||||
any.config-value ==0.8.2.1,
|
||||
any.constraints ==0.13.3,
|
||||
any.containers ==0.6.2.1,
|
||||
any.contravariant ==1.5.5,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cookie ==0.4.5,
|
||||
any.criterion ==1.5.13.0,
|
||||
criterion -embed-data-files -fast,
|
||||
any.criterion-measurement ==0.1.3.0,
|
||||
criterion-measurement -fast,
|
||||
any.cryptohash-md5 ==0.11.101.0,
|
||||
any.cryptohash-sha1 ==0.11.101.0,
|
||||
cryptol +relocatable -static,
|
||||
cryptol-remote-api -notthreaded -static,
|
||||
cryptol-test-runner -static,
|
||||
any.cryptonite ==0.30,
|
||||
cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
|
||||
any.data-binary-ieee754 ==0.4.4,
|
||||
any.data-default-class ==0.1.2.0,
|
||||
any.data-fix ==0.3.2,
|
||||
any.deepseq ==1.4.4.0,
|
||||
any.dense-linear-algebra ==0.1.0.0,
|
||||
any.deriving-compat ==0.6,
|
||||
deriving-compat +base-4-9 +new-functor-classes +template-haskell-2-11,
|
||||
any.directory ==1.3.6.0,
|
||||
any.distributive ==0.6.2.1,
|
||||
distributive +semigroups +tagged,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.easy-file ==0.2.2,
|
||||
any.entropy ==0.4.1.7,
|
||||
entropy -halvm,
|
||||
any.exact-pi ==0.5.0.2,
|
||||
any.exceptions ==0.10.4,
|
||||
exceptions +transformers-0-4,
|
||||
any.extensible-exceptions ==0.1.1.4,
|
||||
any.extra ==1.7.10,
|
||||
any.fail ==4.9.0.0,
|
||||
any.fast-logger ==3.1.1,
|
||||
any.filelock ==0.1.1.5,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.fingertree ==0.1.5.0,
|
||||
any.free ==5.1.7,
|
||||
any.ghc-boot-th ==8.8.4,
|
||||
any.ghc-prim ==0.5.3,
|
||||
any.gitrev ==1.3.1,
|
||||
any.happy ==1.20.0,
|
||||
any.hashable ==1.3.5.0,
|
||||
hashable +integer-gmp -random-initial-seed,
|
||||
any.hashtables ==1.2.4.2,
|
||||
hashtables -bounds-checking -debug -detailed-profiling -portable -sse42 +unsafe-tricks,
|
||||
any.haskeline ==0.7.5.0,
|
||||
any.heredoc ==0.2.0.0,
|
||||
any.hostname ==1.0,
|
||||
any.hourglass ==0.2.12,
|
||||
any.hsc2hs ==0.68.8,
|
||||
hsc2hs -in-ghc-tree,
|
||||
any.http-date ==0.0.11,
|
||||
any.http-types ==0.12.3,
|
||||
any.http2 ==3.0.3,
|
||||
http2 -devel -doc -h2spec,
|
||||
any.indexed-traversable ==0.1.2,
|
||||
any.indexed-traversable-instances ==0.1.1,
|
||||
any.integer-gmp ==1.0.2.0,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.integer-roots ==1.0.2.0,
|
||||
any.invariant ==0.5.5,
|
||||
any.io-streams ==1.5.2.1,
|
||||
io-streams +network -nointeractivetests +zlib,
|
||||
any.iproute ==1.7.12,
|
||||
any.js-chart ==2.9.4.1,
|
||||
any.kan-extensions ==5.2.3,
|
||||
any.lens ==5.1,
|
||||
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
|
||||
any.libBF ==0.6.3,
|
||||
libBF -system-libbf,
|
||||
any.math-functions ==0.3.4.2,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==9.2.0,
|
||||
megaparsec -dev,
|
||||
any.memory ==0.17.0,
|
||||
memory +support_bytestring +support_deepseq,
|
||||
any.microstache ==1.0.2,
|
||||
any.mod ==0.1.2.2,
|
||||
mod +semirings +vector,
|
||||
any.monad-control ==1.0.3.1,
|
||||
any.monad-par ==0.3.5,
|
||||
monad-par -chaselev -newgeneric,
|
||||
any.monad-par-extras ==0.3.3,
|
||||
any.monadLib ==3.10.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.mwc-random ==0.15.0.2,
|
||||
any.nats ==1.1.2,
|
||||
nats +binary +hashable +template-haskell,
|
||||
any.network ==3.1.2.7,
|
||||
network -devel,
|
||||
any.network-byte-order ==0.1.6,
|
||||
any.network-info ==0.2.1,
|
||||
any.newtype-generics ==0.6.1,
|
||||
any.numtype-dk ==0.5.0.3,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
any.optparse-applicative ==0.16.1.0,
|
||||
optparse-applicative +process,
|
||||
any.panic ==0.4.0.1,
|
||||
any.parallel ==3.2.2.0,
|
||||
any.parameterized-utils ==2.1.5.0,
|
||||
parameterized-utils +unsafe-operations,
|
||||
any.parsec ==3.1.14.0,
|
||||
any.parser-combinators ==1.3.0,
|
||||
parser-combinators -dev,
|
||||
any.pem ==0.2.4,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.prettyprinter ==1.7.1,
|
||||
prettyprinter -buildreadme +text,
|
||||
any.primitive ==0.7.3.0,
|
||||
any.process ==1.6.9.0,
|
||||
any.profunctors ==5.6.2,
|
||||
any.psqueues ==0.2.7.3,
|
||||
any.quickcheck-instances ==0.3.27,
|
||||
quickcheck-instances -bytestring-builder,
|
||||
any.random ==1.2.1,
|
||||
any.reflection ==2.1.6,
|
||||
reflection -slow +template-haskell,
|
||||
any.regex-base ==0.94.0.2,
|
||||
any.regex-compat ==0.95.2.1,
|
||||
any.regex-posix ==0.96.0.1,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.3,
|
||||
any.rts ==1.0,
|
||||
any.safe ==0.3.19,
|
||||
any.sbv ==9.0,
|
||||
any.scientific ==0.3.7.0,
|
||||
scientific -bytestring-builder -integer-simple,
|
||||
any.scotty ==0.12,
|
||||
any.semialign ==1.2.0.1,
|
||||
semialign +semigroupoids,
|
||||
any.semigroupoids ==5.3.7,
|
||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||
any.semigroups ==0.20,
|
||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||
any.semirings ==0.6,
|
||||
semirings +containers +unordered-containers,
|
||||
any.silently ==1.2.5.2,
|
||||
any.simple-get-opt ==0.4,
|
||||
any.simple-sendfile ==0.2.30,
|
||||
simple-sendfile +allow-bsd,
|
||||
any.simple-smt ==0.9.7,
|
||||
any.splitmix ==0.1.0.4,
|
||||
splitmix -optimised-mixer,
|
||||
any.statistics ==0.16.0.2,
|
||||
any.stm ==2.5.0.0,
|
||||
any.streaming-commons ==0.2.2.4,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.syb ==0.7.2.1,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.tasty ==1.4.2.1,
|
||||
tasty +clock +unix,
|
||||
any.tasty-hunit ==0.10.0.3,
|
||||
any.tasty-quickcheck ==0.10.2,
|
||||
any.template-haskell ==2.15.0.0,
|
||||
any.temporary ==1.3,
|
||||
any.terminfo ==0.4.1.4,
|
||||
any.test-framework ==0.8.2.0,
|
||||
any.test-framework-hunit ==0.3.0.2,
|
||||
test-framework-hunit -base3 +base4,
|
||||
any.test-lib ==0.4,
|
||||
any.text ==1.2.4.0,
|
||||
any.text-short ==0.1.5,
|
||||
text-short -asserts,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.3.0,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.19,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.6.1,
|
||||
time-compat -old-locale,
|
||||
any.time-manager ==0.0.0,
|
||||
any.tls ==1.5.7,
|
||||
tls +compat -hans +network,
|
||||
any.tls-session-manager ==0.0.4,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.6,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.7.1,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.type-equality ==1,
|
||||
any.unbounded-delays ==0.1.1.1,
|
||||
any.uniplate ==1.6.13,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-compat ==0.5.4,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unliftio ==0.2.22.0,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.19.1,
|
||||
unordered-containers -debug,
|
||||
any.utf8-string ==1.0.2,
|
||||
any.uuid ==1.3.15,
|
||||
any.uuid-types ==1.0.5,
|
||||
any.vault ==0.3.1.5,
|
||||
vault +useghc,
|
||||
any.vector ==0.12.3.1,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.4,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.vector-binary-instances ==0.2.5.2,
|
||||
any.vector-th-unbox ==0.2.2,
|
||||
any.versions ==5.0.3,
|
||||
any.void ==0.7.3,
|
||||
void -safe,
|
||||
any.wai ==3.2.3,
|
||||
any.wai-extra ==3.1.10,
|
||||
wai-extra -build-example,
|
||||
any.wai-logger ==2.4.0,
|
||||
any.warp ==3.3.20,
|
||||
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
||||
any.warp-tls ==3.3.2,
|
||||
any.wcwidth ==0.0.2,
|
||||
wcwidth -cli +split-base,
|
||||
any.what4 ==1.3,
|
||||
what4 -drealtestdisable -solvertests -stptestdisable,
|
||||
any.witherable ==0.4.2,
|
||||
any.word8 ==0.1.3,
|
||||
any.x509 ==1.7.6,
|
||||
any.x509-store ==1.6.9,
|
||||
any.x509-validation ==1.6.12,
|
||||
any.xml ==1.3.14,
|
||||
any.zenc ==0.1.2,
|
||||
any.zlib ==0.6.3.0,
|
||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
index-state: hackage.haskell.org 2022-05-04T18:13:54Z
|
@ -11,10 +11,7 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.abstract-par ==0.3.3,
|
||||
any.adjunctions ==4.4,
|
||||
any.adjunctions ==4.4.2,
|
||||
any.aeson ==2.0.3.0,
|
||||
aeson -cffi +ordered-keymap,
|
||||
any.alex ==3.2.7.1,
|
||||
@ -23,7 +20,7 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.appar ==0.1.8,
|
||||
any.arithmoi ==0.12.0.1,
|
||||
any.arithmoi ==0.12.0.2,
|
||||
any.array ==0.5.4.0,
|
||||
any.asn1-encoding ==0.9.6,
|
||||
any.asn1-parse ==0.9.5,
|
||||
@ -35,16 +32,18 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.15.1.0,
|
||||
any.base-compat ==0.12.1,
|
||||
any.base-compat-batteries ==0.12.1,
|
||||
any.base-orphans ==0.8.6,
|
||||
any.base-compat ==0.12.2,
|
||||
any.base-compat-batteries ==0.12.2,
|
||||
any.base-orphans ==0.8.7,
|
||||
any.base64-bytestring ==1.2.1.0,
|
||||
any.basement ==0.0.14,
|
||||
any.bifunctors ==5.5.11,
|
||||
any.basement ==0.0.15,
|
||||
any.bifunctors ==5.5.13,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.bimap ==0.4.0,
|
||||
any.bimap ==0.5.0,
|
||||
any.binary ==0.8.8.0,
|
||||
any.binary-orphans ==1.0.2,
|
||||
any.binary-orphans ==1.0.3,
|
||||
any.bitvec ==1.1.3.0,
|
||||
bitvec -libgmp,
|
||||
any.bitwise ==1.0.0.1,
|
||||
any.blaze-builder ==0.4.2.2,
|
||||
any.blaze-html ==0.9.1.2,
|
||||
@ -56,9 +55,9 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.cabal-doctest ==1.0.9,
|
||||
any.call-stack ==0.4.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.cassava ==0.5.2.0,
|
||||
any.cassava ==0.5.3.0,
|
||||
cassava -bytestring--lt-0_10_4,
|
||||
any.cereal ==0.5.8.2,
|
||||
any.cereal ==0.5.8.3,
|
||||
cereal -bytestring-builder,
|
||||
any.chimera ==0.3.2.0,
|
||||
chimera +representable,
|
||||
@ -69,19 +68,19 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.concurrent-extra ==0.7.0.12,
|
||||
any.config-value ==0.8.2.1,
|
||||
any.constraints ==0.13.3,
|
||||
any.config-value ==0.8.3,
|
||||
any.constraints ==0.13.4,
|
||||
any.containers ==0.6.4.1,
|
||||
any.contravariant ==1.5.5,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cookie ==0.4.5,
|
||||
any.criterion ==1.5.13.0,
|
||||
any.criterion ==1.6.0.0,
|
||||
criterion -embed-data-files -fast,
|
||||
any.criterion-measurement ==0.1.3.0,
|
||||
any.criterion-measurement ==0.2.0.0,
|
||||
criterion-measurement -fast,
|
||||
any.cryptohash-md5 ==0.11.101.0,
|
||||
any.cryptohash-sha1 ==0.11.101.0,
|
||||
cryptol +relocatable -static,
|
||||
cryptol +ffi +relocatable -static,
|
||||
cryptol-remote-api -notthreaded -static,
|
||||
cryptol-test-runner -static,
|
||||
any.cryptonite ==0.30,
|
||||
@ -91,7 +90,7 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.data-fix ==0.3.2,
|
||||
any.deepseq ==1.4.5.0,
|
||||
any.dense-linear-algebra ==0.1.0.0,
|
||||
any.deriving-compat ==0.6,
|
||||
any.deriving-compat ==0.6.1,
|
||||
deriving-compat +base-4-9 +new-functor-classes +template-haskell-2-11,
|
||||
any.directory ==1.3.6.2,
|
||||
any.distributive ==0.6.2.1,
|
||||
@ -99,18 +98,18 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.easy-file ==0.2.2,
|
||||
any.entropy ==0.4.1.7,
|
||||
entropy -halvm,
|
||||
any.entropy ==0.4.1.10,
|
||||
entropy -donotgetentropy,
|
||||
any.exact-pi ==0.5.0.2,
|
||||
any.exceptions ==0.10.4,
|
||||
any.extensible-exceptions ==0.1.1.4,
|
||||
any.extra ==1.7.10,
|
||||
any.extra ==1.7.12,
|
||||
any.fail ==4.9.0.0,
|
||||
any.fast-logger ==3.1.1,
|
||||
any.filelock ==0.1.1.5,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.fingertree ==0.1.5.0,
|
||||
any.free ==5.1.7,
|
||||
any.free ==5.1.9,
|
||||
any.ghc-bignum ==1.1,
|
||||
any.ghc-boot-th ==9.0.2,
|
||||
any.ghc-prim ==0.7.0,
|
||||
@ -122,6 +121,7 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
hashtables -bounds-checking -debug -detailed-profiling -portable -sse42 +unsafe-tricks,
|
||||
any.haskeline ==0.8.2,
|
||||
any.heredoc ==0.2.0.0,
|
||||
any.hgmp ==0.1.2.1,
|
||||
any.hostname ==1.0,
|
||||
any.hourglass ==0.2.12,
|
||||
any.hsc2hs ==0.68.8,
|
||||
@ -130,35 +130,38 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.http-types ==0.12.3,
|
||||
any.http2 ==3.0.3,
|
||||
http2 -devel -doc -h2spec,
|
||||
any.ieee754 ==0.8.0,
|
||||
any.indexed-traversable ==0.1.2,
|
||||
any.indexed-traversable-instances ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1.1.1,
|
||||
any.integer-gmp ==1.1,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.integer-roots ==1.0.2.0,
|
||||
any.invariant ==0.5.5,
|
||||
any.io-streams ==1.5.2.1,
|
||||
any.invariant ==0.6,
|
||||
any.io-streams ==1.5.2.2,
|
||||
io-streams +network -nointeractivetests +zlib,
|
||||
any.iproute ==1.7.12,
|
||||
any.js-chart ==2.9.4.1,
|
||||
any.kan-extensions ==5.2.3,
|
||||
any.lens ==5.1,
|
||||
any.kan-extensions ==5.2.5,
|
||||
any.language-c99 ==0.2.0,
|
||||
any.language-c99-simple ==0.2.2,
|
||||
any.language-c99-util ==0.2.0,
|
||||
any.lens ==5.1.1,
|
||||
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
|
||||
any.libBF ==0.6.3,
|
||||
any.libBF ==0.6.5.1,
|
||||
libBF -system-libbf,
|
||||
any.libffi ==0.2,
|
||||
libffi +ghc-bundled-libffi,
|
||||
any.math-functions ==0.3.4.2,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==9.2.0,
|
||||
any.megaparsec ==9.2.2,
|
||||
megaparsec -dev,
|
||||
any.memory ==0.17.0,
|
||||
any.memory ==0.18.0,
|
||||
memory +support_bytestring +support_deepseq,
|
||||
any.microstache ==1.0.2,
|
||||
any.microstache ==1.0.2.2,
|
||||
any.mod ==0.1.2.2,
|
||||
mod +semirings +vector,
|
||||
any.monad-control ==1.0.3.1,
|
||||
any.monad-par ==0.3.5,
|
||||
monad-par -chaselev -newgeneric,
|
||||
any.monad-par-extras ==0.3.3,
|
||||
any.monadLib ==3.10.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.mwc-random ==0.15.0.2,
|
||||
@ -168,7 +171,7 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
network -devel,
|
||||
any.network-byte-order ==0.1.6,
|
||||
any.network-info ==0.2.1,
|
||||
any.newtype-generics ==0.6.1,
|
||||
any.newtype-generics ==0.6.2,
|
||||
any.numtype-dk ==0.5.0.3,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
@ -185,20 +188,20 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.prettyprinter ==1.7.1,
|
||||
prettyprinter -buildreadme +text,
|
||||
any.primitive ==0.7.3.0,
|
||||
any.primitive ==0.7.4.0,
|
||||
any.process ==1.6.13.2,
|
||||
any.profunctors ==5.6.2,
|
||||
any.psqueues ==0.2.7.3,
|
||||
any.quickcheck-instances ==0.3.27,
|
||||
any.quickcheck-instances ==0.3.28,
|
||||
quickcheck-instances -bytestring-builder,
|
||||
any.random ==1.2.1,
|
||||
any.random ==1.2.1.1,
|
||||
any.reflection ==2.1.6,
|
||||
reflection -slow +template-haskell,
|
||||
any.regex-base ==0.94.0.2,
|
||||
any.regex-compat ==0.95.2.1,
|
||||
any.regex-posix ==0.96.0.1,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.3,
|
||||
any.resourcet ==1.2.6,
|
||||
any.rts ==1.0.2,
|
||||
any.safe ==0.3.19,
|
||||
any.sbv ==9.0,
|
||||
@ -213,23 +216,23 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||
any.semirings ==0.6,
|
||||
semirings +containers +unordered-containers,
|
||||
any.silently ==1.2.5.2,
|
||||
any.silently ==1.2.5.3,
|
||||
any.simple-get-opt ==0.4,
|
||||
any.simple-sendfile ==0.2.30,
|
||||
simple-sendfile +allow-bsd,
|
||||
any.simple-smt ==0.9.7,
|
||||
any.splitmix ==0.1.0.4,
|
||||
splitmix -optimised-mixer,
|
||||
any.statistics ==0.16.0.2,
|
||||
any.statistics ==0.16.1.0,
|
||||
any.stm ==2.5.0.0,
|
||||
any.streaming-commons ==0.2.2.4,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.syb ==0.7.2.1,
|
||||
any.syb ==0.7.2.2,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.tasty ==1.4.2.1,
|
||||
any.tasty ==1.4.2.3,
|
||||
tasty +clock +unix,
|
||||
any.tasty-hunit ==0.10.0.3,
|
||||
any.tasty-quickcheck ==0.10.2,
|
||||
@ -244,30 +247,30 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.text-short ==0.1.5,
|
||||
text-short -asserts,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.3.0,
|
||||
any.th-abstraction ==0.4.5.0,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.19,
|
||||
any.th-lift-instances ==0.1.20,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.6.1,
|
||||
time-compat -old-locale,
|
||||
any.time-manager ==0.0.0,
|
||||
any.tls ==1.5.7,
|
||||
any.tls ==1.6.0,
|
||||
tls +compat -hans +network,
|
||||
any.tls-session-manager ==0.0.4,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.6,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.7.1,
|
||||
any.transformers-compat ==0.7.2,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.type-equality ==1,
|
||||
any.unbounded-delays ==0.1.1.1,
|
||||
any.uniplate ==1.6.13,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-compat ==0.5.4,
|
||||
any.unix-compat ==0.6,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unix-time ==0.4.8,
|
||||
any.unliftio ==0.2.22.0,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.19.1,
|
||||
@ -279,7 +282,7 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
vault +useghc,
|
||||
any.vector ==0.12.3.1,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.4,
|
||||
any.vector-algorithms ==0.9.0.1,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.vector-binary-instances ==0.2.5.2,
|
||||
any.vector-th-unbox ==0.2.2,
|
||||
@ -287,19 +290,19 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.void ==0.7.3,
|
||||
void -safe,
|
||||
any.wai ==3.2.3,
|
||||
any.wai-extra ==3.1.10,
|
||||
any.wai-extra ==3.1.12.1,
|
||||
wai-extra -build-example,
|
||||
any.wai-logger ==2.4.0,
|
||||
any.warp ==3.3.20,
|
||||
any.warp ==3.3.22,
|
||||
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
||||
any.warp-tls ==3.3.2,
|
||||
any.warp-tls ==3.3.3,
|
||||
any.wcwidth ==0.0.2,
|
||||
wcwidth -cli +split-base,
|
||||
any.what4 ==1.3,
|
||||
what4 -drealtestdisable -solvertests -stptestdisable,
|
||||
any.witherable ==0.4.2,
|
||||
any.word8 ==0.1.3,
|
||||
any.x509 ==1.7.6,
|
||||
any.x509 ==1.7.7,
|
||||
any.x509-store ==1.6.9,
|
||||
any.x509-validation ==1.6.12,
|
||||
any.xml ==1.3.14,
|
||||
@ -307,4 +310,4 @@ constraints: any.Cabal ==3.4.1.0,
|
||||
any.zlib ==0.6.3.0,
|
||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
index-state: hackage.haskell.org 2022-05-04T18:13:54Z
|
||||
index-state: hackage.haskell.org 2022-09-24T14:14:21Z
|
||||
|
@ -11,10 +11,7 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.abstract-par ==0.3.3,
|
||||
any.adjunctions ==4.4,
|
||||
any.adjunctions ==4.4.2,
|
||||
any.aeson ==2.0.3.0,
|
||||
aeson -cffi +ordered-keymap,
|
||||
any.alex ==3.2.7.1,
|
||||
@ -23,7 +20,7 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.appar ==0.1.8,
|
||||
any.arithmoi ==0.12.0.1,
|
||||
any.arithmoi ==0.12.0.2,
|
||||
any.array ==0.5.4.0,
|
||||
any.asn1-encoding ==0.9.6,
|
||||
any.asn1-parse ==0.9.5,
|
||||
@ -34,17 +31,19 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.attoparsec ==0.14.4,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.16.1.0,
|
||||
any.base-compat ==0.12.1,
|
||||
any.base-compat-batteries ==0.12.1,
|
||||
any.base-orphans ==0.8.6,
|
||||
any.base ==4.16.3.0,
|
||||
any.base-compat ==0.12.2,
|
||||
any.base-compat-batteries ==0.12.2,
|
||||
any.base-orphans ==0.8.7,
|
||||
any.base64-bytestring ==1.2.1.0,
|
||||
any.basement ==0.0.14,
|
||||
any.bifunctors ==5.5.11,
|
||||
any.basement ==0.0.15,
|
||||
any.bifunctors ==5.5.13,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.bimap ==0.4.0,
|
||||
any.bimap ==0.5.0,
|
||||
any.binary ==0.8.9.0,
|
||||
any.binary-orphans ==1.0.2,
|
||||
any.binary-orphans ==1.0.3,
|
||||
any.bitvec ==1.1.3.0,
|
||||
bitvec -libgmp,
|
||||
any.bitwise ==1.0.0.1,
|
||||
any.blaze-builder ==0.4.2.2,
|
||||
any.blaze-html ==0.9.1.2,
|
||||
@ -52,13 +51,13 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.bsb-http-chunked ==0.0.0.4,
|
||||
any.bv-sized ==1.0.4,
|
||||
any.byteorder ==1.0.4,
|
||||
any.bytestring ==0.11.3.0,
|
||||
any.bytestring ==0.11.3.1,
|
||||
any.cabal-doctest ==1.0.9,
|
||||
any.call-stack ==0.4.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.cassava ==0.5.2.0,
|
||||
any.cassava ==0.5.3.0,
|
||||
cassava -bytestring--lt-0_10_4,
|
||||
any.cereal ==0.5.8.2,
|
||||
any.cereal ==0.5.8.3,
|
||||
cereal -bytestring-builder,
|
||||
any.chimera ==0.3.2.0,
|
||||
chimera +representable,
|
||||
@ -69,19 +68,19 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.concurrent-extra ==0.7.0.12,
|
||||
any.config-value ==0.8.2.1,
|
||||
any.constraints ==0.13.3,
|
||||
any.config-value ==0.8.3,
|
||||
any.constraints ==0.13.4,
|
||||
any.containers ==0.6.5.1,
|
||||
any.contravariant ==1.5.5,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cookie ==0.4.5,
|
||||
any.criterion ==1.5.13.0,
|
||||
any.criterion ==1.6.0.0,
|
||||
criterion -embed-data-files -fast,
|
||||
any.criterion-measurement ==0.1.3.0,
|
||||
any.criterion-measurement ==0.2.0.0,
|
||||
criterion-measurement -fast,
|
||||
any.cryptohash-md5 ==0.11.101.0,
|
||||
any.cryptohash-sha1 ==0.11.101.0,
|
||||
cryptol +relocatable -static,
|
||||
cryptol +ffi +relocatable -static,
|
||||
cryptol-remote-api -notthreaded -static,
|
||||
cryptol-test-runner -static,
|
||||
any.cryptonite ==0.30,
|
||||
@ -91,7 +90,7 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.data-fix ==0.3.2,
|
||||
any.deepseq ==1.4.6.1,
|
||||
any.dense-linear-algebra ==0.1.0.0,
|
||||
any.deriving-compat ==0.6,
|
||||
any.deriving-compat ==0.6.1,
|
||||
deriving-compat +base-4-9 +new-functor-classes +template-haskell-2-11,
|
||||
any.directory ==1.3.6.2,
|
||||
any.distributive ==0.6.2.1,
|
||||
@ -99,20 +98,20 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.easy-file ==0.2.2,
|
||||
any.entropy ==0.4.1.7,
|
||||
entropy -halvm,
|
||||
any.entropy ==0.4.1.10,
|
||||
entropy -donotgetentropy,
|
||||
any.exact-pi ==0.5.0.2,
|
||||
any.exceptions ==0.10.4,
|
||||
any.extensible-exceptions ==0.1.1.4,
|
||||
any.extra ==1.7.10,
|
||||
any.extra ==1.7.12,
|
||||
any.fail ==4.9.0.0,
|
||||
any.fast-logger ==3.1.1,
|
||||
any.filelock ==0.1.1.5,
|
||||
any.filepath ==1.4.2.2,
|
||||
any.fingertree ==0.1.5.0,
|
||||
any.free ==5.1.7,
|
||||
any.free ==5.1.9,
|
||||
any.ghc-bignum ==1.2,
|
||||
any.ghc-boot-th ==9.2.2,
|
||||
any.ghc-boot-th ==9.2.4,
|
||||
any.ghc-prim ==0.8.0,
|
||||
any.gitrev ==1.3.1,
|
||||
any.happy ==1.20.0,
|
||||
@ -122,6 +121,7 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
hashtables -bounds-checking -debug -detailed-profiling -portable -sse42 +unsafe-tricks,
|
||||
any.haskeline ==0.8.2,
|
||||
any.heredoc ==0.2.0.0,
|
||||
any.hgmp ==0.1.2.1,
|
||||
any.hostname ==1.0,
|
||||
any.hourglass ==0.2.12,
|
||||
any.hsc2hs ==0.68.8,
|
||||
@ -130,35 +130,38 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.http-types ==0.12.3,
|
||||
any.http2 ==3.0.3,
|
||||
http2 -devel -doc -h2spec,
|
||||
any.ieee754 ==0.8.0,
|
||||
any.indexed-traversable ==0.1.2,
|
||||
any.indexed-traversable-instances ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1.1.1,
|
||||
any.integer-gmp ==1.1,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.integer-roots ==1.0.2.0,
|
||||
any.invariant ==0.5.5,
|
||||
any.io-streams ==1.5.2.1,
|
||||
any.invariant ==0.6,
|
||||
any.io-streams ==1.5.2.2,
|
||||
io-streams +network -nointeractivetests +zlib,
|
||||
any.iproute ==1.7.12,
|
||||
any.js-chart ==2.9.4.1,
|
||||
any.kan-extensions ==5.2.3,
|
||||
any.lens ==5.1,
|
||||
any.kan-extensions ==5.2.5,
|
||||
any.language-c99 ==0.2.0,
|
||||
any.language-c99-simple ==0.2.2,
|
||||
any.language-c99-util ==0.2.0,
|
||||
any.lens ==5.1.1,
|
||||
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
|
||||
any.libBF ==0.6.3,
|
||||
any.libBF ==0.6.5.1,
|
||||
libBF -system-libbf,
|
||||
any.libffi ==0.2,
|
||||
libffi +ghc-bundled-libffi,
|
||||
any.math-functions ==0.3.4.2,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==9.2.0,
|
||||
any.megaparsec ==9.2.2,
|
||||
megaparsec -dev,
|
||||
any.memory ==0.17.0,
|
||||
any.memory ==0.18.0,
|
||||
memory +support_bytestring +support_deepseq,
|
||||
any.microstache ==1.0.2,
|
||||
any.microstache ==1.0.2.2,
|
||||
any.mod ==0.1.2.2,
|
||||
mod +semirings +vector,
|
||||
any.monad-control ==1.0.3.1,
|
||||
any.monad-par ==0.3.5,
|
||||
monad-par -chaselev -newgeneric,
|
||||
any.monad-par-extras ==0.3.3,
|
||||
any.monadLib ==3.10.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.mwc-random ==0.15.0.2,
|
||||
@ -168,7 +171,7 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
network -devel,
|
||||
any.network-byte-order ==0.1.6,
|
||||
any.network-info ==0.2.1,
|
||||
any.newtype-generics ==0.6.1,
|
||||
any.newtype-generics ==0.6.2,
|
||||
any.numtype-dk ==0.5.0.3,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
@ -185,20 +188,20 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.prettyprinter ==1.7.1,
|
||||
prettyprinter -buildreadme +text,
|
||||
any.primitive ==0.7.3.0,
|
||||
any.primitive ==0.7.4.0,
|
||||
any.process ==1.6.13.2,
|
||||
any.profunctors ==5.6.2,
|
||||
any.psqueues ==0.2.7.3,
|
||||
any.quickcheck-instances ==0.3.27,
|
||||
any.quickcheck-instances ==0.3.28,
|
||||
quickcheck-instances -bytestring-builder,
|
||||
any.random ==1.2.1,
|
||||
any.random ==1.2.1.1,
|
||||
any.reflection ==2.1.6,
|
||||
reflection -slow +template-haskell,
|
||||
any.regex-base ==0.94.0.2,
|
||||
any.regex-compat ==0.95.2.1,
|
||||
any.regex-posix ==0.96.0.1,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.3,
|
||||
any.resourcet ==1.2.6,
|
||||
any.rts ==1.0.2,
|
||||
any.safe ==0.3.19,
|
||||
any.sbv ==9.0,
|
||||
@ -213,23 +216,23 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||
any.semirings ==0.6,
|
||||
semirings +containers +unordered-containers,
|
||||
any.silently ==1.2.5.2,
|
||||
any.silently ==1.2.5.3,
|
||||
any.simple-get-opt ==0.4,
|
||||
any.simple-sendfile ==0.2.30,
|
||||
simple-sendfile +allow-bsd,
|
||||
any.simple-smt ==0.9.7,
|
||||
any.splitmix ==0.1.0.4,
|
||||
splitmix -optimised-mixer,
|
||||
any.statistics ==0.16.0.2,
|
||||
any.statistics ==0.16.1.0,
|
||||
any.stm ==2.5.0.2,
|
||||
any.streaming-commons ==0.2.2.4,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.syb ==0.7.2.1,
|
||||
any.syb ==0.7.2.2,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.tasty ==1.4.2.1,
|
||||
any.tasty ==1.4.2.3,
|
||||
tasty +clock +unix,
|
||||
any.tasty-hunit ==0.10.0.3,
|
||||
any.tasty-quickcheck ==0.10.2,
|
||||
@ -244,30 +247,30 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.text-short ==0.1.5,
|
||||
text-short -asserts,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.3.0,
|
||||
any.th-abstraction ==0.4.5.0,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.19,
|
||||
any.th-lift-instances ==0.1.20,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.11.1.1,
|
||||
any.time-compat ==1.9.6.1,
|
||||
time-compat -old-locale,
|
||||
any.time-manager ==0.0.0,
|
||||
any.tls ==1.5.7,
|
||||
any.tls ==1.6.0,
|
||||
tls +compat -hans +network,
|
||||
any.tls-session-manager ==0.0.4,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.6,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.7.1,
|
||||
any.transformers-compat ==0.7.2,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.type-equality ==1,
|
||||
any.unbounded-delays ==0.1.1.1,
|
||||
any.uniplate ==1.6.13,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-compat ==0.5.4,
|
||||
any.unix-compat ==0.6,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unix-time ==0.4.8,
|
||||
any.unliftio ==0.2.22.0,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.19.1,
|
||||
@ -279,7 +282,7 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
vault +useghc,
|
||||
any.vector ==0.12.3.1,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.4,
|
||||
any.vector-algorithms ==0.9.0.1,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.vector-binary-instances ==0.2.5.2,
|
||||
any.vector-th-unbox ==0.2.2,
|
||||
@ -287,19 +290,19 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.void ==0.7.3,
|
||||
void -safe,
|
||||
any.wai ==3.2.3,
|
||||
any.wai-extra ==3.1.10,
|
||||
any.wai-extra ==3.1.12.1,
|
||||
wai-extra -build-example,
|
||||
any.wai-logger ==2.4.0,
|
||||
any.warp ==3.3.20,
|
||||
any.warp ==3.3.22,
|
||||
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
||||
any.warp-tls ==3.3.2,
|
||||
any.warp-tls ==3.3.3,
|
||||
any.wcwidth ==0.0.2,
|
||||
wcwidth -cli +split-base,
|
||||
any.what4 ==1.3,
|
||||
what4 -drealtestdisable -solvertests -stptestdisable,
|
||||
any.witherable ==0.4.2,
|
||||
any.word8 ==0.1.3,
|
||||
any.x509 ==1.7.6,
|
||||
any.x509 ==1.7.7,
|
||||
any.x509-store ==1.6.9,
|
||||
any.x509-validation ==1.6.12,
|
||||
any.xml ==1.3.14,
|
||||
@ -307,4 +310,4 @@ constraints: any.Cabal ==3.6.3.0,
|
||||
any.zlib ==0.6.3.0,
|
||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
index-state: hackage.haskell.org 2022-05-04T18:13:54Z
|
||||
index-state: hackage.haskell.org 2022-09-24T14:14:21Z
|
@ -1,10 +1,17 @@
|
||||
ARG GHCVER="8.10.7"
|
||||
ARG GHCVER_BOOTSTRAP="8.10.2"
|
||||
FROM debian:buster-20210511 AS toolchain
|
||||
FROM ubuntu:22.04 AS toolchain
|
||||
ARG PORTABILITY=false
|
||||
RUN apt-get update && apt-get install -y libncurses-dev libz-dev unzip \
|
||||
build-essential curl libffi-dev libffi6 libgmp-dev libgmp10 libncurses-dev libncurses5 libtinfo5 libnuma-dev \
|
||||
$(if ${PORTABILITY}; then echo git autoconf python3; fi)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
# ghcup requirements
|
||||
build-essential curl libffi-dev libffi8 libgmp-dev libgmp10 libncurses-dev libncurses6 libtinfo6 \
|
||||
# Cryptol dependencies
|
||||
zlib1g-dev \
|
||||
# GHC build dependencies
|
||||
$(if ${PORTABILITY}; then echo git autoconf python3 libnuma-dev; fi) \
|
||||
# Miscellaneous
|
||||
unzip
|
||||
ENV GHCUP_INSTALL_BASE_PREFIX=/opt \
|
||||
PATH=/opt/.ghcup/bin:$PATH
|
||||
RUN curl -o /usr/local/bin/ghcup "https://downloads.haskell.org/~ghcup/0.1.17.7/x86_64-linux-ghcup-0.1.17.7" && \
|
||||
@ -57,14 +64,14 @@ ENV PATH=/usr/local/bin:/cryptol/rootfs/usr/local/bin:$PATH
|
||||
RUN mkdir -p rootfs/"${CRYPTOLPATH}" \
|
||||
&& cp -r lib/* rootfs/"${CRYPTOLPATH}"
|
||||
WORKDIR /cryptol/rootfs/usr/local/bin
|
||||
RUN curl -sL -o solvers.zip "https://github.com/GaloisInc/what4-solvers/releases/download/snapshot-20220114/ubuntu-18.04-bin.zip" && \
|
||||
RUN curl -sL -o solvers.zip "https://github.com/GaloisInc/what4-solvers/releases/download/snapshot-20220812/ubuntu-22.04-bin.zip" && \
|
||||
unzip solvers.zip && rm solvers.zip && chmod +x *
|
||||
USER root
|
||||
RUN chown -R root:root /cryptol/rootfs
|
||||
|
||||
FROM debian:buster-20210511-slim
|
||||
FROM ubuntu:22.04
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libgmp10 libgomp1 libffi6 libncurses6 libtinfo6 libreadline7 libnuma-dev openssl \
|
||||
&& apt-get install -y libgmp10 libgomp1 libffi8 libncurses6 libtinfo6 libreadline8 libnuma-dev openssl \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
RUN useradd -m cryptol && chown -R cryptol:cryptol /home/cryptol
|
||||
COPY --from=build /cryptol/rootfs /
|
||||
|
@ -79,6 +79,11 @@ cryptolError modErr warns =
|
||||
(20710, [ ("source", jsonPretty src)
|
||||
, ("errors", jsonList (map jsonPretty errs))
|
||||
])
|
||||
ExpandPropGuardsError src err ->
|
||||
(20711, [ ("source", jsonPretty src)
|
||||
, ("errors", jsonPretty err)
|
||||
])
|
||||
|
||||
NoIncludeErrors src errs ->
|
||||
-- TODO: structured error here
|
||||
(20720, [ ("source", jsonPretty src)
|
||||
|
@ -52,6 +52,7 @@ library
|
||||
bytestring >= 0.10,
|
||||
array >= 0.4,
|
||||
containers >= 0.5,
|
||||
criterion-measurement,
|
||||
cryptohash-sha1 >= 0.11 && < 0.12,
|
||||
deepseq >= 1.3,
|
||||
directory >= 1.2.2.0,
|
||||
@ -61,11 +62,14 @@ library
|
||||
ghc-prim,
|
||||
GraphSCC >= 1.0.4,
|
||||
heredoc >= 0.2,
|
||||
language-c99,
|
||||
language-c99-simple,
|
||||
libBF >= 0.6 && < 0.7,
|
||||
MemoTrie >= 0.6 && < 0.7,
|
||||
monad-control >= 1.0,
|
||||
monadLib >= 3.7.2,
|
||||
parameterized-utils >= 2.0.2,
|
||||
pretty,
|
||||
prettyprinter >= 1.7.0,
|
||||
pretty-show,
|
||||
process >= 1.2,
|
||||
@ -76,6 +80,7 @@ library
|
||||
text >= 1.1,
|
||||
tf-random >= 0.5,
|
||||
transformers-base >= 0.4,
|
||||
vector,
|
||||
mtl >= 2.2.1,
|
||||
time >= 1.6.0.1,
|
||||
panic >= 0.3,
|
||||
@ -87,8 +92,12 @@ library
|
||||
build-depends: integer-gmp >= 1.0 && < 1.1
|
||||
|
||||
if flag(ffi)
|
||||
build-depends: libffi >= 0.2,
|
||||
unix
|
||||
build-depends: hgmp,
|
||||
libffi >= 0.2
|
||||
if os(windows)
|
||||
build-depends: Win32
|
||||
else
|
||||
build-depends: unix
|
||||
cpp-options: -DFFI_ENABLED
|
||||
|
||||
Build-tool-depends: alex:alex, happy:happy
|
||||
@ -103,6 +112,7 @@ library
|
||||
Cryptol.Parser.Names,
|
||||
Cryptol.Parser.Name,
|
||||
Cryptol.Parser.NoPat,
|
||||
Cryptol.Parser.ExpandPropGuards,
|
||||
Cryptol.Parser.NoInclude,
|
||||
Cryptol.Parser.Selector,
|
||||
Cryptol.Parser.Utils,
|
||||
@ -117,6 +127,8 @@ library
|
||||
Cryptol.Utils.Misc,
|
||||
Cryptol.Utils.Patterns,
|
||||
Cryptol.Utils.Logger,
|
||||
Cryptol.Utils.Benchmark,
|
||||
Cryptol.Utils.Types,
|
||||
Cryptol.Version,
|
||||
|
||||
Cryptol.ModuleSystem,
|
||||
@ -199,6 +211,7 @@ library
|
||||
Cryptol.Eval.Concrete,
|
||||
Cryptol.Eval.Env,
|
||||
Cryptol.Eval.FFI,
|
||||
Cryptol.Eval.FFI.GenHeader,
|
||||
Cryptol.Eval.Generic,
|
||||
Cryptol.Eval.Prims,
|
||||
Cryptol.Eval.Reference,
|
||||
|
@ -19,6 +19,54 @@ Type Signatures
|
||||
f,g : {a,b} (fin a) => [a] b
|
||||
|
||||
|
||||
Numeric Constraint Guards
|
||||
-------------------------
|
||||
|
||||
A declaration with a signature can use *numeric constraint guards*,
|
||||
which are used to change the behavior of a functoin depending on its
|
||||
numeric type parameters. For example:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
len : {n} (fin n) => [n]a -> Integer
|
||||
len xs | n == 0 => 0
|
||||
| n > 0 => 1 + len (drop `{1} xs)
|
||||
|
||||
Each behavior starts with ``|`` and lists some constraints on the numeric
|
||||
parameters to a declaration. When applied, the function will use the first
|
||||
definition that satisfies the provided numeric parameters.
|
||||
|
||||
Numeric constraint guards are quite similar to an ``if`` expression,
|
||||
except that decisions are based on *types* rather than values. There
|
||||
is also an important difference to simply using demotion and an
|
||||
actual ``if`` statement:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
len' : {n} (fin n) => [n]a -> Integer
|
||||
len' xs = if `n == 0 => 0
|
||||
| `n > 0 => 1 + len (drop `{1} xs)
|
||||
|
||||
The definition of ``len'`` is rejected, because the *value based* ``if``
|
||||
expression does provide the *type based* fact ``n >= 1`` which is
|
||||
required by ``drop `{1} xs``, while in ``len``, the type-checker
|
||||
locally-assumes the constraint ``n > 0`` in that constraint-guarded branch
|
||||
and so it can in fact determine that ``n >= 1``.
|
||||
|
||||
Requirements:
|
||||
- Numeric constraint guards only support constraints over numeric literals,
|
||||
such as ``fin``, ``<=``, ``==``, etc.
|
||||
Type constraint aliases can also be used as long as they only constrain
|
||||
numeric literals.
|
||||
- The numeric constraint guards of a declaration should be exhaustive. The
|
||||
type-checker will attempt to prove that the set of constraint guards is
|
||||
exhaustive, but if it can't then it will issue a non-exhaustive constraint
|
||||
guards warning. This warning is controlled by the environmental option
|
||||
``warnNonExhaustiveConstraintGuards``.
|
||||
- Each constraint guard is checked *independently* of the others, and there
|
||||
are no implict assumptions that the previous behaviors do not match---
|
||||
instead the programmer needs to specify all constraints explicitly
|
||||
in the guard.
|
||||
|
||||
Layout
|
||||
------
|
||||
|
@ -7,13 +7,26 @@ C (or other languages that use the C calling convention).
|
||||
Platform support
|
||||
----------------
|
||||
|
||||
The FFI is currently **not supported on Windows**, and only works on Unix-like
|
||||
systems (macOS and Linux).
|
||||
The FFI is built on top of the C ``libffi`` library, and as such, it should be
|
||||
portable across many operating systems. We have tested it to work on Linux,
|
||||
macOS, and Windows.
|
||||
|
||||
Basic usage
|
||||
-----------
|
||||
|
||||
Suppose we want to call the following C function:
|
||||
Suppose we want to implement the following function in C:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
add : [32] -> [32] -> [32]
|
||||
|
||||
In our Cryptol file, we declare it as a ``foreign`` function with no body:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
foreign add : [32] -> [32] -> [32]
|
||||
|
||||
Then we write the following C function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -21,11 +34,16 @@ Suppose we want to call the following C function:
|
||||
return x + y;
|
||||
}
|
||||
|
||||
In our Cryptol file, we write a ``foreign`` declaration with no body:
|
||||
Cryptol can generate a C header file containing the appropriate function
|
||||
prototypes given the corresponding Cryptol ``foreign`` declarations with the
|
||||
``:generate-foreign-header`` command. You can then ``#include`` the generated
|
||||
header file in your C file to help write the C implementation.
|
||||
|
||||
.. code-block:: cryptol
|
||||
.. code-block::
|
||||
|
||||
foreign add : [32] -> [32] -> [32]
|
||||
Cryptol> :generate-foreign-header Example.cry
|
||||
Loading module Example
|
||||
Writing header to Example.h
|
||||
|
||||
The C code must first be compiled into a dynamically loaded shared library. When
|
||||
Cryptol loads the module containing the ``foreign`` declaration, it will look
|
||||
@ -35,6 +53,7 @@ extension it uses is platform-specific:
|
||||
|
||||
* On Linux, it looks for the extension ``.so``.
|
||||
* On macOS, it looks for the extension ``.dylib``.
|
||||
* On Windows, it looks for the extension ``.dll``.
|
||||
|
||||
For example, if you are on Linux and your ``foreign`` declaration is in
|
||||
``Foo.cry``, Cryptol will dynamically load ``Foo.so``. Then for each ``foreign``
|
||||
@ -61,9 +80,9 @@ The whole process would look something like this:
|
||||
|
||||
Note: Since Cryptol currently only accesses the compiled binary and not the C
|
||||
source, it has no way of checking that the Cryptol function type you declare in
|
||||
your Cryptol code actually matches the type of the C function. **It is your
|
||||
responsibility to make sure the types match up**. If they do not then there may
|
||||
be undefined behavior.
|
||||
your Cryptol code actually matches the type of the C function. It can generate
|
||||
the correct C headers but if the actual implementation does not match it there
|
||||
may be undefined behavior.
|
||||
|
||||
Compiling C code
|
||||
----------------
|
||||
@ -73,6 +92,7 @@ simple usages, you can do this manually with the following commands:
|
||||
|
||||
* Linux: ``cc -fPIC -shared Foo.c -o Foo.so``
|
||||
* macOS: ``cc -dynamiclib Foo.c -o Foo.dylib``
|
||||
* Windows: ``cc -fPIC -shared Foo.c -o Foo.dll``
|
||||
|
||||
Converting between Cryptol and C types
|
||||
--------------------------------------
|
||||
@ -81,6 +101,10 @@ This section describes how a given Cryptol function signature maps to a C
|
||||
function prototype. The FFI only supports a limited set of Cryptol types which
|
||||
have a clear translation into C.
|
||||
|
||||
This mapping can now be done automatically with the ``:generate-foreign-header``
|
||||
command mentioned above; however, this section is still worth reading to
|
||||
understand the supported types and what the resulting C parameters mean.
|
||||
|
||||
Overall structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -146,8 +170,8 @@ When converting to C, ``True`` is converted to ``1`` and ``False`` to ``0``.
|
||||
When converting to Cryptol, any nonzero number is converted to ``True`` and
|
||||
``0`` is converted to ``False``.
|
||||
|
||||
Integral types
|
||||
~~~~~~~~~~~~~~
|
||||
Bit Vector Types
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Let ``K : #`` be a Cryptol type. Note ``K`` must be an actual fixed numeric type
|
||||
and not a type variable.
|
||||
@ -167,7 +191,7 @@ are ignored. For instance, for the Cryptol type ``[4]``, the Cryptol value ``0xf
|
||||
: [4]`` is converted to the C value ``uint8_t`` ``0x0f``, and the C ``uint8_t``
|
||||
``0xaf`` is converted to the Cryptol value ``0xf : [4]``.
|
||||
|
||||
Note that words larger than 64 bits are not supported, since there is no
|
||||
Note that bit vectors larger than 64 bits are not supported, since there is no
|
||||
standard C integral type for that. You can split it into a sequence of smaller
|
||||
words first in Cryptol, then use the FFI conversion for sequences of words to
|
||||
handle it in C as an array.
|
||||
@ -185,23 +209,50 @@ Cryptol type C type
|
||||
Note: the Cryptol ``Float`` types are defined in the built-in module ``Float``.
|
||||
Other sizes of floating points are not supported.
|
||||
|
||||
Math Types
|
||||
~~~~~~~~~~
|
||||
|
||||
Values of high precision types and ``Z`` are represented using the GMP library.
|
||||
|
||||
============ ==========
|
||||
Cryptol type C type
|
||||
============ ==========
|
||||
``Integer`` ``mpz_t``
|
||||
``Rational`` ``mpq_t``
|
||||
``Z n`` ``mpz_t``
|
||||
============ ==========
|
||||
|
||||
Results of these types are returned in *output* parameters,
|
||||
but since both ``mpz_t`` and ``mpz_q`` are already reference
|
||||
types there is no need for an extra pointer in the result.
|
||||
For example, a Cryptol function ``f : Integer -> Rational``
|
||||
would correspond to a C function ``f(mpz_t in, mpq_t out)``.
|
||||
|
||||
All parameters passed to the C function (no matter if
|
||||
input or output) are managed by Cryptol, which takes care
|
||||
to call ``init`` before their use and ``clear`` after.
|
||||
|
||||
|
||||
Sequences
|
||||
~~~~~~~~~
|
||||
|
||||
Let ``n : #`` be a Cryptol type, possibly containing type variables, that
|
||||
satisfies ``fin n``, and ``T`` be one of the above Cryptol *integral types* or
|
||||
*floating point types*. Let ``U`` be the C type that ``T`` corresponds to.
|
||||
Let ``n1, n2, ..., nk : #`` be Cryptol types (with ``k >= 1``), possibly
|
||||
containing type variables, that satisfy ``fin n1, fin n2, ..., fin nk``, and
|
||||
``T`` be one of the above Cryptol *bit vector types*, *floating point types*, or
|
||||
*math types*. Let ``U`` be the C type that ``T`` corresponds to.
|
||||
|
||||
============ ===========
|
||||
Cryptol type C type
|
||||
============ ===========
|
||||
``[n]T`` ``U*``
|
||||
============ ===========
|
||||
==================== ===========
|
||||
Cryptol type C type
|
||||
==================== ===========
|
||||
``[n1][n2]...[nk]T`` ``U*``
|
||||
==================== ===========
|
||||
|
||||
The C pointer points to an array of ``n`` elements of type ``U``. Note that,
|
||||
while the length of the array itself is not explicitly passed along with the
|
||||
pointer, any type arguments contained in the size are passed as C ``size_t``'s
|
||||
earlier, so the C code can always know the length of the array.
|
||||
The C pointer points to an array of ``n1 * n2 * ... * nk`` elements of type
|
||||
``U``. If the sequence is multidimensional, it is flattened and stored
|
||||
contiguously, similar to the representation of multidimensional arrays in C.
|
||||
Note that, while the dimensions of the array itself are not explicitly passed
|
||||
along with the pointer, any type arguments contained in the size are passed as C
|
||||
``size_t``'s earlier, so the C code can always know the dimensions of the array.
|
||||
|
||||
Tuples and records
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
@ -232,17 +283,18 @@ type synonyms in ``foreign`` declarations to improve readability.
|
||||
Return values
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
If the Cryptol return type is ``Bit`` or one of the above *integral types* or
|
||||
If the Cryptol return type is ``Bit`` or one of the above *bit vector types* or
|
||||
*floating point types*, the value is returned directly from the C function. In
|
||||
that case, the return type of the C function will be the C type corresponding to
|
||||
the Cryptol type, and no extra arguments are added.
|
||||
|
||||
If the Cryptol return type is a sequence, tuple, or record, then the value is
|
||||
returned using output arguments, and the return type of the C function will be
|
||||
``void``. For tuples and records, each component is recursively returned as
|
||||
If the Cryptol return type is one of the *math types*, a sequence, tuple,
|
||||
or record, then the value is returned using output arguments,
|
||||
and the return type of the C function will be ``void``.
|
||||
For tuples and records, each component is recursively returned as
|
||||
output arguments. When treated as an output argument, each C type ``U`` will be
|
||||
a pointer ``U*`` instead, except in the case of sequences, where the output and
|
||||
input versions are the same type, because it is already a pointer.
|
||||
a pointer ``U*`` instead, except in the case of *math types* and sequences,
|
||||
where the output and input versions are the same type, because it is already a pointer.
|
||||
|
||||
Quick reference
|
||||
~~~~~~~~~~~~~~~
|
||||
@ -258,12 +310,15 @@ Cryptol type (or kind) C argument type(s) C return type C output
|
||||
``[K]Bit`` where ``32 < K <= 64`` ``uint64_t`` ``uint64_t`` ``uint64_t*``
|
||||
``Float32`` ``float`` ``float`` ``float*``
|
||||
``Float64`` ``double`` ``double`` ``double*``
|
||||
``[n]T`` ``U*`` N/A ``U*``
|
||||
``Integer`` ``mpz_t`` N/A ``mpz_t``
|
||||
``Rational`` ``mpq_t`` N/A ``mpq_t``
|
||||
``Z n`` ``mpz_t`` N/A ``mpz_t``
|
||||
``[n1][n2]...[nk]T`` ``U*`` N/A ``U*``
|
||||
``(T1, T2, ..., Tn)`` ``U1, U2, ..., Un`` N/A ``V1, V2, ..., Vn``
|
||||
``{f1: T1, f2: T2, ..., fn: Tn}`` ``U1, U2, ..., Un`` N/A ``V1, V2, ..., Vn``
|
||||
================================== =================== ============= =========================
|
||||
|
||||
where ``K`` is a constant number, ``n`` is a variable number, ``Ti`` is a type,
|
||||
where ``K`` is a constant number, ``ni`` are variable numbers, ``Ti`` is a type,
|
||||
``Ui`` is its C argument type, and ``Vi`` is its C output argument type.
|
||||
|
||||
Memory
|
||||
@ -273,6 +328,8 @@ When pointers are involved, namely in the cases of sequences and output
|
||||
arguments, they point to memory. This memory is always allocated and deallocated
|
||||
by Cryptol; the C code does not need to manage this memory.
|
||||
|
||||
For GMP types, Cryptol will call ``init`` and ``clear`` as needed.
|
||||
|
||||
In the case of sequences, the pointer will point to an array. In the case of an
|
||||
output argument for a non-sequence type, the pointer will point to a piece of
|
||||
memory large enough to hold the given C type, and you should not try to access
|
||||
@ -302,5 +359,5 @@ corresponds to the C signature
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void f(size_t n, uint16_t *in0, uint8_t in1, uint64_t in2,
|
||||
double *out0, uint32_t *out1);
|
||||
void f(size_t n, uint16_t *in0, uint8_t in1_a, uint64_t in1_b,
|
||||
double *out_0, uint32_t *out_1);
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: a4ccf7f1b3589b784c5cab7c48946aab
|
||||
config: 766b28421f9ffa9f611038e48286ed1c
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Basic Syntax — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -41,6 +42,7 @@
|
||||
<li class="toctree-l1 current"><a class="current reference internal" href="#">Basic Syntax</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#declarations">Declarations</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#type-signatures">Type Signatures</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#numeric-constraint-guards">Numeric Constraint Guards</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#layout">Layout</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#comments">Comments</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#identifiers">Identifiers</a></li>
|
||||
@ -81,21 +83,67 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="basic-syntax">
|
||||
<section id="basic-syntax">
|
||||
<h1>Basic Syntax<a class="headerlink" href="#basic-syntax" title="Permalink to this headline"></a></h1>
|
||||
<div class="section" id="declarations">
|
||||
<section id="declarations">
|
||||
<h2>Declarations<a class="headerlink" href="#declarations" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span> <span class="n">x</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="type-signatures">
|
||||
</section>
|
||||
<section id="type-signatures">
|
||||
<h2>Type Signatures<a class="headerlink" href="#type-signatures" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="p">,</span><span class="n">g</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">}</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="n">b</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="p">,</span><span class="n">g</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="p">]</span><span class="w"> </span><span class="n">b</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="numeric-constraint-guards">
|
||||
<h2>Numeric Constraint Guards<a class="headerlink" href="#numeric-constraint-guards" title="Permalink to this headline"></a></h2>
|
||||
<p>A declaration with a signature can use <em>numeric constraint guards</em>,
|
||||
which are used to change the behavior of a functoin depending on its
|
||||
numeric type parameters. For example:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">len</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">n</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="nf">len</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="p">(</span><span class="n">drop</span><span class="w"> </span><span class="p">`{</span><span class="mi">1</span><span class="p">}</span><span class="w"> </span><span class="n">xs</span><span class="p">)</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="section" id="layout">
|
||||
<p>Each behavior starts with <code class="docutils literal notranslate"><span class="pre">|</span></code> and lists some constraints on the numeric
|
||||
parameters to a declaration. When applied, the function will use the first
|
||||
definition that satisfies the provided numeric parameters.</p>
|
||||
<p>Numeric constraint guards are quite similar to an <code class="docutils literal notranslate"><span class="pre">if</span></code> expression,
|
||||
except that decisions are based on <em>types</em> rather than values. There
|
||||
is also an important difference to simply using demotion and an
|
||||
actual <code class="docutils literal notranslate"><span class="pre">if</span></code> statement:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">len'</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">n</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="nf">len'</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="p">`</span><span class="n">n</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="p">`</span><span class="n">n</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="p">(</span><span class="n">drop</span><span class="w"> </span><span class="p">`{</span><span class="mi">1</span><span class="p">}</span><span class="w"> </span><span class="n">xs</span><span class="p">)</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The definition of <code class="docutils literal notranslate"><span class="pre">len'</span></code> is rejected, because the <em>value based</em> <code class="docutils literal notranslate"><span class="pre">if</span></code>
|
||||
expression does provide the <em>type based</em> fact <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">>=</span> <span class="pre">1</span></code> which is
|
||||
required by <code class="docutils literal notranslate"><span class="pre">drop</span> <span class="pre">`{1}</span> <span class="pre">xs</span></code>, while in <code class="docutils literal notranslate"><span class="pre">len</span></code>, the type-checker
|
||||
locally-assumes the constraint <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">></span> <span class="pre">0</span></code> in that constraint-guarded branch
|
||||
and so it can in fact determine that <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">>=</span> <span class="pre">1</span></code>.</p>
|
||||
<dl class="simple">
|
||||
<dt>Requirements:</dt><dd><ul class="simple">
|
||||
<li><p>Numeric constraint guards only support constraints over numeric literals,
|
||||
such as <code class="docutils literal notranslate"><span class="pre">fin</span></code>, <code class="docutils literal notranslate"><span class="pre"><=</span></code>, <code class="docutils literal notranslate"><span class="pre">==</span></code>, etc.
|
||||
Type constraint aliases can also be used as long as they only constrain
|
||||
numeric literals.</p></li>
|
||||
<li><p>The numeric constraint guards of a declaration should be exhaustive. The
|
||||
type-checker will attempt to prove that the set of constraint guards is
|
||||
exhaustive, but if it can’t then it will issue a non-exhaustive constraint
|
||||
guards warning. This warning is controlled by the environmental option
|
||||
<code class="docutils literal notranslate"><span class="pre">warnNonExhaustiveConstraintGuards</span></code>.</p></li>
|
||||
<li><p>Each constraint guard is checked <em>independently</em> of the others, and there
|
||||
are no implict assumptions that the previous behaviors do not match—
|
||||
instead the programmer needs to specify all constraints explicitly
|
||||
in the guard.</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section id="layout">
|
||||
<h2>Layout<a class="headerlink" href="#layout" title="Permalink to this headline"></a></h2>
|
||||
<p>Groups of declarations are organized based on indentation.
|
||||
Declarations with the same indentation belong to the same group.
|
||||
@ -103,35 +151,35 @@ Lines of text that are indented more than the beginning of a
|
||||
declaration belong to that declaration, while lines of text that are
|
||||
indented less terminate a group of declarations. Consider, for example,
|
||||
the following Cryptol declarations:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span> <span class="n">x</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span>
|
||||
<span class="kr">where</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span>
|
||||
<span class="n">z</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
|
||||
<span class="nf">g</span> <span class="n">y</span> <span class="ow">=</span> <span class="n">y</span>
|
||||
<span class="nf">g</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This group has two declarations, one for <cite>f</cite> and one for <cite>g</cite>. All the
|
||||
lines between <cite>f</cite> and <cite>g</cite> that are indented more than <cite>f</cite> belong to
|
||||
<cite>f</cite>. The same principle applies to the declarations in the <code class="docutils literal notranslate"><span class="pre">where</span></code> block
|
||||
of <cite>f</cite>, which defines two more local names, <cite>y</cite> and <cite>z</cite>.</p>
|
||||
</div>
|
||||
<div class="section" id="comments">
|
||||
</section>
|
||||
<section id="comments">
|
||||
<h2>Comments<a class="headerlink" href="#comments" title="Permalink to this headline"></a></h2>
|
||||
<p>Cryptol supports block comments, which start with <code class="docutils literal notranslate"><span class="pre">/*</span></code> and end with
|
||||
<code class="docutils literal notranslate"><span class="pre">*/</span></code>, and line comments, which start with <code class="docutils literal notranslate"><span class="pre">//</span></code> and terminate at the
|
||||
end of the line. Block comments may be nested arbitrarily.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="cm">/* This is a block comment */</span>
|
||||
<span class="c1">// This is a line comment</span>
|
||||
<span class="cm">/* This is a /* Nested */ block comment */</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="cm">/* This is a block comment */</span><span class="w"></span>
|
||||
<span class="c1">// This is a line comment</span><span class="w"></span>
|
||||
<span class="cm">/* This is a /* Nested */ block comment */</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition-todo admonition" id="id1">
|
||||
<p class="admonition-title">Todo</p>
|
||||
<p>Document <code class="docutils literal notranslate"><span class="pre">/**</span> <span class="pre">*/</span></code></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="identifiers">
|
||||
</section>
|
||||
<section id="identifiers">
|
||||
<h2>Identifiers<a class="headerlink" href="#identifiers" title="Permalink to this headline"></a></h2>
|
||||
<p>Cryptol identifiers consist of one or more characters. The first
|
||||
character must be either an English letter or underscore (<code class="docutils literal notranslate"><span class="pre">_</span></code>). The
|
||||
@ -141,13 +189,13 @@ meaning in the language, so they may not be used in programmer-defined
|
||||
names (see <a class="reference internal" href="#keywords-and-built-in-operators">Keywords and Built-in Operators</a>).</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id2">
|
||||
<div class="code-block-caption"><span class="caption-text">Examples of identifiers</span><a class="headerlink" href="#id2" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">name</span> <span class="n">name1</span> <span class="n">name'</span> <span class="n">longer_name</span>
|
||||
<span class="kt">Name</span> <span class="kt">Name2</span> <span class="kt">Name''</span> <span class="n">longerName</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">name</span><span class="w"> </span><span class="n">name1</span><span class="w"> </span><span class="n">name'</span><span class="w"> </span><span class="n">longer_name</span><span class="w"></span>
|
||||
<span class="kt">Name</span><span class="w"> </span><span class="kt">Name2</span><span class="w"> </span><span class="kt">Name''</span><span class="w"> </span><span class="n">longerName</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="keywords-and-built-in-operators">
|
||||
</section>
|
||||
<section id="keywords-and-built-in-operators">
|
||||
<h2>Keywords and Built-in Operators<a class="headerlink" href="#keywords-and-built-in-operators" title="Permalink to this headline"></a></h2>
|
||||
<p>The following identifiers have special meanings in Cryptol, and may
|
||||
not be used for programmer defined names:</p>
|
||||
@ -223,8 +271,8 @@ precedence last.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="built-in-type-level-operators">
|
||||
</section>
|
||||
<section id="built-in-type-level-operators">
|
||||
<h2>Built-in Type-level Operators<a class="headerlink" href="#built-in-type-level-operators" title="Permalink to this headline"></a></h2>
|
||||
<p>Cryptol includes a variety of operators that allow computations on
|
||||
the numeric types used to specify the sizes of sequences.</p>
|
||||
@ -278,8 +326,8 @@ the numeric types used to specify the sizes of sequences.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="numeric-literals">
|
||||
</section>
|
||||
<section id="numeric-literals">
|
||||
<h2>Numeric Literals<a class="headerlink" href="#numeric-literals" title="Permalink to this headline"></a></h2>
|
||||
<p>Numeric literals may be written in binary, octal, decimal, or
|
||||
hexadecimal notation. The base of a literal is determined by its prefix:
|
||||
@ -287,12 +335,12 @@ hexadecimal notation. The base of a literal is determined by its prefix:
|
||||
decimal, and <code class="docutils literal notranslate"><span class="pre">0x</span></code> for hexadecimal.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id6">
|
||||
<div class="code-block-caption"><span class="caption-text">Examples of literals</span><a class="headerlink" href="#id6" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">254</span> <span class="c1">// Decimal literal</span>
|
||||
<span class="mi">0254</span> <span class="c1">// Decimal literal</span>
|
||||
<span class="mi">0</span><span class="n">b11111110</span> <span class="c1">// Binary literal</span>
|
||||
<span class="mo">0o376</span> <span class="c1">// Octal literal</span>
|
||||
<span class="mh">0xFE</span> <span class="c1">// Hexadecimal literal</span>
|
||||
<span class="mh">0xfe</span> <span class="c1">// Hexadecimal literal</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">254</span><span class="w"> </span><span class="c1">// Decimal literal</span><span class="w"></span>
|
||||
<span class="mi">0254</span><span class="w"> </span><span class="c1">// Decimal literal</span><span class="w"></span>
|
||||
<span class="mi">0</span><span class="n">b11111110</span><span class="w"> </span><span class="c1">// Binary literal</span><span class="w"></span>
|
||||
<span class="mo">0o376</span><span class="w"> </span><span class="c1">// Octal literal</span><span class="w"></span>
|
||||
<span class="mh">0xFE</span><span class="w"> </span><span class="c1">// Hexadecimal literal</span><span class="w"></span>
|
||||
<span class="mh">0xfe</span><span class="w"> </span><span class="c1">// Hexadecimal literal</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -303,12 +351,12 @@ of digits in the literal. Decimal literals are overloaded, and so the
|
||||
type is inferred from context in which the literal is used. Examples:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id7">
|
||||
<div class="code-block-caption"><span class="caption-text">Literals and their types</span><a class="headerlink" href="#id7" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">0</span><span class="n">b1010</span> <span class="c1">// : [4], 1 * number of digits</span>
|
||||
<span class="mo">0o1234</span> <span class="c1">// : [12], 3 * number of digits</span>
|
||||
<span class="mh">0x1234</span> <span class="c1">// : [16], 4 * number of digits</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">0</span><span class="n">b1010</span><span class="w"> </span><span class="c1">// : [4], 1 * number of digits</span><span class="w"></span>
|
||||
<span class="mo">0o1234</span><span class="w"> </span><span class="c1">// : [12], 3 * number of digits</span><span class="w"></span>
|
||||
<span class="mh">0x1234</span><span class="w"> </span><span class="c1">// : [16], 4 * number of digits</span><span class="w"></span>
|
||||
|
||||
<span class="mi">10</span> <span class="c1">// : {a}. (Literal 10 a) => a</span>
|
||||
<span class="c1">// a = Integer or [n] where n >= width 10</span>
|
||||
<span class="mi">10</span><span class="w"> </span><span class="c1">// : {a}. (Literal 10 a) => a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="c1">// a = Integer or [n] where n >= width 10</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -318,8 +366,8 @@ Numeric literals in polynomial notation result in bit sequences of length
|
||||
one more than the degree of the polynomial. Examples:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id8">
|
||||
<div class="code-block-caption"><span class="caption-text">Polynomial literals</span><a class="headerlink" href="#id8" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="o"><|</span> <span class="n">x</span><span class="o">^^</span><span class="mi">6</span> <span class="o">+</span> <span class="n">x</span><span class="o">^^</span><span class="mi">4</span> <span class="o">+</span> <span class="n">x</span><span class="o">^^</span><span class="mi">2</span> <span class="o">+</span> <span class="n">x</span><span class="o">^^</span><span class="mi">1</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">|></span> <span class="c1">// : [7], equal to 0b1010111</span>
|
||||
<span class="o"><|</span> <span class="n">x</span><span class="o">^^</span><span class="mi">4</span> <span class="o">+</span> <span class="n">x</span><span class="o">^^</span><span class="mi">3</span> <span class="o">+</span> <span class="n">x</span> <span class="o">|></span> <span class="c1">// : [5], equal to 0b11010</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="o"><|</span><span class="w"> </span><span class="n">x</span><span class="o">^^</span><span class="mi">6</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="o">^^</span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="o">^^</span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="o">^^</span><span class="mi">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">|></span><span class="w"> </span><span class="c1">// : [7], equal to 0b1010111</span><span class="w"></span>
|
||||
<span class="o"><|</span><span class="w"> </span><span class="n">x</span><span class="o">^^</span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="o">^^</span><span class="mi">3</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">|></span><span class="w"> </span><span class="c1">// : [5], equal to 0b11010</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -332,10 +380,10 @@ Decimal fractional literals use exponent base 10, and the symbol <code class="do
|
||||
Examples:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id9">
|
||||
<div class="code-block-caption"><span class="caption-text">Fractional literals</span><a class="headerlink" href="#id9" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mf">10.2</span>
|
||||
<span class="mf">10.2e3</span> <span class="c1">// 10.2 * 10^3</span>
|
||||
<span class="mh">0x30</span><span class="o">.</span><span class="mi">1</span> <span class="c1">// 3 * 64 + 1/16</span>
|
||||
<span class="mh">0x30</span><span class="o">.</span><span class="mi">1</span><span class="n">p4</span> <span class="c1">// (3 * 64 + 1/16) * 2^4</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mf">10.2</span><span class="w"></span>
|
||||
<span class="mf">10.2e3</span><span class="w"> </span><span class="c1">// 10.2 * 10^3</span><span class="w"></span>
|
||||
<span class="mh">0x30</span><span class="o">.</span><span class="mi">1</span><span class="w"> </span><span class="c1">// 3 * 64 + 1/16</span><span class="w"></span>
|
||||
<span class="mh">0x30</span><span class="o">.</span><span class="mi">1</span><span class="n">p4</span><span class="w"> </span><span class="c1">// (3 * 64 + 1/16) * 2^4</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -349,13 +397,13 @@ to the closest representable even number.</p>
|
||||
literal value but may be used to improve readability. Here are some examples:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id10">
|
||||
<div class="code-block-caption"><span class="caption-text">Using _</span><a class="headerlink" href="#id10" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">0</span><span class="n">b_0000_0010</span>
|
||||
<span class="mi">0</span><span class="n">x_FFFF_FFEA</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">0</span><span class="n">b_0000_0010</span><span class="w"></span>
|
||||
<span class="mi">0</span><span class="n">x_FFFF_FFEA</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Basic Types — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -80,9 +81,9 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="basic-types">
|
||||
<section id="basic-types">
|
||||
<h1>Basic Types<a class="headerlink" href="#basic-types" title="Permalink to this headline"></a></h1>
|
||||
<div class="section" id="tuples-and-records">
|
||||
<section id="tuples-and-records">
|
||||
<h2>Tuples and Records<a class="headerlink" href="#tuples-and-records" title="Permalink to this headline"></a></h2>
|
||||
<p>Tuples and records are used for packaging multiple values together.
|
||||
Tuples are enclosed in parentheses, while records are enclosed in
|
||||
@ -90,69 +91,69 @@ curly braces. The components of both tuples and records are separated by
|
||||
commas. The components of tuples are expressions, while the
|
||||
components of records are a label and a value separated by an equal
|
||||
sign. Examples:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span> <span class="c1">// A tuple with 3 component</span>
|
||||
<span class="nb">()</span> <span class="c1">// A tuple with no components</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="c1">// A tuple with 3 component</span><span class="w"></span>
|
||||
<span class="nb">()</span><span class="w"> </span><span class="c1">// A tuple with no components</span><span class="w"></span>
|
||||
|
||||
<span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">2</span> <span class="p">}</span> <span class="c1">// A record with two fields, `x` and `y`</span>
|
||||
<span class="p">{}</span> <span class="c1">// A record with no fields</span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// A record with two fields, `x` and `y`</span><span class="w"></span>
|
||||
<span class="p">{}</span><span class="w"> </span><span class="c1">// A record with no fields</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The components of tuples are identified by position, while the
|
||||
components of records are identified by their label, and so the
|
||||
ordering of record components is not important for most purposes.
|
||||
Examples:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> <span class="c1">// True</span>
|
||||
<span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// False</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">// True</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="c1">// False</span><span class="w"></span>
|
||||
|
||||
<span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">2</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">2</span> <span class="p">}</span> <span class="c1">// True</span>
|
||||
<span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">2</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">1</span> <span class="p">}</span> <span class="c1">// True</span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// True</span><span class="w"></span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// True</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Ordering on tuples and records is defined lexicographically. Tuple
|
||||
components are compared in the order they appear, whereas record
|
||||
fields are compared in alphabetical order of field names.</p>
|
||||
<div class="section" id="accessing-fields">
|
||||
<section id="accessing-fields">
|
||||
<h3>Accessing Fields<a class="headerlink" href="#accessing-fields" title="Permalink to this headline"></a></h3>
|
||||
<p>The components of a record or a tuple may be accessed in two ways: via
|
||||
pattern matching or by using explicit component selectors. Explicit
|
||||
component selectors are written as follows:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span><span class="o">.</span><span class="mi">0</span> <span class="o">==</span> <span class="mi">15</span>
|
||||
<span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span><span class="o">.</span><span class="mi">1</span> <span class="o">==</span> <span class="mi">20</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="mi">15</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">)</span><span class="o">.</span><span class="mi">0</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">15</span><span class="w"></span>
|
||||
<span class="p">(</span><span class="mi">15</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">)</span><span class="o">.</span><span class="mi">1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">20</span><span class="w"></span>
|
||||
|
||||
<span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">15</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">20</span> <span class="p">}</span><span class="o">.</span><span class="n">x</span> <span class="o">==</span> <span class="mi">15</span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">}</span><span class="o">.</span><span class="n">x</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">15</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Explicit record selectors may be used only if the program contains
|
||||
sufficient type information to determine the shape of the tuple or
|
||||
record. For example:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">type</span> <span class="kt">T</span> <span class="ow">=</span> <span class="p">{</span> <span class="n">sign</span> <span class="kt">:</span> <span class="kr">Bit</span><span class="p">,</span> <span class="n">number</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">15</span><span class="p">]</span> <span class="p">}</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">type</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">sign</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kr">Bit</span><span class="p">,</span><span class="w"> </span><span class="n">number</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">15</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Valid definition:</span>
|
||||
<span class="c1">// the type of the record is known.</span>
|
||||
<span class="nf">isPositive</span> <span class="kt">:</span> <span class="kt">T</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="nf">isPositive</span> <span class="n">x</span> <span class="ow">=</span> <span class="n">x</span><span class="o">.</span><span class="n">sign</span>
|
||||
<span class="c1">// Valid definition:</span><span class="w"></span>
|
||||
<span class="c1">// the type of the record is known.</span><span class="w"></span>
|
||||
<span class="nf">isPositive</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="nf">isPositive</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="o">.</span><span class="n">sign</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Invalid definition:</span>
|
||||
<span class="c1">// insufficient type information.</span>
|
||||
<span class="nf">badDef</span> <span class="n">x</span> <span class="ow">=</span> <span class="n">x</span><span class="o">.</span><span class="n">f</span>
|
||||
<span class="c1">// Invalid definition:</span><span class="w"></span>
|
||||
<span class="c1">// insufficient type information.</span><span class="w"></span>
|
||||
<span class="nf">badDef</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="o">.</span><span class="n">f</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The components of a tuple or a record may also be accessed using
|
||||
pattern matching. Patterns for tuples and records mirror the syntax
|
||||
for constructing values: tuple patterns use parentheses, while record
|
||||
patterns use braces. Examples:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">getFst</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">_</span><span class="p">)</span> <span class="ow">=</span> <span class="n">x</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">getFst</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"></span>
|
||||
|
||||
<span class="nf">distance2</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="n">xPos</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="n">yPos</span> <span class="p">}</span> <span class="ow">=</span> <span class="n">xPos</span> <span class="o">^^</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">yPos</span> <span class="o">^^</span> <span class="mi">2</span>
|
||||
<span class="nf">distance2</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">xPos</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">yPos</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">xPos</span><span class="w"> </span><span class="o">^^</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">yPos</span><span class="w"> </span><span class="o">^^</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="n">p</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="kr">where</span>
|
||||
<span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">=</span> <span class="n">p</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">p</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Selectors are also lifted through sequence and function types, point-wise,
|
||||
so that the following equations should hold:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">xs</span><span class="o">.</span><span class="n">l</span> <span class="o">==</span> <span class="p">[</span> <span class="n">x</span><span class="o">.</span><span class="n">l</span> <span class="o">|</span> <span class="n">x</span> <span class="ow"><-</span> <span class="n">xs</span> <span class="p">]</span> <span class="c1">// sequences</span>
|
||||
<span class="nf">f</span><span class="o">.</span><span class="n">l</span> <span class="o">==</span> <span class="nf">\</span><span class="n">x</span> <span class="ow">-></span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">l</span> <span class="c1">// functions</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">xs</span><span class="o">.</span><span class="n">l</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="n">x</span><span class="o">.</span><span class="n">l</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="c1">// sequences</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="o">.</span><span class="n">l</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nf">\</span><span class="n">x</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">l</span><span class="w"> </span><span class="c1">// functions</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Thus, if we have a sequence of tuples, <code class="docutils literal notranslate"><span class="pre">xs</span></code>, then we can quickly obtain a
|
||||
@ -161,31 +162,31 @@ sequence with only the tuples’ first components by writing <code class="docuti
|
||||
then we can write <code class="docutils literal notranslate"><span class="pre">f.0</span></code> to get a function that computes only the first
|
||||
entry in the tuple.</p>
|
||||
<p>This behavior is quite handy when examining complex data at the REPL.</p>
|
||||
</div>
|
||||
<div class="section" id="updating-fields">
|
||||
</section>
|
||||
<section id="updating-fields">
|
||||
<h3>Updating Fields<a class="headerlink" href="#updating-fields" title="Permalink to this headline"></a></h3>
|
||||
<p>The components of a record or a tuple may be updated using the following
|
||||
notation:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// Example values</span>
|
||||
<span class="nf">r</span> <span class="ow">=</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">15</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">20</span> <span class="p">}</span> <span class="c1">// a record</span>
|
||||
<span class="nf">t</span> <span class="ow">=</span> <span class="p">(</span><span class="kr">True</span><span class="p">,</span><span class="kr">True</span><span class="p">)</span> <span class="c1">// a tuple</span>
|
||||
<span class="nf">n</span> <span class="ow">=</span> <span class="p">{</span> <span class="n">pt</span> <span class="ow">=</span> <span class="n">r</span><span class="p">,</span> <span class="n">size</span> <span class="ow">=</span> <span class="mi">100</span> <span class="p">}</span> <span class="c1">// nested record</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// Example values</span><span class="w"></span>
|
||||
<span class="nf">r</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// a record</span><span class="w"></span>
|
||||
<span class="nf">t</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">(</span><span class="kr">True</span><span class="p">,</span><span class="kr">True</span><span class="p">)</span><span class="w"> </span><span class="c1">// a tuple</span><span class="w"></span>
|
||||
<span class="nf">n</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pt</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// nested record</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Setting fields</span>
|
||||
<span class="p">{</span> <span class="n">r</span> <span class="o">|</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">30</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">30</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">20</span> <span class="p">}</span>
|
||||
<span class="p">{</span> <span class="n">t</span> <span class="o">|</span> <span class="mi">0</span> <span class="ow">=</span> <span class="kr">False</span> <span class="p">}</span> <span class="o">==</span> <span class="p">(</span><span class="kr">False</span><span class="p">,</span><span class="kr">True</span><span class="p">)</span>
|
||||
<span class="c1">// Setting fields</span><span class="w"></span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">False</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">(</span><span class="kr">False</span><span class="p">,</span><span class="kr">True</span><span class="p">)</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Update relative to the old value</span>
|
||||
<span class="p">{</span> <span class="n">r</span> <span class="o">|</span> <span class="n">x</span> <span class="ow">-></span> <span class="n">x</span> <span class="o">+</span> <span class="mi">5</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">20</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">20</span> <span class="p">}</span>
|
||||
<span class="c1">// Update relative to the old value</span><span class="w"></span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Update a nested field</span>
|
||||
<span class="p">{</span> <span class="n">n</span> <span class="o">|</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="ow">=</span> <span class="mi">10</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="n">pt</span> <span class="ow">=</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">10</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">20</span> <span class="p">},</span> <span class="n">size</span> <span class="ow">=</span> <span class="mi">100</span> <span class="p">}</span>
|
||||
<span class="p">{</span> <span class="n">n</span> <span class="o">|</span> <span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="ow">-></span> <span class="n">x</span> <span class="o">+</span> <span class="mi">10</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="n">pt</span> <span class="ow">=</span> <span class="p">{</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">25</span><span class="p">,</span> <span class="n">y</span> <span class="ow">=</span> <span class="mi">20</span> <span class="p">},</span> <span class="n">size</span> <span class="ow">=</span> <span class="mi">100</span> <span class="p">}</span>
|
||||
<span class="c1">// Update a nested field</span><span class="w"></span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pt</span><span class="o">.</span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pt</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
<span class="p">{</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pt</span><span class="o">.</span><span class="n">x</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pt</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">25</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="sequences">
|
||||
</section>
|
||||
</section>
|
||||
<section id="sequences">
|
||||
<h2>Sequences<a class="headerlink" href="#sequences" title="Permalink to this headline"></a></h2>
|
||||
<p>A sequence is a fixed-length collection of elements of the same type.
|
||||
The type of a finite sequence of length <cite>n</cite>, with elements of type <cite>a</cite>
|
||||
@ -193,25 +194,25 @@ is <code class="docutils literal notranslate"><span class="pre">[n]</span> <span
|
||||
<em>word</em>. We may abbreviate the type <code class="docutils literal notranslate"><span class="pre">[n]</span> <span class="pre">Bit</span></code> as <code class="docutils literal notranslate"><span class="pre">[n]</span></code>. An infinite
|
||||
sequence with elements of type <cite>a</cite> has type <code class="docutils literal notranslate"><span class="pre">[inf]</span> <span class="pre">a</span></code>, and <code class="docutils literal notranslate"><span class="pre">[inf]</span></code> is
|
||||
an infinite stream of bits.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">e1</span><span class="p">,</span><span class="n">e2</span><span class="p">,</span><span class="n">e3</span><span class="p">]</span> <span class="c1">// A sequence with three elements</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">e1</span><span class="p">,</span><span class="n">e2</span><span class="p">,</span><span class="n">e3</span><span class="p">]</span><span class="w"> </span><span class="c1">// A sequence with three elements</span><span class="w"></span>
|
||||
|
||||
<span class="p">[</span><span class="n">t1</span> <span class="o">..</span> <span class="n">t2</span><span class="p">]</span> <span class="c1">// Enumeration</span>
|
||||
<span class="p">[</span><span class="n">t1</span> <span class="o">..</span> <span class="o"><</span><span class="n">t2</span><span class="p">]</span> <span class="c1">// Enumeration (exclusive bound)</span>
|
||||
<span class="p">[</span><span class="n">t1</span> <span class="o">..</span> <span class="n">t2</span> <span class="n">by</span> <span class="n">n</span><span class="p">]</span> <span class="c1">// Enumeration (stride)</span>
|
||||
<span class="p">[</span><span class="n">t1</span> <span class="o">..</span> <span class="o"><</span><span class="n">t2</span> <span class="n">by</span> <span class="n">n</span><span class="p">]</span> <span class="c1">// Enumeration (stride, ex. bound)</span>
|
||||
<span class="p">[</span><span class="n">t1</span> <span class="o">..</span> <span class="n">t2</span> <span class="n">down</span> <span class="n">by</span> <span class="n">n</span><span class="p">]</span> <span class="c1">// Enumeration (downward stride)</span>
|
||||
<span class="p">[</span><span class="n">t1</span> <span class="o">..</span> <span class="o">></span><span class="n">t2</span> <span class="n">down</span> <span class="n">by</span> <span class="n">n</span><span class="p">]</span> <span class="c1">// Enumeration (downward stride, ex. bound)</span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span> <span class="o">..</span> <span class="n">t3</span><span class="p">]</span> <span class="c1">// Enumeration (step by t2 - t1)</span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="n">t2</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="o"><</span><span class="n">t2</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration (exclusive bound)</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="n">t2</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">n</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration (stride)</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="o"><</span><span class="n">t2</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">n</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration (stride, ex. bound)</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="n">t2</span><span class="w"> </span><span class="n">down</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">n</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration (downward stride)</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="o">></span><span class="n">t2</span><span class="w"> </span><span class="n">down</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">n</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration (downward stride, ex. bound)</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">t1</span><span class="p">,</span><span class="w"> </span><span class="n">t2</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="n">t3</span><span class="p">]</span><span class="w"> </span><span class="c1">// Enumeration (step by t2 - t1)</span><span class="w"></span>
|
||||
|
||||
<span class="p">[</span><span class="n">e1</span> <span class="o">...</span><span class="p">]</span> <span class="c1">// Infinite sequence starting at e1</span>
|
||||
<span class="p">[</span><span class="n">e1</span><span class="p">,</span> <span class="n">e2</span> <span class="o">...</span><span class="p">]</span> <span class="c1">// Infinite sequence stepping by e2-e1</span>
|
||||
<span class="p">[</span><span class="n">e1</span><span class="w"> </span><span class="o">...</span><span class="p">]</span><span class="w"> </span><span class="c1">// Infinite sequence starting at e1</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="n">e1</span><span class="p">,</span><span class="w"> </span><span class="n">e2</span><span class="w"> </span><span class="o">...</span><span class="p">]</span><span class="w"> </span><span class="c1">// Infinite sequence stepping by e2-e1</span><span class="w"></span>
|
||||
|
||||
<span class="p">[</span> <span class="n">e</span> <span class="o">|</span> <span class="n">p11</span> <span class="ow"><-</span> <span class="n">e11</span><span class="p">,</span> <span class="n">p12</span> <span class="ow"><-</span> <span class="n">e12</span> <span class="c1">// Sequence comprehensions</span>
|
||||
<span class="o">|</span> <span class="n">p21</span> <span class="ow"><-</span> <span class="n">e21</span><span class="p">,</span> <span class="n">p22</span> <span class="ow"><-</span> <span class="n">e22</span> <span class="p">]</span>
|
||||
<span class="p">[</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">p11</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="n">e11</span><span class="p">,</span><span class="w"> </span><span class="n">p12</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="n">e12</span><span class="w"> </span><span class="c1">// Sequence comprehensions</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">p21</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="n">e21</span><span class="p">,</span><span class="w"> </span><span class="n">p22</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="n">e22</span><span class="w"> </span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="nf">x</span> <span class="ow">=</span> <span class="n">generate</span> <span class="p">(</span><span class="nf">\</span><span class="n">i</span> <span class="ow">-></span> <span class="n">e</span><span class="p">)</span> <span class="c1">// Sequence from generating function</span>
|
||||
<span class="nf">x</span> <span class="o">@</span> <span class="n">i</span> <span class="ow">=</span> <span class="n">e</span> <span class="c1">// Sequence with index binding</span>
|
||||
<span class="nf">arr</span> <span class="o">@</span> <span class="n">i</span> <span class="o">@</span> <span class="n">j</span> <span class="ow">=</span> <span class="n">e</span> <span class="c1">// Two-dimensional sequence</span>
|
||||
<span class="nf">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">generate</span><span class="w"> </span><span class="p">(</span><span class="nf">\</span><span class="n">i</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="c1">// Sequence from generating function</span><span class="w"></span>
|
||||
<span class="nf">x</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="c1">// Sequence with index binding</span><span class="w"></span>
|
||||
<span class="nf">arr</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="c1">// Two-dimensional sequence</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note: the bounds in finite sequences (those with <cite>..</cite>) are type
|
||||
@ -259,19 +260,19 @@ a location
|
||||
</tbody>
|
||||
</table>
|
||||
<p>There are also lifted pointwise operations.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">,</span> <span class="n">p4</span><span class="p">]</span> <span class="c1">// Sequence pattern</span>
|
||||
<span class="nf">p1</span> <span class="o">#</span> <span class="n">p2</span> <span class="c1">// Split sequence pattern</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">p1</span><span class="p">,</span><span class="w"> </span><span class="n">p2</span><span class="p">,</span><span class="w"> </span><span class="n">p3</span><span class="p">,</span><span class="w"> </span><span class="n">p4</span><span class="p">]</span><span class="w"> </span><span class="c1">// Sequence pattern</span><span class="w"></span>
|
||||
<span class="nf">p1</span><span class="w"> </span><span class="o">#</span><span class="w"> </span><span class="n">p2</span><span class="w"> </span><span class="c1">// Split sequence pattern</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="functions">
|
||||
</section>
|
||||
<section id="functions">
|
||||
<h2>Functions<a class="headerlink" href="#functions" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">\</span><span class="n">p1</span> <span class="n">p2</span> <span class="ow">-></span> <span class="n">e</span> <span class="c1">// Lambda expression</span>
|
||||
<span class="nf">f</span> <span class="n">p1</span> <span class="n">p2</span> <span class="ow">=</span> <span class="n">e</span> <span class="c1">// Function definition</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">\</span><span class="n">p1</span><span class="w"> </span><span class="n">p2</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="c1">// Lambda expression</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="n">p1</span><span class="w"> </span><span class="n">p2</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="c1">// Function definition</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Expressions — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -82,134 +83,134 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="expressions">
|
||||
<section id="expressions">
|
||||
<h1>Expressions<a class="headerlink" href="#expressions" title="Permalink to this headline"></a></h1>
|
||||
<p>This section provides an overview of the Cryptol’s expression syntax.</p>
|
||||
<div class="section" id="calling-functions">
|
||||
<section id="calling-functions">
|
||||
<h2>Calling Functions<a class="headerlink" href="#calling-functions" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span> <span class="mi">2</span> <span class="c1">// call `f` with parameter `2`</span>
|
||||
<span class="nf">g</span> <span class="n">x</span> <span class="n">y</span> <span class="c1">// call `g` with two parameters: `x` and `y`</span>
|
||||
<span class="nf">h</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="c1">// call `h` with one parameter, the pair `(x,y)`</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// call `f` with parameter `2`</span><span class="w"></span>
|
||||
<span class="nf">g</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="c1">// call `g` with two parameters: `x` and `y`</span><span class="w"></span>
|
||||
<span class="nf">h</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="c1">// call `h` with one parameter, the pair `(x,y)`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="prefix-operators">
|
||||
</section>
|
||||
<section id="prefix-operators">
|
||||
<h2>Prefix Operators<a class="headerlink" href="#prefix-operators" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="o">-</span><span class="mi">2</span> <span class="c1">// call unary `-` with parameter `2`</span>
|
||||
<span class="o">-</span> <span class="mi">2</span> <span class="c1">// call unary `-` with parameter `2`</span>
|
||||
<span class="nf">f</span> <span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="c1">// call `f` with one argument: `-2`, parens are important</span>
|
||||
<span class="o">-</span><span class="n">f</span> <span class="mi">2</span> <span class="c1">// call unary `-` with parameter `f 2`</span>
|
||||
<span class="o">-</span> <span class="n">f</span> <span class="mi">2</span> <span class="c1">// call unary `-` with parameter `f 2`</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="o">-</span><span class="mi">2</span><span class="w"> </span><span class="c1">// call unary `-` with parameter `2`</span><span class="w"></span>
|
||||
<span class="o">-</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// call unary `-` with parameter `2`</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">// call `f` with one argument: `-2`, parens are important</span><span class="w"></span>
|
||||
<span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// call unary `-` with parameter `f 2`</span><span class="w"></span>
|
||||
<span class="o">-</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// call unary `-` with parameter `f 2`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="infix-functions">
|
||||
</section>
|
||||
<section id="infix-functions">
|
||||
<h2>Infix Functions<a class="headerlink" href="#infix-functions" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">2</span> <span class="o">+</span> <span class="mi">3</span> <span class="c1">// call `+` with two parameters: `2` and `3`</span>
|
||||
<span class="mi">2</span> <span class="o">+</span> <span class="mi">3</span> <span class="o">*</span> <span class="mi">5</span> <span class="c1">// call `+` with two parameters: `2` and `3 * 5`</span>
|
||||
<span class="p">(</span><span class="o">+</span><span class="p">)</span> <span class="mi">2</span> <span class="mi">3</span> <span class="c1">// call `+` with two parameters: `2` and `3`</span>
|
||||
<span class="nf">f</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">g</span> <span class="mi">3</span> <span class="c1">// call `+` with two parameters: `f 2` and `g 3`</span>
|
||||
<span class="o">-</span> <span class="mi">2</span> <span class="o">+</span> <span class="o">-</span> <span class="mi">3</span> <span class="c1">// call `+` with two parameters: `-2` and `-3`</span>
|
||||
<span class="o">-</span> <span class="n">f</span> <span class="mi">2</span> <span class="o">+</span> <span class="o">-</span> <span class="n">g</span> <span class="mi">3</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="c1">// call `+` with two parameters: `2` and `3`</span><span class="w"></span>
|
||||
<span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="c1">// call `+` with two parameters: `2` and `3 * 5`</span><span class="w"></span>
|
||||
<span class="p">(</span><span class="o">+</span><span class="p">)</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="c1">// call `+` with two parameters: `2` and `3`</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="c1">// call `+` with two parameters: `f 2` and `g 3`</span><span class="w"></span>
|
||||
<span class="o">-</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="c1">// call `+` with two parameters: `-2` and `-3`</span><span class="w"></span>
|
||||
<span class="o">-</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="type-annotations">
|
||||
</section>
|
||||
<section id="type-annotations">
|
||||
<h2>Type Annotations<a class="headerlink" href="#type-annotations" title="Permalink to this headline"></a></h2>
|
||||
<p>Explicit type annotations may be added on expressions, patterns, and
|
||||
in argument definitions.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">x</span> <span class="kt">:</span> <span class="kr">Bit</span> <span class="c1">// specify that `x` has type `Bit`</span>
|
||||
<span class="nf">f</span> <span class="n">x</span> <span class="kt">:</span> <span class="kr">Bit</span> <span class="c1">// specify that `f x` has type `Bit`</span>
|
||||
<span class="o">-</span> <span class="n">f</span> <span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="c1">// specify that `- f x` has type `[8]`</span>
|
||||
<span class="mi">2</span> <span class="o">+</span> <span class="mi">3</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="c1">// specify that `2 + 3` has type `[8]`</span>
|
||||
<span class="nf">\</span><span class="n">x</span> <span class="ow">-></span> <span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="c1">// type annotation is on `x`, not the function</span>
|
||||
<span class="kr">if</span> <span class="n">x</span>
|
||||
<span class="kr">then</span> <span class="n">y</span>
|
||||
<span class="kr">else</span> <span class="n">z</span> <span class="kt">:</span> <span class="kr">Bit</span> <span class="c1">// the type annotation is on `z`, not the whole `if`</span>
|
||||
<span class="p">[</span><span class="mi">1</span><span class="o">..</span><span class="mi">9</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]]</span> <span class="c1">// specify that elements in `[1..9]` have type `[8]`</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kr">Bit</span><span class="w"> </span><span class="c1">// specify that `x` has type `Bit`</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kr">Bit</span><span class="w"> </span><span class="c1">// specify that `f x` has type `Bit`</span><span class="w"></span>
|
||||
<span class="o">-</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"> </span><span class="c1">// specify that `- f x` has type `[8]`</span><span class="w"></span>
|
||||
<span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"> </span><span class="c1">// specify that `2 + 3` has type `[8]`</span><span class="w"></span>
|
||||
<span class="nf">\</span><span class="n">x</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"> </span><span class="c1">// type annotation is on `x`, not the function</span><span class="w"></span>
|
||||
<span class="kr">if</span><span class="w"> </span><span class="n">x</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kr">Bit</span><span class="w"> </span><span class="c1">// the type annotation is on `z`, not the whole `if`</span><span class="w"></span>
|
||||
<span class="p">[</span><span class="mi">1</span><span class="o">..</span><span class="mi">9</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]]</span><span class="w"> </span><span class="c1">// specify that elements in `[1..9]` have type `[8]`</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="p">(</span><span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">])</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1">// type annotation on patterns</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">])</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="c1">// type annotation on patterns</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition-todo admonition" id="id1">
|
||||
<p class="admonition-title">Todo</p>
|
||||
<p>Patterns with type variables</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="explicit-type-instantiation">
|
||||
</section>
|
||||
<section id="explicit-type-instantiation">
|
||||
<h2>Explicit Type Instantiation<a class="headerlink" href="#explicit-type-instantiation" title="Permalink to this headline"></a></h2>
|
||||
<p>If <code class="docutils literal notranslate"><span class="pre">f</span></code> is a polymorphic value with type:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span> <span class="kt">:</span> <span class="p">{</span> <span class="n">tyParam</span> <span class="p">}</span> <span class="n">tyParam</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="n">zero</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">tyParam</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="n">tyParam</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">zero</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>you can evaluate <code class="docutils literal notranslate"><span class="pre">f</span></code>, passing it a type parameter:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span> <span class="p">`{</span> <span class="n">tyParam</span> <span class="ow">=</span> <span class="mi">13</span> <span class="p">}</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="p">`{</span><span class="w"> </span><span class="n">tyParam</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">13</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="local-declarations">
|
||||
</section>
|
||||
<section id="local-declarations">
|
||||
<h2>Local Declarations<a class="headerlink" href="#local-declarations" title="Permalink to this headline"></a></h2>
|
||||
<p>Local declarations have the weakest precedence of all expressions.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">2</span> <span class="o">+</span> <span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="kt">T</span><span class="p">]</span>
|
||||
<span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="kt">T</span> <span class="ow">=</span> <span class="mi">8</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">2</span> <span class="c1">// `T` and `x` are in scope of `2 + x : `[T]`</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="kt">T</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">8</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// `T` and `x` are in scope of `2 + x : `[T]`</span><span class="w"></span>
|
||||
|
||||
<span class="kr">if</span> <span class="n">x</span> <span class="kr">then</span> <span class="mi">1</span> <span class="kr">else</span> <span class="mi">2</span>
|
||||
<span class="kr">where</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">2</span> <span class="c1">// `x` is in scope in the whole `if`</span>
|
||||
<span class="kr">if</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">where</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// `x` is in scope in the whole `if`</span><span class="w"></span>
|
||||
|
||||
<span class="nf">\</span><span class="n">y</span> <span class="ow">-></span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
|
||||
<span class="kr">where</span> <span class="n">x</span> <span class="ow">=</span> <span class="mi">2</span> <span class="c1">// `y` is not in scope in the defintion of `x`</span>
|
||||
<span class="nf">\</span><span class="n">y</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">where</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">// `y` is not in scope in the defintion of `x`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="block-arguments">
|
||||
</section>
|
||||
<section id="block-arguments">
|
||||
<h2>Block Arguments<a class="headerlink" href="#block-arguments" title="Permalink to this headline"></a></h2>
|
||||
<p>When used as the last argument to a function call,
|
||||
<code class="docutils literal notranslate"><span class="pre">if</span></code> and lambda expressions do not need parens:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span> <span class="nf">\</span><span class="n">x</span> <span class="ow">-></span> <span class="n">x</span> <span class="c1">// call `f` with one argument `x -> x`</span>
|
||||
<span class="mi">2</span> <span class="o">+</span> <span class="kr">if</span> <span class="n">x</span>
|
||||
<span class="kr">then</span> <span class="n">y</span>
|
||||
<span class="kr">else</span> <span class="n">z</span> <span class="c1">// call `+` with two arguments: `2` and `if ...`</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="nf">\</span><span class="n">x</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="c1">// call `f` with one argument `x -> x`</span><span class="w"></span>
|
||||
<span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="n">x</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="c1">// call `+` with two arguments: `2` and `if ...`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="conditionals">
|
||||
</section>
|
||||
<section id="conditionals">
|
||||
<h2>Conditionals<a class="headerlink" href="#conditionals" title="Permalink to this headline"></a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">...</span> <span class="pre">then</span> <span class="pre">...</span> <span class="pre">else</span></code> construct can be used with
|
||||
multiple branches. For example:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">x</span> <span class="ow">=</span> <span class="kr">if</span> <span class="n">y</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="kr">then</span> <span class="mi">22</span> <span class="kr">else</span> <span class="mi">33</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="mi">22</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="mi">33</span><span class="w"></span>
|
||||
|
||||
<span class="nf">x</span> <span class="ow">=</span> <span class="kr">if</span> <span class="n">y</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="kr">then</span> <span class="mi">1</span>
|
||||
<span class="o">|</span> <span class="n">y</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">==</span> <span class="mi">0</span> <span class="kr">then</span> <span class="mi">2</span>
|
||||
<span class="o">|</span> <span class="n">y</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">==</span> <span class="mi">0</span> <span class="kr">then</span> <span class="mi">3</span>
|
||||
<span class="kr">else</span> <span class="mi">7</span>
|
||||
<span class="nf">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="kr">then</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="demoting-numeric-types-to-values">
|
||||
</section>
|
||||
<section id="demoting-numeric-types-to-values">
|
||||
<h2>Demoting Numeric Types to Values<a class="headerlink" href="#demoting-numeric-types-to-values" title="Permalink to this headline"></a></h2>
|
||||
<p>The value corresponding to a numeric type may be accessed using the
|
||||
following notation:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">`</span><span class="n">t</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">`</span><span class="n">t</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here <cite>t</cite> should be a finite type expression with numeric kind. The resulting
|
||||
expression will be of a numeric base type, which is sufficiently large
|
||||
to accommodate the value of the type:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">`</span><span class="n">t</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Literal</span> <span class="n">t</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="p">`</span><span class="n">t</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Literal</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This backtick notation is syntax sugar for an application of the
|
||||
<cite>number</cite> primtive, so the above may be written as:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">number</span><span class="p">`{</span><span class="n">t</span><span class="p">}</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Literal</span> <span class="n">t</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">number</span><span class="p">`{</span><span class="n">t</span><span class="p">}</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Literal</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If a type cannot be inferred from context, a suitable type will be
|
||||
automatically chosen if possible, usually <cite>Integer</cite>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Foreign Function Interface — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -51,8 +52,9 @@
|
||||
<li class="toctree-l3"><a class="reference internal" href="#overall-structure">Overall structure</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#type-parameters">Type parameters</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#bit">Bit</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#integral-types">Integral types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#bit-vector-types">Bit Vector Types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#floating-point-types">Floating point types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#math-types">Math Types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#sequences">Sequences</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#tuples-and-records">Tuples and records</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#type-synonyms">Type synonyms</a></li>
|
||||
@ -91,25 +93,39 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="foreign-function-interface">
|
||||
<section id="foreign-function-interface">
|
||||
<h1>Foreign Function Interface<a class="headerlink" href="#foreign-function-interface" title="Permalink to this headline"></a></h1>
|
||||
<p>The foreign function interface (FFI) allows Cryptol to call functions written in
|
||||
C (or other languages that use the C calling convention).</p>
|
||||
<div class="section" id="platform-support">
|
||||
<section id="platform-support">
|
||||
<h2>Platform support<a class="headerlink" href="#platform-support" title="Permalink to this headline"></a></h2>
|
||||
<p>The FFI is currently <strong>not supported on Windows</strong>, and only works on Unix-like
|
||||
systems (macOS and Linux).</p>
|
||||
</div>
|
||||
<div class="section" id="basic-usage">
|
||||
<p>The FFI is built on top of the C <code class="docutils literal notranslate"><span class="pre">libffi</span></code> library, and as such, it should be
|
||||
portable across many operating systems. We have tested it to work on Linux,
|
||||
macOS, and Windows.</p>
|
||||
</section>
|
||||
<section id="basic-usage">
|
||||
<h2>Basic usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline"></a></h2>
|
||||
<p>Suppose we want to call the following C function:</p>
|
||||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">uint32_t</span> <span class="nf">add</span><span class="p">(</span><span class="kt">uint32_t</span> <span class="n">x</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<p>Suppose we want to implement the following function in C:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">add</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">32</span><span class="p">]</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">[</span><span class="mi">32</span><span class="p">]</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">[</span><span class="mi">32</span><span class="p">]</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In our Cryptol file, we write a <code class="docutils literal notranslate"><span class="pre">foreign</span></code> declaration with no body:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">foreign</span> <span class="n">add</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">32</span><span class="p">]</span> <span class="ow">-></span> <span class="p">[</span><span class="mi">32</span><span class="p">]</span> <span class="ow">-></span> <span class="p">[</span><span class="mi">32</span><span class="p">]</span>
|
||||
<p>In our Cryptol file, we declare it as a <code class="docutils literal notranslate"><span class="pre">foreign</span></code> function with no body:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">foreign</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">32</span><span class="p">]</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">[</span><span class="mi">32</span><span class="p">]</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">[</span><span class="mi">32</span><span class="p">]</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Then we write the following C function:</p>
|
||||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">uint32_t</span><span class="w"> </span><span class="nf">add</span><span class="p">(</span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="p">;</span><span class="w"></span>
|
||||
<span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Cryptol can generate a C header file containing the appropriate function
|
||||
prototypes given the corresponding Cryptol <code class="docutils literal notranslate"><span class="pre">foreign</span></code> declarations with the
|
||||
<code class="docutils literal notranslate"><span class="pre">:generate-foreign-header</span></code> command. You can then <code class="docutils literal notranslate"><span class="pre">#include</span></code> the generated
|
||||
header file in your C file to help write the C implementation.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Cryptol</span><span class="o">></span> <span class="p">:</span><span class="n">generate</span><span class="o">-</span><span class="n">foreign</span><span class="o">-</span><span class="n">header</span> <span class="n">Example</span><span class="o">.</span><span class="n">cry</span>
|
||||
<span class="n">Loading</span> <span class="n">module</span> <span class="n">Example</span>
|
||||
<span class="n">Writing</span> <span class="n">header</span> <span class="n">to</span> <span class="n">Example</span><span class="o">.</span><span class="n">h</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The C code must first be compiled into a dynamically loaded shared library. When
|
||||
@ -120,6 +136,7 @@ extension it uses is platform-specific:</p>
|
||||
<ul class="simple">
|
||||
<li><p>On Linux, it looks for the extension <code class="docutils literal notranslate"><span class="pre">.so</span></code>.</p></li>
|
||||
<li><p>On macOS, it looks for the extension <code class="docutils literal notranslate"><span class="pre">.dylib</span></code>.</p></li>
|
||||
<li><p>On Windows, it looks for the extension <code class="docutils literal notranslate"><span class="pre">.dll</span></code>.</p></li>
|
||||
</ul>
|
||||
<p>For example, if you are on Linux and your <code class="docutils literal notranslate"><span class="pre">foreign</span></code> declaration is in
|
||||
<code class="docutils literal notranslate"><span class="pre">Foo.cry</span></code>, Cryptol will dynamically load <code class="docutils literal notranslate"><span class="pre">Foo.so</span></code>. Then for each <code class="docutils literal notranslate"><span class="pre">foreign</span></code>
|
||||
@ -142,31 +159,35 @@ Main> add 1 2
|
||||
</div>
|
||||
<p>Note: Since Cryptol currently only accesses the compiled binary and not the C
|
||||
source, it has no way of checking that the Cryptol function type you declare in
|
||||
your Cryptol code actually matches the type of the C function. <strong>It is your
|
||||
responsibility to make sure the types match up</strong>. If they do not then there may
|
||||
be undefined behavior.</p>
|
||||
</div>
|
||||
<div class="section" id="compiling-c-code">
|
||||
your Cryptol code actually matches the type of the C function. It can generate
|
||||
the correct C headers but if the actual implementation does not match it there
|
||||
may be undefined behavior.</p>
|
||||
</section>
|
||||
<section id="compiling-c-code">
|
||||
<h2>Compiling C code<a class="headerlink" href="#compiling-c-code" title="Permalink to this headline"></a></h2>
|
||||
<p>Cryptol currently does not handle compilation of C code to shared libraries. For
|
||||
simple usages, you can do this manually with the following commands:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Linux: <code class="docutils literal notranslate"><span class="pre">cc</span> <span class="pre">-fPIC</span> <span class="pre">-shared</span> <span class="pre">Foo.c</span> <span class="pre">-o</span> <span class="pre">Foo.so</span></code></p></li>
|
||||
<li><p>macOS: <code class="docutils literal notranslate"><span class="pre">cc</span> <span class="pre">-dynamiclib</span> <span class="pre">Foo.c</span> <span class="pre">-o</span> <span class="pre">Foo.dylib</span></code></p></li>
|
||||
<li><p>Windows: <code class="docutils literal notranslate"><span class="pre">cc</span> <span class="pre">-fPIC</span> <span class="pre">-shared</span> <span class="pre">Foo.c</span> <span class="pre">-o</span> <span class="pre">Foo.dll</span></code></p></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="converting-between-cryptol-and-c-types">
|
||||
</section>
|
||||
<section id="converting-between-cryptol-and-c-types">
|
||||
<h2>Converting between Cryptol and C types<a class="headerlink" href="#converting-between-cryptol-and-c-types" title="Permalink to this headline"></a></h2>
|
||||
<p>This section describes how a given Cryptol function signature maps to a C
|
||||
function prototype. The FFI only supports a limited set of Cryptol types which
|
||||
have a clear translation into C.</p>
|
||||
<div class="section" id="overall-structure">
|
||||
<p>This mapping can now be done automatically with the <code class="docutils literal notranslate"><span class="pre">:generate-foreign-header</span></code>
|
||||
command mentioned above; however, this section is still worth reading to
|
||||
understand the supported types and what the resulting C parameters mean.</p>
|
||||
<section id="overall-structure">
|
||||
<h3>Overall structure<a class="headerlink" href="#overall-structure" title="Permalink to this headline"></a></h3>
|
||||
<p>Cryptol <code class="docutils literal notranslate"><span class="pre">foreign</span></code> bindings must be functions. These functions may have
|
||||
multiple (curried) arguments; they may also be polymorphic, with certain
|
||||
limitations. That is, the general structure of a <code class="docutils literal notranslate"><span class="pre">foreign</span></code> declaration would
|
||||
look something like this:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">foreign</span> <span class="n">f</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a1</span><span class="p">,</span> <span class="o">...</span><span class="p">,</span> <span class="n">ak</span><span class="p">}</span> <span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="o">...</span><span class="p">,</span> <span class="n">cn</span><span class="p">)</span> <span class="ow">=></span> <span class="kt">T1</span> <span class="ow">-></span> <span class="o">...</span> <span class="ow">-></span> <span class="kt">Tm</span> <span class="ow">-></span> <span class="kt">Tr</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">foreign</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a1</span><span class="p">,</span><span class="w"> </span><span class="o">...</span><span class="p">,</span><span class="w"> </span><span class="n">ak</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="n">c1</span><span class="p">,</span><span class="w"> </span><span class="o">...</span><span class="p">,</span><span class="w"> </span><span class="n">cn</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">T1</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="o">...</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Tm</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Tr</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Each type argument to the Cryptol function (<code class="docutils literal notranslate"><span class="pre">a1,</span> <span class="pre">...,</span> <span class="pre">ak</span></code> above) corresponds
|
||||
@ -186,8 +207,8 @@ arguments are used, they are passed last, after the C arguments corresponding to
|
||||
Cryptol arguments.</p>
|
||||
<p>The following tables list the C type(s) that each Cryptol type (or kind)
|
||||
corresponds to.</p>
|
||||
</div>
|
||||
<div class="section" id="type-parameters">
|
||||
</section>
|
||||
<section id="type-parameters">
|
||||
<h3>Type parameters<a class="headerlink" href="#type-parameters" title="Permalink to this headline"></a></h3>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
@ -213,8 +234,8 @@ does not fit in a <code class="docutils literal notranslate"><span class="pre">s
|
||||
check this statically by requiring that all type variables in foreign functions
|
||||
satisfy <code class="docutils literal notranslate"><span class="pre"><</span> <span class="pre">2^^64</span></code> instead of just <code class="docutils literal notranslate"><span class="pre">fin</span></code>, in practice this would be too
|
||||
cumbersome.)</p>
|
||||
</div>
|
||||
<div class="section" id="bit">
|
||||
</section>
|
||||
<section id="bit">
|
||||
<h3>Bit<a class="headerlink" href="#bit" title="Permalink to this headline"></a></h3>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
@ -235,9 +256,9 @@ cumbersome.)</p>
|
||||
<p>When converting to C, <code class="docutils literal notranslate"><span class="pre">True</span></code> is converted to <code class="docutils literal notranslate"><span class="pre">1</span></code> and <code class="docutils literal notranslate"><span class="pre">False</span></code> to <code class="docutils literal notranslate"><span class="pre">0</span></code>.
|
||||
When converting to Cryptol, any nonzero number is converted to <code class="docutils literal notranslate"><span class="pre">True</span></code> and
|
||||
<code class="docutils literal notranslate"><span class="pre">0</span></code> is converted to <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="integral-types">
|
||||
<h3>Integral types<a class="headerlink" href="#integral-types" title="Permalink to this headline"></a></h3>
|
||||
</section>
|
||||
<section id="bit-vector-types">
|
||||
<h3>Bit Vector Types<a class="headerlink" href="#bit-vector-types" title="Permalink to this headline"></a></h3>
|
||||
<p>Let <code class="docutils literal notranslate"><span class="pre">K</span> <span class="pre">:</span> <span class="pre">#</span></code> be a Cryptol type. Note <code class="docutils literal notranslate"><span class="pre">K</span></code> must be an actual fixed numeric type
|
||||
and not a type variable.</p>
|
||||
<table class="docutils align-default">
|
||||
@ -270,12 +291,12 @@ value is padded with zero bits, and when converting to Cryptol the extra bits
|
||||
are ignored. For instance, for the Cryptol type <code class="docutils literal notranslate"><span class="pre">[4]</span></code>, the Cryptol value <code class="docutils literal notranslate"><span class="pre">0xf</span>
|
||||
<span class="pre">:</span> <span class="pre">[4]</span></code> is converted to the C value <code class="docutils literal notranslate"><span class="pre">uint8_t</span></code> <code class="docutils literal notranslate"><span class="pre">0x0f</span></code>, and the C <code class="docutils literal notranslate"><span class="pre">uint8_t</span></code>
|
||||
<code class="docutils literal notranslate"><span class="pre">0xaf</span></code> is converted to the Cryptol value <code class="docutils literal notranslate"><span class="pre">0xf</span> <span class="pre">:</span> <span class="pre">[4]</span></code>.</p>
|
||||
<p>Note that words larger than 64 bits are not supported, since there is no
|
||||
<p>Note that bit vectors larger than 64 bits are not supported, since there is no
|
||||
standard C integral type for that. You can split it into a sequence of smaller
|
||||
words first in Cryptol, then use the FFI conversion for sequences of words to
|
||||
handle it in C as an array.</p>
|
||||
</div>
|
||||
<div class="section" id="floating-point-types">
|
||||
</section>
|
||||
<section id="floating-point-types">
|
||||
<h3>Floating point types<a class="headerlink" href="#floating-point-types" title="Permalink to this headline"></a></h3>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
@ -298,16 +319,14 @@ handle it in C as an array.</p>
|
||||
</table>
|
||||
<p>Note: the Cryptol <code class="docutils literal notranslate"><span class="pre">Float</span></code> types are defined in the built-in module <code class="docutils literal notranslate"><span class="pre">Float</span></code>.
|
||||
Other sizes of floating points are not supported.</p>
|
||||
</div>
|
||||
<div class="section" id="sequences">
|
||||
<h3>Sequences<a class="headerlink" href="#sequences" title="Permalink to this headline"></a></h3>
|
||||
<p>Let <code class="docutils literal notranslate"><span class="pre">n</span> <span class="pre">:</span> <span class="pre">#</span></code> be a Cryptol type, possibly containing type variables, that
|
||||
satisfies <code class="docutils literal notranslate"><span class="pre">fin</span> <span class="pre">n</span></code>, and <code class="docutils literal notranslate"><span class="pre">T</span></code> be one of the above Cryptol <em>integral types</em> or
|
||||
<em>floating point types</em>. Let <code class="docutils literal notranslate"><span class="pre">U</span></code> be the C type that <code class="docutils literal notranslate"><span class="pre">T</span></code> corresponds to.</p>
|
||||
</section>
|
||||
<section id="math-types">
|
||||
<h3>Math Types<a class="headerlink" href="#math-types" title="Permalink to this headline"></a></h3>
|
||||
<p>Values of high precision types and <code class="docutils literal notranslate"><span class="pre">Z</span></code> are represented using the GMP library.</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 52%" />
|
||||
<col style="width: 48%" />
|
||||
<col style="width: 55%" />
|
||||
<col style="width: 45%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>Cryptol type</p></th>
|
||||
@ -315,17 +334,56 @@ satisfies <code class="docutils literal notranslate"><span class="pre">fin</span
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">[n]T</span></code></p></td>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">Integer</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpz_t</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">Rational</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpq_t</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">Z</span> <span class="pre">n</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpz_t</span></code></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Results of these types are returned in <em>output</em> parameters,
|
||||
but since both <code class="docutils literal notranslate"><span class="pre">mpz_t</span></code> and <code class="docutils literal notranslate"><span class="pre">mpz_q</span></code> are already reference
|
||||
types there is no need for an extra pointer in the result.
|
||||
For example, a Cryptol function <code class="docutils literal notranslate"><span class="pre">f</span> <span class="pre">:</span> <span class="pre">Integer</span> <span class="pre">-></span> <span class="pre">Rational</span></code>
|
||||
would correspond to a C function <code class="docutils literal notranslate"><span class="pre">f(mpz_t</span> <span class="pre">in,</span> <span class="pre">mpq_t</span> <span class="pre">out)</span></code>.</p>
|
||||
<p>All parameters passed to the C function (no matter if
|
||||
input or output) are managed by Cryptol, which takes care
|
||||
to call <code class="docutils literal notranslate"><span class="pre">init</span></code> before their use and <code class="docutils literal notranslate"><span class="pre">clear</span></code> after.</p>
|
||||
</section>
|
||||
<section id="sequences">
|
||||
<h3>Sequences<a class="headerlink" href="#sequences" title="Permalink to this headline"></a></h3>
|
||||
<p>Let <code class="docutils literal notranslate"><span class="pre">n1,</span> <span class="pre">n2,</span> <span class="pre">...,</span> <span class="pre">nk</span> <span class="pre">:</span> <span class="pre">#</span></code> be Cryptol types (with <code class="docutils literal notranslate"><span class="pre">k</span> <span class="pre">>=</span> <span class="pre">1</span></code>), possibly
|
||||
containing type variables, that satisfy <code class="docutils literal notranslate"><span class="pre">fin</span> <span class="pre">n1,</span> <span class="pre">fin</span> <span class="pre">n2,</span> <span class="pre">...,</span> <span class="pre">fin</span> <span class="pre">nk</span></code>, and
|
||||
<code class="docutils literal notranslate"><span class="pre">T</span></code> be one of the above Cryptol <em>bit vector types</em>, <em>floating point types</em>, or
|
||||
<em>math types</em>. Let <code class="docutils literal notranslate"><span class="pre">U</span></code> be the C type that <code class="docutils literal notranslate"><span class="pre">T</span></code> corresponds to.</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 65%" />
|
||||
<col style="width: 35%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>Cryptol type</p></th>
|
||||
<th class="head"><p>C type</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">[n1][n2]...[nk]T</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">U*</span></code></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The C pointer points to an array of <code class="docutils literal notranslate"><span class="pre">n</span></code> elements of type <code class="docutils literal notranslate"><span class="pre">U</span></code>. Note that,
|
||||
while the length of the array itself is not explicitly passed along with the
|
||||
pointer, any type arguments contained in the size are passed as C <code class="docutils literal notranslate"><span class="pre">size_t</span></code>’s
|
||||
earlier, so the C code can always know the length of the array.</p>
|
||||
</div>
|
||||
<div class="section" id="tuples-and-records">
|
||||
<p>The C pointer points to an array of <code class="docutils literal notranslate"><span class="pre">n1</span> <span class="pre">*</span> <span class="pre">n2</span> <span class="pre">*</span> <span class="pre">...</span> <span class="pre">*</span> <span class="pre">nk</span></code> elements of type
|
||||
<code class="docutils literal notranslate"><span class="pre">U</span></code>. If the sequence is multidimensional, it is flattened and stored
|
||||
contiguously, similar to the representation of multidimensional arrays in C.
|
||||
Note that, while the dimensions of the array itself are not explicitly passed
|
||||
along with the pointer, any type arguments contained in the size are passed as C
|
||||
<code class="docutils literal notranslate"><span class="pre">size_t</span></code>’s earlier, so the C code can always know the dimensions of the array.</p>
|
||||
</section>
|
||||
<section id="tuples-and-records">
|
||||
<h3>Tuples and records<a class="headerlink" href="#tuples-and-records" title="Permalink to this headline"></a></h3>
|
||||
<p>Let <code class="docutils literal notranslate"><span class="pre">T1,</span> <span class="pre">T2,</span> <span class="pre">...,</span> <span class="pre">Tn</span></code> be Cryptol types supported by the FFI (which may be any
|
||||
of the types mentioned above, or tuples and records themselves). Let
|
||||
@ -354,26 +412,27 @@ correspond to. Let <code class="docutils literal notranslate"><span class="pre">
|
||||
an argument behaves the same as if you passed its components individually. This
|
||||
flattening is applied recursively for nested tuples and records. Note that this
|
||||
means empty tuples don’t map to any C values at all.</p>
|
||||
</div>
|
||||
<div class="section" id="type-synonyms">
|
||||
</section>
|
||||
<section id="type-synonyms">
|
||||
<h3>Type synonyms<a class="headerlink" href="#type-synonyms" title="Permalink to this headline"></a></h3>
|
||||
<p>All type synonyms are expanded before applying the above rules, so you can use
|
||||
type synonyms in <code class="docutils literal notranslate"><span class="pre">foreign</span></code> declarations to improve readability.</p>
|
||||
</div>
|
||||
<div class="section" id="return-values">
|
||||
</section>
|
||||
<section id="return-values">
|
||||
<h3>Return values<a class="headerlink" href="#return-values" title="Permalink to this headline"></a></h3>
|
||||
<p>If the Cryptol return type is <code class="docutils literal notranslate"><span class="pre">Bit</span></code> or one of the above <em>integral types</em> or
|
||||
<p>If the Cryptol return type is <code class="docutils literal notranslate"><span class="pre">Bit</span></code> or one of the above <em>bit vector types</em> or
|
||||
<em>floating point types</em>, the value is returned directly from the C function. In
|
||||
that case, the return type of the C function will be the C type corresponding to
|
||||
the Cryptol type, and no extra arguments are added.</p>
|
||||
<p>If the Cryptol return type is a sequence, tuple, or record, then the value is
|
||||
returned using output arguments, and the return type of the C function will be
|
||||
<code class="docutils literal notranslate"><span class="pre">void</span></code>. For tuples and records, each component is recursively returned as
|
||||
<p>If the Cryptol return type is one of the <em>math types</em>, a sequence, tuple,
|
||||
or record, then the value is returned using output arguments,
|
||||
and the return type of the C function will be <code class="docutils literal notranslate"><span class="pre">void</span></code>.
|
||||
For tuples and records, each component is recursively returned as
|
||||
output arguments. When treated as an output argument, each C type <code class="docutils literal notranslate"><span class="pre">U</span></code> will be
|
||||
a pointer <code class="docutils literal notranslate"><span class="pre">U*</span></code> instead, except in the case of sequences, where the output and
|
||||
input versions are the same type, because it is already a pointer.</p>
|
||||
</div>
|
||||
<div class="section" id="quick-reference">
|
||||
a pointer <code class="docutils literal notranslate"><span class="pre">U*</span></code> instead, except in the case of <em>math types</em> and sequences,
|
||||
where the output and input versions are the same type, because it is already a pointer.</p>
|
||||
</section>
|
||||
<section id="quick-reference">
|
||||
<h3>Quick reference<a class="headerlink" href="#quick-reference" title="Permalink to this headline"></a></h3>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
@ -430,32 +489,48 @@ input versions are the same type, because it is already a pointer.</p>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">double</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">double*</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">[n]T</span></code></p></td>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">Integer</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpz_t</span></code></p></td>
|
||||
<td><p>N/A</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpz_t</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">Rational</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpq_t</span></code></p></td>
|
||||
<td><p>N/A</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpq_t</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">Z</span> <span class="pre">n</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpz_t</span></code></p></td>
|
||||
<td><p>N/A</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">mpz_t</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">[n1][n2]...[nk]T</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">U*</span></code></p></td>
|
||||
<td><p>N/A</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">U*</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">(T1,</span> <span class="pre">T2,</span> <span class="pre">...,</span> <span class="pre">Tn)</span></code></p></td>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">(T1,</span> <span class="pre">T2,</span> <span class="pre">...,</span> <span class="pre">Tn)</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">U1,</span> <span class="pre">U2,</span> <span class="pre">...,</span> <span class="pre">Un</span></code></p></td>
|
||||
<td><p>N/A</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">V1,</span> <span class="pre">V2,</span> <span class="pre">...,</span> <span class="pre">Vn</span></code></p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">{f1:</span> <span class="pre">T1,</span> <span class="pre">f2:</span> <span class="pre">T2,</span> <span class="pre">...,</span> <span class="pre">fn:</span> <span class="pre">Tn}</span></code></p></td>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">{f1:</span> <span class="pre">T1,</span> <span class="pre">f2:</span> <span class="pre">T2,</span> <span class="pre">...,</span> <span class="pre">fn:</span> <span class="pre">Tn}</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">U1,</span> <span class="pre">U2,</span> <span class="pre">...,</span> <span class="pre">Un</span></code></p></td>
|
||||
<td><p>N/A</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">V1,</span> <span class="pre">V2,</span> <span class="pre">...,</span> <span class="pre">Vn</span></code></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>where <code class="docutils literal notranslate"><span class="pre">K</span></code> is a constant number, <code class="docutils literal notranslate"><span class="pre">n</span></code> is a variable number, <code class="docutils literal notranslate"><span class="pre">Ti</span></code> is a type,
|
||||
<p>where <code class="docutils literal notranslate"><span class="pre">K</span></code> is a constant number, <code class="docutils literal notranslate"><span class="pre">ni</span></code> are variable numbers, <code class="docutils literal notranslate"><span class="pre">Ti</span></code> is a type,
|
||||
<code class="docutils literal notranslate"><span class="pre">Ui</span></code> is its C argument type, and <code class="docutils literal notranslate"><span class="pre">Vi</span></code> is its C output argument type.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="memory">
|
||||
</section>
|
||||
</section>
|
||||
<section id="memory">
|
||||
<h2>Memory<a class="headerlink" href="#memory" title="Permalink to this headline"></a></h2>
|
||||
<p>When pointers are involved, namely in the cases of sequences and output
|
||||
arguments, they point to memory. This memory is always allocated and deallocated
|
||||
by Cryptol; the C code does not need to manage this memory.</p>
|
||||
<p>For GMP types, Cryptol will call <code class="docutils literal notranslate"><span class="pre">init</span></code> and <code class="docutils literal notranslate"><span class="pre">clear</span></code> as needed.</p>
|
||||
<p>In the case of sequences, the pointer will point to an array. In the case of an
|
||||
output argument for a non-sequence type, the pointer will point to a piece of
|
||||
memory large enough to hold the given C type, and you should not try to access
|
||||
@ -464,25 +539,25 @@ any adjacent memory.</p>
|
||||
corresponding to the Cryptol values in the sequence. For output arguments, the
|
||||
memory may be uninitialized when passed to C, and the C code should not read
|
||||
from it. It must write to the memory the value it is returning.</p>
|
||||
</div>
|
||||
<div class="section" id="evaluation">
|
||||
</section>
|
||||
<section id="evaluation">
|
||||
<h2>Evaluation<a class="headerlink" href="#evaluation" title="Permalink to this headline"></a></h2>
|
||||
<p>All Cryptol arguments are fully evaluated when a foreign function is called.</p>
|
||||
</div>
|
||||
<div class="section" id="example">
|
||||
</section>
|
||||
<section id="example">
|
||||
<h2>Example<a class="headerlink" href="#example" title="Permalink to this headline"></a></h2>
|
||||
<p>The Cryptol signature</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">foreign</span> <span class="n">f</span> <span class="kt">:</span> <span class="p">{</span><span class="n">n</span><span class="p">}</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">)</span> <span class="ow">=></span> <span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="mi">10</span><span class="p">]</span> <span class="ow">-></span> <span class="p">{</span><span class="n">a</span> <span class="kt">:</span> <span class="kr">Bit</span><span class="p">,</span> <span class="n">b</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">64</span><span class="p">]}</span>
|
||||
<span class="ow">-></span> <span class="p">(</span><span class="kt">Float64</span><span class="p">,</span> <span class="p">[</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">][</span><span class="mi">20</span><span class="p">])</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">foreign</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">n</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="mi">10</span><span class="p">]</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kr">Bit</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">64</span><span class="p">]}</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">(</span><span class="kt">Float64</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">][</span><span class="mi">20</span><span class="p">])</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>corresponds to the C signature</p>
|
||||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">f</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">n</span><span class="p">,</span> <span class="kt">uint16_t</span> <span class="o">*</span><span class="n">in0</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">in1</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">in2</span><span class="p">,</span>
|
||||
<span class="kt">double</span> <span class="o">*</span><span class="n">out0</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="o">*</span><span class="n">out1</span><span class="p">);</span>
|
||||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">f</span><span class="p">(</span><span class="kt">size_t</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="o">*</span><span class="n">in0</span><span class="p">,</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">in1_a</span><span class="p">,</span><span class="w"> </span><span class="kt">uint64_t</span><span class="w"> </span><span class="n">in1_b</span><span class="p">,</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kt">double</span><span class="w"> </span><span class="o">*</span><span class="n">out_0</span><span class="p">,</span><span class="w"> </span><span class="kt">uint32_t</span><span class="w"> </span><span class="o">*</span><span class="n">out_1</span><span class="p">);</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Modules — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -97,26 +98,26 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="modules">
|
||||
<section id="modules">
|
||||
<h1>Modules<a class="headerlink" href="#modules" title="Permalink to this headline"></a></h1>
|
||||
<p>A <em>module</em> is used to group some related definitions. Each file may
|
||||
contain at most one top-level module.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">type</span> <span class="kt">T</span> <span class="ow">=</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="kr">type</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mi">10</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">10</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="section" id="hierarchical-module-names">
|
||||
<section id="hierarchical-module-names">
|
||||
<h2>Hierarchical Module Names<a class="headerlink" href="#hierarchical-module-names" title="Permalink to this headline"></a></h2>
|
||||
<p>Module may have either simple or <em>hierarchical</em> names.
|
||||
Hierarchical names are constructed by gluing together ordinary
|
||||
identifiers using the symbol <code class="docutils literal notranslate"><span class="pre">::</span></code>.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">Hash</span><span class="ow">::</span><span class="kt">SHA256</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">Hash</span><span class="ow">::</span><span class="kt">SHA256</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">sha256</span> <span class="ow">=</span> <span class="o">...</span>
|
||||
<span class="nf">sha256</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="o">...</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The structure in the name may be used to group together related
|
||||
@ -125,56 +126,56 @@ name to locate the file containing the definition of the module.
|
||||
For example, when searching for module <code class="docutils literal notranslate"><span class="pre">Hash::SHA256</span></code>, Cryptol
|
||||
will look for a file named <code class="docutils literal notranslate"><span class="pre">SHA256.cry</span></code> in a directory called
|
||||
<code class="docutils literal notranslate"><span class="pre">Hash</span></code>, contained in one of the directories specified by <code class="docutils literal notranslate"><span class="pre">CRYPTOLPATH</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="module-imports">
|
||||
</section>
|
||||
<section id="module-imports">
|
||||
<h2>Module Imports<a class="headerlink" href="#module-imports" title="Permalink to this headline"></a></h2>
|
||||
<p>To use the definitions from one module in another module, we use
|
||||
<code class="docutils literal notranslate"><span class="pre">import</span></code> declarations:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id1">
|
||||
<div class="code-block-caption"><span class="caption-text">module M</span><a class="headerlink" href="#id1" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// Provide some definitions</span>
|
||||
<span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// Provide some definitions</span><span class="w"></span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="literal-block-wrapper docutils container" id="id2">
|
||||
<div class="code-block-caption"><span class="caption-text">module N</span><a class="headerlink" href="#id2" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// Uses definitions from `M`</span>
|
||||
<span class="kr">module</span> <span class="nn">N</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// Uses definitions from `M`</span><span class="w"></span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">M</span> <span class="c1">// import all definitions from `M`</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="c1">// import all definitions from `M`</span><span class="w"></span>
|
||||
|
||||
<span class="nf">g</span> <span class="ow">=</span> <span class="n">f</span> <span class="c1">// `f` was imported from `M`</span>
|
||||
<span class="nf">g</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="c1">// `f` was imported from `M`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="import-lists">
|
||||
<section id="import-lists">
|
||||
<h3>Import Lists<a class="headerlink" href="#import-lists" title="Permalink to this headline"></a></h3>
|
||||
<p>Sometimes, we may want to import only some of the definitions
|
||||
from a module. To do so, we use an import declaration with
|
||||
an <em>import list</em>.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mh">0x02</span>
|
||||
<span class="nf">g</span> <span class="ow">=</span> <span class="mh">0x03</span>
|
||||
<span class="nf">h</span> <span class="ow">=</span> <span class="mh">0x04</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x02</span><span class="w"></span>
|
||||
<span class="nf">g</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x03</span><span class="w"></span>
|
||||
<span class="nf">h</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x04</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">N</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">M</span><span class="p">(</span><span class="n">f</span><span class="p">,</span><span class="n">g</span><span class="p">)</span> <span class="c1">// Imports only `f` and `g`, but not `h`</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">M</span><span class="p">(</span><span class="n">f</span><span class="p">,</span><span class="n">g</span><span class="p">)</span><span class="w"> </span><span class="c1">// Imports only `f` and `g`, but not `h`</span><span class="w"></span>
|
||||
|
||||
<span class="nf">x</span> <span class="ow">=</span> <span class="n">f</span> <span class="o">+</span> <span class="n">g</span>
|
||||
<span class="nf">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">g</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Using explicit import lists helps reduce name collisions.
|
||||
It also tends to make code easier to understand, because
|
||||
it makes it easy to see the source of definitions.</p>
|
||||
</div>
|
||||
<div class="section" id="hiding-imports">
|
||||
</section>
|
||||
<section id="hiding-imports">
|
||||
<h3>Hiding Imports<a class="headerlink" href="#hiding-imports" title="Permalink to this headline"></a></h3>
|
||||
<p>Sometimes a module may provide many definitions, and we want to use
|
||||
most of them but with a few exceptions (e.g., because those would
|
||||
@ -182,47 +183,47 @@ result to a name clash). In such situations it is convenient
|
||||
to use a <em>hiding</em> import:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id3">
|
||||
<div class="code-block-caption"><span class="caption-text">module M</span><a class="headerlink" href="#id3" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mh">0x02</span>
|
||||
<span class="nf">g</span> <span class="ow">=</span> <span class="mh">0x03</span>
|
||||
<span class="nf">h</span> <span class="ow">=</span> <span class="mh">0x04</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x02</span><span class="w"></span>
|
||||
<span class="nf">g</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x03</span><span class="w"></span>
|
||||
<span class="nf">h</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x04</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="literal-block-wrapper docutils container" id="id4">
|
||||
<div class="code-block-caption"><span class="caption-text">module N</span><a class="headerlink" href="#id4" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">N</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">M</span> <span class="k">hiding</span> <span class="p">(</span><span class="nf">h</span><span class="p">)</span> <span class="c1">// Import everything but `h`</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="k">hiding</span><span class="w"> </span><span class="p">(</span><span class="nf">h</span><span class="p">)</span><span class="w"> </span><span class="c1">// Import everything but `h`</span><span class="w"></span>
|
||||
|
||||
<span class="nf">x</span> <span class="ow">=</span> <span class="n">f</span> <span class="o">+</span> <span class="n">g</span>
|
||||
<span class="nf">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">g</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="qualified-module-imports">
|
||||
</section>
|
||||
<section id="qualified-module-imports">
|
||||
<h3>Qualified Module Imports<a class="headerlink" href="#qualified-module-imports" title="Permalink to this headline"></a></h3>
|
||||
<p>Another way to avoid name collisions is by using a
|
||||
<em>qualified</em> import.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id5">
|
||||
<div class="code-block-caption"><span class="caption-text">module M</span><a class="headerlink" href="#id5" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="literal-block-wrapper docutils container" id="id6">
|
||||
<div class="code-block-caption"><span class="caption-text">module N</span><a class="headerlink" href="#id6" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">N</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">M</span> <span class="k">as</span> <span class="n">P</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">P</span><span class="w"></span>
|
||||
|
||||
<span class="nf">g</span> <span class="ow">=</span> <span class="kt">P</span><span class="ow">::</span><span class="n">f</span>
|
||||
<span class="c1">// `f` was imported from `M`</span>
|
||||
<span class="c1">// but when used it needs to be prefixed by the qualifier `P`</span>
|
||||
<span class="nf">g</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">P</span><span class="ow">::</span><span class="n">f</span><span class="w"></span>
|
||||
<span class="c1">// `f` was imported from `M`</span><span class="w"></span>
|
||||
<span class="c1">// but when used it needs to be prefixed by the qualifier `P`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -231,9 +232,9 @@ that happen to have the same name but are defined in different modules.</p>
|
||||
<p>Qualified imports may be combined with import lists or hiding clauses:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id7">
|
||||
<div class="code-block-caption"><span class="caption-text">Example</span><a class="headerlink" href="#id7" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">import</span> <span class="nn">A</span> <span class="k">as</span> <span class="n">B</span> <span class="p">(</span><span class="n">f</span><span class="p">)</span> <span class="c1">// introduces B::f</span>
|
||||
<span class="kr">import</span> <span class="nn">X</span> <span class="k">as</span> <span class="n">Y</span> <span class="n">hiding</span> <span class="p">(</span><span class="n">f</span><span class="p">)</span> <span class="c1">// introduces everything but `f` from X</span>
|
||||
<span class="c1">// using the prefix `X`</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">import</span><span class="w"> </span><span class="nn">A</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">B</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="p">)</span><span class="w"> </span><span class="c1">// introduces B::f</span><span class="w"></span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">X</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">Y</span><span class="w"> </span><span class="n">hiding</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="p">)</span><span class="w"> </span><span class="c1">// introduces everything but `f` from X</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="c1">// using the prefix `X`</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -241,34 +242,34 @@ that happen to have the same name but are defined in different modules.</p>
|
||||
from different modules. For example:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id8">
|
||||
<div class="code-block-caption"><span class="caption-text">Example</span><a class="headerlink" href="#id8" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">import</span> <span class="nn">A</span> <span class="k">as</span> <span class="n">B</span>
|
||||
<span class="kr">import</span> <span class="nn">X</span> <span class="k">as</span> <span class="n">B</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">import</span><span class="w"> </span><span class="nn">A</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">B</span><span class="w"></span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">X</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">B</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Such declarations will introduces all definitions from <code class="docutils literal notranslate"><span class="pre">A</span></code> and <code class="docutils literal notranslate"><span class="pre">X</span></code>
|
||||
but to use them, you would have to qualify using the prefix <code class="docutils literal notranslate"><span class="pre">B::</span></code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="private-blocks">
|
||||
</section>
|
||||
</section>
|
||||
<section id="private-blocks">
|
||||
<h2>Private Blocks<a class="headerlink" href="#private-blocks" title="Permalink to this headline"></a></h2>
|
||||
<p>In some cases, definitions in a module might use helper
|
||||
functions that are not intended to be used outside the module.
|
||||
It is good practice to place such declarations in <em>private blocks</em>:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id9">
|
||||
<div class="code-block-caption"><span class="caption-text">Private blocks</span><a class="headerlink" href="#id9" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mh">0x01</span> <span class="o">+</span> <span class="n">helper1</span> <span class="o">+</span> <span class="n">helper2</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x01</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">helper2</span><span class="w"></span>
|
||||
|
||||
<span class="nf">private</span>
|
||||
<span class="nf">private</span><span class="w"></span>
|
||||
|
||||
<span class="n">helper1</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">helper1</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="n">helper2</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">helper2</span> <span class="ow">=</span> <span class="mi">3</span>
|
||||
<span class="w"> </span><span class="n">helper2</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">helper2</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -278,18 +279,18 @@ private then no additional indentation is needed as the <code class="docutils li
|
||||
extend to the end of the module.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id10">
|
||||
<div class="code-block-caption"><span class="caption-text">Private blocks</span><a class="headerlink" href="#id10" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mh">0x01</span> <span class="o">+</span> <span class="n">helper1</span> <span class="o">+</span> <span class="n">helper2</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x01</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">helper2</span><span class="w"></span>
|
||||
|
||||
<span class="nf">private</span>
|
||||
<span class="nf">private</span><span class="w"></span>
|
||||
|
||||
<span class="nf">helper1</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">helper1</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="nf">helper1</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">helper1</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="nf">helper2</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">helper2</span> <span class="ow">=</span> <span class="mi">3</span>
|
||||
<span class="nf">helper2</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">helper2</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -299,33 +300,33 @@ may contain multiple private blocks. For example, the following module
|
||||
is equivalent to the previous one:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id11">
|
||||
<div class="code-block-caption"><span class="caption-text">Private blocks</span><a class="headerlink" href="#id11" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="nf">f</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="nf">f</span> <span class="ow">=</span> <span class="mh">0x01</span> <span class="o">+</span> <span class="n">helper1</span> <span class="o">+</span> <span class="n">helper2</span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x01</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">helper2</span><span class="w"></span>
|
||||
|
||||
<span class="nf">private</span>
|
||||
<span class="n">helper1</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">helper1</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="nf">private</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">helper1</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="nf">private</span>
|
||||
<span class="n">helper2</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">helper2</span> <span class="ow">=</span> <span class="mi">3</span>
|
||||
<span class="nf">private</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">helper2</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">helper2</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="nested-modules">
|
||||
</section>
|
||||
<section id="nested-modules">
|
||||
<h2>Nested Modules<a class="headerlink" href="#nested-modules" title="Permalink to this headline"></a></h2>
|
||||
<p>Module may be declared withing other modules, using the <code class="docutils literal notranslate"><span class="pre">submodule</span></code> keword.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id12">
|
||||
<div class="code-block-caption"><span class="caption-text">Declaring a nested module called N</span><a class="headerlink" href="#id12" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mh">0x02</span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x02</span><span class="w"></span>
|
||||
|
||||
<span class="n">submodule</span> <span class="kt">N</span> <span class="kr">where</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">2</span>
|
||||
<span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -336,43 +337,43 @@ which works just like an ordinary import except that <code class="docutils liter
|
||||
to the name of a submodule.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id13">
|
||||
<div class="code-block-caption"><span class="caption-text">Using declarations from a submodule.</span><a class="headerlink" href="#id13" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mh">0x02</span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x02</span><span class="w"></span>
|
||||
|
||||
<span class="n">submodule</span> <span class="kt">N</span> <span class="kr">where</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">2</span>
|
||||
<span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">N</span> <span class="n">as</span> <span class="kt">P</span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">P</span><span class="w"></span>
|
||||
|
||||
<span class="n">z</span> <span class="ow">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="kt">P</span><span class="ow">::</span><span class="n">y</span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">P</span><span class="ow">::</span><span class="n">y</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Note that recursive definitions across modules are not allowed.
|
||||
So, in the previous example, it would be an error if <code class="docutils literal notranslate"><span class="pre">y</span></code> was
|
||||
to try to use <code class="docutils literal notranslate"><span class="pre">z</span></code> in its definition.</p>
|
||||
<div class="section" id="implicit-imports">
|
||||
<section id="implicit-imports">
|
||||
<h3>Implicit Imports<a class="headerlink" href="#implicit-imports" title="Permalink to this headline"></a></h3>
|
||||
<p>For convenience, we add an implicit qualified submodule import for
|
||||
each locally defined submodules.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id14">
|
||||
<div class="code-block-caption"><span class="caption-text">Making use of the implicit import for a submodule.</span><a class="headerlink" href="#id14" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mh">0x02</span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x02</span><span class="w"></span>
|
||||
|
||||
<span class="n">submodule</span> <span class="kt">N</span> <span class="kr">where</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">2</span>
|
||||
<span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="n">z</span> <span class="ow">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="kt">N</span><span class="ow">::</span><span class="n">y</span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">N</span><span class="ow">::</span><span class="n">y</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">N::y</span></code> works in the previous example because Cryptol added
|
||||
an implicit import <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">submoulde</span> <span class="pre">N</span> <span class="pre">as</span> <span class="pre">N</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="managing-module-names">
|
||||
</section>
|
||||
<section id="managing-module-names">
|
||||
<h3>Managing Module Names<a class="headerlink" href="#managing-module-names" title="Permalink to this headline"></a></h3>
|
||||
<p>The names of nested modules are managed by the module system just
|
||||
like the name of any other declaration in Cryptol. Thus, nested
|
||||
@ -388,38 +389,38 @@ another top-level module <code class="docutils literal notranslate"><span class=
|
||||
</div></blockquote>
|
||||
<div class="literal-block-wrapper docutils container" id="id15">
|
||||
<div class="code-block-caption"><span class="caption-text">Using a nested module from a different top-level module.</span><a class="headerlink" href="#id15" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">A</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">A</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mh">0x02</span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mh">0x02</span><span class="w"></span>
|
||||
|
||||
<span class="n">submodule</span> <span class="kt">N</span> <span class="kr">where</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">2</span>
|
||||
<span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">B</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">A</span> <span class="c1">// Brings `N` in scope</span>
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">N</span> <span class="c1">// Brings `y` in scope</span>
|
||||
<span class="n">z</span> <span class="ow">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">y</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">B</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">A</span><span class="w"> </span><span class="c1">// Brings `N` in scope</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="c1">// Brings `y` in scope</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="parameterized-modules">
|
||||
</section>
|
||||
</section>
|
||||
<section id="parameterized-modules">
|
||||
<h2>Parameterized Modules<a class="headerlink" href="#parameterized-modules" title="Permalink to this headline"></a></h2>
|
||||
<div class="section" id="interface-modules">
|
||||
<section id="interface-modules">
|
||||
<h3>Interface Modules<a class="headerlink" href="#interface-modules" title="Permalink to this headline"></a></h3>
|
||||
<p>An <em>interface module</em> describes the content of a module
|
||||
without providing a concrete implementation.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id16">
|
||||
<div class="code-block-caption"><span class="caption-text">An interface module.</span><a class="headerlink" href="#id16" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span> <span class="kr">module</span> <span class="nn">I</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span><span class="w"> </span><span class="kr">module</span><span class="w"> </span><span class="nn">I</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span> <span class="c1">// `n` is a numeric type</span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"> </span><span class="c1">// `n` is a numeric type</span><span class="w"></span>
|
||||
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="c1">// Assumptions about the declared numeric type</span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="c1">// Assumptions about the declared numeric type</span><span class="w"></span>
|
||||
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="c1">// A declarations of a constant</span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"> </span><span class="c1">// A declarations of a constant</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -427,39 +428,39 @@ without providing a concrete implementation.</p>
|
||||
other modules:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id17">
|
||||
<div class="code-block-caption"><span class="caption-text">A nested interface module</span><a class="headerlink" href="#id17" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">interface</span> <span class="n">submodule</span> <span class="kt">I</span> <span class="kr">where</span>
|
||||
<span class="w"> </span><span class="n">interface</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span> <span class="c1">// `n` is a numeric type</span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"> </span><span class="c1">// `n` is a numeric type</span><span class="w"></span>
|
||||
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="c1">// Assumptions about the declared numeric type</span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="c1">// Assumptions about the declared numeric type</span><span class="w"></span>
|
||||
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="c1">// A declarations of a constant</span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"> </span><span class="c1">// A declarations of a constant</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="importing-an-interface-module">
|
||||
</section>
|
||||
<section id="importing-an-interface-module">
|
||||
<h3>Importing an Interface Module<a class="headerlink" href="#importing-an-interface-module" title="Permalink to this headline"></a></h3>
|
||||
<p>A module may be parameterized by importing an interface,
|
||||
instead of a concrete module</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id18">
|
||||
<div class="code-block-caption"><span class="caption-text">A parameterized module</span><a class="headerlink" href="#id18" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// The interface desribes the parmaeters</span>
|
||||
<span class="nf">interface</span> <span class="kr">module</span> <span class="nn">I</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span>
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// The interface desribes the parmaeters</span><span class="w"></span>
|
||||
<span class="nf">interface</span><span class="w"> </span><span class="kr">module</span><span class="w"> </span><span class="nn">I</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="c1">// This module is parameterized</span>
|
||||
<span class="kr">module</span> <span class="nn">F</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span>
|
||||
<span class="c1">// This module is parameterized</span><span class="w"></span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"></span>
|
||||
|
||||
<span class="n">y</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -471,46 +472,46 @@ of an interface module maybe be linked to a different concrete
|
||||
module, as described in <a class="reference internal" href="#instantiating-modules"><span class="std std-ref">Instantiating a Parameterized Module</span></a>.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id19">
|
||||
<div class="code-block-caption"><span class="caption-text">Multiple interface parameters</span><a class="headerlink" href="#id19" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span> <span class="kr">module</span> <span class="nn">I</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span>
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span><span class="w"> </span><span class="kr">module</span><span class="w"> </span><span class="nn">I</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="kr">module</span> <span class="nn">F</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span> <span class="n">as</span> <span class="kt">I</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span> <span class="n">as</span> <span class="kt">J</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">I</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">J</span><span class="w"></span>
|
||||
|
||||
<span class="n">y</span> <span class="kt">:</span> <span class="p">[</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="kt">I</span><span class="ow">::</span><span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">I</span><span class="ow">::</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
|
||||
<span class="n">z</span> <span class="kt">:</span> <span class="p">[</span><span class="kt">J</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">z</span> <span class="ow">=</span> <span class="kt">J</span><span class="ow">::</span><span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="kt">J</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">J</span><span class="ow">::</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="interface-constraints">
|
||||
</section>
|
||||
<section id="interface-constraints">
|
||||
<h3>Interface Constraints<a class="headerlink" href="#interface-constraints" title="Permalink to this headline"></a></h3>
|
||||
<p>When working with multiple interfaces, it is to useful
|
||||
to be able to impose additional constraints on the
|
||||
types imported from the interface.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id20">
|
||||
<div class="code-block-caption"><span class="caption-text">Adding constraints to interface parameters</span><a class="headerlink" href="#id20" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span> <span class="kr">module</span> <span class="nn">I</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span>
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span><span class="w"> </span><span class="kr">module</span><span class="w"> </span><span class="nn">I</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="kr">module</span> <span class="nn">F</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span> <span class="n">as</span> <span class="kt">I</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span> <span class="n">as</span> <span class="kt">J</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">I</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">J</span><span class="w"></span>
|
||||
|
||||
<span class="n">interface</span> <span class="n">constraint</span> <span class="p">(</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span> <span class="o">==</span> <span class="kt">J</span><span class="ow">::</span><span class="n">n</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="n">interface</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kt">J</span><span class="ow">::</span><span class="n">n</span><span class="p">)</span><span class="w"></span>
|
||||
|
||||
<span class="n">y</span> <span class="kt">:</span> <span class="p">[</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="kt">I</span><span class="ow">::</span><span class="n">x</span> <span class="o">+</span> <span class="kt">J</span><span class="ow">::</span><span class="n">x</span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">I</span><span class="ow">::</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="kt">J</span><span class="ow">::</span><span class="n">x</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -518,30 +519,30 @@ types imported from the interface.</p>
|
||||
(the width of <code class="docutils literal notranslate"><span class="pre">x</span></code>) in both interfaces must be the
|
||||
same. Note that, of course, the two instantiations
|
||||
may provide different values for <code class="docutils literal notranslate"><span class="pre">x</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="instantiating-a-parameterized-module">
|
||||
</section>
|
||||
<section id="instantiating-a-parameterized-module">
|
||||
<span id="instantiating-modules"></span><h3>Instantiating a Parameterized Module<a class="headerlink" href="#instantiating-a-parameterized-module" title="Permalink to this headline"></a></h3>
|
||||
<p>To use a parameterized module we need to provide concrete
|
||||
implementations for the interfaces that it uses, and provide
|
||||
a name for the resulting module. This is done as follows:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id21">
|
||||
<div class="code-block-caption"><span class="caption-text">Instantiating a parameterized module using a single interface.</span><a class="headerlink" href="#id21" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span> <span class="kr">module</span> <span class="nn">I</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span>
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span><span class="w"> </span><span class="kr">module</span><span class="w"> </span><span class="nn">I</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">F</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"></span>
|
||||
|
||||
<span class="n">y</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">Impl</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="ow">=</span> <span class="mi">8</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">26</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">Impl</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">8</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">26</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">MyF</span> <span class="ow">=</span> <span class="kt">F</span> <span class="p">{</span> <span class="kt">Impl</span> <span class="p">}</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">MyF</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kt">Impl</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -553,26 +554,26 @@ we need to provide an implementation module for each
|
||||
interface, using a slight variation on the previous notation.</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id22">
|
||||
<div class="code-block-caption"><span class="caption-text">Instantiating a parameterized module by name.</span><a class="headerlink" href="#id22" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// I is defined as above</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// I is defined as above</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">F</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span> <span class="n">as</span> <span class="kt">I</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="kt">I</span> <span class="n">as</span> <span class="kt">J</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">I</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">J</span><span class="w"></span>
|
||||
|
||||
<span class="n">interface</span> <span class="n">constraint</span> <span class="p">(</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span> <span class="o">==</span> <span class="kt">J</span><span class="ow">::</span><span class="n">n</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="n">interface</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kt">J</span><span class="ow">::</span><span class="n">n</span><span class="p">)</span><span class="w"></span>
|
||||
|
||||
<span class="n">y</span> <span class="kt">:</span> <span class="p">[</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="kt">I</span><span class="ow">::</span><span class="n">x</span> <span class="o">+</span> <span class="kt">J</span><span class="ow">::</span><span class="n">x</span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="kt">I</span><span class="ow">::</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">I</span><span class="ow">::</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="kt">J</span><span class="ow">::</span><span class="n">x</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">Impl1</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="ow">=</span> <span class="mi">8</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">26</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">Impl1</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">8</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">26</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">Impl2</span> <span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="ow">=</span> <span class="mi">8</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">30</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">Impl2</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">8</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">30</span><span class="w"></span>
|
||||
|
||||
<span class="kr">module</span> <span class="nn">MyF</span> <span class="ow">=</span> <span class="kt">F</span> <span class="p">{</span> <span class="kt">I</span> <span class="ow">=</span> <span class="kt">Impl1</span><span class="p">,</span> <span class="kt">J</span> <span class="ow">=</span> <span class="kt">Impl</span> <span class="mi">2</span> <span class="p">}</span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">MyF</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Impl1</span><span class="p">,</span><span class="w"> </span><span class="kt">J</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Impl</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -587,11 +588,11 @@ order in which they are provided is not important.</p>
|
||||
just like any other module:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id23">
|
||||
<div class="code-block-caption"><span class="caption-text">Nested module instantiation.</span><a class="headerlink" href="#id23" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">Somewhere</span> <span class="c1">// defines G</span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">Somewhere</span><span class="w"> </span><span class="c1">// defines G</span><span class="w"></span>
|
||||
|
||||
<span class="n">submodule</span> <span class="kt">F</span> <span class="ow">=</span> <span class="n">submodule</span> <span class="kt">G</span> <span class="p">{</span> <span class="kt">I</span> <span class="p">}</span>
|
||||
<span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">G</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -605,16 +606,16 @@ preceded by the <code class="docutils literal notranslate"><span class="pre">sub
|
||||
use <code class="docutils literal notranslate"><span class="pre">submodule</span> <span class="pre">I</span></code> like this:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id24">
|
||||
<div class="code-block-caption"><span class="caption-text">Nested module instantiation.</span><a class="headerlink" href="#id24" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">Somewhere</span> <span class="c1">// defines G and I</span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">Somewhere</span><span class="w"> </span><span class="c1">// defines G and I</span><span class="w"></span>
|
||||
|
||||
<span class="n">submodule</span> <span class="kt">F</span> <span class="ow">=</span> <span class="n">submodule</span> <span class="kt">G</span> <span class="p">{</span> <span class="n">submodule</span> <span class="kt">I</span> <span class="p">}</span>
|
||||
<span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">G</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">I</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="anonymous-interface-modules">
|
||||
</section>
|
||||
<section id="anonymous-interface-modules">
|
||||
<h3>Anonymous Interface Modules<a class="headerlink" href="#anonymous-interface-modules" title="Permalink to this headline"></a></h3>
|
||||
<p>If we need to just parameterize a module by a couple of types/values,
|
||||
it is quite cumbersome to have to define a whole separate interface module.
|
||||
@ -622,65 +623,65 @@ To make this more convenient we provide the following notation for defining
|
||||
an anonymous interface and using it straight away:</p>
|
||||
<div class="literal-block-wrapper docutils container" id="id25">
|
||||
<div class="code-block-caption"><span class="caption-text">Simple parameterized module.</span><a class="headerlink" href="#id25" title="Permalink to this code"></a></div>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">parameter</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span>
|
||||
<span class="kr">type</span> <span class="n">constraint</span> <span class="p">(</span><span class="kr">fin</span> <span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="n">parameter</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">constraint</span><span class="w"> </span><span class="p">(</span><span class="kr">fin</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="n">f</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">f</span> <span class="ow">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">x</span>
|
||||
<span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">parameter</span></code> block defines an interface module and uses it.
|
||||
Note that the parameters may not use things defined in <code class="docutils literal notranslate"><span class="pre">M</span></code> as
|
||||
the interface is declared outside of <code class="docutils literal notranslate"><span class="pre">M</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="anonymous-instantiation-arguments">
|
||||
</section>
|
||||
<section id="anonymous-instantiation-arguments">
|
||||
<h3>Anonymous Instantiation Arguments<a class="headerlink" href="#anonymous-instantiation-arguments" title="Permalink to this headline"></a></h3>
|
||||
<p>Sometimes it is also a bit cumbersome to have to define a whole
|
||||
separate module just to pass it as an argument to some parameterized
|
||||
module. To make this more convenient we support the following notion
|
||||
for instantiation a module:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// A parameterized module</span>
|
||||
<span class="kr">module</span> <span class="nn">M</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="c1">// A parameterized module</span><span class="w"></span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">parameter</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="kt">:</span> <span class="o">#</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="n">parameter</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="o">#</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="n">f</span> <span class="kt">:</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span>
|
||||
<span class="n">f</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
|
||||
<span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="c1">// A module instantiation</span>
|
||||
<span class="kr">module</span> <span class="nn">N</span> <span class="ow">=</span> <span class="kt">M</span>
|
||||
<span class="kr">where</span>
|
||||
<span class="kr">type</span> <span class="n">n</span> <span class="ow">=</span> <span class="mi">32</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">11</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">helper</span>
|
||||
<span class="c1">// A module instantiation</span><span class="w"></span>
|
||||
<span class="kr">module</span><span class="w"> </span><span class="nn">N</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">M</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">type</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">32</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">11</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">helper</span><span class="w"></span>
|
||||
|
||||
<span class="n">helper</span> <span class="ow">=</span> <span class="mi">12</span>
|
||||
<span class="w"> </span><span class="n">helper</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">12</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The declarations in the <code class="docutils literal notranslate"><span class="pre">where</span></code> block are treated as the
|
||||
definition of an anonymous module which is passed as the argument
|
||||
to parameterized module <code class="docutils literal notranslate"><span class="pre">M</span></code>.</p>
|
||||
</div>
|
||||
<div class="section" id="anonymous-import-instantiations">
|
||||
</section>
|
||||
<section id="anonymous-import-instantiations">
|
||||
<h3>Anonymous Import Instantiations<a class="headerlink" href="#anonymous-import-instantiations" title="Permalink to this headline"></a></h3>
|
||||
<p>We provide syntactic sugar for importing and instantiating a functor
|
||||
at the same time:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">submodule</span> <span class="kt">F</span> <span class="kr">where</span>
|
||||
<span class="n">parameter</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">parameter</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">F</span> <span class="kr">where</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">where</span></code> block may is the same as the <code class="docutils literal notranslate"><span class="pre">where</span></code> block in
|
||||
@ -688,73 +689,73 @@ expressions: you may define type synonyms and values, but nothing else
|
||||
(e.g., no <code class="docutils literal notranslate"><span class="pre">newtype</span></code>).</p>
|
||||
<p>It is also possible to import and instantiate using an existing module
|
||||
like this:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">submodule</span> <span class="kt">F</span> <span class="kr">where</span>
|
||||
<span class="n">parameter</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">parameter</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
|
||||
<span class="nf">submodule</span> <span class="kt">G</span> <span class="kr">where</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">7</span>
|
||||
<span class="nf">submodule</span><span class="w"> </span><span class="kt">G</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
|
||||
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">F</span> <span class="p">{</span> <span class="n">submodule</span> <span class="kt">G</span> <span class="p">}</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">G</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Semantically, instantiating imports declare a local nested module and
|
||||
import it. For example, the <code class="docutils literal notranslate"><span class="pre">where</span></code> import from above is equivalent
|
||||
to the following declarations:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">submodule</span> <span class="kt">F</span> <span class="kr">where</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
|
||||
<span class="n">parameter</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="n">parameter</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="nf">submodule</span> <span class="kt">M</span> <span class="kr">where</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">2</span>
|
||||
<span class="nf">submodule</span><span class="w"> </span><span class="kt">M</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="nf">submodule</span> <span class="kt">N</span> <span class="ow">=</span> <span class="n">submodule</span> <span class="kt">F</span> <span class="p">{</span> <span class="n">submodule</span> <span class="kt">M</span> <span class="p">}</span>
|
||||
<span class="nf">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">M</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
|
||||
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">N</span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">N</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="passing-through-module-parameters">
|
||||
</section>
|
||||
<section id="passing-through-module-parameters">
|
||||
<h3>Passing Through Module Parameters<a class="headerlink" href="#passing-through-module-parameters" title="Permalink to this headline"></a></h3>
|
||||
<p>Occasionally it is useful to define a functor that instantiates <em>another</em>
|
||||
functor using the same parameters as the functor being defined
|
||||
(i.e., a functor parameter is passed on to another functor). This can
|
||||
be done by using the keyword <code class="docutils literal notranslate"><span class="pre">interface</span></code> followed by the name of a parameter
|
||||
in an instantiation. Here is an example:</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span> <span class="n">submodule</span> <span class="kt">S</span> <span class="kr">where</span>
|
||||
<span class="n">x</span> <span class="kt">:</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">interface</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">S</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// A functor, parameterized on S</span>
|
||||
<span class="nf">submodule</span> <span class="kt">G</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="n">submodule</span> <span class="kt">S</span>
|
||||
<span class="n">y</span> <span class="ow">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="c1">// A functor, parameterized on S</span><span class="w"></span>
|
||||
<span class="nf">submodule</span><span class="w"> </span><span class="kt">G</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">S</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Another functor, also parameterize on S</span>
|
||||
<span class="nf">submodule</span> <span class="kt">F</span> <span class="kr">where</span>
|
||||
<span class="kr">import</span> <span class="nn">interface</span> <span class="n">submodule</span> <span class="kt">S</span> <span class="n">as</span> <span class="kt">A</span>
|
||||
<span class="c1">// Another functor, also parameterize on S</span><span class="w"></span>
|
||||
<span class="nf">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">interface</span><span class="w"> </span><span class="n">submodule</span><span class="w"> </span><span class="kt">S</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">A</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Instantiate `G` using parameter `A` of `F`</span>
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">G</span> <span class="p">{</span> <span class="n">interface</span> <span class="kt">A</span> <span class="p">}</span> <span class="c1">// Brings `y` in scope</span>
|
||||
<span class="w"> </span><span class="c1">// Instantiate `G` using parameter `A` of `F`</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">G</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">interface</span><span class="w"> </span><span class="kt">A</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c1">// Brings `y` in scope</span><span class="w"></span>
|
||||
|
||||
<span class="n">z</span> <span class="ow">=</span> <span class="kt">A</span><span class="ow">::</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
|
||||
<span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">A</span><span class="ow">::</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
|
||||
|
||||
<span class="c1">// Brings `z` into scope: z = A::x + y</span>
|
||||
<span class="c1">// = 5 + (5 + 1)</span>
|
||||
<span class="c1">// = 11</span>
|
||||
<span class="kr">import</span> <span class="nn">submodule</span> <span class="kt">F</span> <span class="kr">where</span>
|
||||
<span class="n">x</span> <span class="ow">=</span> <span class="mi">5</span>
|
||||
<span class="c1">// Brings `z` into scope: z = A::x + y</span><span class="w"></span>
|
||||
<span class="c1">// = 5 + (5 + 1)</span><span class="w"></span>
|
||||
<span class="c1">// = 11</span><span class="w"></span>
|
||||
<span class="kr">import</span><span class="w"> </span><span class="nn">submodule</span><span class="w"> </span><span class="kt">F</span><span class="w"> </span><span class="kr">where</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">5</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Overloaded Operations — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -82,102 +83,102 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="overloaded-operations">
|
||||
<section id="overloaded-operations">
|
||||
<h1>Overloaded Operations<a class="headerlink" href="#overloaded-operations" title="Permalink to this headline"></a></h1>
|
||||
<div class="section" id="equality">
|
||||
<section id="equality">
|
||||
<h2>Equality<a class="headerlink" href="#equality" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Eq</span>
|
||||
<span class="p">(</span><span class="o">==</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Eq</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o">!=</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Eq</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o">===</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">}</span> <span class="p">(</span><span class="kt">Eq</span> <span class="n">b</span><span class="p">)</span> <span class="ow">=></span> <span class="p">(</span><span class="n">a</span> <span class="ow">-></span> <span class="n">b</span><span class="p">)</span> <span class="ow">-></span> <span class="p">(</span><span class="n">a</span> <span class="ow">-></span> <span class="n">b</span><span class="p">)</span> <span class="ow">-></span> <span class="p">(</span><span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span><span class="p">)</span>
|
||||
<span class="p">(</span><span class="o">!==</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">}</span> <span class="p">(</span><span class="kt">Eq</span> <span class="n">b</span><span class="p">)</span> <span class="ow">=></span> <span class="p">(</span><span class="n">a</span> <span class="ow">-></span> <span class="n">b</span><span class="p">)</span> <span class="ow">-></span> <span class="p">(</span><span class="n">a</span> <span class="ow">-></span> <span class="n">b</span><span class="p">)</span> <span class="ow">-></span> <span class="p">(</span><span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span><span class="p">)</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Eq</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">==</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Eq</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">!=</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Eq</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">===</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Eq</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="p">)</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">!==</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Eq</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="p">)</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="comparisons">
|
||||
</section>
|
||||
<section id="comparisons">
|
||||
<h2>Comparisons<a class="headerlink" href="#comparisons" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">Cmp</span>
|
||||
<span class="p">(</span><span class="o"><</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o">></span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o"><=</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o">>=</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="kr">min</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="kr">max</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="n">abs</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kr">Cmp</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Ring</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">Cmp</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o"><</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">></span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o"><=</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">>=</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">min</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="kr">max</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">abs</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kr">Cmp</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="signed-comparisons">
|
||||
</section>
|
||||
<section id="signed-comparisons">
|
||||
<h2>Signed Comparisons<a class="headerlink" href="#signed-comparisons" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">SignedCmp</span>
|
||||
<span class="p">(</span><span class="o"><$</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">SignedCmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o">>$</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">SignedCmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o"><=$</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">SignedCmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<span class="p">(</span><span class="o">>=$</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">SignedCmp</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="kr">Bit</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">SignedCmp</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o"><$</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">SignedCmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">>$</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">SignedCmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o"><=$</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">SignedCmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">>=$</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">SignedCmp</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kr">Bit</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="zero">
|
||||
</section>
|
||||
<section id="zero">
|
||||
<h2>Zero<a class="headerlink" href="#zero" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Zero</span>
|
||||
<span class="n">zero</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Zero</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Zero</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">zero</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Zero</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="logical-operations">
|
||||
</section>
|
||||
<section id="logical-operations">
|
||||
<h2>Logical Operations<a class="headerlink" href="#logical-operations" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Logic</span>
|
||||
<span class="p">(</span><span class="o">&&</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Logic</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">||</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Logic</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">^</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Logic</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="n">complement</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Logic</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Logic</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">&&</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Logic</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">||</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Logic</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">^</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Logic</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">complement</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Logic</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="basic-arithmetic">
|
||||
</section>
|
||||
<section id="basic-arithmetic">
|
||||
<h2>Basic Arithmetic<a class="headerlink" href="#basic-arithmetic" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Ring</span>
|
||||
<span class="n">fromInteger</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="kt">Integer</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">+</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">-</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="n">negate</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">^^</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">,</span> <span class="n">e</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Integral</span> <span class="n">e</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">e</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Ring</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">fromInteger</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">Integer</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">+</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">-</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">negate</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">^^</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="kt">Integral</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="integral-operations">
|
||||
</section>
|
||||
<section id="integral-operations">
|
||||
<h2>Integral Operations<a class="headerlink" href="#integral-operations" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Integral</span>
|
||||
<span class="p">(</span><span class="o">/</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Integral</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">%</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Integral</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">^^</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">,</span> <span class="n">e</span><span class="p">}</span> <span class="p">(</span><span class="kt">Ring</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Integral</span> <span class="n">e</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">e</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="n">toInteger</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Integral</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="kt">Integer</span>
|
||||
<span class="n">infFrom</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Integral</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="p">[</span><span class="kr">inf</span><span class="p">]</span><span class="n">a</span>
|
||||
<span class="n">infFromThen</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Integral</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="p">[</span><span class="kr">inf</span><span class="p">]</span><span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Integral</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">/</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Integral</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">%</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Integral</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">^^</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Ring</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="kt">Integral</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">toInteger</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Integral</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">infFrom</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Integral</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">[</span><span class="kr">inf</span><span class="p">]</span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">infFromThen</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Integral</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="p">[</span><span class="kr">inf</span><span class="p">]</span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="division">
|
||||
</section>
|
||||
<section id="division">
|
||||
<h2>Division<a class="headerlink" href="#division" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Field</span>
|
||||
<span class="n">recip</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Field</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<span class="p">(</span><span class="o">/.</span><span class="p">)</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Field</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span> <span class="ow">-></span> <span class="n">a</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Field</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">recip</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Field</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="p">(</span><span class="o">/.</span><span class="p">)</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Field</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="n">a</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="rounding">
|
||||
</section>
|
||||
<section id="rounding">
|
||||
<h2>Rounding<a class="headerlink" href="#rounding" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Round</span>
|
||||
<span class="n">ceiling</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Round</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="kt">Integer</span>
|
||||
<span class="n">floor</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Round</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="kt">Integer</span>
|
||||
<span class="n">trunc</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Round</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="kt">Integer</span>
|
||||
<span class="n">roundAway</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Round</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="kt">Integer</span>
|
||||
<span class="n">roundToEven</span> <span class="kt">:</span> <span class="p">{</span><span class="n">a</span><span class="p">}</span> <span class="p">(</span><span class="kt">Round</span> <span class="n">a</span><span class="p">)</span> <span class="ow">=></span> <span class="n">a</span> <span class="ow">-></span> <span class="kt">Integer</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kt">Round</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">ceiling</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Round</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">floor</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Round</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">trunc</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Round</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">roundAway</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Round</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="w"> </span><span class="n">roundToEven</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">}</span><span class="w"> </span><span class="p">(</span><span class="kt">Round</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-></span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Cryptol Reference Manual — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -70,7 +71,7 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="cryptol-reference-manual">
|
||||
<section id="cryptol-reference-manual">
|
||||
<h1>Cryptol Reference Manual<a class="headerlink" href="#cryptol-reference-manual" title="Permalink to this headline"></a></h1>
|
||||
<div class="toctree-wrapper compound">
|
||||
<p class="caption" role="heading"><span class="caption-text">Cryptol Reference Manual</span></p>
|
||||
@ -78,6 +79,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="BasicSyntax.html">Basic Syntax</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="BasicSyntax.html#declarations">Declarations</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="BasicSyntax.html#type-signatures">Type Signatures</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="BasicSyntax.html#numeric-constraint-guards">Numeric Constraint Guards</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="BasicSyntax.html#layout">Layout</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="BasicSyntax.html#comments">Comments</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="BasicSyntax.html#identifiers">Identifiers</a></li>
|
||||
@ -160,8 +162,9 @@
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#overall-structure">Overall structure</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#type-parameters">Type parameters</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#bit">Bit</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#integral-types">Integral types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#bit-vector-types">Bit Vector Types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#floating-point-types">Floating point types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#math-types">Math Types</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#sequences">Sequences</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#tuples-and-records">Tuples and records</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="FFI.html#type-synonyms">Type synonyms</a></li>
|
||||
@ -176,7 +179,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Type Declarations — Cryptol 2.11.0 documentation</title>
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
@ -75,11 +76,11 @@
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<div class="section" id="type-declarations">
|
||||
<section id="type-declarations">
|
||||
<h1>Type Declarations<a class="headerlink" href="#type-declarations" title="Permalink to this headline"></a></h1>
|
||||
<div class="section" id="type-synonyms">
|
||||
<section id="type-synonyms">
|
||||
<h2>Type Synonyms<a class="headerlink" href="#type-synonyms" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">type</span> <span class="kt">T</span> <span class="n">a</span> <span class="n">b</span> <span class="ow">=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="n">b</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">type</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="p">]</span><span class="w"> </span><span class="n">b</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A <code class="docutils literal notranslate"><span class="pre">type</span></code> declaration creates a synonym for a
|
||||
@ -89,10 +90,10 @@ use sites and is treated as though the user had instead
|
||||
written the body of the type synonym in line.
|
||||
Type synonyms may mention other synonyms, but it is not
|
||||
allowed to create a recursive collection of type synonyms.</p>
|
||||
</div>
|
||||
<div class="section" id="newtypes">
|
||||
</section>
|
||||
<section id="newtypes">
|
||||
<h2>Newtypes<a class="headerlink" href="#newtypes" title="Permalink to this headline"></a></h2>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">newtype</span> <span class="kt">NewT</span> <span class="n">a</span> <span class="n">b</span> <span class="ow">=</span> <span class="p">{</span> <span class="nb">seq</span> <span class="kt">:</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span><span class="n">b</span> <span class="p">}</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="kr">newtype</span><span class="w"> </span><span class="kt">NewT</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nb">seq</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="p">]</span><span class="n">b</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A <code class="docutils literal notranslate"><span class="pre">newtype</span></code> declaration declares a new named type which is defined by
|
||||
@ -108,8 +109,8 @@ recursive groups.</p>
|
||||
<p>Every <code class="docutils literal notranslate"><span class="pre">newtype</span></code> declaration brings into scope a new function with the
|
||||
same name as the type which can be used to create values of the
|
||||
newtype.</p>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">x</span> <span class="kt">:</span> <span class="kt">NewT</span> <span class="mi">3</span> <span class="kt">Integer</span>
|
||||
<span class="nf">x</span> <span class="ow">=</span> <span class="kt">NewT</span> <span class="p">{</span> <span class="nb">seq</span> <span class="ow">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span> <span class="p">}</span>
|
||||
<div class="highlight-cryptol notranslate"><div class="highlight"><pre><span></span><span class="nf">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="kt">NewT</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="kt">Integer</span><span class="w"></span>
|
||||
<span class="nf">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">NewT</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nb">seq</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Just as with records, field projections can be used directly on values
|
||||
@ -118,8 +119,8 @@ of newtypes to extract the values in the body of the type.</p>
|
||||
6
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -19,6 +19,54 @@ Type Signatures
|
||||
f,g : {a,b} (fin a) => [a] b
|
||||
|
||||
|
||||
Numeric Constraint Guards
|
||||
-------------------------
|
||||
|
||||
A declaration with a signature can use *numeric constraint guards*,
|
||||
which are used to change the behavior of a functoin depending on its
|
||||
numeric type parameters. For example:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
len : {n} (fin n) => [n]a -> Integer
|
||||
len xs | n == 0 => 0
|
||||
| n > 0 => 1 + len (drop `{1} xs)
|
||||
|
||||
Each behavior starts with ``|`` and lists some constraints on the numeric
|
||||
parameters to a declaration. When applied, the function will use the first
|
||||
definition that satisfies the provided numeric parameters.
|
||||
|
||||
Numeric constraint guards are quite similar to an ``if`` expression,
|
||||
except that decisions are based on *types* rather than values. There
|
||||
is also an important difference to simply using demotion and an
|
||||
actual ``if`` statement:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
len' : {n} (fin n) => [n]a -> Integer
|
||||
len' xs = if `n == 0 => 0
|
||||
| `n > 0 => 1 + len (drop `{1} xs)
|
||||
|
||||
The definition of ``len'`` is rejected, because the *value based* ``if``
|
||||
expression does provide the *type based* fact ``n >= 1`` which is
|
||||
required by ``drop `{1} xs``, while in ``len``, the type-checker
|
||||
locally-assumes the constraint ``n > 0`` in that constraint-guarded branch
|
||||
and so it can in fact determine that ``n >= 1``.
|
||||
|
||||
Requirements:
|
||||
- Numeric constraint guards only support constraints over numeric literals,
|
||||
such as ``fin``, ``<=``, ``==``, etc.
|
||||
Type constraint aliases can also be used as long as they only constrain
|
||||
numeric literals.
|
||||
- The numeric constraint guards of a declaration should be exhaustive. The
|
||||
type-checker will attempt to prove that the set of constraint guards is
|
||||
exhaustive, but if it can't then it will issue a non-exhaustive constraint
|
||||
guards warning. This warning is controlled by the environmental option
|
||||
``warnNonExhaustiveConstraintGuards``.
|
||||
- Each constraint guard is checked *independently* of the others, and there
|
||||
are no implict assumptions that the previous behaviors do not match---
|
||||
instead the programmer needs to specify all constraints explicitly
|
||||
in the guard.
|
||||
|
||||
Layout
|
||||
------
|
||||
|
@ -7,13 +7,26 @@ C (or other languages that use the C calling convention).
|
||||
Platform support
|
||||
----------------
|
||||
|
||||
The FFI is currently **not supported on Windows**, and only works on Unix-like
|
||||
systems (macOS and Linux).
|
||||
The FFI is built on top of the C ``libffi`` library, and as such, it should be
|
||||
portable across many operating systems. We have tested it to work on Linux,
|
||||
macOS, and Windows.
|
||||
|
||||
Basic usage
|
||||
-----------
|
||||
|
||||
Suppose we want to call the following C function:
|
||||
Suppose we want to implement the following function in C:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
add : [32] -> [32] -> [32]
|
||||
|
||||
In our Cryptol file, we declare it as a ``foreign`` function with no body:
|
||||
|
||||
.. code-block:: cryptol
|
||||
|
||||
foreign add : [32] -> [32] -> [32]
|
||||
|
||||
Then we write the following C function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -21,11 +34,16 @@ Suppose we want to call the following C function:
|
||||
return x + y;
|
||||
}
|
||||
|
||||
In our Cryptol file, we write a ``foreign`` declaration with no body:
|
||||
Cryptol can generate a C header file containing the appropriate function
|
||||
prototypes given the corresponding Cryptol ``foreign`` declarations with the
|
||||
``:generate-foreign-header`` command. You can then ``#include`` the generated
|
||||
header file in your C file to help write the C implementation.
|
||||
|
||||
.. code-block:: cryptol
|
||||
.. code-block::
|
||||
|
||||
foreign add : [32] -> [32] -> [32]
|
||||
Cryptol> :generate-foreign-header Example.cry
|
||||
Loading module Example
|
||||
Writing header to Example.h
|
||||
|
||||
The C code must first be compiled into a dynamically loaded shared library. When
|
||||
Cryptol loads the module containing the ``foreign`` declaration, it will look
|
||||
@ -35,6 +53,7 @@ extension it uses is platform-specific:
|
||||
|
||||
* On Linux, it looks for the extension ``.so``.
|
||||
* On macOS, it looks for the extension ``.dylib``.
|
||||
* On Windows, it looks for the extension ``.dll``.
|
||||
|
||||
For example, if you are on Linux and your ``foreign`` declaration is in
|
||||
``Foo.cry``, Cryptol will dynamically load ``Foo.so``. Then for each ``foreign``
|
||||
@ -61,9 +80,9 @@ The whole process would look something like this:
|
||||
|
||||
Note: Since Cryptol currently only accesses the compiled binary and not the C
|
||||
source, it has no way of checking that the Cryptol function type you declare in
|
||||
your Cryptol code actually matches the type of the C function. **It is your
|
||||
responsibility to make sure the types match up**. If they do not then there may
|
||||
be undefined behavior.
|
||||
your Cryptol code actually matches the type of the C function. It can generate
|
||||
the correct C headers but if the actual implementation does not match it there
|
||||
may be undefined behavior.
|
||||
|
||||
Compiling C code
|
||||
----------------
|
||||
@ -73,6 +92,7 @@ simple usages, you can do this manually with the following commands:
|
||||
|
||||
* Linux: ``cc -fPIC -shared Foo.c -o Foo.so``
|
||||
* macOS: ``cc -dynamiclib Foo.c -o Foo.dylib``
|
||||
* Windows: ``cc -fPIC -shared Foo.c -o Foo.dll``
|
||||
|
||||
Converting between Cryptol and C types
|
||||
--------------------------------------
|
||||
@ -81,6 +101,10 @@ This section describes how a given Cryptol function signature maps to a C
|
||||
function prototype. The FFI only supports a limited set of Cryptol types which
|
||||
have a clear translation into C.
|
||||
|
||||
This mapping can now be done automatically with the ``:generate-foreign-header``
|
||||
command mentioned above; however, this section is still worth reading to
|
||||
understand the supported types and what the resulting C parameters mean.
|
||||
|
||||
Overall structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -146,8 +170,8 @@ When converting to C, ``True`` is converted to ``1`` and ``False`` to ``0``.
|
||||
When converting to Cryptol, any nonzero number is converted to ``True`` and
|
||||
``0`` is converted to ``False``.
|
||||
|
||||
Integral types
|
||||
~~~~~~~~~~~~~~
|
||||
Bit Vector Types
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Let ``K : #`` be a Cryptol type. Note ``K`` must be an actual fixed numeric type
|
||||
and not a type variable.
|
||||
@ -167,7 +191,7 @@ are ignored. For instance, for the Cryptol type ``[4]``, the Cryptol value ``0xf
|
||||
: [4]`` is converted to the C value ``uint8_t`` ``0x0f``, and the C ``uint8_t``
|
||||
``0xaf`` is converted to the Cryptol value ``0xf : [4]``.
|
||||
|
||||
Note that words larger than 64 bits are not supported, since there is no
|
||||
Note that bit vectors larger than 64 bits are not supported, since there is no
|
||||
standard C integral type for that. You can split it into a sequence of smaller
|
||||
words first in Cryptol, then use the FFI conversion for sequences of words to
|
||||
handle it in C as an array.
|
||||
@ -185,23 +209,50 @@ Cryptol type C type
|
||||
Note: the Cryptol ``Float`` types are defined in the built-in module ``Float``.
|
||||
Other sizes of floating points are not supported.
|
||||
|
||||
Math Types
|
||||
~~~~~~~~~~
|
||||
|
||||
Values of high precision types and ``Z`` are represented using the GMP library.
|
||||
|
||||
============ ==========
|
||||
Cryptol type C type
|
||||
============ ==========
|
||||
``Integer`` ``mpz_t``
|
||||
``Rational`` ``mpq_t``
|
||||
``Z n`` ``mpz_t``
|
||||
============ ==========
|
||||
|
||||
Results of these types are returned in *output* parameters,
|
||||
but since both ``mpz_t`` and ``mpz_q`` are already reference
|
||||
types there is no need for an extra pointer in the result.
|
||||
For example, a Cryptol function ``f : Integer -> Rational``
|
||||
would correspond to a C function ``f(mpz_t in, mpq_t out)``.
|
||||
|
||||
All parameters passed to the C function (no matter if
|
||||
input or output) are managed by Cryptol, which takes care
|
||||
to call ``init`` before their use and ``clear`` after.
|
||||
|
||||
|
||||
Sequences
|
||||
~~~~~~~~~
|
||||
|
||||
Let ``n : #`` be a Cryptol type, possibly containing type variables, that
|
||||
satisfies ``fin n``, and ``T`` be one of the above Cryptol *integral types* or
|
||||
*floating point types*. Let ``U`` be the C type that ``T`` corresponds to.
|
||||
Let ``n1, n2, ..., nk : #`` be Cryptol types (with ``k >= 1``), possibly
|
||||
containing type variables, that satisfy ``fin n1, fin n2, ..., fin nk``, and
|
||||
``T`` be one of the above Cryptol *bit vector types*, *floating point types*, or
|
||||
*math types*. Let ``U`` be the C type that ``T`` corresponds to.
|
||||
|
||||
============ ===========
|
||||
Cryptol type C type
|
||||
============ ===========
|
||||
``[n]T`` ``U*``
|
||||
============ ===========
|
||||
==================== ===========
|
||||
Cryptol type C type
|
||||
==================== ===========
|
||||
``[n1][n2]...[nk]T`` ``U*``
|
||||
==================== ===========
|
||||
|
||||
The C pointer points to an array of ``n`` elements of type ``U``. Note that,
|
||||
while the length of the array itself is not explicitly passed along with the
|
||||
pointer, any type arguments contained in the size are passed as C ``size_t``'s
|
||||
earlier, so the C code can always know the length of the array.
|
||||
The C pointer points to an array of ``n1 * n2 * ... * nk`` elements of type
|
||||
``U``. If the sequence is multidimensional, it is flattened and stored
|
||||
contiguously, similar to the representation of multidimensional arrays in C.
|
||||
Note that, while the dimensions of the array itself are not explicitly passed
|
||||
along with the pointer, any type arguments contained in the size are passed as C
|
||||
``size_t``'s earlier, so the C code can always know the dimensions of the array.
|
||||
|
||||
Tuples and records
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
@ -232,17 +283,18 @@ type synonyms in ``foreign`` declarations to improve readability.
|
||||
Return values
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
If the Cryptol return type is ``Bit`` or one of the above *integral types* or
|
||||
If the Cryptol return type is ``Bit`` or one of the above *bit vector types* or
|
||||
*floating point types*, the value is returned directly from the C function. In
|
||||
that case, the return type of the C function will be the C type corresponding to
|
||||
the Cryptol type, and no extra arguments are added.
|
||||
|
||||
If the Cryptol return type is a sequence, tuple, or record, then the value is
|
||||
returned using output arguments, and the return type of the C function will be
|
||||
``void``. For tuples and records, each component is recursively returned as
|
||||
If the Cryptol return type is one of the *math types*, a sequence, tuple,
|
||||
or record, then the value is returned using output arguments,
|
||||
and the return type of the C function will be ``void``.
|
||||
For tuples and records, each component is recursively returned as
|
||||
output arguments. When treated as an output argument, each C type ``U`` will be
|
||||
a pointer ``U*`` instead, except in the case of sequences, where the output and
|
||||
input versions are the same type, because it is already a pointer.
|
||||
a pointer ``U*`` instead, except in the case of *math types* and sequences,
|
||||
where the output and input versions are the same type, because it is already a pointer.
|
||||
|
||||
Quick reference
|
||||
~~~~~~~~~~~~~~~
|
||||
@ -258,12 +310,15 @@ Cryptol type (or kind) C argument type(s) C return type C output
|
||||
``[K]Bit`` where ``32 < K <= 64`` ``uint64_t`` ``uint64_t`` ``uint64_t*``
|
||||
``Float32`` ``float`` ``float`` ``float*``
|
||||
``Float64`` ``double`` ``double`` ``double*``
|
||||
``[n]T`` ``U*`` N/A ``U*``
|
||||
``Integer`` ``mpz_t`` N/A ``mpz_t``
|
||||
``Rational`` ``mpq_t`` N/A ``mpq_t``
|
||||
``Z n`` ``mpz_t`` N/A ``mpz_t``
|
||||
``[n1][n2]...[nk]T`` ``U*`` N/A ``U*``
|
||||
``(T1, T2, ..., Tn)`` ``U1, U2, ..., Un`` N/A ``V1, V2, ..., Vn``
|
||||
``{f1: T1, f2: T2, ..., fn: Tn}`` ``U1, U2, ..., Un`` N/A ``V1, V2, ..., Vn``
|
||||
================================== =================== ============= =========================
|
||||
|
||||
where ``K`` is a constant number, ``n`` is a variable number, ``Ti`` is a type,
|
||||
where ``K`` is a constant number, ``ni`` are variable numbers, ``Ti`` is a type,
|
||||
``Ui`` is its C argument type, and ``Vi`` is its C output argument type.
|
||||
|
||||
Memory
|
||||
@ -273,6 +328,8 @@ When pointers are involved, namely in the cases of sequences and output
|
||||
arguments, they point to memory. This memory is always allocated and deallocated
|
||||
by Cryptol; the C code does not need to manage this memory.
|
||||
|
||||
For GMP types, Cryptol will call ``init`` and ``clear`` as needed.
|
||||
|
||||
In the case of sequences, the pointer will point to an array. In the case of an
|
||||
output argument for a non-sequence type, the pointer will point to a piece of
|
||||
memory large enough to hold the given C type, and you should not try to access
|
||||
@ -302,5 +359,5 @@ corresponds to the C signature
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void f(size_t n, uint16_t *in0, uint8_t in1, uint64_t in2,
|
||||
double *out0, uint32_t *out1);
|
||||
void f(size_t n, uint16_t *in0, uint8_t in1_a, uint64_t in1_b,
|
||||
double *out_0, uint32_t *out_1);
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* _sphinx_javascript_frameworks_compat.js
|
||||
* ~~~~~~~~~~
|
||||
*
|
||||
* Compatability shim for jQuery and underscores.js.
|
||||
*
|
||||
* WILL BE REMOVED IN Sphinx 6.0
|
||||
* xref RemovedInSphinx60Warning
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* select a different prefix for underscore
|
||||
*/
|
||||
$u = _.noConflict();
|
||||
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
if (!x) {
|
||||
return x
|
||||
}
|
||||
return decodeURIComponent(x.replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
/**
|
||||
* small helper function to urlencode strings
|
||||
*/
|
||||
jQuery.urlencode = encodeURIComponent;
|
||||
|
||||
/**
|
||||
* This function returns the parsed url parameters of the
|
||||
* current request. Multiple values per key are supported,
|
||||
* it will always return arrays of strings for the value parts.
|
||||
*/
|
||||
jQuery.getQueryParameters = function(s) {
|
||||
if (typeof s === 'undefined')
|
||||
s = document.location.search;
|
||||
var parts = s.substr(s.indexOf('?') + 1).split('&');
|
||||
var result = {};
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var tmp = parts[i].split('=', 2);
|
||||
var key = jQuery.urldecode(tmp[0]);
|
||||
var value = jQuery.urldecode(tmp[1]);
|
||||
if (key in result)
|
||||
result[key].push(value);
|
||||
else
|
||||
result[key] = [value];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* highlight a given string on a jquery object by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
jQuery.fn.highlightText = function(text, className) {
|
||||
function highlight(node, addItems) {
|
||||
if (node.nodeType === 3) {
|
||||
var val = node.nodeValue;
|
||||
var pos = val.toLowerCase().indexOf(text);
|
||||
if (pos >= 0 &&
|
||||
!jQuery(node.parentNode).hasClass(className) &&
|
||||
!jQuery(node.parentNode).hasClass("nohighlight")) {
|
||||
var span;
|
||||
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
|
||||
if (isInSVG) {
|
||||
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
||||
} else {
|
||||
span = document.createElement("span");
|
||||
span.className = className;
|
||||
}
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling));
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
if (isInSVG) {
|
||||
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
var bbox = node.parentElement.getBBox();
|
||||
rect.x.baseVal.value = bbox.x;
|
||||
rect.y.baseVal.value = bbox.y;
|
||||
rect.width.baseVal.value = bbox.width;
|
||||
rect.height.baseVal.value = bbox.height;
|
||||
rect.setAttribute('class', className);
|
||||
addItems.push({
|
||||
"parent": node.parentNode,
|
||||
"target": rect});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!jQuery(node).is("button, select, textarea")) {
|
||||
jQuery.each(node.childNodes, function() {
|
||||
highlight(this, addItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
var addItems = [];
|
||||
var result = this.each(function() {
|
||||
highlight(this, addItems);
|
||||
});
|
||||
for (var i = 0; i < addItems.length; ++i) {
|
||||
jQuery(addItems[i].parent).before(addItems[i].target);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
* backward compatibility for jQuery.browser
|
||||
* This will be supported until firefox bug is fixed.
|
||||
*/
|
||||
if (!jQuery.browser) {
|
||||
jQuery.uaMatch = function(ua) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(msie) ([\w.]+)/.exec(ua) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || "",
|
||||
version: match[ 2 ] || "0"
|
||||
};
|
||||
};
|
||||
jQuery.browser = {};
|
||||
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
|
||||
}
|
@ -731,8 +731,9 @@ dl.glossary dt {
|
||||
|
||||
.classifier:before {
|
||||
font-style: normal;
|
||||
margin: 0.5em;
|
||||
margin: 0 0.5em;
|
||||
content: ":";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
abbr, acronym {
|
||||
|
10872
docs/RefMan/_build/html/_static/jquery-3.5.1.js
vendored
10872
docs/RefMan/_build/html/_static/jquery-3.5.1.js
vendored
File diff suppressed because it is too large
Load Diff
10881
docs/RefMan/_build/html/_static/jquery-3.6.0.js
vendored
10881
docs/RefMan/_build/html/_static/jquery-3.6.0.js
vendored
File diff suppressed because it is too large
Load Diff
10881
docs/RefMan/_build/html/_static/jquery.js
vendored
10881
docs/RefMan/_build/html/_static/jquery.js
vendored
File diff suppressed because one or more lines are too long
@ -1,21 +1,26 @@
|
||||
pre { line-height: 125%; }
|
||||
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight { background: #f8f8f8; }
|
||||
.highlight .c { color: #408080; font-style: italic } /* Comment */
|
||||
.highlight { background: #f8f8f8; }
|
||||
.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
|
||||
.highlight .err { border: 1px solid #FF0000 } /* Error */
|
||||
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
|
||||
.highlight .o { color: #666666 } /* Operator */
|
||||
.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
|
||||
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
|
||||
.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
|
||||
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
|
||||
.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
|
||||
.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #9C6500 } /* Comment.Preproc */
|
||||
.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
|
||||
.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
|
||||
.highlight .gd { color: #A00000 } /* Generic.Deleted */
|
||||
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||
.highlight .gr { color: #E40000 } /* Generic.Error */
|
||||
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { color: #00A000 } /* Generic.Inserted */
|
||||
.highlight .go { color: #888888 } /* Generic.Output */
|
||||
.highlight .gi { color: #008400 } /* Generic.Inserted */
|
||||
.highlight .go { color: #717171 } /* Generic.Output */
|
||||
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
||||
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
@ -28,15 +33,15 @@
|
||||
.highlight .kt { color: #B00040 } /* Keyword.Type */
|
||||
.highlight .m { color: #666666 } /* Literal.Number */
|
||||
.highlight .s { color: #BA2121 } /* Literal.String */
|
||||
.highlight .na { color: #7D9029 } /* Name.Attribute */
|
||||
.highlight .na { color: #687822 } /* Name.Attribute */
|
||||
.highlight .nb { color: #008000 } /* Name.Builtin */
|
||||
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||||
.highlight .no { color: #880000 } /* Name.Constant */
|
||||
.highlight .nd { color: #AA22FF } /* Name.Decorator */
|
||||
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
|
||||
.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
|
||||
.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
|
||||
.highlight .nf { color: #0000FF } /* Name.Function */
|
||||
.highlight .nl { color: #A0A000 } /* Name.Label */
|
||||
.highlight .nl { color: #767600 } /* Name.Label */
|
||||
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||||
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
|
||||
.highlight .nv { color: #19177C } /* Name.Variable */
|
||||
@ -53,11 +58,11 @@
|
||||
.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
|
||||
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
|
||||
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
|
||||
.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
|
||||
.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #008000 } /* Literal.String.Other */
|
||||
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
|
||||
.highlight .sr { color: #A45A77 } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
|
||||
|
@ -328,7 +328,12 @@ var Search = {
|
||||
var results = [];
|
||||
|
||||
for (var prefix in objects) {
|
||||
for (var name in objects[prefix]) {
|
||||
if (!(objects[prefix] instanceof Array)) {
|
||||
objects[prefix] = Object.entries(objects[prefix]).map(([name, match]) => [...match, name]);
|
||||
}
|
||||
for (var iMatch = 0; iMatch != objects[prefix].length; ++iMatch) {
|
||||
var match = objects[prefix][iMatch];
|
||||
var name = match[4];
|
||||
var fullname = (prefix ? prefix + '.' : '') + name;
|
||||
var fullnameLower = fullname.toLowerCase()
|
||||
if (fullnameLower.indexOf(object) > -1) {
|
||||
@ -342,7 +347,6 @@ var Search = {
|
||||
} else if (parts[parts.length - 1].indexOf(object) > -1) {
|
||||
score += Scorer.objPartialMatch;
|
||||
}
|
||||
var match = objects[prefix][name];
|
||||
var objname = objnames[match[1]][2];
|
||||
var title = titles[match[0]];
|
||||
// If more than one term searched for, we require other words to be
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
313
docs/ffi-presentation.md
Normal file
313
docs/ffi-presentation.md
Normal file
@ -0,0 +1,313 @@
|
||||
---
|
||||
title: Cryptol FFI
|
||||
author: Bretton
|
||||
date: 2022-09-02
|
||||
---
|
||||
|
||||
# Cryptol FFI
|
||||
|
||||
- Call functions written in C
|
||||
|
||||
---
|
||||
|
||||
# Why?
|
||||
|
||||
- Performance
|
||||
- Use existing code in C
|
||||
- Do things that Cryptol can't do?
|
||||
|
||||
---
|
||||
|
||||
# What does it look like?
|
||||
|
||||
```cry
|
||||
foreign add : [32] -> [32] -> [32]
|
||||
```
|
||||
|
||||
```c
|
||||
uint32_t add(uint32_t x, uint32_t y) {
|
||||
return x + y;
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
Main> add 1 2
|
||||
0x00000003
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# How do you use it?
|
||||
|
||||
```
|
||||
+-------------+
|
||||
| Example.cry | ------------------------+ +---------------Cryptol---------------+
|
||||
+-------------+ | | Cryptol> :l Example.cry |
|
||||
| | Loading module Cryptol |
|
||||
+-----------+ +---------------+ +------>| Loading module Example |
|
||||
| Example.c | =====> | Example.so | -------->| Loading dynamic library Example.so |
|
||||
+-----------+ cc | Example.dylib | dlopen | Example> add 1 2 |
|
||||
+---------------+ | 0x00000003 |
|
||||
+-------------------------------------+
|
||||
```
|
||||
|
||||
- Find shared library with same name as Cryptol file
|
||||
- Dynamically load with `dlopen`
|
||||
- Bind each `foreign` function with `dlsym`
|
||||
- Windows not supported yet
|
||||
- Compile it yourself (for now...)
|
||||
- `cc -fPIC -shared Example.c -o Example.so`
|
||||
- `cc -dynamiclib Example.c -o Example.dylib`
|
||||
|
||||
---
|
||||
|
||||
# How does it work?
|
||||
|
||||
- Since Cryptol is interpreted, number/types of arguments to foreign functions are not known statically
|
||||
- `libffi` calls functions with the right calling conventions given interface at runtime
|
||||
- Rant about `libffi` in Haskell
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## Basic types
|
||||
|
||||
Cryptol | C
|
||||
--- | ---
|
||||
Bit | uint8_t
|
||||
[K]Bit, 0 <= K <= 8 | uint8_t
|
||||
[K]Bit, 8 < K <= 16 | uint16_t
|
||||
[K]Bit, 16 < K <= 32 | uint32_t
|
||||
[K]Bit, 32 < K <= 64 | uint64_t
|
||||
Float32 | float
|
||||
Float64 | double
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## Multiple arguments?
|
||||
|
||||
Cryptol | C
|
||||
--- | ---
|
||||
A -> B -> ... -> Z | Z' (A', B', ...)
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## More complex types
|
||||
|
||||
- So far it has been pretty simple
|
||||
- How about sequences? I guess we need arrays
|
||||
- Who allocates the memory?
|
||||
- Who owns the memory?
|
||||
- How are they passed vs returned?
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## Sequences
|
||||
|
||||
Cryptol | C
|
||||
--- | ---
|
||||
[n1][n2]...[nk]T | U*
|
||||
|
||||
where
|
||||
|
||||
T | U
|
||||
--- | ---
|
||||
[K]Bit, 0 <= K <= 8 | uint8_t
|
||||
[K]Bit, 8 < K <= 16 | uint16_t
|
||||
[K]Bit, 16 < K <= 32 | uint32_t
|
||||
[K]Bit, 32 < K <= 64 | uint64_t
|
||||
Float32 | float
|
||||
Float64 | double
|
||||
|
||||
- Cryptol allocates and owns all memory
|
||||
- Sequence as Cryptol parameter: `const U*` C parameter
|
||||
- Sequence as Cryptol return type: `U*` C output parameter
|
||||
- Passed after Cryptol parameters
|
||||
- Return type of C function is `void`
|
||||
- Multidimensional sequences: flatten (except the [K]Bit part)
|
||||
- How about n1, n2, ..., nk?
|
||||
- Must be `fin`
|
||||
|
||||
---
|
||||
|
||||
# Supported ~~types~~ kinds?
|
||||
|
||||
## Numeric type arguments
|
||||
|
||||
Cryptol | C
|
||||
--- | ---
|
||||
\# | size_t
|
||||
|
||||
- Must be `fin`
|
||||
- Type arguments are passed before any value arguments
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## Tuples and records as parameters
|
||||
|
||||
- Passed as separate arguments
|
||||
|
||||
Cryptol | C (multiple!)
|
||||
--- | ---
|
||||
(T1, T2, ..., Tn) | U1, U2, ..., Un
|
||||
{s1: T1, s2: T2, ..., sn: Tn} | U1, U2, ..., Un
|
||||
|
||||
where
|
||||
|
||||
Cryptol | C
|
||||
--- | ---
|
||||
Ti | Ui
|
||||
|
||||
Note:
|
||||
- Order of record fields is however it's written in the type in the source code
|
||||
- Uncurried and curried Cryptol functions correspond to the same C function
|
||||
- () corresponds to no arguments at all
|
||||
- Can be nested
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## Tuples and records as return types
|
||||
|
||||
- Returned as separate output parameters
|
||||
- This means the component types need to become pointers
|
||||
- Except for sequences which are already pointers
|
||||
|
||||
Cryptol | C (multiple!)
|
||||
--- | ---
|
||||
(T1, T2, ..., Tn) | V1, V2, ..., Vn
|
||||
{s1: T1, s2: T2, ..., sn: Tn} | V1, V2, ..., Vn
|
||||
|
||||
where
|
||||
|
||||
Cryptol parameter | C
|
||||
--- | ---
|
||||
Ti | Ui
|
||||
|
||||
and Vi = if Ui is a pointer type then Ui else Ui*
|
||||
|
||||
Note:
|
||||
- Return type of C function is `void`
|
||||
- () corresponds to no return value and no output arguments
|
||||
- Can be nested
|
||||
|
||||
---
|
||||
|
||||
# Supported types
|
||||
|
||||
## Type synonyms
|
||||
|
||||
- Type synonyms are expanded before applying the previous rules
|
||||
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
```cry
|
||||
foreign f : {n} (fin n) => [n][10] -> {a : Bit, b : [64]} -> (Float64, [n + 1][20])
|
||||
```
|
||||
|
||||
```c
|
||||
void f(size_t n, uint16_t *in0, uint8_t in1, uint64_t in2,
|
||||
double *out0, uint32_t *out1);
|
||||
```
|
||||
|
||||
- More examples in FFI tests
|
||||
|
||||
---
|
||||
|
||||
# Evaluation
|
||||
|
||||
- All arguments are fully evaluated
|
||||
- Result will be fully evaluated too (of course)
|
||||
|
||||
---
|
||||
|
||||
# Questionable uses of FFI
|
||||
|
||||
```cry
|
||||
foreign print : {n} (fin n) => [n][8] -> ()
|
||||
```
|
||||
|
||||
```c
|
||||
void print(size_t n, char *s) {
|
||||
printf("%.*s\n", (int) n, s);
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
Main> print "Hello world!"
|
||||
Hello world!
|
||||
()
|
||||
```
|
||||
|
||||
```cry
|
||||
foreign launchMissiles : ()
|
||||
```
|
||||
|
||||
etc
|
||||
|
||||
- Cryptol functions should be pure
|
||||
- Beware of laziness
|
||||
|
||||
---
|
||||
|
||||
# AES example
|
||||
|
||||
- Replacement for `SuiteB` module using AES-NI for AES functions
|
||||
- ~5.5x faster
|
||||
- But could actually be much faster, if not limited to 1 block
|
||||
|
||||
---
|
||||
|
||||
# Somewhat interesting(?) implementation details
|
||||
|
||||
- `ForeignPtr` for `dlclose`
|
||||
- Interesting types in FFI marshalling
|
||||
```hs
|
||||
getMarshalBasicArg :: FFIBasicType ->
|
||||
(forall a. FFIArg a => (GenValue Concrete -> Eval a) -> b) -> b
|
||||
data GetRet = GetRet
|
||||
{ getRetAsValue :: forall a. FFIRet a => IO a
|
||||
, getRetAsOutArgs :: [SomeFFIArg] -> IO () }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Future work
|
||||
|
||||
- Automatically generate header files from `foreign` declarations
|
||||
- Support Windows
|
||||
- Support Integer/Z
|
||||
- Cryptol implementation of `foreign` functions + SAW integration
|
||||
|
||||
---
|
||||
|
||||
# Other stuff (not FFI)
|
||||
|
||||
- `:time` command for benchmarking evaluation of Cryptol expressions
|
||||
- Evaluates it a bunch of times and reports the average time
|
||||
- Import specific operators
|
||||
- `import M ((<+>))`
|
||||
- Fixed fixity (fixedity?) of prefix operators
|
||||
- `-x**2` parses as `-(x**2)` not `(-x)**2`
|
||||
|
||||
---
|
||||
|
||||
# Thank you!
|
||||
|
||||
- Iavor, Eddy, Ryan
|
||||
|
||||
# Questions?
|
||||
|
||||
- Why is the Cryptol logo a water drop
|
2
examples/SuiteB_FFI/.gitignore
vendored
Normal file
2
examples/SuiteB_FFI/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.so
|
||||
*.dylib
|
46
examples/SuiteB_FFI/Makefile
Normal file
46
examples/SuiteB_FFI/Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
SHELL = /bin/bash
|
||||
CFLAGS = -O3 -Wall -Wextra -Werror
|
||||
|
||||
.PHONY: test perf-test perf-bench clean
|
||||
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
|
||||
ifdef PORTABLE
|
||||
CFLAGS += -maes -mssse3
|
||||
else
|
||||
CFLAGS += -march=native
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(shell uname),Darwin)
|
||||
|
||||
SO = SuiteB_FFI.dylib
|
||||
TEST_OUT_EXT = .stdout.darwin
|
||||
|
||||
$(SO): SuiteB_FFI.c
|
||||
$(CC) $(CFLAGS) -dynamiclib $< -o $@
|
||||
|
||||
else
|
||||
|
||||
SO = SuiteB_FFI.so
|
||||
TEST_OUT_EXT = .stdout
|
||||
|
||||
$(SO): SuiteB_FFI.c
|
||||
$(CC) $(CFLAGS) -fPIC -shared $< -o $@
|
||||
|
||||
endif
|
||||
|
||||
test: $(SO)
|
||||
diff tests/aes-vectors.icry$(TEST_OUT_EXT) <(cryptol -b tests/aes-vectors.icry)
|
||||
diff tests/aes-mct-ecb.icry$(TEST_OUT_EXT) <(cryptol -b tests/aes-mct-ecb.icry)
|
||||
|
||||
perf-test: $(SO)
|
||||
time cryptol -b tests/aes-mct-ecb.icry
|
||||
time cryptol -b ../../tests/suiteb/aes-mct-ecb.icry
|
||||
|
||||
perf-bench: $(SO)
|
||||
cryptol -b perf-bench.icry
|
||||
|
||||
clean:
|
||||
rm $(SO)
|
58
examples/SuiteB_FFI/README.md
Normal file
58
examples/SuiteB_FFI/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# `SuiteB_FFI`
|
||||
|
||||
`SuiteB_FFI` is a drop-in replacement for the builtin `SuiteB` module, using the
|
||||
FFI to implement AES operations with hardware AES-NI instructions when
|
||||
available, and falling back to the `SuiteB` software implementation in Cryptol
|
||||
and Haskell otherwise.
|
||||
|
||||
When AES-NI is available, it is several times faster than `SuiteB`; on a Linux
|
||||
machine with an Intel i7-10510U it is about 5.5x faster. Note that AES-NI is
|
||||
only available on modern x86-64 processors, but you could modify this to support
|
||||
similar instructions for other architectures or bind to a portable C library
|
||||
instead.
|
||||
|
||||
The actual AES implementation is written with x86-64 intrinsics in C and based
|
||||
on Intel's [AES-NI
|
||||
whitepaper](https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf)
|
||||
but with modifications to support how the `SuiteB` module's API is structured.
|
||||
In particular, the representation of round keys as `[4][32]` in `SuiteB` means
|
||||
that we need to do a byte swap every time we access memory to correct for
|
||||
endianness.
|
||||
|
||||
Maintaining compatibility with `SuiteB` actually severely limits the speedup
|
||||
that we can achieve: right now about 96% of the time spent calling the encrypt
|
||||
function in Cryptol is spent doing the Cryptol evaluation surrounding the FFI
|
||||
call and the actual AES computation only takes up less than 4% of the total
|
||||
time. This is because the encrypt function in `SuiteB` only encrypts one block,
|
||||
so if you were to create a foreign function that encrypted many blocks at once,
|
||||
the overhead would be much smaller relative to the work done in the foreign
|
||||
function and you would achieve a much greater speedup.
|
||||
|
||||
The implementation passes the AES tests from the Cryptol SuiteB test suite
|
||||
(`aes-mct-ecb` and `aes-vectors`) but has not been verified beyond that.
|
||||
|
||||
## Usage
|
||||
|
||||
Run `make` to build the C code. The code checks for hardware AES-NI support at
|
||||
runtime with `cpuid` when any AES function is first used. On non-x86-64
|
||||
platforms, running `make` will build a dummy implementation that always falls
|
||||
back to software `SuiteB`. On x86-64, `make` uses `-march=native` to build an
|
||||
optimized version for running on the current machine. To build a (somewhat)
|
||||
portable version that will run on any x86-64 machine with AES-NI and SSSE3, use
|
||||
`make PORTABLE=1`. Once it is built, loading the `SuiteB_FFI` Cryptol module
|
||||
will automatically load the shared library.
|
||||
|
||||
Run `make test` to test correctness. This runs the tests in the `tests/`
|
||||
directory which are copied from Cryptol's `/tests/suiteb/` but using the
|
||||
`SuiteB_FFI` module instead of `SuiteB`.
|
||||
|
||||
Run `make perf-test` to test performance on the `aes-mct-ecb` test. This prints
|
||||
out the time it takes to run the test with the FFI version and the Cryptol
|
||||
version.
|
||||
|
||||
Run `make perf-bench` to test the performance of the individual AES-128
|
||||
functions with Cryptol's `:time` benchmarking command. This prints out the
|
||||
benchmarked time for the key expansion and encryption functions for both
|
||||
implementations, and the speedup in both cases.
|
||||
|
||||
Run `make clean` to delete generated files.
|
384
examples/SuiteB_FFI/SuiteB_FFI.c
Normal file
384
examples/SuiteB_FFI/SuiteB_FFI.c
Normal file
@ -0,0 +1,384 @@
|
||||
// Based on sample code from the Intel AES-NI whitepaper
|
||||
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#include <cpuid.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
// Since Cryptol represents the round keys using [4][32], we need to do a byte
|
||||
// swap every time we write/read the keys to/from memory to correct for
|
||||
// endianness.
|
||||
#define BSWAP32_128 _mm_set_epi64x(0x0c0d0e0f08090a0b, 0x0405060700010203)
|
||||
|
||||
uint8_t checkAESNISupported() {
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
|
||||
return 0;
|
||||
}
|
||||
return (ecx & bit_AES) != 0;
|
||||
}
|
||||
|
||||
static inline void invert_schedule(unsigned int roundKeysLength,
|
||||
const uint32_t *encInitialKey, const uint32_t *encRoundKeys,
|
||||
const uint32_t *encFinalKey, uint32_t *decInitialKey, uint32_t *decRoundKeys,
|
||||
uint32_t *decFinalKey) {
|
||||
__m128i tmp;
|
||||
__m128i bswap32 = BSWAP32_128;
|
||||
__m128i *encRoundKeys128 = (__m128i *) encRoundKeys;
|
||||
__m128i *decRoundKeys128 = (__m128i *) decRoundKeys;
|
||||
memcpy(decInitialKey, encFinalKey, 16);
|
||||
for (unsigned int i = 0; i < roundKeysLength; ++i) {
|
||||
tmp = _mm_loadu_si128(encRoundKeys128 + roundKeysLength - 1 - i);
|
||||
tmp = _mm_shuffle_epi8(tmp, bswap32);
|
||||
tmp = _mm_aesimc_si128(tmp);
|
||||
tmp = _mm_shuffle_epi8(tmp, bswap32);
|
||||
_mm_storeu_si128(decRoundKeys128 + i, tmp);
|
||||
}
|
||||
memcpy(decFinalKey, encInitialKey, 16);
|
||||
}
|
||||
|
||||
static inline __m128i prepare_roundkey_128(__m128i tmp1, __m128i tmp2) {
|
||||
__m128i tmp3;
|
||||
tmp2 = _mm_shuffle_epi32(tmp2, 0xff);
|
||||
tmp3 = _mm_slli_si128(tmp1, 0x4);
|
||||
tmp1 = _mm_xor_si128(tmp1, tmp3);
|
||||
tmp3 = _mm_slli_si128(tmp3, 0x4);
|
||||
tmp1 = _mm_xor_si128(tmp1, tmp3);
|
||||
tmp3 = _mm_slli_si128(tmp3, 0x4);
|
||||
tmp1 = _mm_xor_si128(tmp1, tmp3);
|
||||
tmp1 = _mm_xor_si128(tmp1, tmp2);
|
||||
return tmp1;
|
||||
}
|
||||
|
||||
void aesniExpandEncrypt128(const uint8_t *key, uint32_t *encInitialKey,
|
||||
uint32_t *encRoundKeys, uint32_t *encFinalKey) {
|
||||
__m128i tmp1, tmp2, tmp3;
|
||||
__m128i bswap32 = BSWAP32_128;
|
||||
__m128i *encRoundKeys128 = (__m128i *) encRoundKeys;
|
||||
tmp1 = _mm_loadu_si128((__m128i *) key);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128((__m128i *) encInitialKey, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x1);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x2);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 1, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x4);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 2, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x8);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 3, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x10);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 4, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x20);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 5, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x40);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 6, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x80);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 7, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x1b);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 8, tmp3);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp1, 0x36);
|
||||
tmp1 = prepare_roundkey_128(tmp1, tmp2);
|
||||
tmp3 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128((__m128i *) encFinalKey, tmp3);
|
||||
}
|
||||
|
||||
void aesniExpandEncryptDecrypt128(const uint8_t *key, uint32_t *encInitialKey,
|
||||
uint32_t *encRoundKeys, uint32_t *encFinalKey, uint32_t *decInitialKey,
|
||||
uint32_t *decRoundKeys, uint32_t *decFinalKey) {
|
||||
aesniExpandEncrypt128(key, encInitialKey, encRoundKeys, encFinalKey);
|
||||
invert_schedule(9, encInitialKey, encRoundKeys, encFinalKey, decInitialKey,
|
||||
decRoundKeys, decFinalKey);
|
||||
}
|
||||
|
||||
void aesniExpandDecrypt128(const uint8_t *key, uint32_t *decInitialKey,
|
||||
uint32_t *decRoundKeys, uint32_t *decFinalKey) {
|
||||
uint32_t encInitialKey[4];
|
||||
uint32_t encRoundKeys[4 * 9];
|
||||
uint32_t encFinalKey[4];
|
||||
aesniExpandEncryptDecrypt128(key, encInitialKey, encRoundKeys, encFinalKey,
|
||||
decInitialKey, decRoundKeys, decFinalKey);
|
||||
}
|
||||
|
||||
static inline void prepare_roundkey_192(__m128i *tmp1, __m128i *tmp2,
|
||||
__m128i *tmp3) {
|
||||
__m128i tmp4;
|
||||
*tmp2 = _mm_shuffle_epi32(*tmp2, 0x55);
|
||||
tmp4 = _mm_slli_si128(*tmp1, 0x4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, tmp4);
|
||||
tmp4 = _mm_slli_si128(tmp4, 0x4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, tmp4);
|
||||
tmp4 = _mm_slli_si128(tmp4, 0x4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, tmp4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, *tmp2);
|
||||
*tmp2 = _mm_shuffle_epi32(*tmp1, 0xff);
|
||||
tmp4 = _mm_slli_si128(*tmp3, 0x4);
|
||||
*tmp3 = _mm_xor_si128(*tmp3, tmp4);
|
||||
*tmp3 = _mm_xor_si128(*tmp3, *tmp2);
|
||||
}
|
||||
|
||||
void aesniExpandEncrypt192(const uint8_t *key, uint32_t *encInitialKey,
|
||||
uint32_t *encRoundKeys, uint32_t *encFinalKey) {
|
||||
__m128i tmp1, tmp2, tmp3, tmp4;
|
||||
__m128i bswap32 = BSWAP32_128;
|
||||
__m128i *key128 = (__m128i *) key;
|
||||
__m128i *encRoundKeys128 = (__m128i *) encRoundKeys;
|
||||
tmp1 = _mm_loadu_si128(key128);
|
||||
tmp3 = _mm_loadu_si128(key128 + 1);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128((__m128i *) encInitialKey, tmp4);
|
||||
tmp4 = tmp3;
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x1);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp4, (__m128d) tmp1, 0);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128, tmp4);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp1, (__m128d) tmp3, 1);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 1, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x2);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 2, tmp4);
|
||||
tmp4 = tmp3;
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x4);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp4, (__m128d) tmp1, 0);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 3, tmp4);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp1, (__m128d) tmp3, 1);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 4, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x8);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 5, tmp4);
|
||||
tmp4 = tmp3;
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x10);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp4, (__m128d) tmp1, 0);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 6, tmp4);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp1, (__m128d) tmp3, 1);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 7, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x20);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 8, tmp4);
|
||||
tmp4 = tmp3;
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x40);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp4, (__m128d) tmp1, 0);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 9, tmp4);
|
||||
tmp4 = (__m128i) _mm_shuffle_pd((__m128d) tmp1, (__m128d) tmp3, 1);
|
||||
tmp4 = _mm_shuffle_epi8(tmp4, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 10, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x80);
|
||||
prepare_roundkey_192(&tmp1, &tmp2, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128((__m128i *) encFinalKey, tmp4);
|
||||
}
|
||||
|
||||
void aesniExpandEncryptDecrypt192(const uint8_t *key, uint32_t *encInitialKey,
|
||||
uint32_t *encRoundKeys, uint32_t *encFinalKey, uint32_t *decInitialKey,
|
||||
uint32_t *decRoundKeys, uint32_t *decFinalKey) {
|
||||
aesniExpandEncrypt192(key, encInitialKey, encRoundKeys, encFinalKey);
|
||||
invert_schedule(11, encInitialKey, encRoundKeys, encFinalKey, decInitialKey,
|
||||
decRoundKeys, decFinalKey);
|
||||
}
|
||||
|
||||
void aesniExpandDecrypt192(const uint8_t *key, uint32_t *decInitialKey,
|
||||
uint32_t *decRoundKeys, uint32_t *decFinalKey) {
|
||||
uint32_t encInitialKey[4];
|
||||
uint32_t encRoundKeys[4 * 11];
|
||||
uint32_t encFinalKey[4];
|
||||
aesniExpandEncryptDecrypt192(key, encInitialKey, encRoundKeys, encFinalKey,
|
||||
decInitialKey, decRoundKeys, decFinalKey);
|
||||
}
|
||||
|
||||
static inline void prepare_roundkey_256_1(__m128i *tmp1, __m128i *tmp2) {
|
||||
__m128i tmp4;
|
||||
*tmp2 = _mm_shuffle_epi32(*tmp2, 0xff);
|
||||
tmp4 = _mm_slli_si128(*tmp1, 0x4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, tmp4);
|
||||
tmp4 = _mm_slli_si128(tmp4, 0x4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, tmp4);
|
||||
tmp4 = _mm_slli_si128(tmp4, 0x4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, tmp4);
|
||||
*tmp1 = _mm_xor_si128(*tmp1, *tmp2);
|
||||
}
|
||||
|
||||
static inline void prepare_roundkey_256_2(__m128i *tmp1, __m128i *tmp3) {
|
||||
__m128i tmp2, tmp4;
|
||||
tmp4 = _mm_aeskeygenassist_si128(*tmp1, 0x0);
|
||||
tmp2 = _mm_shuffle_epi32(tmp4, 0xaa);
|
||||
tmp4 = _mm_slli_si128(*tmp3, 0x4);
|
||||
*tmp3 = _mm_xor_si128(*tmp3, tmp4);
|
||||
tmp4 = _mm_slli_si128(tmp4, 0x4);
|
||||
*tmp3 = _mm_xor_si128(*tmp3, tmp4);
|
||||
tmp4 = _mm_slli_si128(tmp4, 0x4);
|
||||
*tmp3 = _mm_xor_si128(*tmp3, tmp4);
|
||||
*tmp3 = _mm_xor_si128(*tmp3, tmp2);
|
||||
}
|
||||
|
||||
void aesniExpandEncrypt256(const uint8_t *key, uint32_t *encInitialKey,
|
||||
uint32_t *encRoundKeys, uint32_t *encFinalKey) {
|
||||
__m128i tmp1, tmp2, tmp3, tmp4;
|
||||
__m128i bswap32 = BSWAP32_128;
|
||||
__m128i *key128 = (__m128i *) key;
|
||||
__m128i *encRoundKeys128 = (__m128i *) encRoundKeys;
|
||||
tmp1 = _mm_loadu_si128(key128);
|
||||
tmp3 = _mm_loadu_si128(key128 + 1);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128((__m128i *) encInitialKey, tmp4);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128 (tmp3, 0x01);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 1, tmp4);
|
||||
prepare_roundkey_256_2(&tmp1, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 2, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x02);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 3, tmp4);
|
||||
prepare_roundkey_256_2(&tmp1, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 4, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x04);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 5, tmp4);
|
||||
prepare_roundkey_256_2(&tmp1, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 6, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x08);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 7, tmp4);
|
||||
prepare_roundkey_256_2(&tmp1, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 8, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x10);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 9, tmp4);
|
||||
prepare_roundkey_256_2(&tmp1, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 10, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x20);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 11, tmp4);
|
||||
prepare_roundkey_256_2(&tmp1, &tmp3);
|
||||
tmp4 = _mm_shuffle_epi8(tmp3, bswap32);
|
||||
_mm_storeu_si128(encRoundKeys128 + 12, tmp4);
|
||||
tmp2 = _mm_aeskeygenassist_si128(tmp3, 0x40);
|
||||
prepare_roundkey_256_1(&tmp1, &tmp2);
|
||||
tmp4 = _mm_shuffle_epi8(tmp1, bswap32);
|
||||
_mm_storeu_si128((__m128i *) encFinalKey, tmp4);
|
||||
}
|
||||
|
||||
void aesniExpandEncryptDecrypt256(const uint8_t *key, uint32_t *encInitialKey,
|
||||
uint32_t *encRoundKeys, uint32_t *encFinalKey, uint32_t *decInitialKey,
|
||||
uint32_t *decRoundKeys, uint32_t *decFinalKey) {
|
||||
aesniExpandEncrypt256(key, encInitialKey, encRoundKeys, encFinalKey);
|
||||
invert_schedule(13, encInitialKey, encRoundKeys, encFinalKey, decInitialKey,
|
||||
decRoundKeys, decFinalKey);
|
||||
}
|
||||
|
||||
void aesniExpandDecrypt256(const uint8_t *key, uint32_t *decInitialKey,
|
||||
uint32_t *decRoundKeys, uint32_t *decFinalKey) {
|
||||
uint32_t encInitialKey[4];
|
||||
uint32_t encRoundKeys[4 * 13];
|
||||
uint32_t encFinalKey[4];
|
||||
aesniExpandEncryptDecrypt256(key, encInitialKey, encRoundKeys, encFinalKey,
|
||||
decInitialKey, decRoundKeys, decFinalKey);
|
||||
}
|
||||
|
||||
void aesniEncryptBlock(size_t k, const uint32_t *encInitialKey,
|
||||
const uint32_t *encRoundKeys, const uint32_t *encFinalKey,
|
||||
const uint8_t *plaintext, uint8_t *ciphertext) {
|
||||
__m128i tmp1, tmp2;
|
||||
__m128i bswap32 = BSWAP32_128;
|
||||
__m128i *encRoundKeys128 = (__m128i *) encRoundKeys;
|
||||
tmp1 = _mm_loadu_si128((__m128i *) plaintext);
|
||||
tmp2 = _mm_loadu_si128((__m128i *) encInitialKey);
|
||||
tmp2 = _mm_shuffle_epi8(tmp2, bswap32);
|
||||
tmp1 = _mm_xor_si128(tmp1, tmp2);
|
||||
for (size_t i = 0; i < k + 5; i++) {
|
||||
tmp2 = _mm_loadu_si128(encRoundKeys128 + i);
|
||||
tmp2 = _mm_shuffle_epi8(tmp2, bswap32);
|
||||
tmp1 = _mm_aesenc_si128(tmp1, tmp2);
|
||||
}
|
||||
tmp2 = _mm_loadu_si128((__m128i *) encFinalKey);
|
||||
tmp2 = _mm_shuffle_epi8(tmp2, bswap32);
|
||||
tmp1 = _mm_aesenclast_si128(tmp1, tmp2);
|
||||
_mm_storeu_si128((__m128i *) ciphertext, tmp1);
|
||||
}
|
||||
|
||||
void aesniDecryptBlock(size_t k, const uint32_t *decInitialKey,
|
||||
const uint32_t *decRoundKeys, const uint32_t *decFinalKey,
|
||||
const uint8_t *ciphertext, uint8_t *plaintext) {
|
||||
__m128i tmp1, tmp2;
|
||||
__m128i bswap32 = BSWAP32_128;
|
||||
__m128i *decRoundKeys128 = (__m128i *) decRoundKeys;
|
||||
tmp1 = _mm_loadu_si128((__m128i *) ciphertext);
|
||||
tmp2 = _mm_loadu_si128((__m128i *) decInitialKey);
|
||||
tmp2 = _mm_shuffle_epi8(tmp2, bswap32);
|
||||
tmp1 = _mm_xor_si128(tmp1, tmp2);
|
||||
for (size_t i = 0; i < k + 5; i++) {
|
||||
tmp2 = _mm_loadu_si128(decRoundKeys128 + i);
|
||||
tmp2 = _mm_shuffle_epi8(tmp2, bswap32);
|
||||
tmp1 = _mm_aesdec_si128(tmp1, tmp2);
|
||||
}
|
||||
tmp2 = _mm_loadu_si128((__m128i *) decFinalKey);
|
||||
tmp2 = _mm_shuffle_epi8(tmp2, bswap32);
|
||||
tmp1 = _mm_aesdeclast_si128(tmp1, tmp2);
|
||||
_mm_storeu_si128((__m128i *) plaintext, tmp1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint8_t checkAESNISupported() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *aesniExpandEncrypt128 = NULL;
|
||||
void *aesniExpandEncryptDecrypt128 = NULL;
|
||||
void *aesniExpandDecrypt128 = NULL;
|
||||
void *aesniExpandEncrypt192 = NULL;
|
||||
void *aesniExpandEncryptDecrypt192 = NULL;
|
||||
void *aesniExpandDecrypt192 = NULL;
|
||||
void *aesniExpandEncrypt256 = NULL;
|
||||
void *aesniExpandEncryptDecrypt256 = NULL;
|
||||
void *aesniExpandDecrypt256 = NULL;
|
||||
void *aesniEncryptBlock = NULL;
|
||||
void *aesniDecryptBlock = NULL;
|
||||
|
||||
#endif
|
194
examples/SuiteB_FFI/SuiteB_FFI.cry
Normal file
194
examples/SuiteB_FFI/SuiteB_FFI.cry
Normal file
@ -0,0 +1,194 @@
|
||||
module SuiteB_FFI where
|
||||
|
||||
import SuiteB as SB
|
||||
|
||||
/***** AES ******/
|
||||
|
||||
/**
|
||||
* Key schedule parameter setting for AES-128
|
||||
*/
|
||||
type AES128 = SB::AES128
|
||||
|
||||
/**
|
||||
* Key schedule parameter setting for AES-192
|
||||
*/
|
||||
type AES192 = SB::AES192
|
||||
|
||||
/**
|
||||
* Key schedule parameter setting for AES-256
|
||||
*/
|
||||
type AES256 = SB::AES256
|
||||
|
||||
/**
|
||||
* Element of an AES key schedule for use in a particular round
|
||||
*/
|
||||
type AESRoundKey = SB::AESRoundKey
|
||||
|
||||
/**
|
||||
* Expanded encryption key schedule for AES
|
||||
*/
|
||||
type AESEncryptKeySchedule k = SB::AESEncryptKeySchedule k
|
||||
|
||||
/**
|
||||
* Expanded decryption key schedule for AES
|
||||
*/
|
||||
type AESDecryptKeySchedule k = SB::AESDecryptKeySchedule k
|
||||
|
||||
/**
|
||||
* Encryption key expansion for AES-128.
|
||||
* See FIPS 197, section 5.2.
|
||||
*/
|
||||
aes128EncryptSchedule : [128] -> AESEncryptKeySchedule AES128
|
||||
aes128EncryptSchedule =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandEncrypt128 (split key)
|
||||
else SB::aes128EncryptSchedule
|
||||
|
||||
/**
|
||||
* Decryption key expansion for AES-128, for use in the "equivalent inverse cypher".
|
||||
* See FIPS 197, sections 5.2 and 5.3.5.
|
||||
*/
|
||||
aes128DecryptSchedule : [128] -> AESDecryptKeySchedule AES128
|
||||
aes128DecryptSchedule =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandDecrypt128 (split key)
|
||||
else SB::aes128DecryptSchedule
|
||||
|
||||
/**
|
||||
* Encryption and decryption key schedules for AES-128.
|
||||
* If you will need both schedules, it is slightly more efficient
|
||||
* to call this function than to compute the two schedules separately.
|
||||
* See FIPS 197, sections 5.2 and 5.3.5.
|
||||
*/
|
||||
aes128Schedules : [128] -> (AESEncryptKeySchedule AES128, AESDecryptKeySchedule AES128)
|
||||
aes128Schedules =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandEncryptDecrypt128 (split key)
|
||||
else SB::aes128Schedules
|
||||
|
||||
/**
|
||||
* Encryption key expansion for AES-192.
|
||||
* See FIPS 197, section 5.2.
|
||||
*/
|
||||
aes192EncryptSchedule : [192] -> AESEncryptKeySchedule AES192
|
||||
aes192EncryptSchedule =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandEncrypt192 (split key)
|
||||
else SB::aes192EncryptSchedule
|
||||
|
||||
/**
|
||||
* Decryption key expansion for AES-192, for use in the "equivalent inverse cypher".
|
||||
* See FIPS 197, sections 5.2 and 5.3.5.
|
||||
*/
|
||||
aes192DecryptSchedule : [192] -> AESDecryptKeySchedule AES192
|
||||
aes192DecryptSchedule =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandDecrypt192 (split key)
|
||||
else SB::aes192DecryptSchedule
|
||||
|
||||
/**
|
||||
* Encryption and decryption key schedules for AES-192.
|
||||
* If you will need both schedules, it is slightly more efficient
|
||||
* to call this function than to compute the two schedules separately.
|
||||
* See FIPS 197, sections 5.2 and 5.3.5.
|
||||
*/
|
||||
aes192Schedules : [192] -> (AESEncryptKeySchedule AES192, AESDecryptKeySchedule AES192)
|
||||
aes192Schedules =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandEncryptDecrypt192 (split key)
|
||||
else SB::aes192Schedules
|
||||
|
||||
|
||||
/**
|
||||
* Encryption key expansion for AES-256.
|
||||
* See FIPS 197, section 5.2
|
||||
*/
|
||||
aes256EncryptSchedule : [256] -> AESEncryptKeySchedule AES256
|
||||
aes256EncryptSchedule =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandEncrypt256 (split key)
|
||||
else SB::aes256EncryptSchedule
|
||||
|
||||
/**
|
||||
* Decryption key expansion for AES-256, for use in the "equivalent inverse cypher".
|
||||
* See FIPS 197, sections 5.2 and 5.3.5.
|
||||
*/
|
||||
aes256DecryptSchedule : [256] -> AESDecryptKeySchedule AES256
|
||||
aes256DecryptSchedule =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandDecrypt256 (split key)
|
||||
else SB::aes256DecryptSchedule
|
||||
|
||||
/**
|
||||
* Encryption and decryption key schedules for AES-256.
|
||||
* If you will need both schedules, it is slightly more efficient
|
||||
* to call this function than to compute the two schedules separately.
|
||||
* See FIPS 197, sections 5.2 and 5.3.5.
|
||||
*/
|
||||
aes256Schedules : [256] -> (AESEncryptKeySchedule AES256, AESDecryptKeySchedule AES256)
|
||||
aes256Schedules =
|
||||
if aesniSupported
|
||||
then \key -> aesniExpandEncryptDecrypt256 (split key)
|
||||
else SB::aes256Schedules
|
||||
|
||||
/**
|
||||
* AES block encryption algorithm.
|
||||
* See FIPS 197, section 5.1.
|
||||
*/
|
||||
aesEncryptBlock : {k} (fin k) => AESEncryptKeySchedule k -> [128] -> [128]
|
||||
aesEncryptBlock =
|
||||
if aesniSupported
|
||||
then \schedule plaintext -> join (aesniEncryptBlock schedule (split plaintext))
|
||||
else SB::aesEncryptBlock
|
||||
|
||||
/**
|
||||
* AES block decryption algorithm, via the "equivalent inverse cypher".
|
||||
* See FIPS 197, section 5.3.5.
|
||||
*/
|
||||
aesDecryptBlock : {k} (fin k) => AESDecryptKeySchedule k -> [128] -> [128]
|
||||
aesDecryptBlock =
|
||||
if aesniSupported
|
||||
then \schedule ciphertext -> join (aesniDecryptBlock schedule (split ciphertext))
|
||||
else SB::aesDecryptBlock
|
||||
|
||||
private
|
||||
foreign checkAESNISupported : () -> Bit
|
||||
foreign aesniExpandEncrypt128 : [16][8] -> AESEncryptKeySchedule AES128
|
||||
foreign aesniExpandDecrypt128 : [16][8] -> AESDecryptKeySchedule AES128
|
||||
foreign aesniExpandEncryptDecrypt128 : [16][8]
|
||||
-> (AESEncryptKeySchedule AES128, AESDecryptKeySchedule AES128)
|
||||
foreign aesniExpandEncrypt192 : [24][8] -> AESEncryptKeySchedule AES192
|
||||
foreign aesniExpandDecrypt192 : [24][8] -> AESDecryptKeySchedule AES192
|
||||
foreign aesniExpandEncryptDecrypt192 : [24][8]
|
||||
-> (AESEncryptKeySchedule AES192, AESDecryptKeySchedule AES192)
|
||||
foreign aesniExpandEncrypt256 : [32][8] -> AESEncryptKeySchedule AES256
|
||||
foreign aesniExpandDecrypt256 : [32][8] -> AESDecryptKeySchedule AES256
|
||||
foreign aesniExpandEncryptDecrypt256 : [32][8]
|
||||
-> (AESEncryptKeySchedule AES256, AESDecryptKeySchedule AES256)
|
||||
foreign aesniEncryptBlock : {k} (fin k) => AESEncryptKeySchedule k -> [16][8] -> [16][8]
|
||||
foreign aesniDecryptBlock : {k} (fin k) => AESDecryptKeySchedule k -> [16][8] -> [16][8]
|
||||
|
||||
aesniSupported = checkAESNISupported ()
|
||||
|
||||
|
||||
/***** SHA2 *****/
|
||||
|
||||
/**
|
||||
* The SHA-224 secure hash algorithm. See FIPS 180-4, section 6.3.
|
||||
*/
|
||||
sha224 = SB::sha224
|
||||
|
||||
/**
|
||||
* The SHA-256 secure hash algorithm. See FIPS 180-4, section 6.2.2.
|
||||
*/
|
||||
sha256 = SB::sha256
|
||||
|
||||
/**
|
||||
* The SHA-384 secure hash algorithm. See FIPS 180-4, section 6.5.
|
||||
*/
|
||||
sha384 = SB::sha384
|
||||
|
||||
/**
|
||||
* The SHA-512 secure hash algorithm. See FIPS 180-4, section 6.4.
|
||||
*/
|
||||
sha512 = SB::sha512
|
3
examples/SuiteB_FFI/perf-bench.cry
Normal file
3
examples/SuiteB_FFI/perf-bench.cry
Normal file
@ -0,0 +1,3 @@
|
||||
import SuiteB_FFI as FFI
|
||||
import SuiteB as SB
|
||||
import Float
|
30
examples/SuiteB_FFI/perf-bench.icry
Normal file
30
examples/SuiteB_FFI/perf-bench.icry
Normal file
@ -0,0 +1,30 @@
|
||||
:l perf-bench.cry
|
||||
:set fpBase=10
|
||||
|
||||
:! echo "AES-NI AES-128 key expansion:"
|
||||
FFI::aes128EncryptSchedule 0x1234567890abcdef1234567890abcdef
|
||||
:time FFI::aes128EncryptSchedule 0x1234567890abcdef1234567890abcdef
|
||||
let ffiTime = it.avgCpuTime
|
||||
|
||||
:! echo "Cryptol AES-128 key expansion:"
|
||||
SB::aes128EncryptSchedule 0x1234567890abcdef1234567890abcdef
|
||||
:time SB::aes128EncryptSchedule 0x1234567890abcdef1234567890abcdef
|
||||
let sbTime = it.avgCpuTime
|
||||
|
||||
:! echo "AES-128 key expansion speedup:"
|
||||
fpDiv rne sbTime ffiTime
|
||||
|
||||
let s = SB::aes128EncryptSchedule 0x1234567890abcdef1234567890abcdef
|
||||
|
||||
:! echo "AES-NI AES-128 encrypt:"
|
||||
FFI::aesEncryptBlock s 0x9876543210abcdef9876543210abcdef
|
||||
:time FFI::aesEncryptBlock s 0x9876543210abcdef9876543210abcdef
|
||||
let ffiTime = it.avgCpuTime
|
||||
|
||||
:! echo "Cryptol AES-128 encrypt:"
|
||||
SB::aesEncryptBlock s 0x9876543210abcdef9876543210abcdef
|
||||
:time SB::aesEncryptBlock s 0x9876543210abcdef9876543210abcdef
|
||||
let sbTime = it.avgCpuTime
|
||||
|
||||
:! echo "AES-128 encrypt speedup:"
|
||||
fpDiv rne sbTime ffiTime
|
3193
examples/SuiteB_FFI/tests/aes-mct-ecb.cry
Normal file
3193
examples/SuiteB_FFI/tests/aes-mct-ecb.cry
Normal file
File diff suppressed because it is too large
Load Diff
2
examples/SuiteB_FFI/tests/aes-mct-ecb.icry
Normal file
2
examples/SuiteB_FFI/tests/aes-mct-ecb.icry
Normal file
@ -0,0 +1,2 @@
|
||||
:l aes-mct-ecb.cry
|
||||
:check
|
24
examples/SuiteB_FFI/tests/aes-mct-ecb.icry.stdout
Normal file
24
examples/SuiteB_FFI/tests/aes-mct-ecb.icry.stdout
Normal file
@ -0,0 +1,24 @@
|
||||
Loading module Cryptol
|
||||
Loading module Cryptol
|
||||
Loading module SuiteB
|
||||
Loading module SuiteB_FFI
|
||||
Loading dynamic library SuiteB_FFI.so
|
||||
Loading module Main
|
||||
property aes128_MCT_vectors_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_MCT_vectors_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_MCT_vectors_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_MCT_vectors_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_MCT_vectors_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_MCT_vectors_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
24
examples/SuiteB_FFI/tests/aes-mct-ecb.icry.stdout.darwin
Normal file
24
examples/SuiteB_FFI/tests/aes-mct-ecb.icry.stdout.darwin
Normal file
@ -0,0 +1,24 @@
|
||||
Loading module Cryptol
|
||||
Loading module Cryptol
|
||||
Loading module SuiteB
|
||||
Loading module SuiteB_FFI
|
||||
Loading dynamic library SuiteB_FFI.dylib
|
||||
Loading module Main
|
||||
property aes128_MCT_vectors_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_MCT_vectors_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_MCT_vectors_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_MCT_vectors_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_MCT_vectors_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_MCT_vectors_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
1330
examples/SuiteB_FFI/tests/aes-vectors.cry
Normal file
1330
examples/SuiteB_FFI/tests/aes-vectors.cry
Normal file
File diff suppressed because it is too large
Load Diff
2
examples/SuiteB_FFI/tests/aes-vectors.icry
Normal file
2
examples/SuiteB_FFI/tests/aes-vectors.icry
Normal file
@ -0,0 +1,2 @@
|
||||
:l aes-vectors.cry
|
||||
:check
|
78
examples/SuiteB_FFI/tests/aes-vectors.icry.stdout
Normal file
78
examples/SuiteB_FFI/tests/aes-vectors.icry.stdout
Normal file
@ -0,0 +1,78 @@
|
||||
Loading module Cryptol
|
||||
Loading module Cryptol
|
||||
Loading module SuiteB
|
||||
Loading module SuiteB_FFI
|
||||
Loading dynamic library SuiteB_FFI.so
|
||||
Loading module Main
|
||||
property aes128_GFSBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_GFSBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_GFSBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_GFSBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_GFSBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_GFSBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_KeySBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_KeySBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_KeySBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_KeySBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_KeySBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_KeySBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarTxt_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarTxt_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarTxt_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarTxt_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarTxt_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarTxt_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarKey_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarKey_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarKey_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarKey_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarKey_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarKey_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
78
examples/SuiteB_FFI/tests/aes-vectors.icry.stdout.darwin
Normal file
78
examples/SuiteB_FFI/tests/aes-vectors.icry.stdout.darwin
Normal file
@ -0,0 +1,78 @@
|
||||
Loading module Cryptol
|
||||
Loading module Cryptol
|
||||
Loading module SuiteB
|
||||
Loading module SuiteB_FFI
|
||||
Loading dynamic library SuiteB_FFI.dylib
|
||||
Loading module Main
|
||||
property aes128_GFSBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_GFSBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_GFSBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_GFSBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_GFSBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_GFSBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_KeySBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_KeySBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_KeySBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_KeySBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_KeySBox_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_KeySBox_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarTxt_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarTxt_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarTxt_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarTxt_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarTxt_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarTxt_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarKey_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes128_VarKey_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarKey_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes192_VarKey_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarKey_encrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
||||
property aes256_VarKey_decrypt_correct Using exhaustive testing.
|
||||
Testing... Passed 1 tests.
|
||||
Q.E.D.
|
@ -9,9 +9,10 @@
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
-- | The implementation of loading and calling external functions from shared
|
||||
-- libraries. Currently works on Unix only.
|
||||
-- libraries.
|
||||
module Cryptol.Backend.FFI
|
||||
( ForeignSrc
|
||||
, getForeignSrcPath
|
||||
, loadForeignSrc
|
||||
, unloadForeignSrc
|
||||
#ifdef FFI_ENABLED
|
||||
@ -42,7 +43,12 @@ import Foreign.Concurrent
|
||||
import Foreign.LibFFI
|
||||
import System.FilePath ((-<.>))
|
||||
import System.IO.Error
|
||||
|
||||
#if defined(mingw32_HOST_OS)
|
||||
import System.Win32.DLL
|
||||
#else
|
||||
import System.Posix.DynamicLinker
|
||||
#endif
|
||||
|
||||
import Cryptol.Utils.Panic
|
||||
|
||||
@ -56,12 +62,14 @@ import GHC.Generics
|
||||
|
||||
-- | A source from which we can retrieve implementations of foreign functions.
|
||||
data ForeignSrc = ForeignSrc
|
||||
{ -- | The 'ForeignPtr' wraps the pointer returned by 'dlopen', where the
|
||||
{ -- | The file path of the 'ForeignSrc'.
|
||||
foreignSrcPath :: FilePath
|
||||
-- | The 'ForeignPtr' wraps the pointer returned by 'dlopen', where the
|
||||
-- finalizer calls 'dlclose' when the library is no longer needed. We keep
|
||||
-- references to the 'ForeignPtr' in each foreign function that is in the
|
||||
-- evaluation environment, so that the shared library will stay open as long
|
||||
-- as there are references to it.
|
||||
foreignSrcFPtr :: ForeignPtr ()
|
||||
, foreignSrcFPtr :: ForeignPtr ()
|
||||
-- | We support explicit unloading of the shared library so we keep track of
|
||||
-- if it has already been unloaded, and if so the finalizer does nothing.
|
||||
-- This is updated atomically when the library is unloaded.
|
||||
@ -73,17 +81,24 @@ instance Show ForeignSrc where
|
||||
instance NFData ForeignSrc where
|
||||
rnf ForeignSrc {..} = foreignSrcFPtr `seq` foreignSrcLoaded `deepseq` ()
|
||||
|
||||
-- | Get the file path of the 'ForeignSrc'.
|
||||
getForeignSrcPath :: ForeignSrc -> Maybe FilePath
|
||||
getForeignSrcPath = Just . foreignSrcPath
|
||||
|
||||
-- | Load a 'ForeignSrc' for the given __Cryptol__ file path. The file path of
|
||||
-- the shared library that we try to load is the same as the Cryptol file path
|
||||
-- except with a platform specific extension.
|
||||
loadForeignSrc :: FilePath -> IO (Either FFILoadError ForeignSrc)
|
||||
loadForeignSrc = loadForeignLib >=> traverse \ptr -> do
|
||||
loadForeignSrc = loadForeignLib >=> traverse \(foreignSrcPath, ptr) -> do
|
||||
foreignSrcLoaded <- newMVar True
|
||||
foreignSrcFPtr <- newForeignPtr ptr (unloadForeignSrc' foreignSrcLoaded ptr)
|
||||
pure ForeignSrc {..}
|
||||
|
||||
loadForeignLib :: FilePath -> IO (Either FFILoadError (Ptr ()))
|
||||
#ifdef darwin_HOST_OS
|
||||
loadForeignLib :: FilePath -> IO (Either FFILoadError (FilePath, Ptr ()))
|
||||
#if defined(mingw32_HOST_OS)
|
||||
loadForeignLib path =
|
||||
tryLoad (CantLoadFFISrc path) $ open "dll"
|
||||
#elif defined(darwin_HOST_OS)
|
||||
-- On Darwin, try loading .dylib first, and if that fails try .so
|
||||
loadForeignLib path =
|
||||
(Right <$> open "dylib") `catchIOError` \e1 ->
|
||||
@ -95,9 +110,16 @@ loadForeignLib path =
|
||||
loadForeignLib path =
|
||||
tryLoad (CantLoadFFISrc path) $ open "so"
|
||||
#endif
|
||||
where -- RTLD_NOW so we can make sure that the symbols actually exist at
|
||||
-- module loading time
|
||||
open ext = undl <$> dlopen (path -<.> ext) [RTLD_NOW]
|
||||
where open ext = do
|
||||
let libPath = path -<.> ext
|
||||
#if defined(mingw32_HOST_OS)
|
||||
ptr <- loadLibrary libPath
|
||||
#else
|
||||
-- RTLD_NOW so we can make sure that the symbols actually exist at
|
||||
-- module loading time
|
||||
ptr <- undl <$> dlopen libPath [RTLD_NOW]
|
||||
#endif
|
||||
pure (libPath, ptr)
|
||||
|
||||
-- | Explicitly unload a 'ForeignSrc' immediately instead of waiting for the
|
||||
-- garbage collector to do it. This can be useful if you want to immediately
|
||||
@ -115,7 +137,11 @@ unloadForeignSrc' loaded lib = modifyMVar_ loaded \l -> do
|
||||
pure False
|
||||
|
||||
unloadForeignLib :: Ptr () -> IO ()
|
||||
#if defined(mingw32_HOST_OS)
|
||||
unloadForeignLib = freeLibrary
|
||||
#else
|
||||
unloadForeignLib = dlclose . DLHandle
|
||||
#endif
|
||||
|
||||
withForeignSrc :: ForeignSrc -> (Ptr () -> IO a) -> IO a
|
||||
withForeignSrc ForeignSrc {..} f = withMVar foreignSrcLoaded
|
||||
@ -142,7 +168,13 @@ loadForeignImpl foreignImplSrc name =
|
||||
pure ForeignImpl {..}
|
||||
|
||||
loadForeignFunPtr :: Ptr () -> String -> IO (FunPtr ())
|
||||
#if defined(mingw32_HOST_OS)
|
||||
loadForeignFunPtr source symbol = do
|
||||
addr <- getProcAddress source symbol
|
||||
pure $ castPtrToFunPtr addr
|
||||
#else
|
||||
loadForeignFunPtr = dlsym . DLHandle
|
||||
#endif
|
||||
|
||||
tryLoad :: (String -> FFILoadError) -> IO a -> IO (Either FFILoadError a)
|
||||
tryLoad err = fmap (first $ err . displayException) . tryIOError
|
||||
@ -218,6 +250,9 @@ callForeignImpl ForeignImpl {..} xs = withForeignSrc foreignImplSrc \_ ->
|
||||
|
||||
data ForeignSrc = ForeignSrc deriving (Show, Generic, NFData)
|
||||
|
||||
getForeignSrcPath :: ForeignSrc -> Maybe FilePath
|
||||
getForeignSrcPath _ = Nothing
|
||||
|
||||
loadForeignSrc :: FilePath -> IO (Either FFILoadError ForeignSrc)
|
||||
loadForeignSrc _ = pure $ Right ForeignSrc
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
-- | Errors from dynamic loading of shared libraries for FFI.
|
||||
module Cryptol.Backend.FFI.Error where
|
||||
|
@ -8,6 +8,7 @@ import LibBF
|
||||
|
||||
import Cryptol.Utils.PP
|
||||
import Cryptol.Utils.Panic(panic)
|
||||
import Cryptol.Utils.Types
|
||||
import Cryptol.Backend.Monad( EvalError(..) )
|
||||
|
||||
|
||||
@ -176,3 +177,8 @@ floatFromBits e p bv = BF { bfValue = bfFromBits (fpOpts e p NearEven) bv
|
||||
-- (most significant bit in the significand is set, the rest of it is 0)
|
||||
floatToBits :: Integer -> Integer -> BigFloat -> Integer
|
||||
floatToBits e p bf = bfToBits (fpOpts e p NearEven) bf
|
||||
|
||||
|
||||
-- | Create a 64-bit IEEE-754 float.
|
||||
floatFromDouble :: Double -> BF
|
||||
floatFromDouble = uncurry BF float64ExpPrec . bfFromDouble
|
||||
|
@ -421,10 +421,11 @@ data EvalError
|
||||
| NoPrim Name -- ^ Primitive with no implementation
|
||||
| BadRoundingMode Integer -- ^ Invalid rounding mode
|
||||
| BadValue String -- ^ Value outside the domain of a partial function.
|
||||
| NoMatchingPropGuardCase String -- ^ No prop guard holds for the given type variables.
|
||||
| FFINotSupported Name -- ^ Foreign function cannot be called
|
||||
| FFITypeNumTooBig Name TParam Integer -- ^ Number passed to foreign function
|
||||
-- as a type argument is too large
|
||||
deriving Typeable
|
||||
deriving Typeable
|
||||
|
||||
instance PP EvalError where
|
||||
ppPrec _ e = case e of
|
||||
@ -443,6 +444,7 @@ instance PP EvalError where
|
||||
BadRoundingMode r -> "invalid rounding mode" <+> integer r
|
||||
BadValue x -> "invalid input for" <+> backticks (text x)
|
||||
NoPrim x -> text "unimplemented primitive:" <+> pp x
|
||||
NoMatchingPropGuardCase msg -> text $ "No matching constraint guard; " ++ msg
|
||||
FFINotSupported x -> vcat
|
||||
[ text "cannot call foreign function" <+> pp x
|
||||
, text "FFI calls are not supported in this context"
|
||||
|
@ -15,6 +15,7 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE PatternGuards #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
|
||||
module Cryptol.Eval (
|
||||
moduleEnv
|
||||
@ -35,6 +36,7 @@ module Cryptol.Eval (
|
||||
, Unsupported(..)
|
||||
, WordTooWide(..)
|
||||
, forceValue
|
||||
, checkProp
|
||||
) where
|
||||
|
||||
import Cryptol.Backend
|
||||
@ -63,6 +65,7 @@ import Data.Maybe
|
||||
import qualified Data.IntMap.Strict as IntMap
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Data.Semigroup
|
||||
import Control.Applicative
|
||||
|
||||
import Prelude ()
|
||||
import Prelude.Compat
|
||||
@ -216,12 +219,52 @@ evalExpr sym env expr = case expr of
|
||||
env' <- evalDecls sym ds env
|
||||
evalExpr sym env' e
|
||||
|
||||
EPropGuards guards _ -> {-# SCC "evalExpr->EPropGuards" #-} do
|
||||
let checkedGuards = [ e | (ps,e) <- guards, all (checkProp . evalProp env) ps ]
|
||||
case checkedGuards of
|
||||
(e:_) -> eval e
|
||||
[] -> raiseError sym (NoMatchingPropGuardCase $ "Among constraint guards: " ++ show (fmap pp . fst <$> guards))
|
||||
|
||||
where
|
||||
|
||||
{-# INLINE eval #-}
|
||||
eval = evalExpr sym env
|
||||
ppV = ppValue sym defaultPPOpts
|
||||
|
||||
-- | Checks whether an evaluated `Prop` holds
|
||||
checkProp :: Prop -> Bool
|
||||
checkProp = \case
|
||||
TCon tcon ts ->
|
||||
let ns = toNat' <$> ts in
|
||||
case tcon of
|
||||
PC PEqual | [n1, n2] <- ns -> n1 == n2
|
||||
PC PNeq | [n1, n2] <- ns -> n1 /= n2
|
||||
PC PGeq | [n1, n2] <- ns -> n1 >= n2
|
||||
PC PFin | [n] <- ns -> n /= Inf
|
||||
-- TODO: instantiate UniqueFactorization for Nat'?
|
||||
-- PC PPrime | [n] <- ns -> isJust (isPrime n)
|
||||
PC PTrue -> True
|
||||
_ -> evalPanic "evalProp" ["cannot use this as a guarding constraint: ", show . pp $ TCon tcon ts ]
|
||||
prop -> evalPanic "evalProp" ["cannot use this as a guarding constraint: ", show . pp $ prop ]
|
||||
where
|
||||
toNat' :: Type -> Nat'
|
||||
toNat' = \case
|
||||
TCon (TC (TCNum n)) [] -> Nat n
|
||||
TCon (TC TCInf) [] -> Inf
|
||||
prop -> panic "checkProp" ["Expected `" ++ pretty prop ++ "` to be an evaluated numeric type"]
|
||||
|
||||
|
||||
-- | Evaluates a `Prop` in an `EvalEnv` by substituting all variables according
|
||||
-- to `envTypes` and expanding all type synonyms via `tNoUser`.
|
||||
evalProp :: GenEvalEnv sym -> Prop -> Prop
|
||||
evalProp env@EvalEnv { envTypes } = \case
|
||||
TCon tc tys -> TCon tc (toType . evalType envTypes <$> tys)
|
||||
TVar tv | Just (toType -> ty) <- lookupTypeVar tv envTypes -> ty
|
||||
prop@TUser {} -> evalProp env (tNoUser prop)
|
||||
TVar tv | Nothing <- lookupTypeVar tv envTypes -> panic "evalProp" ["Could not find type variable `" ++ pretty tv ++ "` in the type evaluation environment"]
|
||||
prop -> panic "evalProp" ["Cannot use the following as a type constraint: `" ++ pretty prop ++ "`"]
|
||||
where
|
||||
toType = either tNumTy tValTy
|
||||
|
||||
-- | Capure the current call stack from the evaluation monad and
|
||||
-- annotate function values. When arguments are later applied
|
||||
@ -410,8 +453,10 @@ evalDecl ::
|
||||
GenEvalEnv sym {- ^ An evaluation environment to extend with the given declaration -} ->
|
||||
Decl {- ^ The declaration to evaluate -} ->
|
||||
SEval sym (GenEvalEnv sym)
|
||||
evalDecl sym renv env d =
|
||||
let ?range = nameLoc (dName d) in
|
||||
-- evalDecl sym renv env d =
|
||||
-- let ?range = nameLoc (dName d) in
|
||||
evalDecl sym renv env d = do
|
||||
let ?range = nameLoc (dName d)
|
||||
case dDefinition d of
|
||||
DPrim ->
|
||||
case ?evalPrim =<< asPrim (dName d) of
|
||||
|
@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE BangPatterns #-}
|
||||
{-# LANGUAGE BlockArguments #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
@ -12,30 +13,37 @@
|
||||
|
||||
-- | Evaluation of foreign functions.
|
||||
module Cryptol.Eval.FFI
|
||||
( evalForeignDecls
|
||||
( findForeignDecls
|
||||
, evalForeignDecls
|
||||
) where
|
||||
|
||||
import Data.Maybe
|
||||
|
||||
import Cryptol.Backend.FFI
|
||||
import Cryptol.Backend.FFI.Error
|
||||
import Cryptol.Eval
|
||||
import Cryptol.ModuleSystem.Env
|
||||
import Cryptol.TypeCheck.AST
|
||||
import Cryptol.TypeCheck.FFI.FFIType
|
||||
|
||||
#ifdef FFI_ENABLED
|
||||
|
||||
import Control.Exception(bracket_)
|
||||
import Data.Either
|
||||
import Data.Foldable
|
||||
import Data.IORef
|
||||
import Data.Maybe
|
||||
import Data.Proxy
|
||||
import Data.Ratio
|
||||
import Data.Traversable
|
||||
import Data.Word
|
||||
import Foreign
|
||||
import Foreign.C.Types
|
||||
import GHC.Float
|
||||
import LibBF (bfFromDouble, bfToDouble,
|
||||
pattern NearEven)
|
||||
import System.Directory
|
||||
import LibBF (bfFromDouble, bfToDouble,
|
||||
pattern NearEven)
|
||||
import Numeric.GMP.Raw.Unsafe
|
||||
import Numeric.GMP.Utils
|
||||
|
||||
import Cryptol.Backend
|
||||
import Cryptol.Backend.Concrete
|
||||
import Cryptol.Backend.FloatHelpers
|
||||
import Cryptol.Backend.Monad
|
||||
@ -45,42 +53,36 @@ import Cryptol.Eval.Prims
|
||||
import Cryptol.Eval.Type
|
||||
import Cryptol.Eval.Value
|
||||
import Cryptol.ModuleSystem.Name
|
||||
import Cryptol.TypeCheck.FFI.FFIType
|
||||
import Cryptol.Utils.Ident
|
||||
import Cryptol.Utils.RecordMap
|
||||
|
||||
-- | Find all the foreign declarations in the module and add them to the
|
||||
-- environment. This is a separate pass from the main evaluation functions in
|
||||
-- "Cryptol.Eval" since it only works for the Concrete backend.
|
||||
--
|
||||
-- Note: 'Right' is only returned if we successfully loaded some foreign
|
||||
-- functions and the environment was modified. If there were no foreign
|
||||
-- declarations at all then @Left []@ is returned, so 'Left' does not
|
||||
-- necessarily indicate an error.
|
||||
evalForeignDecls :: ModulePath -> Module -> EvalEnv ->
|
||||
Eval (Either [FFILoadError] (ForeignSrc, EvalEnv))
|
||||
evalForeignDecls path m env = io
|
||||
case mapMaybe getForeign $ mDecls m of
|
||||
[] -> pure $ Left []
|
||||
foreigns ->
|
||||
case path of
|
||||
InFile p -> canonicalizePath p >>= loadForeignSrc >>=
|
||||
\case
|
||||
Right fsrc -> collect <$> for foreigns \(name, ffiType) ->
|
||||
fmap ((name,) . foreignPrimPoly name ffiType) <$>
|
||||
loadForeignImpl fsrc (unpackIdent $ nameIdent name)
|
||||
where collect (partitionEithers -> (errs, primMap))
|
||||
| null errs = Right
|
||||
(fsrc, foldr (uncurry bindVarDirect) env primMap)
|
||||
| otherwise = Left errs
|
||||
Left err -> pure $ Left [err]
|
||||
-- We don't handle in-memory modules for now
|
||||
InMem _ _ -> evalPanic "evalForeignDecls"
|
||||
["Can't find foreign source of in-memory module"]
|
||||
#endif
|
||||
|
||||
-- | Find all the foreign declarations in the module and return their names and
|
||||
-- FFIFunTypes.
|
||||
findForeignDecls :: Module -> [(Name, FFIFunType)]
|
||||
findForeignDecls = mapMaybe getForeign . mDecls
|
||||
where getForeign (NonRecursive Decl { dName, dDefinition = DForeign ffiType })
|
||||
= Just (dName, ffiType)
|
||||
-- Recursive DeclGroups can't have foreign decls
|
||||
getForeign _ = Nothing
|
||||
|
||||
#ifdef FFI_ENABLED
|
||||
|
||||
-- | Add the given foreign declarations to the environment, loading their
|
||||
-- implementations from the given 'ForeignSrc'. This is a separate pass from the
|
||||
-- main evaluation functions in "Cryptol.Eval" since it only works for the
|
||||
-- Concrete backend.
|
||||
evalForeignDecls :: ForeignSrc -> [(Name, FFIFunType)] -> EvalEnv ->
|
||||
Eval (Either [FFILoadError] EvalEnv)
|
||||
evalForeignDecls fsrc decls env = io do
|
||||
ePrims <- for decls \(name, ffiFunType) ->
|
||||
fmap ((name,) . foreignPrimPoly name ffiFunType) <$>
|
||||
loadForeignImpl fsrc (unpackIdent $ nameIdent name)
|
||||
pure case partitionEithers ePrims of
|
||||
([], prims) -> Right $ foldr (uncurry bindVarDirect) env prims
|
||||
(errs, _) -> Left errs
|
||||
|
||||
-- | Generate a 'Prim' value representing the given foreign function, containing
|
||||
-- all the code necessary to marshal arguments and return values and do the
|
||||
-- actual FFI call.
|
||||
@ -105,6 +107,16 @@ data GetRet = GetRet
|
||||
{ getRetAsValue :: forall a. FFIRet a => IO a
|
||||
, getRetAsOutArgs :: [SomeFFIArg] -> IO () }
|
||||
|
||||
-- | Operations needed for returning a basic reference type.
|
||||
data BasicRefRet a = BasicRefRet
|
||||
{ -- | Initialize the object before passing to foreign function.
|
||||
initBasicRefRet :: Ptr a -> IO ()
|
||||
-- | Free the object after returning from foreign function and obtaining
|
||||
-- return value.
|
||||
, clearBasicRefRet :: Ptr a -> IO ()
|
||||
-- | Convert the object to a Cryptol value.
|
||||
, marshalBasicRefRet :: a -> Eval (GenValue Concrete) }
|
||||
|
||||
-- | Generate the monomorphic part of the foreign 'Prim', given a 'TypeEnv'
|
||||
-- containing all the type arguments we have already received.
|
||||
foreignPrim :: Name -> FFIFunType -> ForeignImpl -> TypeEnv -> Prim Concrete
|
||||
@ -147,48 +159,154 @@ foreignPrim name FFIFunType {..} impl tenv = buildFun ffiArgTypes []
|
||||
--
|
||||
-- NOTE: the result must be used only in the callback since it may have a
|
||||
-- limited lifetime (e.g. pointer returned by alloca).
|
||||
marshalArg :: FFIType -> GenValue Concrete ->
|
||||
([SomeFFIArg] -> Eval a) -> Eval a
|
||||
marshalArg FFIBool val f = f [SomeFFIArg @Word8 $ fromBool $ fromVBit val]
|
||||
marshalArg (FFIBasic t) val f = getMarshalBasicArg t \m -> do
|
||||
arg <- m val
|
||||
f [SomeFFIArg arg]
|
||||
marshalArg (FFIArray (evalFinType -> n) t) val f =
|
||||
getMarshalBasicArg t \m -> do
|
||||
args <- traverse (>>= m) $ enumerateSeqMap n $ fromVSeq val
|
||||
-- Since we need to do an Eval action in an IO callback, we need to
|
||||
-- manually unwrap and wrap the Eval datatype
|
||||
Eval \stk ->
|
||||
withArray args \ptr ->
|
||||
runEval stk $ f [SomeFFIArg ptr]
|
||||
marshalArg (FFITuple types) val f = do
|
||||
vals <- sequence $ fromVTuple val
|
||||
marshalArgs (zip types vals) f
|
||||
marshalArg (FFIRecord typeMap) val f = do
|
||||
vals <- traverse (`lookupRecord` val) $ displayOrder typeMap
|
||||
marshalArgs (zip (displayElements typeMap) vals) f
|
||||
marshalArg ::
|
||||
FFIType ->
|
||||
GenValue Concrete ->
|
||||
([SomeFFIArg] -> Eval a) ->
|
||||
Eval a
|
||||
|
||||
marshalArg FFIBool val f = f [SomeFFIArg @Word8 (fromBool (fromVBit val))]
|
||||
|
||||
marshalArg (FFIBasic (FFIBasicVal t)) val f =
|
||||
getMarshalBasicValArg t \doExport ->
|
||||
do arg <- doExport val
|
||||
f [SomeFFIArg arg]
|
||||
|
||||
marshalArg (FFIBasic (FFIBasicRef t)) val f =
|
||||
getMarshalBasicRefArg t \doExport ->
|
||||
-- Since we need to do Eval actions in an IO callback, we need to manually
|
||||
-- unwrap and wrap the Eval datatype
|
||||
Eval \stk ->
|
||||
doExport val \arg ->
|
||||
with arg \ptr ->
|
||||
runEval stk (f [SomeFFIArg ptr])
|
||||
|
||||
marshalArg (FFIArray (map evalFinType -> sizes) bt) val f =
|
||||
case bt of
|
||||
|
||||
FFIBasicVal t ->
|
||||
getMarshalBasicValArg t \doExport ->
|
||||
-- Since we need to do Eval actions in an IO callback,
|
||||
-- we need to manually unwrap and wrap the Eval datatype
|
||||
Eval \stk ->
|
||||
marshalArrayArg stk \v k ->
|
||||
k =<< runEval stk (doExport v)
|
||||
|
||||
FFIBasicRef t -> Eval \stk ->
|
||||
getMarshalBasicRefArg t \doExport ->
|
||||
marshalArrayArg stk doExport
|
||||
|
||||
where marshalArrayArg stk doExport =
|
||||
allocaArray (fromInteger (product sizes)) \ptr -> do
|
||||
-- Traverse the nested sequences and write the elements to the
|
||||
-- array in order.
|
||||
-- ns is the dimensions of the values we are currently
|
||||
-- processing.
|
||||
-- vs is the values we are currently processing.
|
||||
-- nvss is the stack of previous ns and vs that we keep track of
|
||||
-- that we push onto when we start processing a nested sequence
|
||||
-- and pop off when we finish processing the current ones.
|
||||
-- i is the index into the array.
|
||||
|
||||
let
|
||||
-- write next element of multi-dimensional array
|
||||
write (n:ns) (v:vs) nvss !i =
|
||||
do vs' <- traverse (runEval stk)
|
||||
(enumerateSeqMap n (fromVSeq v))
|
||||
write ns vs' ((n, vs):nvss) i
|
||||
|
||||
-- write next element in flat array
|
||||
write [] (v:vs) nvss !i =
|
||||
doExport v \rep ->
|
||||
do pokeElemOff ptr i rep
|
||||
write [] vs nvss (i + 1)
|
||||
|
||||
-- finished with flat array, do next element of multi-d array
|
||||
write ns [] ((n, vs):nvss) !i = write (n:ns) vs nvss i
|
||||
|
||||
-- done
|
||||
write _ _ [] _ = pure ()
|
||||
|
||||
|
||||
write sizes [val] [] 0
|
||||
runEval stk $ f [SomeFFIArg ptr]
|
||||
|
||||
marshalArg (FFITuple types) val f =
|
||||
do vals <- sequence (fromVTuple val)
|
||||
marshalArgs (types `zip` vals) f
|
||||
|
||||
marshalArg (FFIRecord typeMap) val f =
|
||||
do vals <- traverse (`lookupRecord` val) (displayOrder typeMap)
|
||||
marshalArgs (displayElements typeMap `zip` vals) f
|
||||
|
||||
-- Call marshalArg on a bunch of arguments and collect the results together
|
||||
-- (in the order of the arguments).
|
||||
marshalArgs :: [(FFIType, GenValue Concrete)] ->
|
||||
([SomeFFIArg] -> Eval a) -> Eval a
|
||||
marshalArgs ::
|
||||
[(FFIType, GenValue Concrete)] ->
|
||||
([SomeFFIArg] -> Eval a) ->
|
||||
Eval a
|
||||
marshalArgs typesAndVals f = go typesAndVals []
|
||||
where go [] args = f args
|
||||
go ((t, v):tvs) prevArgs = marshalArg t v \currArgs ->
|
||||
go tvs (prevArgs ++ currArgs)
|
||||
where
|
||||
go [] args = f (concat (reverse args))
|
||||
go ((t, v):tvs) prevArgs =
|
||||
marshalArg t v \currArgs ->
|
||||
go tvs (currArgs : prevArgs)
|
||||
|
||||
-- Given a FFIType and a GetRet, obtain a return value and convert it to a
|
||||
-- Given an FFIType and a GetRet, obtain a return value and convert it to a
|
||||
-- Cryptol value. The return value is obtained differently depending on the
|
||||
-- FFIType.
|
||||
marshalRet :: FFIType -> GetRet -> Eval (GenValue Concrete)
|
||||
marshalRet FFIBool gr = VBit . toBool <$> io (getRetAsValue gr @Word8)
|
||||
marshalRet (FFIBasic t) gr = getMarshalBasicRet t (io (getRetAsValue gr) >>=)
|
||||
marshalRet (FFIArray (evalFinType -> n) t) gr = getMarshalBasicRet t \m ->
|
||||
fmap (VSeq n . finiteSeqMap Concrete . map m) $
|
||||
io $ allocaArray (fromInteger n) \ptr -> do
|
||||
getRetAsOutArgs gr [SomeFFIArg ptr]
|
||||
peekArray (fromInteger n) ptr
|
||||
marshalRet FFIBool gr =
|
||||
do rep <- io (getRetAsValue gr @Word8)
|
||||
pure (VBit (toBool rep))
|
||||
|
||||
marshalRet (FFIBasic (FFIBasicVal t)) gr =
|
||||
getMarshalBasicValRet t \doImport ->
|
||||
do rep <- io (getRetAsValue gr)
|
||||
doImport rep
|
||||
|
||||
marshalRet (FFIBasic (FFIBasicRef t)) gr =
|
||||
getBasicRefRet t \how ->
|
||||
Eval \stk ->
|
||||
alloca \ptr ->
|
||||
bracket_ (initBasicRefRet how ptr) (clearBasicRefRet how ptr)
|
||||
do getRetAsOutArgs gr [SomeFFIArg ptr]
|
||||
rep <- peek ptr
|
||||
runEval stk (marshalBasicRefRet how rep)
|
||||
|
||||
marshalRet (FFIArray (map evalFinType -> sizes) bt) gr =
|
||||
Eval \stk -> do
|
||||
let totalSize = fromInteger (product sizes)
|
||||
getResult marshal ptr = do
|
||||
getRetAsOutArgs gr [SomeFFIArg ptr]
|
||||
|
||||
let build (n:ns) !i = do
|
||||
-- We need to be careful to actually run this here and not just
|
||||
-- stick the IO action into the sequence with io, or else we
|
||||
-- will read from the array after it is deallocated.
|
||||
vs <- for [0 .. fromInteger n - 1] \j ->
|
||||
build ns (i * fromInteger n + j)
|
||||
pure (VSeq n (finiteSeqMap Concrete (map pure vs)))
|
||||
build [] !i = peekElemOff ptr i >>= runEval stk . marshal
|
||||
|
||||
build sizes 0
|
||||
|
||||
case bt of
|
||||
|
||||
FFIBasicVal t ->
|
||||
getMarshalBasicValRet t \doImport ->
|
||||
allocaArray totalSize (getResult doImport)
|
||||
|
||||
FFIBasicRef t ->
|
||||
getBasicRefRet t \how ->
|
||||
allocaArray totalSize \ptr ->
|
||||
do let forEach f = for_ [0 .. totalSize - 1] (f . advancePtr ptr)
|
||||
bracket_ (forEach (initBasicRefRet how))
|
||||
(forEach (clearBasicRefRet how))
|
||||
(getResult (marshalBasicRefRet how) ptr)
|
||||
|
||||
marshalRet (FFITuple types) gr = VTuple <$> marshalMultiRet types gr
|
||||
|
||||
marshalRet (FFIRecord typeMap) gr =
|
||||
VRecord . recordFromFields . zip (displayOrder typeMap) <$>
|
||||
marshalMultiRet (displayElements typeMap) gr
|
||||
@ -214,6 +332,25 @@ foreignPrim name FFIFunType {..} impl tenv = buildFun ffiArgTypes []
|
||||
go types []
|
||||
map pure <$> readIORef vals
|
||||
|
||||
-- | Call the callback with a 'BasicRefRet' for the given type.
|
||||
getBasicRefRet :: FFIBasicRefType ->
|
||||
(forall a. Storable a => BasicRefRet a -> b) -> b
|
||||
getBasicRefRet (FFIInteger mbMod) f = f BasicRefRet
|
||||
{ initBasicRefRet = mpz_init
|
||||
, clearBasicRefRet = mpz_clear
|
||||
, marshalBasicRefRet = \mpz -> do
|
||||
n <- io $ peekInteger' mpz
|
||||
VInteger <$>
|
||||
case mbMod of
|
||||
Nothing -> pure n
|
||||
Just m -> intToZn Concrete (evalFinType m) n }
|
||||
getBasicRefRet FFIRational f = f BasicRefRet
|
||||
{ initBasicRefRet = mpq_init
|
||||
, clearBasicRefRet = mpq_clear
|
||||
, marshalBasicRefRet = \mpq -> do
|
||||
r <- io $ peekRational' mpq
|
||||
pure $ VRational $ SRational (numerator r) (denominator r) }
|
||||
|
||||
-- Evaluate a finite numeric type expression.
|
||||
evalFinType :: Type -> Integer
|
||||
evalFinType = finNat' . evalNumType tenv
|
||||
@ -230,32 +367,40 @@ getRetFromAsOutArgs f = GetRet
|
||||
peek ptr
|
||||
, getRetAsOutArgs = f }
|
||||
|
||||
-- | Given a 'FFIBasicType', call the callback with a marshalling function that
|
||||
-- marshals values to the 'FFIArg' type corresponding to the 'FFIBasicType'.
|
||||
-- The callback must be able to handle marshalling functions that marshal to any
|
||||
-- 'FFIArg' type.
|
||||
getMarshalBasicArg :: FFIBasicType ->
|
||||
(forall a. FFIArg a => (GenValue Concrete -> Eval a) -> b) -> b
|
||||
getMarshalBasicArg (FFIWord _ s) f = withWordType s \(_ :: p t) ->
|
||||
f @t $ fmap (fromInteger . bvVal) . fromVWord Concrete "getMarshalBasicArg"
|
||||
getMarshalBasicArg (FFIFloat _ _ s) f =
|
||||
-- | Given a 'FFIBasicValType', call the callback with a marshalling function
|
||||
-- that marshals values to the 'FFIArg' type corresponding to the
|
||||
-- 'FFIBasicValType'. The callback must be able to handle marshalling functions
|
||||
-- that marshal to any 'FFIArg' type.
|
||||
getMarshalBasicValArg ::
|
||||
FFIBasicValType ->
|
||||
(forall rep.
|
||||
FFIArg rep =>
|
||||
(GenValue Concrete -> Eval rep) ->
|
||||
result) ->
|
||||
result
|
||||
|
||||
getMarshalBasicValArg (FFIWord _ s) f = withWordType s \(_ :: p t) ->
|
||||
f @t $ fmap (fromInteger . bvVal) . fromVWord Concrete "getMarshalBasicValArg"
|
||||
|
||||
getMarshalBasicValArg (FFIFloat _ _ s) f =
|
||||
case s of
|
||||
-- LibBF can only convert to 'Double' directly, so we do that first then
|
||||
-- convert to 'Float', which should not result in any loss of precision if
|
||||
-- the original data was 32-bit anyways.
|
||||
FFIFloat32 -> f $ pure . CFloat . double2Float . toDouble
|
||||
FFIFloat64 -> f $ pure . CDouble . toDouble
|
||||
where toDouble = fst . bfToDouble NearEven . bfValue . fromVFloat
|
||||
where
|
||||
toDouble = fst . bfToDouble NearEven . bfValue . fromVFloat
|
||||
|
||||
-- | Given a 'FFIBasicType', call the callback with an unmarshalling function
|
||||
-- from the 'FFIRet' type corresponding to the 'FFIBasicType' to Cryptol values.
|
||||
-- The callback must be able to handle unmarshalling functions from any 'FFIRet'
|
||||
-- type.
|
||||
getMarshalBasicRet :: FFIBasicType ->
|
||||
-- | Given a 'FFIBasicValType', call the callback with an unmarshalling function
|
||||
-- from the 'FFIRet' type corresponding to the 'FFIBasicValType' to Cryptol
|
||||
-- values. The callback must be able to handle unmarshalling functions from any
|
||||
-- 'FFIRet' type.
|
||||
getMarshalBasicValRet :: FFIBasicValType ->
|
||||
(forall a. FFIRet a => (a -> Eval (GenValue Concrete)) -> b) -> b
|
||||
getMarshalBasicRet (FFIWord n s) f = withWordType s \(_ :: p t) ->
|
||||
getMarshalBasicValRet (FFIWord n s) f = withWordType s \(_ :: p t) ->
|
||||
f @t $ word Concrete n . toInteger
|
||||
getMarshalBasicRet (FFIFloat e p s) f =
|
||||
getMarshalBasicValRet (FFIFloat e p s) f =
|
||||
case s of
|
||||
FFIFloat32 -> f $ toValue . \case CFloat x -> float2Double x
|
||||
FFIFloat64 -> f $ toValue . \case CDouble x -> x
|
||||
@ -270,12 +415,27 @@ withWordType FFIWord16 f = f $ Proxy @Word16
|
||||
withWordType FFIWord32 f = f $ Proxy @Word32
|
||||
withWordType FFIWord64 f = f $ Proxy @Word64
|
||||
|
||||
-- | Given a 'FFIBasicRefType', call the callback with a marshalling function
|
||||
-- that takes a Cryptol value and calls its callback with the 'Storable' type
|
||||
-- corresponding to the 'FFIBasicRefType'.
|
||||
getMarshalBasicRefArg :: FFIBasicRefType ->
|
||||
(forall rep.
|
||||
Storable rep =>
|
||||
(GenValue Concrete -> (rep -> IO val) -> IO val) ->
|
||||
result) ->
|
||||
result
|
||||
getMarshalBasicRefArg (FFIInteger _) f = f \val g ->
|
||||
withInInteger' (fromVInteger val) g
|
||||
getMarshalBasicRefArg FFIRational f = f \val g -> do
|
||||
let SRational {..} = fromVRational val
|
||||
withInRational' (sNum % sDenom) g
|
||||
|
||||
#else
|
||||
|
||||
-- | Dummy implementation for when FFI is disabled. Does not add anything to
|
||||
-- the environment.
|
||||
evalForeignDecls :: ModulePath -> Module -> EvalEnv ->
|
||||
Eval (Either [FFILoadError] (ForeignSrc, EvalEnv))
|
||||
evalForeignDecls _ _ _ = pure $ Left []
|
||||
evalForeignDecls :: ForeignSrc -> [(Name, FFIFunType)] -> EvalEnv ->
|
||||
Eval (Either [FFILoadError] EvalEnv)
|
||||
evalForeignDecls _ _ env = pure $ Right env
|
||||
|
||||
#endif
|
||||
|
196
src/Cryptol/Eval/FFI/GenHeader.hs
Normal file
196
src/Cryptol/Eval/FFI/GenHeader.hs
Normal file
@ -0,0 +1,196 @@
|
||||
{-# LANGUAGE BlockArguments #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
-- | Generate C header files from foreign declarations.
|
||||
module Cryptol.Eval.FFI.GenHeader
|
||||
( generateForeignHeader
|
||||
) where
|
||||
|
||||
import Control.Monad.Writer.Strict
|
||||
import Data.Functor
|
||||
import Data.Char(isAlphaNum)
|
||||
import Data.List
|
||||
import Data.Set (Set)
|
||||
import qualified Data.Set as Set
|
||||
import Language.C99.Pretty as C
|
||||
import qualified Language.C99.Simple as C
|
||||
import qualified Text.PrettyPrint as Pretty
|
||||
|
||||
import Cryptol.ModuleSystem.Name
|
||||
import Cryptol.TypeCheck.FFI.FFIType
|
||||
import Cryptol.TypeCheck.Type
|
||||
import Cryptol.Utils.Ident
|
||||
import Cryptol.Utils.RecordMap
|
||||
|
||||
-- | @Include foo@ represents an include statement @#include <foo>@
|
||||
newtype Include = Include String deriving (Eq, Ord)
|
||||
|
||||
-- | The monad for generating headers. We keep track of which headers we need to
|
||||
-- include and add them to the output at the end.
|
||||
type GenHeaderM = Writer (Set Include)
|
||||
|
||||
-- | Generate a C header file from the given foreign declarations.
|
||||
generateForeignHeader :: [(Name, FFIFunType)] -> String
|
||||
generateForeignHeader decls =
|
||||
unlines (map renderInclude $ Set.toAscList incs)
|
||||
++ Pretty.render (C.pretty $ C.translate (C.TransUnit cdecls []))
|
||||
where (cdecls, incs) = runWriter $ traverse convertFun decls
|
||||
|
||||
renderInclude :: Include -> String
|
||||
renderInclude (Include inc) = "#include <" ++ inc ++ ">"
|
||||
|
||||
-- | The "direction" of a parameter (input or output).
|
||||
data ParamDir = In | Out
|
||||
|
||||
-- | The result of converting a Cryptol type into its C representation.
|
||||
data ConvertResult
|
||||
= Direct C.Type -- ^ A type that can be directly returned if it is a return
|
||||
-- type and passed as a single parameter if it is a Cryptol
|
||||
-- parameter type.
|
||||
| Params [C.Param] -- ^ A type that is turned into a number of parameters,
|
||||
-- for both Cryptol parameter and return type cases.
|
||||
|
||||
-- | Convert a Cryptol foreign declaration into a C function declaration.
|
||||
convertFun :: (Name, FFIFunType) -> GenHeaderM C.Decln
|
||||
convertFun (fName, FFIFunType {..}) = do
|
||||
let tpIdent = fmap nameIdent . tpName
|
||||
typeParams <- traverse convertTypeParam (pickNames (map tpIdent ffiTParams))
|
||||
-- Name the input args in0, in1, etc
|
||||
let inPrefixes =
|
||||
case ffiArgTypes of
|
||||
[_] -> ["in"]
|
||||
_ -> ["in" ++ show @Integer i | i <- [0..]]
|
||||
inParams <- convertMultiType In $ zip inPrefixes ffiArgTypes
|
||||
(retType, outParams) <- convertType Out ffiRetType
|
||||
<&> \case
|
||||
Direct u -> (u, [])
|
||||
-- Name the output arg out
|
||||
Params ps -> (C.TypeSpec C.Void, map (prefixParam "out") ps)
|
||||
-- Avoid possible name collisions
|
||||
let params = snd $ mapAccumL renameParam Set.empty $
|
||||
typeParams ++ inParams ++ outParams
|
||||
renameParam names (C.Param u name) =
|
||||
(Set.insert name' names, C.Param u name')
|
||||
where name' = until (`Set.notMember` names) (++ "_") name
|
||||
pure $ C.FunDecln Nothing retType (unpackIdent $ nameIdent fName) params
|
||||
|
||||
|
||||
-- | Convert a Cryptol type parameter to a C value parameter.
|
||||
convertTypeParam :: String -> GenHeaderM C.Param
|
||||
convertTypeParam name = (`C.Param` name) <$> sizeT
|
||||
|
||||
-- | Convert a Cryptol parameter or return type to C.
|
||||
convertType :: ParamDir -> FFIType -> GenHeaderM ConvertResult
|
||||
convertType _ FFIBool = Direct <$> uint8T
|
||||
convertType _ (FFIBasic t) = convertBasicType t
|
||||
convertType _ (FFIArray _ t) = do
|
||||
u <- convertBasicTypeInArray t
|
||||
pure $ Params [C.Param (C.Ptr u) ""]
|
||||
convertType dir (FFITuple ts) = Params <$> convertMultiType dir
|
||||
-- We name the tuple components using their indices
|
||||
(zip (map (componentSuffix . show @Integer) [0..]) ts)
|
||||
convertType dir (FFIRecord tMap) =
|
||||
Params <$> convertMultiType dir (zip names ts)
|
||||
where
|
||||
(fs,ts) = unzip (displayFields tMap)
|
||||
names = map componentSuffix (pickNames (map Just fs))
|
||||
|
||||
-- | Convert many Cryptol types, each associated with a prefix, to C parameters
|
||||
-- named with their prefixes.
|
||||
convertMultiType :: ParamDir -> [(C.Ident, FFIType)] -> GenHeaderM [C.Param]
|
||||
convertMultiType dir = fmap concat . traverse \(prefix, t) ->
|
||||
convertType dir t
|
||||
<&> \case
|
||||
Direct u -> [C.Param u' prefix]
|
||||
where u' = case dir of
|
||||
In -> u
|
||||
-- Turn direct return types into pointer out parameters
|
||||
Out -> C.Ptr u
|
||||
Params ps -> map (prefixParam prefix) ps
|
||||
|
||||
{- | Convert a basic Cryptol FFI type to a C type with its corresponding
|
||||
calling convention. At present all value types use the same calling
|
||||
convention no matter if they are inputs or outputs, so we don't
|
||||
need the 'ParamDir'. -}
|
||||
convertBasicType :: FFIBasicType -> GenHeaderM ConvertResult
|
||||
convertBasicType bt =
|
||||
case bt of
|
||||
FFIBasicVal bvt -> Direct <$> convertBasicValType bvt
|
||||
FFIBasicRef brt -> do t <- convertBasicRefType brt
|
||||
pure (Params [C.Param t ""])
|
||||
|
||||
-- | Convert a basic Cryptol FFI type to a C type.
|
||||
-- This is used when the type is stored in array.
|
||||
convertBasicTypeInArray :: FFIBasicType -> GenHeaderM C.Type
|
||||
convertBasicTypeInArray bt =
|
||||
case bt of
|
||||
FFIBasicVal bvt -> convertBasicValType bvt
|
||||
FFIBasicRef brt -> convertBasicRefType brt
|
||||
|
||||
-- | Convert a basic Cryptol FFI type to a value C type.
|
||||
convertBasicValType :: FFIBasicValType -> GenHeaderM C.Type
|
||||
convertBasicValType (FFIWord _ s) =
|
||||
case s of
|
||||
FFIWord8 -> uint8T
|
||||
FFIWord16 -> uint16T
|
||||
FFIWord32 -> uint32T
|
||||
FFIWord64 -> uint64T
|
||||
convertBasicValType (FFIFloat _ _ s) =
|
||||
case s of
|
||||
FFIFloat32 -> pure $ C.TypeSpec C.Float
|
||||
FFIFloat64 -> pure $ C.TypeSpec C.Double
|
||||
|
||||
-- | Convert a basic Cryptol FFI type to a reference C type.
|
||||
convertBasicRefType :: FFIBasicRefType -> GenHeaderM C.Type
|
||||
convertBasicRefType brt =
|
||||
case brt of
|
||||
FFIInteger {} -> mpzT
|
||||
FFIRational -> mpqT
|
||||
|
||||
prefixParam :: C.Ident -> C.Param -> C.Param
|
||||
prefixParam pre (C.Param u name) = C.Param u (pre ++ name)
|
||||
|
||||
-- | Create a suffix corresponding to some component name of some larger type.
|
||||
componentSuffix :: String -> C.Ident
|
||||
componentSuffix = ('_' :)
|
||||
|
||||
sizeT, uint8T, uint16T, uint32T, uint64T, mpzT, mpqT :: GenHeaderM C.Type
|
||||
sizeT = typedefFromInclude stddefH "size_t"
|
||||
uint8T = typedefFromInclude stdintH "uint8_t"
|
||||
uint16T = typedefFromInclude stdintH "uint16_t"
|
||||
uint32T = typedefFromInclude stdintH "uint32_t"
|
||||
uint64T = typedefFromInclude stdintH "uint64_t"
|
||||
mpzT = typedefFromInclude gmpH "mpz_t"
|
||||
mpqT = typedefFromInclude gmpH "mpq_t"
|
||||
|
||||
stddefH, stdintH, gmpH :: Include
|
||||
stddefH = Include "stddef.h"
|
||||
stdintH = Include "stdint.h"
|
||||
gmpH = Include "gmp.h"
|
||||
|
||||
|
||||
-- | Return a type with the given name, included from some header file.
|
||||
typedefFromInclude :: Include -> C.Ident -> GenHeaderM C.Type
|
||||
typedefFromInclude inc u = do
|
||||
tell $ Set.singleton inc
|
||||
pure $ C.TypeSpec $ C.TypedefName u
|
||||
|
||||
-- | Given some Cryptol identifiers (normal ones, not operators)
|
||||
-- pick suitable unique C names for them
|
||||
pickNames :: [Maybe Ident] -> [String]
|
||||
pickNames xs = snd (mapAccumL add Set.empty xs)
|
||||
where
|
||||
add known x =
|
||||
let y = simplify x
|
||||
ys = y : [ y ++ show i | i <- [ 0 :: Int .. ] ]
|
||||
y' : _ = dropWhile (`Set.member` known) ys
|
||||
in (Set.insert y' known, y')
|
||||
|
||||
simplify x = case x of
|
||||
Just i | let y = filter ok (unpackIdent i), not (null y) -> y
|
||||
_ -> "zz"
|
||||
|
||||
ok x = x == '_' || isAlphaNum x
|
||||
|
@ -1452,12 +1452,12 @@ fromToV sym =
|
||||
PNumPoly \first ->
|
||||
PNumPoly \lst ->
|
||||
PTyPoly \ty ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty in
|
||||
case (first, lst) of
|
||||
(Nat first', Nat lst') ->
|
||||
let len = 1 + (lst' - first')
|
||||
in VSeq len $ indexSeqMap $ \i -> f (first' + i)
|
||||
in mkSeq sym (Nat len) ty $ indexSeqMap $ \i -> f (first' + i)
|
||||
_ -> evalPanic "fromToV" ["invalid arguments"]
|
||||
|
||||
{-# INLINE fromThenToV #-}
|
||||
@ -1469,12 +1469,12 @@ fromThenToV sym =
|
||||
PNumPoly \lst ->
|
||||
PTyPoly \ty ->
|
||||
PNumPoly \len ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty in
|
||||
case (first, next, lst, len) of
|
||||
(Nat first', Nat next', Nat _lst', Nat len') ->
|
||||
let diff = next' - first'
|
||||
in VSeq len' $ indexSeqMap $ \i -> f (first' + i*diff)
|
||||
in mkSeq sym (Nat len') ty $ indexSeqMap $ \i -> f (first' + i*diff)
|
||||
_ -> evalPanic "fromThenToV" ["invalid arguments"]
|
||||
|
||||
{-# INLINE fromToLessThanV #-}
|
||||
@ -1484,12 +1484,12 @@ fromToLessThanV sym =
|
||||
PFinPoly \first ->
|
||||
PNumPoly \bound ->
|
||||
PTyPoly \ty ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty
|
||||
ss = indexSeqMap $ \i -> f (first + i)
|
||||
in case bound of
|
||||
Inf -> VStream ss
|
||||
Nat bound' -> VSeq (bound' - first) ss
|
||||
Inf -> return $ VStream ss
|
||||
Nat bound' -> mkSeq sym (Nat (bound' - first)) ty ss
|
||||
|
||||
{-# INLINE fromToByV #-}
|
||||
-- @[ 0 .. 10 by 2 ]@
|
||||
@ -1499,10 +1499,10 @@ fromToByV sym =
|
||||
PFinPoly \lst ->
|
||||
PFinPoly \stride ->
|
||||
PTyPoly \ty ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty
|
||||
ss = indexSeqMap $ \i -> f (first + i*stride)
|
||||
in VSeq (1 + ((lst - first) `div` stride)) ss
|
||||
in mkSeq sym (Nat (1 + ((lst - first) `div` stride))) ty ss
|
||||
|
||||
{-# INLINE fromToByLessThanV #-}
|
||||
-- @[ 0 .. <10 by 2 ]@
|
||||
@ -1512,12 +1512,12 @@ fromToByLessThanV sym =
|
||||
PNumPoly \bound ->
|
||||
PFinPoly \stride ->
|
||||
PTyPoly \ty ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty
|
||||
ss = indexSeqMap $ \i -> f (first + i*stride)
|
||||
in case bound of
|
||||
Inf -> VStream ss
|
||||
Nat bound' -> VSeq ((bound' - first + stride - 1) `div` stride) ss
|
||||
Inf -> return $ VStream ss
|
||||
Nat bound' -> mkSeq sym (Nat ((bound' - first + stride - 1) `div` stride)) ty ss
|
||||
|
||||
|
||||
{-# INLINE fromToDownByV #-}
|
||||
@ -1528,10 +1528,10 @@ fromToDownByV sym =
|
||||
PFinPoly \lst ->
|
||||
PFinPoly \stride ->
|
||||
PTyPoly \ty ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty
|
||||
ss = indexSeqMap $ \i -> f (first - i*stride)
|
||||
in VSeq (1 + ((first - lst) `div` stride)) ss
|
||||
in mkSeq sym (Nat (1 + ((first - lst) `div` stride))) ty ss
|
||||
|
||||
{-# INLINE fromToDownByGreaterThanV #-}
|
||||
-- @[ 10 .. >0 down by 2 ]@
|
||||
@ -1541,10 +1541,10 @@ fromToDownByGreaterThanV sym =
|
||||
PFinPoly \bound ->
|
||||
PFinPoly \stride ->
|
||||
PTyPoly \ty ->
|
||||
PVal
|
||||
PPrim
|
||||
let !f = mkLit sym ty
|
||||
ss = indexSeqMap $ \i -> f (first - i*stride)
|
||||
in VSeq ((first - bound + stride - 1) `div` stride) ss
|
||||
in mkSeq sym (Nat ((first - bound + stride - 1) `div` stride)) ty ss
|
||||
|
||||
{-# INLINE infFromV #-}
|
||||
infFromV :: Backend sym => sym -> Prim sym
|
||||
|
@ -10,6 +10,8 @@
|
||||
> {-# LANGUAGE BlockArguments #-}
|
||||
> {-# LANGUAGE PatternGuards #-}
|
||||
> {-# LANGUAGE LambdaCase #-}
|
||||
> {-# LANGUAGE NamedFieldPuns #-}
|
||||
> {-# LANGUAGE ViewPatterns #-}
|
||||
>
|
||||
> module Cryptol.Eval.Reference
|
||||
> ( Value(..)
|
||||
@ -32,6 +34,7 @@
|
||||
> import LibBF (BigFloat)
|
||||
> import qualified LibBF as FP
|
||||
> import qualified GHC.Num.Compat as Integer
|
||||
> import qualified Data.List as List
|
||||
>
|
||||
> import Cryptol.ModuleSystem.Name (asPrim)
|
||||
> import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), nAdd, nMin, nMul)
|
||||
@ -46,6 +49,8 @@
|
||||
> import Cryptol.Utils.Panic (panic)
|
||||
> import Cryptol.Utils.PP
|
||||
> import Cryptol.Utils.RecordMap
|
||||
> import Cryptol.Eval (checkProp)
|
||||
> import Cryptol.Eval.Type (evalType, lookupTypeVar, tNumTy, tValTy)
|
||||
>
|
||||
> import qualified Cryptol.ModuleSystem as M
|
||||
> import qualified Cryptol.ModuleSystem.Env as M (loadedModules,loadedNewtypes)
|
||||
@ -332,11 +337,27 @@ assigns values to those variables.
|
||||
> EProofAbs _ e -> evalExpr env e
|
||||
> EProofApp e -> evalExpr env e
|
||||
> EWhere e dgs -> evalExpr (foldl evalDeclGroup env dgs) e
|
||||
|
||||
>
|
||||
> EPropGuards guards _ty ->
|
||||
> case List.find (all (checkProp . evalProp env) . fst) guards of
|
||||
> Just (_, e) -> evalExpr env e
|
||||
> Nothing -> evalPanic "fromVBit" ["No guard constraint was satisfied"]
|
||||
|
||||
> appFun :: E Value -> E Value -> E Value
|
||||
> appFun f v = f >>= \f' -> fromVFun f' v
|
||||
|
||||
> -- | Evaluates a `Prop` in an `EvalEnv` by substituting all variables
|
||||
> -- according to `envTypes` and expanding all type synonyms via `tNoUser`.
|
||||
> evalProp :: Env -> Prop -> Prop
|
||||
> evalProp env@Env { envTypes } = \case
|
||||
> TCon tc tys -> TCon tc (toType . evalType envTypes <$> tys)
|
||||
> TVar tv | Just (toType -> ty) <- lookupTypeVar tv envTypes -> ty
|
||||
> prop@TUser {} -> evalProp env (tNoUser prop)
|
||||
> TVar tv | Nothing <- lookupTypeVar tv envTypes -> panic "evalProp" ["Could not find type variable `" ++ pretty tv ++ "` in the type evaluation environment"]
|
||||
> prop -> panic "evalProp" ["Cannot use the following as a type constraint: `" ++ pretty prop ++ "`"]
|
||||
> where
|
||||
> toType = either tNumTy tValTy
|
||||
|
||||
|
||||
Selectors
|
||||
---------
|
||||
|
@ -18,6 +18,7 @@ import Cryptol.TypeCheck.Solver.InfNat
|
||||
import Cryptol.Utils.Panic (panic)
|
||||
import Cryptol.Utils.Ident (Ident)
|
||||
import Cryptol.Utils.RecordMap
|
||||
import Cryptol.Utils.Types
|
||||
|
||||
import Data.Maybe(fromMaybe)
|
||||
import qualified Data.IntMap.Strict as IntMap
|
||||
@ -27,7 +28,7 @@ import Control.DeepSeq
|
||||
-- | An evaluated type of kind *.
|
||||
-- These types do not contain type variables, type synonyms, or type functions.
|
||||
data TValue
|
||||
= TVBit -- ^ @ Bit @
|
||||
= TVBit -- ^ @ Bit @
|
||||
| TVInteger -- ^ @ Integer @
|
||||
| TVFloat Integer Integer -- ^ @ Float e p @
|
||||
| TVIntMod Integer -- ^ @ Z n @
|
||||
@ -86,6 +87,10 @@ tvSeq :: Nat' -> TValue -> TValue
|
||||
tvSeq (Nat n) t = TVSeq n t
|
||||
tvSeq Inf t = TVStream t
|
||||
|
||||
-- | The Cryptol @Float64@ type.
|
||||
tvFloat64 :: TValue
|
||||
tvFloat64 = uncurry TVFloat float64ExpPrec
|
||||
|
||||
-- | Coerce an extended natural into an integer,
|
||||
-- for values known to be finite
|
||||
finNat' :: Nat' -> Integer
|
||||
@ -100,6 +105,7 @@ finNat' n' =
|
||||
newtype TypeEnv =
|
||||
TypeEnv
|
||||
{ envTypeMap :: IntMap.IntMap (Either Nat' TValue) }
|
||||
deriving (Show)
|
||||
|
||||
instance Monoid TypeEnv where
|
||||
mempty = TypeEnv mempty
|
||||
|
@ -117,6 +117,7 @@ instance FreeVars Expr where
|
||||
EProofAbs p e -> freeVars p <> freeVars e
|
||||
EProofApp e -> freeVars e
|
||||
EWhere e ds -> foldFree ds <> rmVals (defs ds) (freeVars e)
|
||||
EPropGuards guards _ -> mconcat [ freeVars e | (_, e) <- guards ]
|
||||
where
|
||||
foldFree :: (FreeVars a, Defs a) => [a] -> Deps
|
||||
foldFree = foldr updateFree mempty
|
||||
|
@ -18,8 +18,10 @@ module Cryptol.ModuleSystem (
|
||||
, findModule
|
||||
, loadModuleByPath
|
||||
, loadModuleByName
|
||||
, checkModuleByPath
|
||||
, checkExpr
|
||||
, evalExpr
|
||||
, benchmarkExpr
|
||||
, checkDecls
|
||||
, evalDecls
|
||||
, noPat
|
||||
@ -46,6 +48,7 @@ import Cryptol.Parser.Name (PName)
|
||||
import Cryptol.Parser.NoPat (RemovePatterns)
|
||||
import qualified Cryptol.TypeCheck.AST as T
|
||||
import qualified Cryptol.TypeCheck.Interface as T
|
||||
import Cryptol.Utils.Benchmark (BenchmarkStats)
|
||||
import qualified Cryptol.Utils.Ident as M
|
||||
|
||||
-- Public Interface ------------------------------------------------------------
|
||||
@ -67,7 +70,7 @@ loadModuleByPath path minp = do
|
||||
moduleEnv' <- resetModuleEnv $ minpModuleEnv minp
|
||||
runModuleM minp{ minpModuleEnv = moduleEnv' } $ do
|
||||
unloadModule ((InFile path ==) . lmFilePath)
|
||||
m <- Base.loadModuleByPath path
|
||||
m <- Base.loadModuleByPath True path
|
||||
setFocusedModule (T.tcTopEntitytName m)
|
||||
return (InFile path,m)
|
||||
|
||||
@ -81,6 +84,15 @@ loadModuleByName n minp = do
|
||||
setFocusedModule (T.tcTopEntitytName m')
|
||||
return (path,m')
|
||||
|
||||
-- | Parse and typecheck a module, but don't evaluate or change the environment.
|
||||
checkModuleByPath :: FilePath -> ModuleCmd (ModulePath, T.TCTopEntity)
|
||||
checkModuleByPath path minp = do
|
||||
(res, warns) <- runModuleM minp $ Base.loadModuleByPath False path
|
||||
-- restore the old environment
|
||||
let res1 = do (x,_newEnv) <- res
|
||||
pure ((InFile path, x), minpModuleEnv minp)
|
||||
pure (res1, warns)
|
||||
|
||||
-- Extended Environments -------------------------------------------------------
|
||||
|
||||
-- These functions are particularly useful for interactive modes, as
|
||||
@ -96,6 +108,11 @@ checkExpr e env = runModuleM env (interactive (Base.checkExpr e))
|
||||
evalExpr :: T.Expr -> ModuleCmd Concrete.Value
|
||||
evalExpr e env = runModuleM env (interactive (Base.evalExpr e))
|
||||
|
||||
-- | Benchmark an expression.
|
||||
benchmarkExpr :: Double -> T.Expr -> ModuleCmd BenchmarkStats
|
||||
benchmarkExpr period e env =
|
||||
runModuleM env (interactive (Base.benchmarkExpr period e))
|
||||
|
||||
-- | Typecheck top-level declarations.
|
||||
checkDecls :: [P.TopDecl PName] -> ModuleCmd (R.NamingEnv,[T.DeclGroup], Map Name T.TySyn)
|
||||
checkDecls ds env = runModuleM env
|
||||
|
@ -51,6 +51,7 @@ import Cryptol.ModuleSystem.Env ( lookupModule
|
||||
, meCoreLint, CoreLint(..)
|
||||
, ModContext(..)
|
||||
, ModulePath(..), modulePathLabel)
|
||||
import Cryptol.Backend.FFI
|
||||
import qualified Cryptol.Eval as E
|
||||
import qualified Cryptol.Eval.Concrete as Concrete
|
||||
import Cryptol.Eval.Concrete (Concrete(..))
|
||||
@ -61,6 +62,8 @@ import qualified Cryptol.Parser as P
|
||||
import qualified Cryptol.Parser.Unlit as P
|
||||
import Cryptol.Parser.AST as P
|
||||
import Cryptol.Parser.NoPat (RemovePatterns(removePatterns))
|
||||
import qualified Cryptol.Parser.ExpandPropGuards as ExpandPropGuards
|
||||
( expandPropGuards, runExpandPropGuardsM )
|
||||
import Cryptol.Parser.NoInclude (removeIncludesModule)
|
||||
import Cryptol.Parser.Position (HasLoc(..), Range, emptyRange)
|
||||
import qualified Cryptol.TypeCheck as T
|
||||
@ -74,6 +77,7 @@ import Cryptol.Utils.Ident ( preludeName, floatName, arrayName, suiteBName, prim
|
||||
import Cryptol.Utils.PP (pretty)
|
||||
import Cryptol.Utils.Panic (panic)
|
||||
import Cryptol.Utils.Logger(logPutStrLn, logPrint)
|
||||
import Cryptol.Utils.Benchmark
|
||||
|
||||
import Cryptol.Prelude ( preludeContents, floatContents, arrayContents
|
||||
, suiteBContents, primeECContents, preludeReferenceContents )
|
||||
@ -116,6 +120,14 @@ noPat a = do
|
||||
unless (null errs) (noPatErrors errs)
|
||||
return a'
|
||||
|
||||
-- ExpandPropGuards ------------------------------------------------------------
|
||||
|
||||
-- | Run the expandPropGuards pass.
|
||||
expandPropGuards :: Module PName -> ModuleM (Module PName)
|
||||
expandPropGuards a =
|
||||
case ExpandPropGuards.runExpandPropGuardsM $ ExpandPropGuards.expandPropGuards a of
|
||||
Left err -> expandPropGuardsError err
|
||||
Right a' -> pure a'
|
||||
|
||||
-- Parsing ---------------------------------------------------------------------
|
||||
|
||||
@ -179,8 +191,10 @@ parseModule path = do
|
||||
-- Top Level Modules and Signatures ----------------------------------------------
|
||||
|
||||
-- | Load a module by its path.
|
||||
loadModuleByPath :: FilePath -> ModuleM T.TCTopEntity
|
||||
loadModuleByPath path = withPrependedSearchPath [ takeDirectory path ] $ do
|
||||
loadModuleByPath ::
|
||||
Bool {- ^ evaluate declarations in the module -} ->
|
||||
FilePath -> ModuleM T.TCTopEntity
|
||||
loadModuleByPath eval path = withPrependedSearchPath [ takeDirectory path ] $ do
|
||||
let fileName = takeFileName path
|
||||
foundPath <- findFile fileName
|
||||
(fp, pms) <- parseModule (InFile foundPath)
|
||||
@ -197,7 +211,8 @@ loadModuleByPath path = withPrependedSearchPath [ takeDirectory path ] $ do
|
||||
|
||||
case lookupTCEntity n env of
|
||||
-- loadModule will calculate the canonical path again
|
||||
Nothing -> doLoadModule False (FromModule n) (InFile foundPath) fp pm
|
||||
Nothing ->
|
||||
doLoadModule eval False (FromModule n) (InFile foundPath) fp pm
|
||||
Just lm
|
||||
| path' == loaded -> return (lmData lm)
|
||||
| otherwise -> duplicateModuleName n path' loaded
|
||||
@ -216,18 +231,19 @@ loadModuleFrom quiet isrc =
|
||||
do path <- findModule n
|
||||
errorInFile path $
|
||||
do (fp, pms) <- parseModule path
|
||||
ms <- mapM (doLoadModule quiet isrc path fp) pms
|
||||
ms <- mapM (doLoadModule True quiet isrc path fp) pms
|
||||
return (path,last ms)
|
||||
|
||||
-- | Load dependencies, typecheck, and add to the eval environment.
|
||||
doLoadModule ::
|
||||
Bool {- ^ evaluate declarations in the module -} ->
|
||||
Bool {- ^ quiet mode: true suppresses the "loading module" message -} ->
|
||||
ImportSource ->
|
||||
ModulePath ->
|
||||
Fingerprint ->
|
||||
P.Module PName ->
|
||||
ModuleM T.TCTopEntity
|
||||
doLoadModule quiet isrc path fp pm0 =
|
||||
doLoadModule eval quiet isrc path fp pm0 =
|
||||
loading isrc $
|
||||
do let pm = addPrelude pm0
|
||||
loadDeps pm
|
||||
@ -247,28 +263,42 @@ doLoadModule quiet isrc path fp pm0 =
|
||||
let ?evalPrim = \i -> Right <$> Map.lookup i tbl
|
||||
callStacks <- getCallStacks
|
||||
let ?callStacks = callStacks
|
||||
fsrc <- case tcm of
|
||||
T.TCTopModule m | not (T.isParametrizedModule m) ->
|
||||
do (getForeign,_) <-
|
||||
modifyEvalEnvM \env ->
|
||||
do res <- evalForeignDecls path m env
|
||||
pure
|
||||
case res of
|
||||
Left [] -> (pure Nothing, env)
|
||||
Left errs ->
|
||||
(ffiLoadErrors (T.mName m) errs, env)
|
||||
Right (foreignSrc,newEnv) ->
|
||||
(pure (Just foreignSrc), newEnv)
|
||||
fsrc <- getForeign
|
||||
modifyEvalEnv (E.moduleEnv Concrete m)
|
||||
pure fsrc
|
||||
let shouldEval =
|
||||
case tcm of
|
||||
T.TCTopModule m | eval && not (T.isParametrizedModule m) -> Just m
|
||||
_ -> Nothing
|
||||
|
||||
_ -> pure Nothing
|
||||
loadedModule path fp nameEnv fsrc tcm
|
||||
foreignSrc <- case shouldEval of
|
||||
Just m ->
|
||||
do fsrc <- evalForeign m
|
||||
modifyEvalEnv (E.moduleEnv Concrete m)
|
||||
pure fsrc
|
||||
Nothing -> pure Nothing
|
||||
|
||||
loadedModule path fp nameEnv foreignSrc tcm
|
||||
|
||||
return tcm
|
||||
|
||||
|
||||
where
|
||||
evalForeign tcm
|
||||
| null foreigns = pure Nothing
|
||||
| otherwise = case path of
|
||||
InFile p -> io (canonicalizePath p >>= loadForeignSrc) >>=
|
||||
\case
|
||||
Right fsrc -> do
|
||||
unless quiet $
|
||||
case getForeignSrcPath fsrc of
|
||||
Just fpath -> withLogger logPutStrLn $
|
||||
"Loading dynamic library " ++ takeFileName fpath
|
||||
Nothing -> pure ()
|
||||
modifyEvalEnvM (evalForeignDecls fsrc foreigns) >>=
|
||||
\case
|
||||
Right () -> pure $ Just fsrc
|
||||
Left errs -> ffiLoadErrors (T.mName tcm) errs
|
||||
Left err -> ffiLoadErrors (T.mName tcm) [err]
|
||||
InMem m _ -> panic "doLoadModule"
|
||||
["Can't find foreign source of in-memory module", m]
|
||||
where foreigns = findForeignDecls tcm
|
||||
|
||||
|
||||
|
||||
@ -478,8 +508,11 @@ checkModule isrc m = do
|
||||
-- remove pattern bindings
|
||||
npm <- noPat m
|
||||
|
||||
-- run expandPropGuards
|
||||
epgm <- expandPropGuards npm
|
||||
|
||||
-- rename everything
|
||||
renMod <- renameModule npm
|
||||
renMod <- renameModule epgm
|
||||
|
||||
|
||||
{-
|
||||
@ -645,6 +678,22 @@ evalExpr e = do
|
||||
|
||||
io $ E.runEval mempty (E.evalExpr Concrete (env <> deEnv denv) e)
|
||||
|
||||
benchmarkExpr :: Double -> T.Expr -> ModuleM BenchmarkStats
|
||||
benchmarkExpr period e = do
|
||||
env <- getEvalEnv
|
||||
denv <- getDynEnv
|
||||
evopts <- getEvalOptsAction
|
||||
let env' = env <> deEnv denv
|
||||
let tbl = Concrete.primTable evopts
|
||||
let ?evalPrim = \i -> Right <$> Map.lookup i tbl
|
||||
let ?range = emptyRange
|
||||
callStacks <- getCallStacks
|
||||
let ?callStacks = callStacks
|
||||
|
||||
let eval expr = E.runEval mempty $
|
||||
E.evalExpr Concrete env' expr >>= E.forceValue
|
||||
io $ benchmark period eval e
|
||||
|
||||
evalDecls :: [T.DeclGroup] -> ModuleM ()
|
||||
evalDecls dgs = do
|
||||
env <- getEvalEnv
|
||||
|
@ -1,4 +1,5 @@
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
module Cryptol.ModuleSystem.Exports where
|
||||
|
||||
import Data.Set(Set)
|
||||
|
@ -11,6 +11,7 @@
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE PatternGuards #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
module Cryptol.ModuleSystem.Interface (
|
||||
Iface
|
||||
, IfaceG(..)
|
||||
|
@ -32,6 +32,7 @@ import qualified Cryptol.Parser.AST as P
|
||||
import Cryptol.Parser.Position (Located)
|
||||
import Cryptol.Utils.Panic (panic)
|
||||
import qualified Cryptol.Parser.NoPat as NoPat
|
||||
import qualified Cryptol.Parser.ExpandPropGuards as ExpandPropGuards
|
||||
import qualified Cryptol.Parser.NoInclude as NoInc
|
||||
import qualified Cryptol.TypeCheck as T
|
||||
import qualified Cryptol.TypeCheck.AST as T
|
||||
@ -107,6 +108,8 @@ data ModuleError
|
||||
-- ^ Problems during the renaming phase
|
||||
| NoPatErrors ImportSource [NoPat.Error]
|
||||
-- ^ Problems during the NoPat phase
|
||||
| ExpandPropGuardsError ImportSource ExpandPropGuards.Error
|
||||
-- ^ Problems during the ExpandPropGuards phase
|
||||
| NoIncludeErrors ImportSource [NoInc.IncludeError]
|
||||
-- ^ Problems during the NoInclude phase
|
||||
| TypeCheckingFailed ImportSource T.NameMap [(Range,T.Error)]
|
||||
@ -137,6 +140,7 @@ instance NFData ModuleError where
|
||||
RecursiveModules mods -> mods `deepseq` ()
|
||||
RenamerErrors src errs -> src `deepseq` errs `deepseq` ()
|
||||
NoPatErrors src errs -> src `deepseq` errs `deepseq` ()
|
||||
ExpandPropGuardsError src err -> src `deepseq` err `deepseq` ()
|
||||
NoIncludeErrors src errs -> src `deepseq` errs `deepseq` ()
|
||||
TypeCheckingFailed nm src errs -> nm `deepseq` src `deepseq` errs `deepseq` ()
|
||||
ModuleNameMismatch expected found ->
|
||||
@ -182,6 +186,8 @@ instance PP ModuleError where
|
||||
|
||||
NoPatErrors _src errs -> vcat (map pp errs)
|
||||
|
||||
ExpandPropGuardsError _src err -> pp err
|
||||
|
||||
NoIncludeErrors _src errs -> vcat (map NoInc.ppIncludeError errs)
|
||||
|
||||
TypeCheckingFailed _src nm errs -> vcat (map (T.ppNamedError nm) errs)
|
||||
@ -189,7 +195,7 @@ instance PP ModuleError where
|
||||
ModuleNameMismatch expected found ->
|
||||
hang (text "[error]" <+> pp (P.srcRange found) <.> char ':')
|
||||
4 (vcat [ text "File name does not match module name:"
|
||||
, text "Saw:" <+> pp (P.thing found)
|
||||
, text " Actual:" <+> pp (P.thing found)
|
||||
, text "Expected:" <+> pp expected
|
||||
])
|
||||
|
||||
@ -236,6 +242,11 @@ noPatErrors errs = do
|
||||
src <- getImportSource
|
||||
ModuleT (raise (NoPatErrors src errs))
|
||||
|
||||
expandPropGuardsError :: ExpandPropGuards.Error -> ModuleM a
|
||||
expandPropGuardsError err = do
|
||||
src <- getImportSource
|
||||
ModuleT (raise (ExpandPropGuardsError src err))
|
||||
|
||||
noIncludeErrors :: [NoInc.IncludeError] -> ModuleM a
|
||||
noIncludeErrors errs = do
|
||||
src <- getImportSource
|
||||
|
@ -977,6 +977,11 @@ instance Rename BindDef where
|
||||
rename DPrim = return DPrim
|
||||
rename DForeign = return DForeign
|
||||
rename (DExpr e) = DExpr <$> rename e
|
||||
rename (DPropGuards cases) = DPropGuards <$> traverse rename cases
|
||||
|
||||
instance Rename PropGuardCase where
|
||||
rename g = PropGuardCase <$> traverse (rnLocated rename) (pgcProps g)
|
||||
<*> rename (pgcExpr g)
|
||||
|
||||
-- NOTE: this only renames types within the pattern.
|
||||
instance Rename Pattern where
|
||||
|
@ -327,7 +327,7 @@ prim_bind :: { [TopDecl PName] }
|
||||
| mbDoc 'primitive' 'type' schema ':' kind {% mkPrimTypeDecl $1 $4 $6 }
|
||||
|
||||
foreign_bind :: { [TopDecl PName] }
|
||||
: mbDoc 'foreign' name ':' schema { mkForeignDecl $1 $3 $5 }
|
||||
: mbDoc 'foreign' name ':' schema {% mkForeignDecl $1 $3 $5 }
|
||||
|
||||
parameter_decls :: { TopDecl PName }
|
||||
: 'parameter' 'v{' par_decls 'v}' { mkParDecls (reverse $3) }
|
||||
@ -353,11 +353,14 @@ mbDoc :: { Maybe (Located Text) }
|
||||
: doc { Just $1 }
|
||||
| {- empty -} { Nothing }
|
||||
|
||||
|
||||
decl :: { Decl PName }
|
||||
: vars_comma ':' schema { at (head $1,$3) $ DSignature (reverse $1) $3 }
|
||||
| ipat '=' expr { at ($1,$3) $ DPatBind $1 $3 }
|
||||
| '(' op ')' '=' expr { at ($1,$5) $ DPatBind (PVar $2) $5 }
|
||||
| var apats_indices propguards_cases
|
||||
{% mkPropGuardsDecl $1 $2 $3 }
|
||||
| var propguards_cases
|
||||
{% mkConstantPropGuardsDecl $1 $2 }
|
||||
| var apats_indices '=' expr
|
||||
{ at ($1,$4) $ mkIndexedDecl $1 $2 $4 }
|
||||
|
||||
@ -436,6 +439,19 @@ let_decl :: { Decl PName }
|
||||
| 'infix' NUM ops {% mkFixity NonAssoc $2 (reverse $3) }
|
||||
|
||||
|
||||
|
||||
|
||||
propguards_cases :: { [PropGuardCase PName] }
|
||||
: propguards_cases propguards_case { $2 : $1 }
|
||||
| propguards_case { [$1] }
|
||||
|
||||
propguards_case :: { PropGuardCase PName }
|
||||
: '|' propguards_quals '=>' expr { PropGuardCase $2 $4 }
|
||||
|
||||
propguards_quals :: { [Located (Prop PName)] }
|
||||
: type {% mkPropGuards $1 }
|
||||
|
||||
|
||||
newtype :: { Newtype PName }
|
||||
: 'newtype' qname '=' newtype_body
|
||||
{ Newtype $2 [] (thing $4) }
|
||||
|
@ -17,6 +17,7 @@
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE BlockArguments #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module Cryptol.Parser.AST
|
||||
( -- * Names
|
||||
Ident, mkIdent, mkInfix, isInfixIdent, nullIdent, identText
|
||||
@ -75,6 +76,7 @@ module Cryptol.Parser.AST
|
||||
, Signature(..)
|
||||
, ModParam(..)
|
||||
, ParamDecl(..)
|
||||
, PropGuardCase(..)
|
||||
|
||||
-- * Interactive
|
||||
, ReplInput(..)
|
||||
@ -92,6 +94,7 @@ module Cryptol.Parser.AST
|
||||
, emptyFunDesc
|
||||
, PrefixOp(..)
|
||||
, prefixFixity
|
||||
, asEApps
|
||||
|
||||
-- * Positions
|
||||
, Located(..)
|
||||
@ -429,8 +432,15 @@ type LBindDef = Located (BindDef PName)
|
||||
data BindDef name = DPrim
|
||||
| DForeign
|
||||
| DExpr (Expr name)
|
||||
| DPropGuards [PropGuardCase name]
|
||||
deriving (Eq, Show, Generic, NFData, Functor)
|
||||
|
||||
data PropGuardCase name = PropGuardCase
|
||||
{ pgcProps :: [Located (Prop name)]
|
||||
, pgcExpr :: Expr name
|
||||
}
|
||||
deriving (Eq,Generic,NFData,Functor,Show)
|
||||
|
||||
data Pragma = PragmaNote String
|
||||
| PragmaProperty
|
||||
deriving (Eq, Show, Generic, NFData)
|
||||
@ -976,6 +986,7 @@ instance (Show name, PPName name) => PP (BindDef name) where
|
||||
ppPrec _ DPrim = text "<primitive>"
|
||||
ppPrec _ DForeign = text "<foreign>"
|
||||
ppPrec p (DExpr e) = ppPrec p e
|
||||
ppPrec _p (DPropGuards _guards) = text "propguards"
|
||||
|
||||
|
||||
instance PPName name => PP (TySyn name) where
|
||||
@ -1239,6 +1250,8 @@ instance PPName name => PP (Type name) where
|
||||
instance PPName name => PP (Prop name) where
|
||||
ppPrec n (CType t) = ppPrec n t
|
||||
|
||||
instance PPName name => PP [Prop name] where
|
||||
ppPrec n props = parens . commaSep . fmap (ppPrec n) $ props
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Drop all position information, so equality reflects program structure
|
||||
|
137
src/Cryptol/Parser/ExpandPropGuards.hs
Normal file
137
src/Cryptol/Parser/ExpandPropGuards.hs
Normal file
@ -0,0 +1,137 @@
|
||||
{-# LANGUAGE BlockArguments #-}
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
|
||||
-- |
|
||||
-- Module : Cryptol.Parser.PropGuards
|
||||
-- Copyright : (c) 2022 Galois, Inc.
|
||||
-- License : BSD3
|
||||
-- Maintainer : cryptol@galois.com
|
||||
-- Stability : provisional
|
||||
-- Portability : portable
|
||||
--
|
||||
-- Expands PropGuards into a top-level definition for each case, and rewrites
|
||||
-- the body of each case to be an appropriate call to the respectively generated
|
||||
-- function.
|
||||
module Cryptol.Parser.ExpandPropGuards where
|
||||
|
||||
import Control.DeepSeq
|
||||
import Cryptol.Parser.AST
|
||||
import Cryptol.Utils.PP
|
||||
import Cryptol.Utils.Panic (panic)
|
||||
import Data.Text (pack)
|
||||
import GHC.Generics (Generic)
|
||||
|
||||
-- | Monad
|
||||
type ExpandPropGuardsM a = Either Error a
|
||||
|
||||
runExpandPropGuardsM :: ExpandPropGuardsM a -> Either Error a
|
||||
runExpandPropGuardsM m = m
|
||||
|
||||
-- | Error
|
||||
data Error = NoSignature (Located PName)
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
instance PP Error where
|
||||
ppPrec _ err = case err of
|
||||
NoSignature x ->
|
||||
text "At" <+> pp (srcRange x) <.> colon
|
||||
<+> text "Declarations using constraint guards require an explicit type signature."
|
||||
|
||||
expandPropGuards :: ModuleG mname PName -> ExpandPropGuardsM (ModuleG mname PName)
|
||||
expandPropGuards m =
|
||||
do def <- expandModuleDef (mDef m)
|
||||
pure m { mDef = def }
|
||||
|
||||
expandModuleDef :: ModuleDefinition PName -> ExpandPropGuardsM (ModuleDefinition PName)
|
||||
expandModuleDef m =
|
||||
case m of
|
||||
NormalModule ds -> NormalModule . concat <$> mapM expandTopDecl ds
|
||||
FunctorInstance {} -> pure m
|
||||
InterfaceModule {} -> pure m
|
||||
|
||||
expandTopDecl :: TopDecl PName -> ExpandPropGuardsM [TopDecl PName]
|
||||
expandTopDecl topDecl =
|
||||
case topDecl of
|
||||
Decl topLevelDecl ->
|
||||
do ds <- expandDecl (tlValue topLevelDecl)
|
||||
pure [ Decl topLevelDecl { tlValue = d } | d <- ds ]
|
||||
|
||||
DModule tl | NestedModule m <- tlValue tl ->
|
||||
do m1 <- expandPropGuards m
|
||||
pure [DModule tl { tlValue = NestedModule m1 }]
|
||||
|
||||
_ -> pure [topDecl]
|
||||
|
||||
expandDecl :: Decl PName -> ExpandPropGuardsM [Decl PName]
|
||||
expandDecl decl =
|
||||
case decl of
|
||||
DBind bind -> do bs <- expandBind bind
|
||||
pure (map DBind bs)
|
||||
_ -> pure [decl]
|
||||
|
||||
expandBind :: Bind PName -> ExpandPropGuardsM [Bind PName]
|
||||
expandBind bind =
|
||||
case thing (bDef bind) of
|
||||
DPropGuards guards -> do
|
||||
Forall params props t rng <-
|
||||
case bSignature bind of
|
||||
Just schema -> pure schema
|
||||
Nothing -> Left . NoSignature $ bName bind
|
||||
let goGuard ::
|
||||
PropGuardCase PName ->
|
||||
ExpandPropGuardsM (PropGuardCase PName, Bind PName)
|
||||
goGuard (PropGuardCase props' e) = do
|
||||
bName' <- newName (bName bind) (thing <$> props')
|
||||
-- call to generated function
|
||||
tParams <- case bSignature bind of
|
||||
Just (Forall tps _ _ _) -> pure tps
|
||||
Nothing -> Left $ NoSignature (bName bind)
|
||||
typeInsts <-
|
||||
(\(TParam n _ _) -> Right . PosInst $ TUser n [])
|
||||
`traverse` tParams
|
||||
let e' = foldl EApp (EAppT (EVar $ thing bName') typeInsts) (patternToExpr <$> bParams bind)
|
||||
pure
|
||||
( PropGuardCase props' e',
|
||||
bind
|
||||
{ bName = bName',
|
||||
-- include guarded props in signature
|
||||
bSignature = Just (Forall params
|
||||
(props <> map thing props')
|
||||
t rng),
|
||||
-- keeps same location at original bind
|
||||
-- i.e. "on top of" original bind
|
||||
bDef = (bDef bind) {thing = DExpr e}
|
||||
}
|
||||
)
|
||||
(guards', binds') <- unzip <$> mapM goGuard guards
|
||||
pure $
|
||||
bind {bDef = DPropGuards guards' <$ bDef bind} :
|
||||
binds'
|
||||
_ -> pure [bind]
|
||||
|
||||
patternToExpr :: Pattern PName -> Expr PName
|
||||
patternToExpr (PVar locName) = EVar (thing locName)
|
||||
patternToExpr _ =
|
||||
panic "patternToExpr"
|
||||
["Unimplemented: patternToExpr of anything other than PVar"]
|
||||
|
||||
newName :: Located PName -> [Prop PName] -> ExpandPropGuardsM (Located PName)
|
||||
newName locName props =
|
||||
pure case thing locName of
|
||||
Qual modName ident ->
|
||||
let txt = identText ident
|
||||
txt' = pack $ show $ pp props
|
||||
in Qual modName (mkIdent $ txt <> txt') <$ locName
|
||||
UnQual ident ->
|
||||
let txt = identText ident
|
||||
txt' = pack $ show $ pp props
|
||||
in UnQual (mkIdent $ txt <> txt') <$ locName
|
||||
NewName _ _ ->
|
||||
panic "mkName"
|
||||
[ "During expanding prop guards"
|
||||
, "tried to make new name from NewName case of PName"
|
||||
]
|
@ -7,6 +7,7 @@
|
||||
-- Portability : portable
|
||||
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
module Cryptol.Parser.Name where
|
||||
|
||||
@ -33,6 +34,7 @@ data PName = UnQual !Ident
|
||||
-- | Passes that can generate fresh names.
|
||||
data Pass = NoPat
|
||||
| MonoValues
|
||||
| ExpandPropGuards String
|
||||
deriving (Eq,Ord,Show,Generic)
|
||||
|
||||
instance NFData PName
|
||||
@ -54,8 +56,9 @@ getIdent (Qual _ n) = n
|
||||
getIdent (NewName p i) = packIdent ("__" ++ pass ++ show i)
|
||||
where
|
||||
pass = case p of
|
||||
NoPat -> "p"
|
||||
MonoValues -> "mv"
|
||||
NoPat -> "p"
|
||||
MonoValues -> "mv"
|
||||
ExpandPropGuards _ -> "epg"
|
||||
|
||||
isGeneratedName :: PName -> Bool
|
||||
isGeneratedName x =
|
||||
|
@ -9,6 +9,8 @@
|
||||
-- This module defines the scoping rules for value- and type-level
|
||||
-- names in Cryptol.
|
||||
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
module Cryptol.Parser.Names
|
||||
( tnamesNT
|
||||
, tnamesT
|
||||
@ -65,6 +67,7 @@ namesDef :: Ord name => BindDef name -> Set name
|
||||
namesDef DPrim = Set.empty
|
||||
namesDef DForeign = Set.empty
|
||||
namesDef (DExpr e) = namesE e
|
||||
namesDef (DPropGuards guards) = Set.unions (map (namesE . pgcExpr) guards)
|
||||
|
||||
|
||||
-- | The names used by an expression.
|
||||
@ -186,6 +189,11 @@ tnamesDef :: Ord name => BindDef name -> Set name
|
||||
tnamesDef DPrim = Set.empty
|
||||
tnamesDef DForeign = Set.empty
|
||||
tnamesDef (DExpr e) = tnamesE e
|
||||
tnamesDef (DPropGuards guards) = Set.unions (map tnamesPropGuardCase guards)
|
||||
|
||||
tnamesPropGuardCase :: Ord name => PropGuardCase name -> Set name
|
||||
tnamesPropGuardCase c =
|
||||
Set.unions (tnamesE (pgcExpr c) : map (tnamesC . thing) (pgcProps c))
|
||||
|
||||
-- | The type names used by an expression.
|
||||
tnamesE :: Ord name => Expr name -> Set name
|
||||
|
@ -229,6 +229,20 @@ noMatchB b =
|
||||
do e' <- noPatFun (Just (thing (bName b))) 0 (bParams b) e
|
||||
return b { bParams = [], bDef = DExpr e' <$ bDef b }
|
||||
|
||||
DPropGuards guards ->
|
||||
do let nm = thing (bName b)
|
||||
ps = bParams b
|
||||
gs <- mapM (noPatPropGuardCase nm ps) guards
|
||||
pure b { bParams = [], bDef = DPropGuards gs <$ bDef b }
|
||||
|
||||
noPatPropGuardCase ::
|
||||
PName ->
|
||||
[Pattern PName] ->
|
||||
PropGuardCase PName -> NoPatM (PropGuardCase PName)
|
||||
noPatPropGuardCase f xs pc =
|
||||
do e <- noPatFun (Just f) 0 xs (pgcExpr pc)
|
||||
pure pc { pgcExpr = e }
|
||||
|
||||
noMatchD :: Decl PName -> NoPatM [Decl PName]
|
||||
noMatchD decl =
|
||||
case decl of
|
||||
|
@ -19,6 +19,7 @@
|
||||
module Cryptol.Parser.ParserUtils where
|
||||
|
||||
import qualified Data.Text as Text
|
||||
import Data.Char(isAlphaNum)
|
||||
import Data.Maybe(fromMaybe)
|
||||
import Data.Bits(testBit,setBit)
|
||||
import Data.Maybe(mapMaybe)
|
||||
@ -49,6 +50,7 @@ import Cryptol.Utils.Ident( packModName,packIdent,modNameChunks
|
||||
, modNameArg, modNameIfaceMod
|
||||
, modNameToText, modNameIsNormal
|
||||
, modNameToNormalModName
|
||||
, unpackIdent
|
||||
)
|
||||
import Cryptol.Utils.PP
|
||||
import Cryptol.Utils.Panic
|
||||
@ -640,6 +642,35 @@ mkIndexedDecl f (ps, ixs) e =
|
||||
rhs :: Expr PName
|
||||
rhs = mkGenerate (reverse ixs) e
|
||||
|
||||
-- NOTE: The lists of patterns are reversed!
|
||||
mkPropGuardsDecl ::
|
||||
LPName ->
|
||||
([Pattern PName], [Pattern PName]) ->
|
||||
[PropGuardCase PName] ->
|
||||
ParseM (Decl PName)
|
||||
mkPropGuardsDecl f (ps, ixs) guards =
|
||||
do unless (null ixs) $
|
||||
errorMessage (srcRange f)
|
||||
["Indexed sequence definitions may not use constraint guards"]
|
||||
let gs = reverse guards
|
||||
pure $
|
||||
DBind Bind { bName = f
|
||||
, bParams = reverse ps
|
||||
, bDef = Located (srcRange f) (DPropGuards gs)
|
||||
, bSignature = Nothing
|
||||
, bPragmas = []
|
||||
, bMono = False
|
||||
, bInfix = False
|
||||
, bFixity = Nothing
|
||||
, bDoc = Nothing
|
||||
, bExport = Public
|
||||
}
|
||||
|
||||
mkConstantPropGuardsDecl ::
|
||||
LPName -> [PropGuardCase PName] -> ParseM (Decl PName)
|
||||
mkConstantPropGuardsDecl f guards =
|
||||
mkPropGuardsDecl f ([],[]) guards
|
||||
|
||||
-- NOTE: The lists of patterns are reversed!
|
||||
mkIndexedExpr :: ([Pattern PName], [Pattern PName]) -> Expr PName -> Expr PName
|
||||
mkIndexedExpr (ps, ixs) body
|
||||
@ -658,8 +689,18 @@ mkIf ifThens theElse = foldr addIfThen theElse ifThens
|
||||
mkPrimDecl :: Maybe (Located Text) -> LPName -> Schema PName -> [TopDecl PName]
|
||||
mkPrimDecl = mkNoImplDecl DPrim
|
||||
|
||||
mkForeignDecl :: Maybe (Located Text) -> LPName -> Schema PName -> [TopDecl PName]
|
||||
mkForeignDecl = mkNoImplDecl DForeign
|
||||
mkForeignDecl ::
|
||||
Maybe (Located Text) -> LPName -> Schema PName -> ParseM [TopDecl PName]
|
||||
mkForeignDecl mbDoc nm ty =
|
||||
do let txt = unpackIdent (getIdent (thing nm))
|
||||
unless (all isOk txt)
|
||||
(errorMessage (srcRange nm)
|
||||
[ "`" ++ txt ++ "` is not a valid foreign name."
|
||||
, "The name should contain only alpha-numeric characters or '_'."
|
||||
])
|
||||
pure (mkNoImplDecl DForeign mbDoc nm ty)
|
||||
where
|
||||
isOk c = c == '_' || isAlphaNum c
|
||||
|
||||
-- | Generate a signature and a binding for value declarations with no
|
||||
-- implementation (i.e. primitive or foreign declarations). The reason for
|
||||
@ -799,6 +840,10 @@ distrLoc :: Located [a] -> [Located a]
|
||||
distrLoc x = [ Located { srcRange = r, thing = a } | a <- thing x ]
|
||||
where r = srcRange x
|
||||
|
||||
mkPropGuards :: Type PName -> ParseM [Located (Prop PName)]
|
||||
mkPropGuards ty =
|
||||
do lp <- mkProp ty
|
||||
pure [ lp { thing = p } | p <- thing lp ]
|
||||
|
||||
mkProp :: Type PName -> ParseM (Located [Prop PName])
|
||||
mkProp ty =
|
||||
|
@ -1,5 +1,6 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
module Cryptol.Parser.Token where
|
||||
|
||||
import Data.Text(Text)
|
||||
|
@ -10,6 +10,7 @@
|
||||
-- from previous Cryptol versions.
|
||||
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
module Cryptol.Parser.Utils
|
||||
( translateExprToNumT
|
||||
|
@ -69,11 +69,14 @@ import qualified Cryptol.ModuleSystem.Renamer as M
|
||||
import qualified Cryptol.Utils.Ident as M
|
||||
import qualified Cryptol.ModuleSystem.Env as M
|
||||
|
||||
import Cryptol.Backend.FloatHelpers as FP
|
||||
import qualified Cryptol.Backend.Monad as E
|
||||
import qualified Cryptol.Backend.SeqMap as E
|
||||
import Cryptol.Eval.Concrete( Concrete(..) )
|
||||
import qualified Cryptol.Eval.Concrete as Concrete
|
||||
import qualified Cryptol.Eval.Env as E
|
||||
import Cryptol.Eval.FFI
|
||||
import Cryptol.Eval.FFI.GenHeader
|
||||
import qualified Cryptol.Eval.Type as E
|
||||
import qualified Cryptol.Eval.Value as E
|
||||
import qualified Cryptol.Eval.Reference as R
|
||||
@ -89,6 +92,7 @@ import qualified Cryptol.TypeCheck.Parseable as T
|
||||
import qualified Cryptol.TypeCheck.Subst as T
|
||||
import Cryptol.TypeCheck.Solve(defaultReplExpr)
|
||||
import Cryptol.TypeCheck.PP (dump)
|
||||
import qualified Cryptol.Utils.Benchmark as Bench
|
||||
import Cryptol.Utils.PP hiding ((</>))
|
||||
import Cryptol.Utils.Panic(panic)
|
||||
import Cryptol.Utils.RecordMap
|
||||
@ -118,7 +122,7 @@ import System.Environment (lookupEnv)
|
||||
import System.Exit (ExitCode(ExitSuccess))
|
||||
import System.Process (shell,createProcess,waitForProcess)
|
||||
import qualified System.Process as Process(runCommand)
|
||||
import System.FilePath((</>), isPathSeparator)
|
||||
import System.FilePath((</>), (-<.>), isPathSeparator)
|
||||
import System.Directory(getHomeDirectory,setCurrentDirectory,doesDirectoryExist
|
||||
,getTemporaryDirectory,setPermissions,removeFile
|
||||
,emptyPermissions,setOwnerReadable)
|
||||
@ -251,6 +255,22 @@ nbCommandList =
|
||||
, CommandDescr [ ":extract-coq" ] [] (NoArg allTerms)
|
||||
"Print out the post-typechecked AST of all currently defined terms,\nin a Coq-parseable format."
|
||||
""
|
||||
, CommandDescr [ ":time" ] ["EXPR"] (ExprArg timeCmd)
|
||||
"Measure the time it takes to evaluate the given expression."
|
||||
(unlines
|
||||
[ "The expression will be evaluated many times to get accurate results."
|
||||
, "Note that the first evaluation of a binding may take longer due to"
|
||||
, " laziness, and this may affect the reported time. If this is not"
|
||||
, " desired then make sure to evaluate the expression once first before"
|
||||
, " running :time."
|
||||
, "The amount of time to spend collecting measurements can be changed"
|
||||
, " with the timeMeasurementPeriod option."
|
||||
, "Reports the average wall clock time, CPU time, and cycles."
|
||||
, " (Cycles are in unspecified units that may be CPU cycles.)"
|
||||
, "Binds the result to"
|
||||
, " it : { avgTime : Float64"
|
||||
, " , avgCpuTime : Float64"
|
||||
, " , avgCycles : Integer }" ])
|
||||
]
|
||||
|
||||
commandList :: [CommandDescr]
|
||||
@ -290,6 +310,12 @@ commandList =
|
||||
, "number of tests is determined by the \"tests\" option."
|
||||
])
|
||||
""
|
||||
, CommandDescr [ ":generate-foreign-header" ] ["FILE"] (FilenameArg genHeaderCmd)
|
||||
"Generate a C header file from foreign declarations in a Cryptol file."
|
||||
(unlines
|
||||
[ "Converts all foreign declarations in the given Cryptol file into C"
|
||||
, "function declarations, and writes them to a file with the same name"
|
||||
, "but with a .h extension." ])
|
||||
]
|
||||
|
||||
genHelp :: [CommandDescr] -> [String]
|
||||
@ -998,6 +1024,32 @@ typeOfCmd str pos fnm = do
|
||||
rPrint $ runDoc fDisp $ group $ hang
|
||||
(ppPrec 2 expr <+> text ":") 2 (pp sig)
|
||||
|
||||
timeCmd :: String -> (Int, Int) -> Maybe FilePath -> REPL ()
|
||||
timeCmd str pos fnm = do
|
||||
period <- getKnownUser "timeMeasurementPeriod" :: REPL Int
|
||||
quiet <- getKnownUser "timeQuiet"
|
||||
unless quiet $
|
||||
rPutStrLn $ "Measuring for " ++ show period ++ " seconds"
|
||||
pExpr <- replParseExpr str pos fnm
|
||||
(_, def, sig) <- replCheckExpr pExpr
|
||||
replPrepareCheckedExpr def sig >>= \case
|
||||
Nothing -> raise (EvalPolyError sig)
|
||||
Just (_, expr) -> do
|
||||
Bench.BenchmarkStats {..} <- liftModuleCmd
|
||||
(rethrowEvalError . M.benchmarkExpr (fromIntegral period) expr)
|
||||
unless quiet $
|
||||
rPutStrLn $ "Avg time: " ++ Bench.secs benchAvgTime
|
||||
++ " Avg CPU time: " ++ Bench.secs benchAvgCpuTime
|
||||
++ " Avg cycles: " ++ show benchAvgCycles
|
||||
let mkStatsRec time cpuTime cycles = recordFromFields
|
||||
[("avgTime", time), ("avgCpuTime", cpuTime), ("avgCycles", cycles)]
|
||||
itType = E.TVRec $ mkStatsRec E.tvFloat64 E.tvFloat64 E.TVInteger
|
||||
itVal = E.VRecord $ mkStatsRec
|
||||
(pure $ E.VFloat $ FP.floatFromDouble benchAvgTime)
|
||||
(pure $ E.VFloat $ FP.floatFromDouble benchAvgCpuTime)
|
||||
(pure $ E.VInteger $ toInteger benchAvgCycles)
|
||||
bindItVariableVal itType itVal
|
||||
|
||||
readFileCmd :: FilePath -> REPL ()
|
||||
readFileCmd fp = do
|
||||
bytes <- replReadFile fp (\err -> rPutStrLn (show err) >> return Nothing)
|
||||
@ -1177,6 +1229,25 @@ loadHelper how =
|
||||
M.InMem {} -> clearEditPath
|
||||
setDynEnv mempty
|
||||
|
||||
genHeaderCmd :: FilePath -> REPL ()
|
||||
genHeaderCmd path
|
||||
| null path = pure ()
|
||||
| otherwise = do
|
||||
(mPath, m) <- liftModuleCmd $ M.checkModuleByPath path
|
||||
let decls = case m of
|
||||
T.TCTopModule mo -> findForeignDecls mo
|
||||
T.TCTopSignature {} -> []
|
||||
if null decls
|
||||
then rPutStrLn $ "No foreign declarations in " ++ pretty mPath
|
||||
else do
|
||||
let header = generateForeignHeader decls
|
||||
case mPath of
|
||||
M.InFile p -> do
|
||||
let hPath = p -<.> "h"
|
||||
rPutStrLn $ "Writing header to " ++ hPath
|
||||
replWriteFileString hPath header (rPutStrLn . show)
|
||||
M.InMem _ _ -> rPutStrLn header
|
||||
|
||||
versionCmd :: REPL ()
|
||||
versionCmd = displayVersion rPutStrLn
|
||||
|
||||
@ -1348,23 +1419,16 @@ liftModuleCmd cmd =
|
||||
}
|
||||
moduleCmdResult =<< io (cmd minp)
|
||||
|
||||
-- TODO: add filter for my exhaustie prop guards warning here
|
||||
|
||||
moduleCmdResult :: M.ModuleRes a -> REPL a
|
||||
moduleCmdResult (res,ws0) = do
|
||||
warnDefaulting <- getKnownUser "warnDefaulting"
|
||||
warnShadowing <- getKnownUser "warnShadowing"
|
||||
warnPrefixAssoc <- getKnownUser "warnPrefixAssoc"
|
||||
warnNonExhConGrds <- getKnownUser "warnNonExhaustiveConstraintGuards"
|
||||
-- XXX: let's generalize this pattern
|
||||
let isDefaultWarn (T.DefaultingTo _ _) = True
|
||||
isDefaultWarn _ = False
|
||||
|
||||
filterDefaults w | warnDefaulting = Just w
|
||||
filterDefaults (M.TypeCheckWarnings nameMap xs) =
|
||||
case filter (not . isDefaultWarn . snd) xs of
|
||||
[] -> Nothing
|
||||
ys -> Just (M.TypeCheckWarnings nameMap ys)
|
||||
filterDefaults w = Just w
|
||||
|
||||
isShadowWarn (M.SymbolShadowed {}) = True
|
||||
let isShadowWarn (M.SymbolShadowed {}) = True
|
||||
isShadowWarn _ = False
|
||||
|
||||
isPrefixAssocWarn (M.PrefixAssocChanged {}) = True
|
||||
@ -1377,9 +1441,23 @@ moduleCmdResult (res,ws0) = do
|
||||
ys -> Just (M.RenamerWarnings ys)
|
||||
filterRenamer _ _ w = Just w
|
||||
|
||||
let ws = mapMaybe filterDefaults
|
||||
. mapMaybe (filterRenamer warnShadowing isShadowWarn)
|
||||
-- ignore certain warnings during typechecking
|
||||
filterTypecheck :: M.ModuleWarning -> Maybe M.ModuleWarning
|
||||
filterTypecheck (M.TypeCheckWarnings nameMap xs) =
|
||||
case filter (allow . snd) xs of
|
||||
[] -> Nothing
|
||||
ys -> Just (M.TypeCheckWarnings nameMap ys)
|
||||
where
|
||||
allow :: T.Warning -> Bool
|
||||
allow = \case
|
||||
T.DefaultingTo _ _ | not warnDefaulting -> False
|
||||
T.NonExhaustivePropGuards _ | not warnNonExhConGrds -> False
|
||||
_ -> True
|
||||
filterTypecheck w = Just w
|
||||
|
||||
let ws = mapMaybe (filterRenamer warnShadowing isShadowWarn)
|
||||
. mapMaybe (filterRenamer warnPrefixAssoc isPrefixAssocWarn)
|
||||
. mapMaybe filterTypecheck
|
||||
$ ws0
|
||||
names <- M.mctxNameDisp <$> getFocusedEnv
|
||||
mapM_ (rPrint . runDoc names . pp) ws
|
||||
@ -1425,39 +1503,47 @@ replSpecExpr e = liftModuleCmd $ S.specialize e
|
||||
replEvalExpr :: P.Expr P.PName -> REPL (Concrete.Value, T.Type)
|
||||
replEvalExpr expr =
|
||||
do (_,def,sig) <- replCheckExpr expr
|
||||
replEvalCheckedExpr def sig >>= \mb_res -> case mb_res of
|
||||
replEvalCheckedExpr def sig >>= \case
|
||||
Just res -> pure res
|
||||
Nothing -> raise (EvalPolyError sig)
|
||||
|
||||
replEvalCheckedExpr :: T.Expr -> T.Schema -> REPL (Maybe (Concrete.Value, T.Type))
|
||||
replEvalCheckedExpr def sig =
|
||||
do validEvalContext def
|
||||
validEvalContext sig
|
||||
replPrepareCheckedExpr def sig >>=
|
||||
traverse \(tys, def1) -> do
|
||||
let su = T.listParamSubst tys
|
||||
let ty = T.apSubst su (T.sType sig)
|
||||
whenDebug (rPutStrLn (dump def1))
|
||||
|
||||
s <- getTCSolver
|
||||
mbDef <- io (defaultReplExpr s def sig)
|
||||
tenv <- E.envTypes . M.deEnv <$> getDynEnv
|
||||
let tyv = E.evalValType tenv ty
|
||||
|
||||
case mbDef of
|
||||
Nothing -> pure Nothing
|
||||
Just (tys, def1) ->
|
||||
do warnDefaults tys
|
||||
let su = T.listParamSubst tys
|
||||
let ty = T.apSubst su (T.sType sig)
|
||||
whenDebug (rPutStrLn (dump def1))
|
||||
-- add "it" to the namespace via a new declaration
|
||||
itVar <- bindItVariable tyv def1
|
||||
|
||||
tenv <- E.envTypes . M.deEnv <$> getDynEnv
|
||||
let tyv = E.evalValType tenv ty
|
||||
let itExpr = case getLoc def of
|
||||
Nothing -> T.EVar itVar
|
||||
Just rng -> T.ELocated rng (T.EVar itVar)
|
||||
|
||||
-- add "it" to the namespace via a new declaration
|
||||
itVar <- bindItVariable tyv def1
|
||||
-- evaluate the it variable
|
||||
val <- liftModuleCmd (rethrowEvalError . M.evalExpr itExpr)
|
||||
return (val,ty)
|
||||
|
||||
let itExpr = case getLoc def of
|
||||
Nothing -> T.EVar itVar
|
||||
Just rng -> T.ELocated rng (T.EVar itVar)
|
||||
-- | Check that we are in a valid evaluation context and apply defaulting.
|
||||
replPrepareCheckedExpr :: T.Expr -> T.Schema ->
|
||||
REPL (Maybe ([(T.TParam, T.Type)], T.Expr))
|
||||
replPrepareCheckedExpr def sig = do
|
||||
validEvalContext def
|
||||
validEvalContext sig
|
||||
|
||||
-- evaluate the it variable
|
||||
val <- liftModuleCmd (rethrowEvalError . M.evalExpr itExpr)
|
||||
return $ Just (val,ty)
|
||||
s <- getTCSolver
|
||||
mbDef <- io (defaultReplExpr s def sig)
|
||||
|
||||
case mbDef of
|
||||
Nothing -> pure Nothing
|
||||
Just (tys, def1) -> do
|
||||
warnDefaults tys
|
||||
pure $ Just (tys, def1)
|
||||
where
|
||||
warnDefaults ts =
|
||||
case ts of
|
||||
@ -1473,8 +1559,15 @@ itIdent :: M.Ident
|
||||
itIdent = M.packIdent "it"
|
||||
|
||||
replWriteFile :: FilePath -> BS.ByteString -> (X.SomeException -> REPL ()) -> REPL ()
|
||||
replWriteFile fp bytes handler =
|
||||
do x <- io $ X.catch (BS.writeFile fp bytes >> return Nothing) (return . Just)
|
||||
replWriteFile = replWriteFileWith BS.writeFile
|
||||
|
||||
replWriteFileString :: FilePath -> String -> (X.SomeException -> REPL ()) -> REPL ()
|
||||
replWriteFileString = replWriteFileWith writeFile
|
||||
|
||||
replWriteFileWith :: (FilePath -> a -> IO ()) -> FilePath -> a ->
|
||||
(X.SomeException -> REPL ()) -> REPL ()
|
||||
replWriteFileWith write fp contents handler =
|
||||
do x <- io $ X.catch (write fp contents >> return Nothing) (return . Just)
|
||||
maybe (return ()) handler x
|
||||
|
||||
replReadFile :: FilePath -> (X.SomeException -> REPL (Maybe BS.ByteString)) -> REPL (Maybe BS.ByteString)
|
||||
|
@ -909,6 +909,8 @@ userOptions = mkOptionMap
|
||||
"Choose whether to display warnings when expression association has changed due to new prefix operator fixities."
|
||||
, simpleOpt "warnUninterp" ["warn-uninterp"] (EnvBool True) noCheck
|
||||
"Choose whether to issue a warning when uninterpreted functions are used to implement primitives in the symbolic simulator."
|
||||
, simpleOpt "warnNonExhaustiveConstraintGuards" ["warn-nonexhaustive-constraintguards"] (EnvBool True) noCheck
|
||||
"Choose whether to issue a warning when a use of constraint guards is not determined to be exhaustive."
|
||||
, simpleOpt "smtFile" ["smt-file"] (EnvString "-") noCheck
|
||||
"The file to use for SMT-Lib scripts (for debugging or offline proving).\nUse \"-\" for stdout."
|
||||
, OptionDescr "path" [] (EnvString "") noCheck
|
||||
@ -990,6 +992,18 @@ userOptions = mkOptionMap
|
||||
, " * display try to match the order they were written in the source code"
|
||||
, " * canonical use a predictable, canonical order"
|
||||
]
|
||||
|
||||
, simpleOpt "timeMeasurementPeriod" ["time-measurement-period"] (EnvNum 10)
|
||||
checkTimeMeasurementPeriod
|
||||
$ unlines
|
||||
[ "The period of time in seconds to spend collecting measurements when"
|
||||
, " running :time."
|
||||
, "This is a lower bound and the actual time taken might be higher if the"
|
||||
, " evaluation takes a long time."
|
||||
]
|
||||
|
||||
, simpleOpt "timeQuiet" ["time-quiet"] (EnvBool False) noCheck
|
||||
"Suppress output of :time command and only bind result to `it`."
|
||||
]
|
||||
|
||||
|
||||
@ -1085,6 +1099,14 @@ getUserSatNum = do
|
||||
_ -> panic "REPL.Monad.getUserSatNum"
|
||||
[ "invalid satNum option" ]
|
||||
|
||||
checkTimeMeasurementPeriod :: Checker
|
||||
checkTimeMeasurementPeriod (EnvNum n)
|
||||
| n >= 1 = noWarns Nothing
|
||||
| otherwise = noWarns $
|
||||
Just "timeMeasurementPeriod must be a positive integer"
|
||||
checkTimeMeasurementPeriod _ = noWarns $
|
||||
Just "unable to parse value for timeMeasurementPeriod"
|
||||
|
||||
-- Environment Utilities -------------------------------------------------------
|
||||
|
||||
whenDebug :: REPL () -> REPL ()
|
||||
|
@ -201,6 +201,8 @@ rewE rews = go
|
||||
EWhere e dgs -> EWhere <$> go e <*> inLocal
|
||||
(mapM (rewDeclGroup rews) dgs)
|
||||
|
||||
EPropGuards guards ty -> EPropGuards <$> (\(props, e) -> (,) <$> pure props <*> go e) `traverse` guards <*> pure ty
|
||||
|
||||
|
||||
rewM :: RewMap -> Match -> M Match
|
||||
rewM rews ma =
|
||||
|
@ -20,12 +20,16 @@ import qualified Cryptol.ModuleSystem.Env as M
|
||||
import qualified Cryptol.ModuleSystem.Monad as M
|
||||
import Cryptol.ModuleSystem.Name
|
||||
import Cryptol.Utils.Ident(OrigName(..))
|
||||
import Cryptol.Eval (checkProp)
|
||||
|
||||
import Data.Map (Map)
|
||||
import qualified Data.Map as Map
|
||||
import Data.Maybe (catMaybes)
|
||||
import qualified Data.List as List
|
||||
|
||||
import MonadLib hiding (mapM)
|
||||
import Cryptol.ModuleSystem.Base (getPrimMap)
|
||||
|
||||
|
||||
-- Specializer Monad -----------------------------------------------------------
|
||||
|
||||
@ -103,6 +107,16 @@ specializeExpr expr =
|
||||
EProofAbs p e -> EProofAbs p <$> specializeExpr e
|
||||
EProofApp {} -> specializeConst expr
|
||||
EWhere e dgs -> specializeEWhere e dgs
|
||||
-- The type should be monomorphic, and the guarded expressions should
|
||||
-- already be normalized, so we just need to choose the first expression
|
||||
-- that's true.
|
||||
EPropGuards guards ty ->
|
||||
case List.find (all checkProp . fst) guards of
|
||||
Just (_, e) -> specializeExpr e
|
||||
Nothing -> do
|
||||
pm <- liftSpecT getPrimMap
|
||||
pure $ eError pm ty "no constraint guard was satisfied"
|
||||
|
||||
|
||||
specializeMatch :: Match -> SpecM Match
|
||||
specializeMatch (From qn l t e) = From qn l t <$> specializeExpr e
|
||||
|
@ -185,6 +185,8 @@ data Expr = EList [Expr] Type -- ^ List value (with type of elements)
|
||||
|
||||
| EWhere Expr [DeclGroup]
|
||||
|
||||
| EPropGuards [([Prop], Expr)] Type
|
||||
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
|
||||
@ -303,6 +305,12 @@ instance PP (WithNames Expr) where
|
||||
, hang "where" 2 (vcat (map ppW ds))
|
||||
]
|
||||
|
||||
EPropGuards guards _ ->
|
||||
parens (text "propguards" <+> vsep (ppGuard <$> guards))
|
||||
where ppGuard (props, e) = indent 1
|
||||
$ pipe <+> commaSep (ppW <$> props)
|
||||
<+> text "=>" <+> ppW e
|
||||
|
||||
where
|
||||
ppW x = ppWithNames nm x
|
||||
ppWP x = ppWithNamesPrec nm x
|
||||
|
@ -1,3 +1,5 @@
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
module Cryptol.TypeCheck.Default where
|
||||
|
||||
import qualified Data.Set as Set
|
||||
|
@ -68,6 +68,7 @@ subsumes _ _ = False
|
||||
data Warning = DefaultingKind (P.TParam Name) P.Kind
|
||||
| DefaultingWildType P.Kind
|
||||
| DefaultingTo !TVarInfo Type
|
||||
| NonExhaustivePropGuards Name
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
-- | Various errors that might happen during type checking/inference
|
||||
@ -160,6 +161,16 @@ data Error = KindMismatch (Maybe TypeSource) Kind Kind
|
||||
| UnsupportedFFIType TypeSource FFITypeError
|
||||
-- ^ Type is not supported for FFI
|
||||
|
||||
| NestedConstraintGuard Ident
|
||||
-- ^ Constraint guards may only apper at the top-level
|
||||
|
||||
| DeclarationRequiresSignatureCtrGrd Ident
|
||||
-- ^ All declarataions in a recursive group involving
|
||||
-- constraint guards should have signatures
|
||||
|
||||
| InvalidConstraintGuard Prop
|
||||
-- ^ The given constraint may not be used as a constraint guard
|
||||
|
||||
| TemporaryError Doc
|
||||
-- ^ This is for errors that don't fit other cateogories.
|
||||
-- We should not use it much, and is generally to be used
|
||||
@ -226,6 +237,10 @@ errorImportance err =
|
||||
UnsupportedFFIType {} -> 7
|
||||
-- less than UnexpectedTypeWildCard
|
||||
|
||||
NestedConstraintGuard {} -> 10
|
||||
DeclarationRequiresSignatureCtrGrd {} -> 9
|
||||
InvalidConstraintGuard {} -> 5
|
||||
|
||||
|
||||
instance TVars Warning where
|
||||
apSubst su warn =
|
||||
@ -233,6 +248,7 @@ instance TVars Warning where
|
||||
DefaultingKind {} -> warn
|
||||
DefaultingWildType {} -> warn
|
||||
DefaultingTo d ty -> DefaultingTo d $! (apSubst su ty)
|
||||
NonExhaustivePropGuards {} -> warn
|
||||
|
||||
instance FVS Warning where
|
||||
fvs warn =
|
||||
@ -240,6 +256,7 @@ instance FVS Warning where
|
||||
DefaultingKind {} -> Set.empty
|
||||
DefaultingWildType {} -> Set.empty
|
||||
DefaultingTo _ ty -> fvs ty
|
||||
NonExhaustivePropGuards {} -> Set.empty
|
||||
|
||||
instance TVars Error where
|
||||
apSubst su err =
|
||||
@ -284,6 +301,10 @@ instance TVars Error where
|
||||
UnsupportedFFIKind {} -> err
|
||||
UnsupportedFFIType src e -> UnsupportedFFIType src !$ apSubst su e
|
||||
|
||||
NestedConstraintGuard {} -> err
|
||||
DeclarationRequiresSignatureCtrGrd {} -> err
|
||||
InvalidConstraintGuard p -> InvalidConstraintGuard $! apSubst su p
|
||||
|
||||
TemporaryError {} -> err
|
||||
|
||||
|
||||
@ -328,6 +349,10 @@ instance FVS Error where
|
||||
UnsupportedFFIKind {} -> Set.empty
|
||||
UnsupportedFFIType _ t -> fvs t
|
||||
|
||||
NestedConstraintGuard {} -> Set.empty
|
||||
DeclarationRequiresSignatureCtrGrd {} -> Set.empty
|
||||
InvalidConstraintGuard p -> fvs p
|
||||
|
||||
TemporaryError {} -> Set.empty
|
||||
|
||||
instance PP Warning where
|
||||
@ -351,6 +376,10 @@ instance PP (WithNames Warning) where
|
||||
text "Defaulting" <+> pp (tvarDesc d) <+> text "to"
|
||||
<+> ppWithNames names ty
|
||||
|
||||
NonExhaustivePropGuards n ->
|
||||
text "Could not prove that the constraint guards used in defining" <+>
|
||||
pp n <+> text "were exhaustive."
|
||||
|
||||
instance PP (WithNames Error) where
|
||||
ppPrec _ (WithNames err names) =
|
||||
case err of
|
||||
@ -365,8 +394,13 @@ instance PP (WithNames Error) where
|
||||
|
||||
UnexpectedTypeWildCard ->
|
||||
addTVarsDescsAfter names err $
|
||||
nested "Wild card types are not allowed in this context"
|
||||
"(e.g., they cannot be used in type synonyms or FFI declarations)."
|
||||
nested "Wild card types are not allowed in this context" $
|
||||
vcat [ "They cannot be used in:"
|
||||
, bullets [ "type synonyms"
|
||||
, "FFI declarations"
|
||||
, "declarations with constraint guards"
|
||||
]
|
||||
]
|
||||
|
||||
KindMismatch mbsrc k1 k2 ->
|
||||
addTVarsDescsAfter names err $
|
||||
@ -539,6 +573,27 @@ instance PP (WithNames Error) where
|
||||
[ ppWithNames names t
|
||||
, "When checking" <+> pp src ]
|
||||
|
||||
NestedConstraintGuard d ->
|
||||
vcat [ "Local declaration" <+> backticks (pp d)
|
||||
<+> "may not use constraint guards."
|
||||
, "Constraint guards may only appear at the top-level of a module."
|
||||
]
|
||||
|
||||
DeclarationRequiresSignatureCtrGrd d ->
|
||||
vcat [ "The declaration of" <+> backticks (pp d) <+>
|
||||
"requires a full type signature,"
|
||||
, "because it is part of a recursive group with constraint guards."
|
||||
]
|
||||
|
||||
InvalidConstraintGuard p ->
|
||||
let d = case tNoUser p of
|
||||
TCon tc _ -> pp tc
|
||||
_ -> ppWithNames names p
|
||||
in
|
||||
vcat [ backticks d <+> "may not be used in a constraint guard."
|
||||
, "Constraint guards support only numeric comparisons and `fin`."
|
||||
]
|
||||
|
||||
TemporaryError doc -> doc
|
||||
where
|
||||
bullets xs = vcat [ "•" <+> d | d <- xs ]
|
||||
|
@ -1,12 +1,14 @@
|
||||
{-# LANGUAGE BlockArguments #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
-- | Checking and conversion of 'Type's to 'FFIType's.
|
||||
module Cryptol.TypeCheck.FFI
|
||||
( toFFIFunType
|
||||
) where
|
||||
|
||||
import Data.Bifunctor
|
||||
import Data.Containers.ListUtils
|
||||
import Data.Either
|
||||
|
||||
@ -15,6 +17,7 @@ import Cryptol.TypeCheck.FFI.FFIType
|
||||
import Cryptol.TypeCheck.SimpType
|
||||
import Cryptol.TypeCheck.Type
|
||||
import Cryptol.Utils.RecordMap
|
||||
import Cryptol.Utils.Types
|
||||
|
||||
-- | Convert a 'Schema' to a 'FFIFunType', along with any 'Prop's that must be
|
||||
-- satisfied for the 'FFIFunType' to be valid.
|
||||
@ -61,11 +64,14 @@ toFFIType t =
|
||||
case t of
|
||||
TCon (TC TCBit) [] -> Right ([], FFIBool)
|
||||
(toFFIBasicType -> Just r) -> (\fbt -> ([], FFIBasic fbt)) <$> r
|
||||
TCon (TC TCSeq) [sz, bt] ->
|
||||
case toFFIBasicType bt of
|
||||
Just (Right fbt) -> Right ([fin sz], FFIArray sz fbt)
|
||||
Just (Left err) -> Left $ FFITypeError t $ FFIBadComponentTypes [err]
|
||||
Nothing -> Left $ FFITypeError t FFIBadArrayType
|
||||
TCon (TC TCSeq) _ ->
|
||||
(\(szs, fbt) -> (map fin szs, FFIArray szs fbt)) <$> go t
|
||||
where go (toFFIBasicType -> Just r) =
|
||||
case r of
|
||||
Right fbt -> Right ([], fbt)
|
||||
Left err -> Left $ FFITypeError t $ FFIBadComponentTypes [err]
|
||||
go (TCon (TC TCSeq) [sz, ty]) = first (sz:) <$> go ty
|
||||
go _ = Left $ FFITypeError t FFIBadArrayType
|
||||
TCon (TC (TCTuple _)) ts ->
|
||||
case partitionEithers $ map toFFIType ts of
|
||||
([], unzip -> (pss, fts)) -> Right (concat pss, FFITuple fts)
|
||||
@ -90,13 +96,17 @@ toFFIBasicType t =
|
||||
| n <= 32 -> word FFIWord32
|
||||
| n <= 64 -> word FFIWord64
|
||||
| otherwise -> Just $ Left $ FFITypeError t FFIBadWordSize
|
||||
where word = Just . Right . FFIWord n
|
||||
where word = Just . Right . FFIBasicVal . FFIWord n
|
||||
TCon (TC TCFloat) [TCon (TC (TCNum e)) [], TCon (TC (TCNum p)) []]
|
||||
| e == 8, p == 24 -> float FFIFloat32
|
||||
| e == 11, p == 53 -> float FFIFloat64
|
||||
| (e, p) == float32ExpPrec -> float FFIFloat32
|
||||
| (e, p) == float64ExpPrec -> float FFIFloat64
|
||||
| otherwise -> Just $ Left $ FFITypeError t FFIBadFloatSize
|
||||
where float = Just . Right . FFIFloat e p
|
||||
where float = Just . Right . FFIBasicVal . FFIFloat e p
|
||||
TCon (TC TCInteger) [] -> integer Nothing
|
||||
TCon (TC TCIntMod) [n] -> integer $ Just n
|
||||
TCon (TC TCRational) [] -> Just $ Right $ FFIBasicRef FFIRational
|
||||
_ -> Nothing
|
||||
where integer = Just . Right . FFIBasicRef . FFIInteger
|
||||
|
||||
fin :: Type -> Prop
|
||||
fin t = TCon (PC PFin) [t]
|
||||
|
@ -2,6 +2,7 @@
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
-- | Errors from typechecking foreign functions.
|
||||
module Cryptol.TypeCheck.FFI.Error where
|
||||
@ -70,12 +71,13 @@ instance PP (WithNames FFITypeErrorReason) where
|
||||
, "Only Float32 and Float64 are supported" ]
|
||||
FFIBadArrayType -> vcat
|
||||
[ "Unsupported sequence element type"
|
||||
, "Only words or floats are supported as the element type of sequences"
|
||||
, "Only words or floats are supported as the element type of"
|
||||
, "(possibly multidimensional) sequences"
|
||||
]
|
||||
FFIBadComponentTypes errs ->
|
||||
indent 2 $ vcat $ map (ppWithNames names) errs
|
||||
FFIBadType -> vcat
|
||||
[ "Only Bit, words, floats, sequences of words or floats,"
|
||||
, "or structs or tuples of the above are supported as FFI"
|
||||
, "argument or return types"]
|
||||
[ "Only Bit, words, floats, Integer, Z, Rational, sequences, or structs"
|
||||
, "or tuples of the above are supported as FFI argument or return types"
|
||||
]
|
||||
FFINotFunction -> "FFI binding must be a function"
|
||||
|
@ -1,5 +1,6 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
-- | This module defines a nicer intermediate representation of Cryptol types
|
||||
-- allowed for the FFI, which the typechecker generates then stores in the AST.
|
||||
@ -26,21 +27,26 @@ data FFIFunType = FFIFunType
|
||||
data FFIType
|
||||
= FFIBool
|
||||
| FFIBasic FFIBasicType
|
||||
| FFIArray
|
||||
Type -- ^ Size (should be of kind @\#@)
|
||||
FFIBasicType -- ^ Element type
|
||||
-- | [n][m][p]T --> FFIArray [n, m, p] T
|
||||
| FFIArray [Type] FFIBasicType
|
||||
| FFITuple [FFIType]
|
||||
| FFIRecord (RecordMap Ident FFIType)
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
-- | Types which can be elements of FFI sequences.
|
||||
-- | Types which can be elements of FFI arrays.
|
||||
data FFIBasicType
|
||||
= FFIBasicVal FFIBasicValType
|
||||
| FFIBasicRef FFIBasicRefType
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
-- | Basic type which is passed and returned directly by value.
|
||||
data FFIBasicValType
|
||||
= FFIWord
|
||||
Integer -- ^ The size of the Cryptol type
|
||||
Integer -- ^ The size of the Cryptol type
|
||||
FFIWordSize -- ^ The machine word size that it corresponds to
|
||||
| FFIFloat
|
||||
Integer -- ^ Exponent
|
||||
Integer -- ^ Precision
|
||||
Integer -- ^ Exponent
|
||||
Integer -- ^ Precision
|
||||
FFIFloatSize -- ^ The machine float size that it corresponds to
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
@ -55,3 +61,10 @@ data FFIFloatSize
|
||||
= FFIFloat32
|
||||
| FFIFloat64
|
||||
deriving (Show, Generic, NFData)
|
||||
|
||||
-- | Basic type which is passed and returned by reference through a parameter.
|
||||
data FFIBasicRefType
|
||||
= FFIInteger
|
||||
(Maybe Type) -- ^ Modulus (Just for Z, Nothing for Integer)
|
||||
| FFIRational
|
||||
deriving (Show, Generic, NFData)
|
||||
|
@ -15,8 +15,13 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE BlockArguments #-}
|
||||
{-# LANGUAGE Safe #-}
|
||||
-- {-# LANGUAGE Trustworthy #-}
|
||||
-- See Note [-Wincomplete-uni-patterns and irrefutable patterns] in Cryptol.TypeCheck.TypePat
|
||||
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
||||
{-# HLINT ignore "Redundant <$>" #-}
|
||||
{-# HLINT ignore "Redundant <&>" #-}
|
||||
module Cryptol.TypeCheck.Infer
|
||||
( checkE
|
||||
, checkSigB
|
||||
@ -30,7 +35,7 @@ import Data.Text(Text)
|
||||
import qualified Data.Text as Text
|
||||
|
||||
|
||||
import Cryptol.ModuleSystem.Name (lookupPrimDecl,nameLoc)
|
||||
import Cryptol.ModuleSystem.Name (lookupPrimDecl,nameLoc, nameIdent)
|
||||
import Cryptol.Parser.Position
|
||||
import qualified Cryptol.Parser.AST as P
|
||||
import qualified Cryptol.ModuleSystem.Exports as P
|
||||
@ -43,7 +48,8 @@ import Cryptol.TypeCheck.Kind(checkType,checkSchema,checkTySyn,
|
||||
checkPropSyn,checkNewtype,
|
||||
checkParameterType,
|
||||
checkPrimType,
|
||||
checkParameterConstraints)
|
||||
checkParameterConstraints,
|
||||
checkPropGuards)
|
||||
import Cryptol.TypeCheck.Instantiate
|
||||
import Cryptol.TypeCheck.Subst (listSubst,apSubst,(@@),isEmptySubst)
|
||||
import Cryptol.TypeCheck.Unify(rootPath)
|
||||
@ -54,20 +60,22 @@ import Cryptol.Utils.Ident
|
||||
import Cryptol.Utils.Panic(panic)
|
||||
import Cryptol.Utils.RecordMap
|
||||
import Cryptol.IR.TraverseNames(mapNames)
|
||||
import Cryptol.Utils.PP (pp)
|
||||
|
||||
import qualified Data.Map as Map
|
||||
import Data.Map (Map)
|
||||
import qualified Data.Set as Set
|
||||
import Data.List(foldl',sortBy,groupBy)
|
||||
import Data.List(foldl', sortBy, groupBy, partition)
|
||||
import Data.Either(partitionEithers)
|
||||
import Data.Maybe(isJust, fromMaybe, mapMaybe)
|
||||
import Data.List(partition)
|
||||
import Data.Ratio(numerator,denominator)
|
||||
import Data.Traversable(forM)
|
||||
import Data.Function(on)
|
||||
import Control.Monad(zipWithM,unless,foldM,forM_,mplus,when)
|
||||
|
||||
import Control.Monad(zipWithM, unless, foldM, forM_, mplus, zipWithM,
|
||||
unless, foldM, forM_, mplus, when)
|
||||
|
||||
-- import Debug.Trace
|
||||
-- import Cryptol.TypeCheck.PP
|
||||
|
||||
inferTopModule :: P.Module Name -> InferM TCTopEntity
|
||||
inferTopModule m =
|
||||
@ -751,15 +759,18 @@ inferCArm armNum (m : ms) =
|
||||
newGoals CtComprehension [ pFin n' ]
|
||||
return (m1 : ms', Map.insertWith (\_ old -> old) x t ds, tMul n n')
|
||||
|
||||
-- | @inferBinds isTopLevel isRec binds@ performs inference for a
|
||||
-- strongly-connected component of 'P.Bind's.
|
||||
-- If any of the members of the recursive group are already marked
|
||||
-- as monomorphic, then we don't do generalization.
|
||||
-- If @isTopLevel@ is true,
|
||||
-- any bindings without type signatures will be generalized. If it is
|
||||
-- false, and the mono-binds flag is enabled, no bindings without type
|
||||
-- signatures will be generalized, but bindings with signatures will
|
||||
-- be unaffected.
|
||||
{- | @inferBinds isTopLevel isRec binds@ performs inference for a
|
||||
strongly-connected component of 'P.Bind's.
|
||||
If any of the members of the recursive group are already marked
|
||||
as monomorphic, then we don't do generalization.
|
||||
If @isTopLevel@ is true,
|
||||
any bindings without type signatures will be generalized. If it is
|
||||
false, and the mono-binds flag is enabled, no bindings without type
|
||||
signatures will be generalized, but bindings with signatures will
|
||||
be unaffected.
|
||||
|
||||
-}
|
||||
|
||||
inferBinds :: Bool -> Bool -> [P.Bind Name] -> InferM [Decl]
|
||||
inferBinds isTopLevel isRec binds =
|
||||
do -- when mono-binds is enabled, and we're not checking top-level
|
||||
@ -807,6 +818,8 @@ inferBinds isTopLevel isRec binds =
|
||||
genCs <- generalize bs1 cs
|
||||
return (done,genCs)
|
||||
|
||||
checkNumericConstraintGuardsOK isTopLevel sigs noSigs
|
||||
|
||||
rec
|
||||
let exprMap = Map.fromList (map monoUse genBs)
|
||||
(doneBs, genBs) <- check exprMap
|
||||
@ -834,6 +847,37 @@ inferBinds isTopLevel isRec binds =
|
||||
withQs = foldl' appP withTys qs
|
||||
|
||||
|
||||
{-
|
||||
Here we also check that:
|
||||
* Numeric constraint guards appear only at the top level
|
||||
* All definitions in a recursive groups with numberic constraint guards
|
||||
have signatures
|
||||
|
||||
The reason is to avoid interference between local constraints coming
|
||||
from the guards and type inference. It might be possible to
|
||||
relex these requirements, but this requires some more careful thought on
|
||||
the interaction between the two, and the effects on pricniple types.
|
||||
-}
|
||||
checkNumericConstraintGuardsOK ::
|
||||
Bool -> [P.Bind Name] -> [P.Bind Name] -> InferM ()
|
||||
checkNumericConstraintGuardsOK isTopLevel haveSig noSig =
|
||||
do unless isTopLevel
|
||||
(mapM_ (mkErr NestedConstraintGuard) withGuards)
|
||||
unless (null withGuards)
|
||||
(mapM_ (mkErr DeclarationRequiresSignatureCtrGrd) noSig)
|
||||
where
|
||||
mkErr f b =
|
||||
do let nm = P.bName b
|
||||
inRange (srcRange nm) (recordError (f (nameIdent (thing nm))))
|
||||
|
||||
withGuards = filter hasConstraintGuards haveSig
|
||||
-- When desugaring constraint guards we check that they have signatures,
|
||||
-- so no need to look at noSig
|
||||
|
||||
hasConstraintGuards b =
|
||||
case thing (P.bDef b) of
|
||||
P.DPropGuards {} -> True
|
||||
_ -> False
|
||||
|
||||
|
||||
|
||||
@ -854,9 +898,10 @@ guessType exprMap b@(P.Bind { .. }) =
|
||||
|
||||
Just s ->
|
||||
do let wildOk = case thing bDef of
|
||||
P.DForeign {} -> NoWildCards
|
||||
P.DPrim -> NoWildCards
|
||||
P.DExpr {} -> AllowWildCards
|
||||
P.DForeign {} -> NoWildCards
|
||||
P.DPrim -> NoWildCards
|
||||
P.DExpr {} -> AllowWildCards
|
||||
P.DPropGuards {} -> NoWildCards
|
||||
s1 <- checkSchema wildOk s
|
||||
return ((name, ExtVar (fst s1)), Left (checkSigB b s1))
|
||||
|
||||
@ -991,25 +1036,33 @@ checkMonoB b t =
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
|
||||
P.DPropGuards _ ->
|
||||
tcPanic "checkMonoB"
|
||||
[ "Used constraint guards without a signature at "
|
||||
, show . pp $ P.bName b ]
|
||||
|
||||
-- XXX: Do we really need to do the defaulting business in two different places?
|
||||
checkSigB :: P.Bind Name -> (Schema,[Goal]) -> InferM Decl
|
||||
checkSigB b (Forall as asmps0 t0, validSchema) = case thing (P.bDef b) of
|
||||
checkSigB b (Forall as asmps0 t0, validSchema) =
|
||||
let name = thing (P.bName b) in
|
||||
case thing (P.bDef b) of
|
||||
|
||||
-- XXX what should we do with validSchema in this case?
|
||||
P.DPrim ->
|
||||
do return Decl { dName = thing (P.bName b)
|
||||
, dSignature = Forall as asmps0 t0
|
||||
, dDefinition = DPrim
|
||||
, dPragmas = P.bPragmas b
|
||||
, dInfix = P.bInfix b
|
||||
, dFixity = P.bFixity b
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
-- XXX what should we do with validSchema in this case?
|
||||
P.DPrim ->
|
||||
return Decl
|
||||
{ dName = name
|
||||
, dSignature = Forall as asmps0 t0
|
||||
, dDefinition = DPrim
|
||||
, dPragmas = P.bPragmas b
|
||||
, dInfix = P.bInfix b
|
||||
, dFixity = P.bFixity b
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
|
||||
P.DForeign ->
|
||||
do let loc = getLoc b
|
||||
name = thing $ P.bName b
|
||||
src = DefinitionOf name
|
||||
P.DForeign -> do
|
||||
let loc = getLoc b
|
||||
name' = thing $ P.bName b
|
||||
src = DefinitionOf name'
|
||||
inRangeMb loc do
|
||||
-- Ensure all type params are of kind #
|
||||
forM_ as \a ->
|
||||
@ -1019,8 +1072,8 @@ checkSigB b (Forall as asmps0 t0, validSchema) = case thing (P.bDef b) of
|
||||
ffiFunType <-
|
||||
case toFFIFunType (Forall as asmps0 t0) of
|
||||
Right (props, ffiFunType) -> ffiFunType <$ do
|
||||
ffiGoals <- traverse (newGoal (CtFFI name)) props
|
||||
proveImplication True (Just name) as asmps0 $
|
||||
ffiGoals <- traverse (newGoal (CtFFI name')) props
|
||||
proveImplication True (Just name') as asmps0 $
|
||||
validSchema ++ ffiGoals
|
||||
Left err -> do
|
||||
recordErrorLoc loc $ UnsupportedFFIType src err
|
||||
@ -1037,54 +1090,198 @@ checkSigB b (Forall as asmps0 t0, validSchema) = case thing (P.bDef b) of
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
|
||||
P.DExpr e0 ->
|
||||
inRangeMb (getLoc b) $
|
||||
withTParams as $
|
||||
do (e1,cs0) <- collectGoals $
|
||||
do let nm = thing (P.bName b)
|
||||
tGoal = WithSource t0 (DefinitionOf nm) (getLoc b)
|
||||
e1 <- checkFun (P.FunDesc (Just nm) 0) (P.bParams b) e0 tGoal
|
||||
addGoals validSchema
|
||||
() <- simplifyAllConstraints -- XXX: using `asmps` also?
|
||||
return e1
|
||||
P.DExpr e0 ->
|
||||
inRangeMb (getLoc b) $
|
||||
withTParams as $ do
|
||||
(t, asmps, e2) <- checkBindDefExpr [] asmps0 e0
|
||||
|
||||
asmps1 <- applySubstPreds asmps0
|
||||
cs <- applySubstGoals cs0
|
||||
return Decl
|
||||
{ dName = name
|
||||
, dSignature = Forall as asmps t
|
||||
, dDefinition = DExpr (foldr ETAbs (foldr EProofAbs e2 asmps) as)
|
||||
, dPragmas = P.bPragmas b
|
||||
, dInfix = P.bInfix b
|
||||
, dFixity = P.bFixity b
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
|
||||
let findKeep vs keep todo =
|
||||
let stays (_,cvs) = not $ Set.null $ Set.intersection vs cvs
|
||||
(yes,perhaps) = partition stays todo
|
||||
(stayPs,newVars) = unzip yes
|
||||
in case stayPs of
|
||||
[] -> (keep,map fst todo)
|
||||
_ -> findKeep (Set.unions (vs:newVars)) (stayPs ++ keep) perhaps
|
||||
P.DPropGuards cases0 ->
|
||||
inRangeMb (getLoc b) $
|
||||
withTParams as $ do
|
||||
asmps1 <- applySubstPreds asmps0
|
||||
t1 <- applySubst t0
|
||||
cases1 <- mapM checkPropGuardCase cases0
|
||||
|
||||
let -- if a goal mentions any of these variables, we'll commit to
|
||||
-- solving it now.
|
||||
stickyVars = Set.fromList (map tpVar as) `Set.union` fvs asmps1
|
||||
(stay,leave) = findKeep stickyVars []
|
||||
[ (c, fvs c) | c <- cs ]
|
||||
exh <- checkExhaustive (P.bName b) as asmps1 (map fst cases1)
|
||||
unless exh $
|
||||
-- didn't prove exhaustive i.e. none of the guarding props
|
||||
-- necessarily hold
|
||||
recordWarning (NonExhaustivePropGuards name)
|
||||
|
||||
addGoals leave
|
||||
let schema = Forall as asmps1 t1
|
||||
|
||||
return Decl
|
||||
{ dName = name
|
||||
, dSignature = schema
|
||||
, dDefinition = DExpr
|
||||
(foldr ETAbs
|
||||
(foldr EProofAbs
|
||||
(EPropGuards cases1 t1)
|
||||
asmps1)
|
||||
as)
|
||||
, dPragmas = P.bPragmas b
|
||||
, dInfix = P.bInfix b
|
||||
, dFixity = P.bFixity b
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
|
||||
|
||||
su <- proveImplication False (Just (thing (P.bName b))) as asmps1 stay
|
||||
extendSubst su
|
||||
where
|
||||
|
||||
let asmps = concatMap pSplitAnd (apSubst su asmps1)
|
||||
t <- applySubst t0
|
||||
e2 <- applySubst e1
|
||||
checkBindDefExpr ::
|
||||
[Prop] -> [Prop] -> P.Expr Name -> InferM (Type, [Prop], Expr)
|
||||
checkBindDefExpr asmpsSign asmps1 e0 = do
|
||||
|
||||
return Decl
|
||||
{ dName = thing (P.bName b)
|
||||
, dSignature = Forall as asmps t
|
||||
, dDefinition = DExpr (foldr ETAbs (foldr EProofAbs e2 asmps) as)
|
||||
, dPragmas = P.bPragmas b
|
||||
, dInfix = P.bInfix b
|
||||
, dFixity = P.bFixity b
|
||||
, dDoc = P.bDoc b
|
||||
}
|
||||
(e1,cs0) <- collectGoals $ do
|
||||
let nm = thing (P.bName b)
|
||||
tGoal = WithSource t0 (DefinitionOf nm) (getLoc b)
|
||||
e1 <- checkFun (P.FunDesc (Just nm) 0) (P.bParams b) e0 tGoal
|
||||
addGoals validSchema
|
||||
() <- simplifyAllConstraints -- XXX: using `asmps` also?
|
||||
return e1
|
||||
asmps2 <- applySubstPreds asmps1
|
||||
cs <- applySubstGoals cs0
|
||||
|
||||
let findKeep vs keep todo =
|
||||
let stays (_,cvs) = not $ Set.null $ Set.intersection vs cvs
|
||||
(yes,perhaps) = partition stays todo
|
||||
(stayPs,newVars) = unzip yes
|
||||
in case stayPs of
|
||||
[] -> (keep,map fst todo)
|
||||
_ -> findKeep (Set.unions (vs:newVars)) (stayPs ++ keep) perhaps
|
||||
|
||||
let -- if a goal mentions any of these variables, we'll commit to
|
||||
-- solving it now.
|
||||
stickyVars = Set.fromList (map tpVar as) `Set.union` fvs asmps2
|
||||
(stay,leave) = findKeep stickyVars []
|
||||
[ (c, fvs c) | c <- cs ]
|
||||
|
||||
addGoals leave
|
||||
|
||||
-- includes asmpsSign for the sake of implication, but doesn't actually
|
||||
-- include them in the resulting asmps
|
||||
su <- proveImplication True (Just (thing (P.bName b))) as (asmpsSign <> asmps2) stay
|
||||
extendSubst su
|
||||
|
||||
let asmps = concatMap pSplitAnd (apSubst su asmps2)
|
||||
t <- applySubst t0
|
||||
e2 <- applySubst e1
|
||||
|
||||
pure (t, asmps, e2)
|
||||
|
||||
|
||||
|
||||
{- |
|
||||
Given a DPropGuards of the form
|
||||
|
||||
@
|
||||
f : {...} A
|
||||
f | (B1, B2) => ...
|
||||
| (C1, C2, C2) => ...
|
||||
@
|
||||
|
||||
we check that it is exhaustive by trying to prove the following
|
||||
implications:
|
||||
|
||||
@
|
||||
A /\ ~B1 => C1 /\ C2 /\ C3
|
||||
A /\ ~B2 => C1 /\ C2 /\ C3
|
||||
@
|
||||
|
||||
The implications were derive by the following general algorithm:
|
||||
- Find that @(C1, C2, C3)@ is the guard that has the most conjuncts, so we
|
||||
will keep it on the RHS of the generated implications in order to minimize
|
||||
the number of implications we need to check.
|
||||
- Negate @(B1, B2)@ which yields @(~B1) \/ (~B2)@. This is a disjunction, so
|
||||
we need to consider a branch for each disjunct --- one branch gets the
|
||||
assumption @~B1@ and another branch gets the assumption @~B2@. Each
|
||||
branch's implications need to be proven independently.
|
||||
|
||||
-}
|
||||
checkExhaustive :: Located Name -> [TParam] -> [Prop] -> [[Prop]] -> InferM Bool
|
||||
checkExhaustive name as asmps guards =
|
||||
case sortBy cmpByLonger guards of
|
||||
[] -> pure False -- XXX: we should check the asmps are unsatisfiable
|
||||
longest : rest -> doGoals (theAlts rest) (map toGoal longest)
|
||||
|
||||
where
|
||||
cmpByLonger props1 props2 = compare (length props2) (length props1)
|
||||
-- reversed, so that longets is first
|
||||
|
||||
theAlts :: [[Prop]] -> [[Prop]]
|
||||
theAlts = map concat . sequence . map chooseNeg
|
||||
|
||||
-- Choose one of the things to negate
|
||||
chooseNeg ps =
|
||||
case ps of
|
||||
[] -> []
|
||||
p : qs -> (pNegNumeric p ++ qs) : [ p : alts | alts <- chooseNeg qs ]
|
||||
|
||||
|
||||
|
||||
-- Try to validate all cases
|
||||
doGoals todo gs =
|
||||
case todo of
|
||||
[] -> pure True
|
||||
alt : more ->
|
||||
do ok <- canProve (asmps ++ alt) gs
|
||||
if ok then doGoals more gs
|
||||
else pure False
|
||||
|
||||
toGoal :: Prop -> Goal
|
||||
toGoal prop =
|
||||
Goal
|
||||
{ goalSource = CtPropGuardsExhaustive (thing name)
|
||||
, goalRange = srcRange name
|
||||
, goal = prop
|
||||
}
|
||||
|
||||
canProve :: [Prop] -> [Goal] -> InferM Bool
|
||||
canProve asmps' goals =
|
||||
tryProveImplication (Just (thing name)) as asmps' goals
|
||||
|
||||
{- | This function does not validate anything---it just translates into
|
||||
the type-checkd syntax. The actual validation of the guard will happen
|
||||
when the (automatically generated) function corresponding to the guard is
|
||||
checked, assuming 'ExpandpropGuards' did its job correctly.
|
||||
|
||||
-}
|
||||
checkPropGuardCase :: P.PropGuardCase Name -> InferM ([Prop],Expr)
|
||||
checkPropGuardCase (P.PropGuardCase guards e0) =
|
||||
do ps <- checkPropGuards guards
|
||||
tys <- mapM (`checkType` Nothing) ts
|
||||
let rhsTs = foldl ETApp (getV eV) tys
|
||||
rhsPs = foldl (\e _p -> EProofApp e) rhsTs ps
|
||||
rhs = foldl EApp rhsPs (map getV es)
|
||||
pure (ps,rhs)
|
||||
|
||||
where
|
||||
(e1,es) = P.asEApps e0
|
||||
(eV,ts) = case e1 of
|
||||
P.EAppT ex1 tis -> (ex1, map getT tis)
|
||||
_ -> (e1, [])
|
||||
|
||||
getV ex =
|
||||
case ex of
|
||||
P.EVar x -> EVar x
|
||||
_ -> bad "Expression is not a variable."
|
||||
|
||||
getT ti =
|
||||
case ti of
|
||||
P.PosInst t -> t
|
||||
P.NamedInst {} -> bad "Unexpeceted NamedInst"
|
||||
|
||||
bad msg = panic "checkPropGuardCase" [msg]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -221,6 +221,7 @@ data ConstraintSource
|
||||
| CtImprovement
|
||||
| CtPattern TypeSource -- ^ Constraints arising from type-checking patterns
|
||||
| CtModuleInstance -- ^ Instantiating a parametrized module
|
||||
| CtPropGuardsExhaustive Name -- ^ Checking that a use of prop guards is exhastive
|
||||
| CtFFI Name -- ^ Constraints on a foreign declaration required
|
||||
-- by the FFI (e.g. sequences must be finite)
|
||||
deriving (Show, Generic, NFData)
|
||||
@ -250,8 +251,10 @@ instance TVars ConstraintSource where
|
||||
CtImprovement -> src
|
||||
CtPattern _ -> src
|
||||
CtModuleInstance -> src
|
||||
CtPropGuardsExhaustive _ -> src
|
||||
CtFFI _ -> src
|
||||
|
||||
|
||||
instance FVS Goal where
|
||||
fvs g = fvs (goal g)
|
||||
|
||||
@ -356,6 +359,7 @@ instance PP ConstraintSource where
|
||||
CtImprovement -> "examination of collected goals"
|
||||
CtPattern ad -> "checking a pattern:" <+> pp ad
|
||||
CtModuleInstance -> "module instantiation"
|
||||
CtPropGuardsExhaustive n -> "exhaustion check for prop guards used in defining" <+> pp n
|
||||
CtFFI f -> "declaration of foreign function" <+> pp f
|
||||
|
||||
ppUse :: Expr -> Doc
|
||||
|
@ -6,6 +6,7 @@
|
||||
-- Stability : provisional
|
||||
-- Portability : portable
|
||||
{-# Language OverloadedStrings #-}
|
||||
{-# Language Safe #-}
|
||||
module Cryptol.TypeCheck.Instantiate
|
||||
( instantiateWith
|
||||
, TypeArg(..)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user