mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-12 07:04:07 +00:00
Compare commits
2 Commits
issue_2178
...
privateNam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4204d5b64d | ||
|
|
9b8a803dff |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,6 +1,3 @@
|
||||
*.lean text eol=lf
|
||||
*.expected.out -text
|
||||
RELEASES.md merge=union
|
||||
stage0/** binary linguist-generated
|
||||
# The following file is often manually edited, so do show it in diffs
|
||||
stage0/src/stdlib_flags.h -binary -linguist-generated
|
||||
|
||||
30
.github/ISSUE_TEMPLATE.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
### Prerequisites
|
||||
|
||||
* [ ] Put an X between the brackets on this line if you have done all of the following:
|
||||
* Checked that your issue isn't already [filed](https://github.com/leanprover/lean4/issues).
|
||||
* Reduced the issue to a self-contained, reproducible test case.
|
||||
|
||||
### Description
|
||||
|
||||
[Description of the issue]
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
1. [First Step]
|
||||
2. [Second Step]
|
||||
3. [and so on...]
|
||||
|
||||
**Expected behavior:** [What you expect to happen]
|
||||
|
||||
**Actual behavior:** [What actually happens]
|
||||
|
||||
**Reproduces how often:** [What percentage of the time does it reproduce?]
|
||||
|
||||
### Versions
|
||||
|
||||
You can get this information from copy and pasting the output of `lean --version`,
|
||||
please include the OS and what version of the OS you're running.
|
||||
|
||||
### Additional Information
|
||||
|
||||
Any additional information, configuration or data that might be necessary to reproduce the issue.
|
||||
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,45 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* [ ] Put an X between the brackets on this line if you have done all of the following:
|
||||
* Check that your issue is not already [filed](https://github.com/leanprover/lean4/issues).
|
||||
* Reduce the issue to a minimal, self-contained, reproducible test case. Avoid dependencies to mathlib4 or std4.
|
||||
|
||||
### Description
|
||||
|
||||
[Clear and concise description of the issue]
|
||||
|
||||
### Context
|
||||
|
||||
[Broader context that the issue occured in. If there was any prior discussion on [the Lean Zulip](https://leanprover.zulipchat.com), link it here as well.]
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Expected behavior:** [Clear and concise description of what you expect to happen]
|
||||
|
||||
**Actual behavior:** [Clear and concise description of what actually happens]
|
||||
|
||||
### Versions
|
||||
|
||||
[Output of `lean --version` in the folder that the issue occured in]
|
||||
[OS version]
|
||||
|
||||
### Additional Information
|
||||
|
||||
[Additional information, configuration or data that might be necessary to reproduce the issue]
|
||||
|
||||
### Impact
|
||||
|
||||
Add :+1: to [issues you consider important](https://github.com/leanprover/lean4/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc). If others are impacted by this issue, please ask them to add :+1: to it.
|
||||
26
.github/ISSUE_TEMPLATE/rfc.md
vendored
26
.github/ISSUE_TEMPLATE/rfc.md
vendored
@@ -1,26 +0,0 @@
|
||||
---
|
||||
name: Request for comments
|
||||
about: Create a feature proposal
|
||||
title: 'RFC: '
|
||||
labels: RFC
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Proposal
|
||||
|
||||
Clear and detailed description of the proposal. Consider the following questions:
|
||||
|
||||
- **User Experience**: How does this feature improve the user experience?
|
||||
|
||||
- **Beneficiaries**: Which Lean users and projects benefit most from this feature/change?
|
||||
|
||||
- **Maintainability**: Will this change streamline code maintenance or simplify its structure?
|
||||
|
||||
### Community Feedback
|
||||
|
||||
Ideas should be discussed on [the Lean Zulip](https://leanprover.zulipchat.com) prior to submitting a proposal. Summarize all prior discussions and link them here.
|
||||
|
||||
### Impact
|
||||
|
||||
Add :+1: to [issues you consider important](https://github.com/leanprover/lean4/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc). If others benefit from the changes in this proposal being added, please ask them to add :+1: to it.
|
||||
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,13 +0,0 @@
|
||||
# Read and remove this section before submitting
|
||||
|
||||
* Ensure your PR follows the [External Contribution Guidelines](https://github.com/leanprover/lean4/blob/master/CONTRIBUTING.md).
|
||||
* Please make sure the PR has excellent documentation and tests. If we label it `missing documentation` or `missing tests` then it needs fixing!
|
||||
* Add the link to your `RFC` or `bug` issue below.
|
||||
* If the issue does not already have approval from a developer, submit the PR as draft.
|
||||
* Remove this section before submitting.
|
||||
|
||||
You can manage the `awaiting-review`, `awaiting-author`, and `WIP` labels yourself, by writing a comment containing one of these labels on its own line.
|
||||
|
||||
# Summary
|
||||
|
||||
Link to `RFC` or `bug` issue:
|
||||
26
.github/workflows/backport.yml
vendored
26
.github/workflows/backport.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Backport
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
backport:
|
||||
name: Backport
|
||||
runs-on: ubuntu-latest
|
||||
# Only react to merged PRs for security reasons.
|
||||
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
|
||||
if: >
|
||||
github.event.pull_request.merged
|
||||
&& (
|
||||
github.event.action == 'closed'
|
||||
|| (
|
||||
github.event.action == 'labeled'
|
||||
&& contains(github.event.label.name, 'backport')
|
||||
)
|
||||
)
|
||||
steps:
|
||||
- uses: tibdex/backport@v2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
159
.github/workflows/ci.yml
vendored
159
.github/workflows/ci.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
- cron: '0 7 * * *' # 8AM CET/11PM PT
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
@@ -35,59 +35,12 @@ jobs:
|
||||
LEAN_VERSION_STRING="nightly-$(date -u +%F)"
|
||||
# do nothing if commit already has a different tag
|
||||
if [[ $(git name-rev --name-only --tags --no-undefined HEAD 2> /dev/null || echo $LEAN_VERSION_STRING) == $LEAN_VERSION_STRING ]]; then
|
||||
echo "nightly=$LEAN_VERSION_STRING" >> $GITHUB_OUTPUT
|
||||
echo "::set-output name=nightly::$LEAN_VERSION_STRING"
|
||||
fi
|
||||
fi
|
||||
|
||||
# This job determines if this CI build is for a tagged release.
|
||||
# It only runs when a tag is pushed to the `leanprover` repository.
|
||||
# It sets `set-release.outputs.RELEASE_TAG` to the tag, if the tag is "v" followed by a valid semver,
|
||||
# and sets `set-release.outputs.{LEAN_VERSION_MAJOR,LEAN_VERSION_MINOR,LEAN_VERSION_PATCH,LEAN_SPECIAL_VERSION_DESC}`
|
||||
# to the semver components parsed via regex.
|
||||
set-release:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
LEAN_VERSION_MAJOR: ${{ steps.set.outputs.LEAN_VERSION_MAJOR }}
|
||||
LEAN_VERSION_MINOR: ${{ steps.set.outputs.LEAN_VERSION_MINOR }}
|
||||
LEAN_VERSION_PATCH: ${{ steps.set.outputs.LEAN_VERSION_PATCH }}
|
||||
LEAN_SPECIAL_VERSION_DESC: ${{ steps.set.outputs.LEAN_SPECIAL_VERSION_DESC }}
|
||||
RELEASE_TAG: ${{ steps.set.outputs.RELEASE_TAG }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'leanprover/lean4'
|
||||
- name: Check for official release
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'leanprover/lean4'
|
||||
id: set
|
||||
run: |
|
||||
TAG_NAME=${GITHUB_REF##*/}
|
||||
|
||||
# From https://github.com/fsaintjacques/semver-tool/blob/master/src/semver
|
||||
|
||||
NAT='0|[1-9][0-9]*'
|
||||
ALPHANUM='[0-9]*[A-Za-z-][0-9A-Za-z-]*'
|
||||
IDENT="$NAT|$ALPHANUM"
|
||||
FIELD='[0-9A-Za-z-]+'
|
||||
|
||||
SEMVER_REGEX="\
|
||||
^[vV]?\
|
||||
($NAT)\\.($NAT)\\.($NAT)\
|
||||
(\\-(${IDENT})(\\.(${IDENT}))*)?\
|
||||
(\\+${FIELD}(\\.${FIELD})*)?$"
|
||||
|
||||
if [[ ${TAG_NAME} =~ ${SEMVER_REGEX} ]]; then
|
||||
echo "Tag ${TAG_NAME} matches SemVer regex, with groups ${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]} ${BASH_REMATCH[4]}"
|
||||
echo "LEAN_VERSION_MAJOR=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT
|
||||
echo "LEAN_VERSION_MINOR=${BASH_REMATCH[2]}" >> $GITHUB_OUTPUT
|
||||
echo "LEAN_VERSION_PATCH=${BASH_REMATCH[3]}" >> $GITHUB_OUTPUT
|
||||
echo "LEAN_SPECIAL_VERSION_DESC=${BASH_REMATCH[4]##-}" >> $GITHUB_OUTPUT
|
||||
echo "RELEASE_TAG=$TAG_NAME" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Tag ${TAG_NAME} did not match SemVer regex."
|
||||
fi
|
||||
|
||||
build:
|
||||
needs: [set-nightly, set-release]
|
||||
needs: set-nightly
|
||||
if: github.event_name != 'schedule' || github.repository == 'leanprover/lean4'
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
@@ -97,17 +50,6 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
# portable release build: use channel with older glibc (2.27)
|
||||
- name: Linux LLVM
|
||||
os: ubuntu-latest
|
||||
release: false
|
||||
shell: nix-shell --arg pkgsDist "import (fetchTarball \"channel:nixos-19.03\") {{}}" --run "bash -euxo pipefail {0}"
|
||||
llvm-url: https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst
|
||||
prepare-llvm: ../script/prepare-llvm-linux.sh lean-llvm*
|
||||
binary-check: ldd -v
|
||||
# foreign code may be linked against more recent glibc
|
||||
# reverse-ffi needs to be updated to link to LLVM libraries
|
||||
CTEST_OPTIONS: -E 'foreign|leanlaketest_reverse-ffi'
|
||||
CMAKE_OPTIONS: -DLLVM=ON -DLLVM_CONFIG=${GITHUB_WORKSPACE}/build/llvm-host/bin/llvm-config
|
||||
- name: Linux release
|
||||
os: ubuntu-latest
|
||||
release: true
|
||||
@@ -116,7 +58,7 @@ jobs:
|
||||
prepare-llvm: ../script/prepare-llvm-linux.sh lean-llvm*
|
||||
binary-check: ldd -v
|
||||
# foreign code may be linked against more recent glibc
|
||||
CTEST_OPTIONS: -E 'foreign'
|
||||
CTEST_OPTIONS: -E 'foreign|leanlaketest_git'
|
||||
- name: Linux
|
||||
os: ubuntu-latest
|
||||
check-stage3: true
|
||||
@@ -125,17 +67,18 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Debug
|
||||
# exclude seriously slow tests
|
||||
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest|benchtest'
|
||||
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest'
|
||||
- name: Linux fsanitize
|
||||
os: ubuntu-latest
|
||||
# turn off custom allocator & symbolic functions to make LSAN do its magic
|
||||
CMAKE_OPTIONS: -DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address,undefined -DLEANC_EXTRA_FLAGS='-fsanitize=address,undefined -fsanitize-link-c++-runtime' -DSMALL_ALLOCATOR=OFF -DBSYMBOLIC=OFF
|
||||
# exclude seriously slow/problematic tests (laketests crash)
|
||||
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest|benchtest'
|
||||
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest'
|
||||
- name: macOS
|
||||
os: macos-latest
|
||||
release: true
|
||||
shell: bash -euxo pipefail {0}
|
||||
CMAKE_OPTIONS: -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15
|
||||
llvm-url: https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst
|
||||
prepare-llvm: ../script/prepare-llvm-macos.sh lean-llvm*
|
||||
binary-check: otool -L
|
||||
@@ -145,7 +88,7 @@ jobs:
|
||||
release: true
|
||||
cross: true
|
||||
shell: bash -euxo pipefail {0}
|
||||
CMAKE_OPTIONS: -DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-darwin_aarch64
|
||||
CMAKE_OPTIONS: -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-darwin_aarch64
|
||||
llvm-url: https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-apple-darwin.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst
|
||||
prepare-llvm: EXTRA_FLAGS=--target=aarch64-apple-darwin ../script/prepare-llvm-macos.sh lean-llvm-aarch64-* lean-llvm-x86_64-*
|
||||
binary-check: otool -L
|
||||
@@ -154,7 +97,7 @@ jobs:
|
||||
os: windows-2022
|
||||
release: true
|
||||
shell: msys2 {0}
|
||||
CMAKE_OPTIONS: -G "Unix Makefiles" -DUSE_GMP=OFF
|
||||
CMAKE_OPTIONS: -G "Unix Makefiles"
|
||||
# for reasons unknown, interactivetests are flaky on Windows
|
||||
CTEST_OPTIONS: --repeat until-pass:2
|
||||
llvm-url: https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst
|
||||
@@ -162,21 +105,12 @@ jobs:
|
||||
binary-check: ldd
|
||||
- name: Linux aarch64
|
||||
os: ubuntu-latest
|
||||
CMAKE_OPTIONS: -DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64
|
||||
CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=$GMP -DLEAN_INSTALL_SUFFIX=-linux_aarch64
|
||||
release: true
|
||||
cross: true
|
||||
shell: nix-shell --arg pkgsDist "import (fetchTarball \"channel:nixos-19.03\") {{ localSystem.config = \"aarch64-unknown-linux-gnu\"; }}" --run "bash -euxo pipefail {0}"
|
||||
llvm-url: https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst
|
||||
prepare-llvm: EXTRA_FLAGS=--target=aarch64-unknown-linux-gnu ../script/prepare-llvm-linux.sh lean-llvm-aarch64-* lean-llvm-x86_64-*
|
||||
- name: Web Assembly
|
||||
os: ubuntu-latest
|
||||
# Build a native 32bit binary in stage0 and use it to compile the oleans and the wasm build
|
||||
CMAKE_OPTIONS: -DCMAKE_C_COMPILER_WORKS=1 -DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_CMAKE_CXX_COMPILER=clang++ -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_EXECUTABLE_SUFFIX="" -DUSE_GMP=OFF -DMMAP=OFF -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DCMAKE_AR=../emsdk/emsdk-main/upstream/emscripten/emar -DCMAKE_TOOLCHAIN_FILE=../emsdk/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
|
||||
wasm: true
|
||||
cross: true
|
||||
shell: bash -euxo pipefail {0}
|
||||
# Just a few selected test because wasm is slow
|
||||
CTEST_OPTIONS: -R "leantest_1007\.lean|leantest_Format\.lean|leanruntest\_1037.lean|leanruntest_ac_rfl\.lean"
|
||||
# complete all jobs
|
||||
fail-fast: false
|
||||
name: ${{ matrix.name }}
|
||||
@@ -191,19 +125,14 @@ jobs:
|
||||
LSAN_OPTIONS: max_leaks=10
|
||||
# somehow MinGW clang64 (or cmake?) defaults to `g++` even though it doesn't exist
|
||||
CXX: c++
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.12.0/install
|
||||
if: matrix.os == 'ubuntu-latest' && !matrix.wasm
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Install MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
@@ -215,17 +144,6 @@ jobs:
|
||||
run: |
|
||||
brew install ccache tree zstd coreutils gmp
|
||||
if: matrix.os == 'macos-latest'
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v11
|
||||
with:
|
||||
version: 3.1.44
|
||||
actions-cache-folder: emsdk
|
||||
if: matrix.wasm
|
||||
- name: Install 32bit c libs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-multilib g++-multilib ccache
|
||||
if: matrix.wasm
|
||||
- name: Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -239,17 +157,10 @@ jobs:
|
||||
# open nix-shell once for initial setup
|
||||
true
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Set up core dumps
|
||||
run: |
|
||||
mkdir -p $PWD/coredumps
|
||||
# store in current directory, for easy uploading together with binary
|
||||
echo $PWD/coredumps/%e.%p.%t | sudo tee /proc/sys/kernel/core_pattern
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
ulimit -c unlimited # coredumps
|
||||
OPTIONS=()
|
||||
if [[ -n '${{ matrix.prepare-llvm }}' ]]; then
|
||||
wget -q ${{ matrix.llvm-url }}
|
||||
@@ -259,13 +170,6 @@ jobs:
|
||||
if [[ -n '${{ matrix.release }}' && -n '${{ needs.set-nightly.outputs.nightly }}' ]]; then
|
||||
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.set-nightly.outputs.nightly }})
|
||||
fi
|
||||
if [[ -n '${{ matrix.release }}' && -n '${{ needs.set-release.outputs.RELEASE_TAG }}' ]]; then
|
||||
OPTIONS+=(-DLEAN_VERSION_MAJOR=${{ needs.set-release.outputs.LEAN_VERSION_MAJOR }})
|
||||
OPTIONS+=(-DLEAN_VERSION_MINOR=${{ needs.set-release.outputs.LEAN_VERSION_MINOR }})
|
||||
OPTIONS+=(-DLEAN_VERSION_PATCH=${{ needs.set-release.outputs.LEAN_VERSION_PATCH }})
|
||||
OPTIONS+=(-DLEAN_VERSION_IS_RELEASE=1)
|
||||
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.set-release.outputs.LEAN_SPECIAL_VERSION_DESC }})
|
||||
fi
|
||||
# contortion to support empty OPTIONS with old macOS bash
|
||||
cmake .. ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
|
||||
make -j4
|
||||
@@ -281,7 +185,7 @@ jobs:
|
||||
dir=$(echo lean-*)
|
||||
mkdir pack
|
||||
# high-compression tar.zst + zip for release, fast tar.zst otherwise
|
||||
if [[ '${{ startsWith(github.ref, 'refs/tags/') && matrix.release }}' == true || -n '${{ needs.set-nightly.outputs.nightly }}' || -n '${{ needs.set-release.outputs.RELEASE_TAG }}' ]]; then
|
||||
if [[ '${{ startsWith(github.ref, 'refs/tags/v') && matrix.release }}' == true || -n '${{ needs.set-nightly.outputs.nightly }}' ]]; then
|
||||
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -19 -o pack/$dir.tar.zst
|
||||
zip -rq pack/$dir.zip $dir
|
||||
else
|
||||
@@ -299,23 +203,20 @@ jobs:
|
||||
- name: Test
|
||||
run: |
|
||||
cd build/stage1
|
||||
ulimit -c unlimited # coredumps
|
||||
# exclude nonreproducible test
|
||||
ctest -j4 --output-on-failure ${{ matrix.CTEST_OPTIONS }} < /dev/null
|
||||
if: matrix.wasm || !matrix.cross
|
||||
ctest -j4 --output-on-failure -E leanlaketest_git ${{ matrix.CTEST_OPTIONS }} < /dev/null
|
||||
if: ${{ !matrix.cross }}
|
||||
- name: Check Test Binary
|
||||
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
|
||||
if: ${{ !matrix.cross }}
|
||||
- name: Build Stage 2
|
||||
run: |
|
||||
cd build
|
||||
ulimit -c unlimited # coredumps
|
||||
make -j4 stage2
|
||||
if: matrix.build-stage2 || matrix.check-stage3
|
||||
- name: Check Stage 3
|
||||
run: |
|
||||
cd build
|
||||
ulimit -c unlimited # coredumps
|
||||
make -j4 check-stage3
|
||||
if: matrix.check-stage3
|
||||
- name: Test Speedcenter Benchmarks
|
||||
@@ -328,38 +229,13 @@ jobs:
|
||||
- name: Check rebootstrap
|
||||
run: |
|
||||
cd build
|
||||
ulimit -c unlimited # coredumps
|
||||
make update-stage0 && make -j4
|
||||
if: matrix.name == 'Linux'
|
||||
- name: CCache stats
|
||||
run: ccache -s
|
||||
- name: Show stacktrace for coredumps
|
||||
if: ${{ failure() }} && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
for c in coredumps/*; do
|
||||
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
|
||||
echo bt | $GDB/bin/gdb -q $progbin $c || true
|
||||
done
|
||||
- name: Upload coredumps
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ failure() }} && matrix.os == 'ubuntu-latest'
|
||||
with:
|
||||
name: coredumps-${{ matrix.name }}
|
||||
path: |
|
||||
./coredumps
|
||||
./build/stage0/bin/lean
|
||||
./build/stage0/lib/lean/libleanshared.so
|
||||
./build/stage1/bin/lean
|
||||
./build/stage1/lib/lean/libleanshared.so
|
||||
./build/stage2/bin/lean
|
||||
./build/stage2/lib/lean/libleanshared.so
|
||||
|
||||
# This job creates releases from tags
|
||||
# (whether they are "unofficial" releases for experiments, or official releases when the tag is "v" followed by a semver string.)
|
||||
# We do not attempt to automatically construct a changelog here:
|
||||
# unofficial releases don't need them, and official release notes will be written by a human.
|
||||
release:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
@@ -374,8 +250,6 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# This job creates nightly releases during the cron job.
|
||||
# It is responsible for creating the tag, and automatically generating a changelog.
|
||||
release-nightly:
|
||||
needs: [set-nightly, build]
|
||||
if: needs.set-nightly.outputs.nightly
|
||||
@@ -396,8 +270,7 @@ jobs:
|
||||
git fetch nightly --tags
|
||||
git tag ${{ needs.set-nightly.outputs.nightly }}
|
||||
git push nightly ${{ needs.set-nightly.outputs.nightly }}
|
||||
git push origin refs/tags/${{ needs.set-nightly.outputs.nightly }}:refs/heads/nightly
|
||||
last_tag=$(git log HEAD^ --simplify-by-decoration --pretty="format:%d" | grep -o "nightly-[-0-9]*" | head -n 1)
|
||||
last_tag=$(git describe HEAD^ --abbrev=0 --tags)
|
||||
echo -e "*Changes since ${last_tag}:*\n\n" > diff.md
|
||||
git show $last_tag:RELEASES.md > old.md
|
||||
#./script/diff_changelogs.py old.md doc/changes.md >> diff.md
|
||||
|
||||
43
.github/workflows/labels-from-comments.yml
vendored
43
.github/workflows/labels-from-comments.yml
vendored
@@ -1,43 +0,0 @@
|
||||
# This workflow allows any user to add one of the `awaiting-review`, `awaiting-author`, or `WIP` labels,
|
||||
# by commenting on the PR or issue.
|
||||
# Other labels from this set are removed automatically at the same time.
|
||||
|
||||
name: Label PR based on Comment
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
update-label:
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP'))
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Add label based on comment
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
const commentLines = context.payload.comment.body.split('\r\n');
|
||||
|
||||
const awaitingReview = commentLines.includes('awaiting-review');
|
||||
const awaitingAuthor = commentLines.includes('awaiting-author');
|
||||
const wip = commentLines.includes('WIP');
|
||||
|
||||
if (awaitingReview || awaitingAuthor || wip) {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'awaiting-review' }).catch(() => {});
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'awaiting-author' }).catch(() => {});
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'WIP' }).catch(() => {});
|
||||
}
|
||||
|
||||
if (awaitingReview) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['awaiting-review'] });
|
||||
}
|
||||
if (awaitingAuthor) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['awaiting-author'] });
|
||||
}
|
||||
if (wip) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['WIP'] });
|
||||
}
|
||||
8
.github/workflows/nix-ci.yml
vendored
8
.github/workflows/nix-ci.yml
vendored
@@ -34,9 +34,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
@@ -84,13 +81,14 @@ jobs:
|
||||
skipPush: true # we push specific outputs only
|
||||
- name: Build
|
||||
run: |
|
||||
nix build $NIX_BUILD_ARGS .#cacheRoots -o push-build
|
||||
# .o files are not a runtime dependency on macOS because of lack of thin archives
|
||||
nix build $NIX_BUILD_ARGS .#stage0 .#stage1.lean-all .#Lean.oTree .#iTree .#modDepsFiles -o push-build
|
||||
- name: Test
|
||||
run: |
|
||||
nix build $NIX_BUILD_ARGS .#test -o push-test
|
||||
- name: Build manual
|
||||
run: |
|
||||
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc#{lean-mdbook,leanInk,alectryon,test,inked} -o push-doc
|
||||
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc#{lean-mdbook,leanInk,alectryon,test} -o push-doc
|
||||
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc
|
||||
if: matrix.name == 'Nix Linux'
|
||||
- name: Push to Cachix
|
||||
|
||||
126
.github/workflows/pr-release.yml
vendored
126
.github/workflows/pr-release.yml
vendored
@@ -1,126 +0,0 @@
|
||||
# Push a release to the lean4-pr-releases repository, whenever someone pushes to a PR branch.
|
||||
|
||||
# This needs to run with the `secrets.PR_RELEASES_TOKEN` token available,
|
||||
# but PR branches will generally come from forks,
|
||||
# so it is not possible to run this using the `pull_request` or `pull_request_target` workflows.
|
||||
# Instead we use `workflow_run`, which essentially allows us to escalate privileges
|
||||
# (but only runs the CI as described in the `master` branch, not in the PR branch).
|
||||
|
||||
name: PR release
|
||||
|
||||
on:
|
||||
workflow_run: # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run
|
||||
workflows: [CI]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
on-success:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.workflow_run.conclusion == 'success' && github.repository == 'leanprover/lean4'
|
||||
steps:
|
||||
- name: Retrieve information about the original workflow
|
||||
uses: potiuk/get-workflow-origin@v1_1 # https://github.com/marketplace/actions/get-workflow-origin
|
||||
id: workflow-info
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sourceRunId: ${{ github.event.workflow_run.id }}
|
||||
- name: Checkout
|
||||
# Only proceed if the previous workflow had a pull request number.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
# Since `workflow_run` runs on master, we need to specify which commit to check out,
|
||||
# so that we tag the PR.
|
||||
ref: ${{ steps.workflow-info.outputs.targetCommitSha }}
|
||||
# We need a full checkout, so that we can push the PR commits to the `lean4-pr-releases` repo.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact from the previous workflow.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v2 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
name: build-.*
|
||||
name_is_regexp: true
|
||||
- name: Prepare release
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
git remote add pr-releases https://foo:'${{ secrets.PR_RELEASES_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-pr-releases.git
|
||||
# Try to delete any existing release for the current PR.
|
||||
gh release delete --repo ${{ github.repository_owner }}/lean4-pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} -y || true
|
||||
git tag -f pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
draft: false
|
||||
tag_name: pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
repository: ${{ github.repository_owner }}/lean4-pr-releases
|
||||
env:
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Add label
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
number: ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
labels: toolchain-available
|
||||
|
||||
# We next automatically create a Mathlib branch using this toolchain.
|
||||
# Mathlib CI will be responsible for reporting back success or failure
|
||||
# to the PR comments asynchronously.
|
||||
- name: Cleanup workspace
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
sudo rm -rf *
|
||||
|
||||
# Checkout the mathlib4 repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: leanprover-community/mathlib4
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
ref: nightly-testing # This is more likely than `master` to work with the base of this PR.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check if branch exists
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: check_branch
|
||||
run: |
|
||||
git config user.name "leanprover-community-mathlib4-bot"
|
||||
git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com"
|
||||
|
||||
EXISTS=$(git ls-remote --heads origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} | wc -l)
|
||||
echo "Branch exists: $EXISTS"
|
||||
if [ "$EXISTS" = "0" ]; then
|
||||
echo "Branch does not exist, creating it."
|
||||
git checkout -b lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, pushing an empty commit."
|
||||
git checkout lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# The Mathlib `nightly-testing` branch may have moved since this branch was created, so merge their changes.
|
||||
# If the base of this Lean4 PR becomes significantly older than the nightly being used by `nightly-testing`
|
||||
# this will cause breakages rather than fixing them!
|
||||
# Without cumbersome requirements that Lean4 PRs are based off nightlies, I'm not sure there is a perfect solution here.
|
||||
git merge nightly-testing --strategy-option ours --no-commit --allow-unrelated-histories
|
||||
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
git push origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
20
.github/workflows/stale.yml
vendored
20
.github/workflows/stale.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: 'Label stale PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
days-before-stale: -1
|
||||
days-before-pr-stale: 30
|
||||
days-before-close: -1
|
||||
stale-pr-label: 'stale'
|
||||
only-labels: 'awaiting-author'
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,7 +3,6 @@
|
||||
.#*
|
||||
*.lock
|
||||
build
|
||||
!/src/lake/Lake/Build
|
||||
GPATH
|
||||
GRTAGS
|
||||
GSYMS
|
||||
@@ -26,4 +25,4 @@ fwIn.txt
|
||||
fwOut.txt
|
||||
wdErr.txt
|
||||
wdIn.txt
|
||||
wdOut.txt
|
||||
wdOut.txt
|
||||
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "lake"]
|
||||
path = src/lake
|
||||
url = https://github.com/leanprover/lake.git
|
||||
ignore = untracked
|
||||
@@ -15,9 +15,6 @@ foreach(var ${vars})
|
||||
# must forward options that generate incompatible .olean format
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
if("${var}" MATCHES "LLVM*")
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
elseif(("${var}" MATCHES "CMAKE_.*") AND NOT ("${var}" MATCHES "CMAKE_BUILD_TYPE") AND NOT ("${var}" MATCHES "CMAKE_HOME_DIRECTORY"))
|
||||
list(APPEND PLATFORM_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
@@ -26,10 +23,23 @@ endforeach()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
|
||||
if(NOT (DEFINED STAGE0_CMAKE_EXECUTABLE_SUFFIX))
|
||||
set(STAGE0_CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "Emscripten")
|
||||
# For Emscripten, we build GMP before any of the stages and reuse it in all of them.
|
||||
set(GMP_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/gmp-root)
|
||||
set(EMSCRIPTEN_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s MAIN_MODULE=1 -O3")
|
||||
ExternalProject_Add(
|
||||
gmp
|
||||
URL https://gmplib.org/download/gmp/gmp-6.2.1.tar.bz2
|
||||
URL_HASH SHA256=eae9326beb4158c386e39a356818031bd28f3124cf915f8c5b1dc4c7a36b4d7c
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND emconfigure ./configure "CFLAGS=${EMSCRIPTEN_FLAGS}" --host=wasm32-unknown-emscripten --disable-assembly --prefix=${GMP_INSTALL_PREFIX}
|
||||
BUILD_COMMAND emmake make -j4
|
||||
INSTALL_COMMAND emmake make install
|
||||
)
|
||||
set(EXTRA_DEPENDS "gmp")
|
||||
list(APPEND CL_ARGS "-DGMP_INSTALL_PREFIX=${GMP_INSTALL_PREFIX}")
|
||||
list(APPEND PLATFORM_ARGS "-DGMP_INSTALL_PREFIX=${GMP_INSTALL_PREFIX}")
|
||||
endif()
|
||||
|
||||
ExternalProject_add(stage0
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}/stage0"
|
||||
SOURCE_SUBDIR src
|
||||
@@ -44,7 +54,7 @@ ExternalProject_add(stage1
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage1
|
||||
CMAKE_ARGS -DSTAGE=1 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage0 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${STAGE0_CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS}
|
||||
CMAKE_ARGS -DSTAGE=1 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage0 ${CL_ARGS}
|
||||
BUILD_ALWAYS ON
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage0
|
||||
@@ -53,7 +63,7 @@ ExternalProject_add(stage2
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage2
|
||||
CMAKE_ARGS -DSTAGE=2 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage1 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS}
|
||||
CMAKE_ARGS -DSTAGE=2 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage1 ${CL_ARGS}
|
||||
BUILD_ALWAYS ON
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage1
|
||||
@@ -63,7 +73,7 @@ ExternalProject_add(stage3
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage3
|
||||
CMAKE_ARGS -DSTAGE=3 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage2 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS}
|
||||
CMAKE_ARGS -DSTAGE=3 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage2 ${CL_ARGS}
|
||||
BUILD_ALWAYS ON
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage2
|
||||
|
||||
@@ -1,75 +1,57 @@
|
||||
External Contribution Guidelines
|
||||
============
|
||||
# Contribution Guidelines
|
||||
|
||||
In the past, we accepted most pull requests. This practice produced hard to maintain code, performance problems, and bugs. In order to improve the quality and maintainability of our codebase, we've established the following guidelines for external contributions.
|
||||
Thank you for your interest in contributing to Lean! There are many ways to contribute and we appreciate all of them.
|
||||
|
||||
Helpful links
|
||||
-------
|
||||
## Bug reports
|
||||
|
||||
* [Development Setup](./doc/dev/index.md)
|
||||
* [Testing](./doc/dev/testing.md)
|
||||
* [Commit convention](./doc/dev/commit_convention.md)
|
||||
Bug reports as new issues are always welcome. Please check the existing [issues](https://github.com/leanprover/lean4/issues) first.
|
||||
Reduce the issue to a self-contained, reproducible test case.
|
||||
If you have the chance, before reporting a bug, please search existing issues, as it's possible that
|
||||
someone else has already reported your error.
|
||||
If you're not sure if something is a bug or not, feel free to file a bug anyway. You may also want to discuss it with the Lean
|
||||
community using the [lean4 Zulip channel](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4).
|
||||
|
||||
Before You Submit a Pull Request (PR):
|
||||
-------
|
||||
## Simple fixes
|
||||
|
||||
**Start with an Issue**: Before submitting a PR, always open an issue discussing the problem you wish to solve or the feature you'd like to add. Use the prefix `RFC:` (request for comments) if you are proposing a new feature. Ask for feedback from other users. Take the time to summarize all the feedback. This allows the maintainers to evaluate your proposal more efficiently. When creating a RFC, consider the following questions:
|
||||
Simple fixes for **typos and clear bugs** are welcome.
|
||||
|
||||
- **User Experience**: How does this feature improve the user experience?
|
||||
## Documentation
|
||||
|
||||
- **Beneficiaries**: Which Lean users and projects do benefit most from this feature/change?
|
||||
Tutorial-like examples are very welcome.
|
||||
They are useful for finding rough edges and bugs in Lean 4, for highlighting new features, and for showing how to use Lean.
|
||||
If you want to store your tutorial in the Lean 4 repository to make sure future changes will not break it, we suggest the following workflow:
|
||||
* Contact one of the Lean developers on Zulip, and check whether your tutorial is a good match for the Lean 4 repository.
|
||||
* Send bug reports and report rough edges. We will work with you until the tutorial looks great.
|
||||
* Add plenty of comments and make sure others will be able to follow it.
|
||||
* Create a pull request in the Lean 4 repository. After merging, we will link it to the official documentation and make sure it becomes part of our test suite.
|
||||
|
||||
- **Community Feedback**: Have you sought feedback or insights from other Lean users?
|
||||
You can use `.lean` or `.md` files to create your tutorial. The `.md` files are ideal when you want to format your prose using markdown. For an example, see [this `.md` file](https://github.com/leanprover/lean4/blob/master/doc/lean3changes.md).
|
||||
|
||||
- **Maintainability**: Will this change streamline code maintenance or simplify its structure?
|
||||
Contributions to the reference manual are also welcome, but since Lean 4 is changing rapidly, please contact us first using Zulip
|
||||
to find out which parts are stable enough to document. We will work with you to get this kind of
|
||||
pull request merged. We are also happy to meet using Zoom, Skype or Google hangout to coordinate this kind of effort.
|
||||
|
||||
**Understand the Project**: Familiarize yourself with the project, existing issues, and latest commits. Ensure your contribution aligns with the project's direction and priorities.
|
||||
As Lean 4 matures, other forms of documentation (e.g., doc-strings) will be welcome too.
|
||||
|
||||
**Stay Updated**: Regularly fetch and merge changes from the main branch to ensure your branch is up-to-date and can be smoothly integrated.
|
||||
## "Help wanted"
|
||||
|
||||
**Help wanted**: We have issues tagged with ["help wanted"](https://github.com/leanprover/lean4/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22), if you want to contribute to the project, please take a look at them. If you are interested in one of them, post comments, ask questions, and engage with the core developers there.
|
||||
For issues marked as [`help wanted`](https://github.com/leanprover/lean4/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22), pull requests (PR) are welcome and we will work with you to get a PR merged. Some of these issues are nontrivial. If you are interested, please consider adding comments to the issue and/or messaging the Lean developers in [Zulip](https://leanprover.zulipchat.com/#).
|
||||
|
||||
Quality Over Quantity:
|
||||
-----
|
||||
## Unexpected Pull Requests
|
||||
|
||||
**Focused Changes**: Each PR should address a single, clearly-defined issue or feature. Avoid making multiple unrelated changes in a single PR.
|
||||
We have very few core developers, and we cannot review arbitrary pull requests (PRs). Moreover, many features involve subtle tradeoffs, and it may require significant time and energy to even assess a proposed design. We suggest the following workflow:
|
||||
|
||||
**Write Tests**: Every new feature or bug fix should come with relevant tests. This ensures the robustness and reliability of the contribution.
|
||||
* First, discuss your idea with the Lean community on Zulip. Ask the community to help collect examples, document the requirements, and detect complications.
|
||||
* If there is broad support, create a detailed issue for it on the Lean 4 repository at GitHub, and tag the issue with `RFC`.
|
||||
* Ask the community for help documenting the requirements, and for collecting examples and concerns.
|
||||
* Wait for one of the core developers to give you a "go ahead". At this point, the core developers will work with you to make sure your PR gets merged.
|
||||
|
||||
**Documentation**: Update relevant documentation, including comments in the code, to explain the logic and reasoning behind your changes.
|
||||
We don't want to waste your time by you implementing a feature and then us not being able to merge it.
|
||||
|
||||
Coding Standards:
|
||||
----
|
||||
## How to Contribute
|
||||
|
||||
**Follow the Code Style**: Ensure that your code follows the established coding style of the project.
|
||||
|
||||
**Lean on Lean**: Use Lean's built-in features and libraries effectively, avoiding reinventions.
|
||||
|
||||
**Performance**: Make sure that your changes do not introduce performance regressions. If possible, optimize the solution for speed and resource usage.
|
||||
|
||||
PR Submission:
|
||||
---
|
||||
|
||||
**Descriptive Title and Summary**: The PR title should briefly explain the purpose of the PR. The summary should give more detailed information on what changes are made and why. Links to Zulip threads are not acceptable as a summary. You are responsible for summarizing the discussion, and getting support for it.
|
||||
|
||||
**Link to Relevant Issues**: Reference any issues that your PR addresses to provide context.
|
||||
|
||||
**Stay Responsive**: Once the PR is submitted, stay responsive to feedback and be prepared to make necessary revisions. We will close any PR that has been inactive (no response or updates from the submitter) for more than a month.
|
||||
|
||||
Reviews and Feedback:
|
||||
----
|
||||
|
||||
**Be Patient**: Given the limited number of full-time maintainers and the volume of PRs, reviews may take some time.
|
||||
|
||||
**Engage Constructively**: Always approach feedback positively and constructively. Remember, reviews are about ensuring the best quality for the project, not personal criticism.
|
||||
|
||||
**Continuous Integration**: Ensure that all CI checks pass on your PR. Failed checks will delay the review process. The maintainers will not check PRs containing failures.
|
||||
|
||||
What to Expect:
|
||||
----
|
||||
|
||||
**Not All PRs Get Merged**: While we appreciate every contribution, not all PRs will be merged. Ensure your changes align with the project's goals and quality standards.
|
||||
|
||||
**Feedback is a Gift**: It helps improve the project and can also help you grow as a developer or contributor.
|
||||
|
||||
**Community Involvement**: Engage with the Lean community on our communication channels. This can lead to better collaboration and understanding of the project's direction.
|
||||
* Always follow the [commit convention](https://leanprover.github.io/lean4/doc/dev/commit_convention.html).
|
||||
* Follow the style of the surrounding code. When in doubt, look at other files using the particular syntax as well.
|
||||
* Make sure your code is documented.
|
||||
* New features or bug fixes should come with appropriate tests.
|
||||
* Ensure all tests work before submitting a PR; see [Development Setup](https://leanprover.github.io/lean4/doc/make/index.html#development-setup) and [Fixing Tests](https://leanprover.github.io/lean4/doc/dev/fixing_tests.html).
|
||||
|
||||
23
README.md
23
README.md
@@ -1,25 +1,22 @@
|
||||
This is the repository for **Lean 4**.
|
||||
|
||||
We provide [nightly releases](https://github.com/leanprover/lean4-nightly/releases)
|
||||
and have just begun regular [stable point releases](https://github.com/leanprover/lean4/releases).
|
||||
This is the repository for **Lean 4**, which is currently being released as milestone releases towards a first stable release.
|
||||
[Lean 3](https://github.com/leanprover/lean) is still the latest stable release.
|
||||
|
||||
# About
|
||||
|
||||
- [Quickstart](https://github.com/leanprover/lean4/blob/master/doc/quickstart.md)
|
||||
- [Walkthrough installation video](https://www.youtube.com/watch?v=yZo6k48L0VY)
|
||||
- [Quick tour video](https://youtu.be/zyXtbb_eYbY)
|
||||
- [Homepage](https://lean-lang.org)
|
||||
- [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/)
|
||||
- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/)
|
||||
- [Manual](https://lean-lang.org/lean4/doc/)
|
||||
- [Homepage](https://leanprover.github.io)
|
||||
- [Theorem Proving Tutorial](https://leanprover.github.io/theorem_proving_in_lean4/)
|
||||
- [Functional Programming in Lean](https://leanprover.github.io/functional_programming_in_lean/) **first chapter is available!**
|
||||
- [Manual](https://leanprover.github.io/lean4/doc/)
|
||||
- [Release notes](RELEASES.md) starting at v4.0.0-m3
|
||||
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
|
||||
- [External Contribution Guidelines](CONTRIBUTING.md)
|
||||
- [FAQ](https://lean-lang.org/lean4/doc/faq.html)
|
||||
- [Examples](https://leanprover.github.io/lean4/doc/examples.html)
|
||||
- [FAQ](https://leanprover.github.io/lean4/doc/faq.html)
|
||||
|
||||
# Installation
|
||||
|
||||
See [Setting Up Lean](https://lean-lang.org/lean4/doc/setup.html).
|
||||
See [Setting Up Lean](https://leanprover.github.io/lean4/doc/setup.html).
|
||||
|
||||
# Contributing
|
||||
|
||||
@@ -27,4 +24,4 @@ Please read our [Contribution Guidelines](CONTRIBUTING.md) first.
|
||||
|
||||
# Building from Source
|
||||
|
||||
See [Building Lean](https://lean-lang.org/lean4/doc/make/index.html).
|
||||
See [Building Lean](https://leanprover.github.io/lean4/doc/make/index.html).
|
||||
|
||||
138
RELEASES.md
138
RELEASES.md
@@ -1,131 +1,7 @@
|
||||
# Lean 4 releases
|
||||
|
||||
We intend to provide regular "minor version" releases of the Lean language at approximately monthly intervals.
|
||||
There is not yet a strong guarantee of backwards compatibility between versions,
|
||||
only an expectation that breaking changes will be documented in this file.
|
||||
|
||||
This file contains work-in-progress notes for the upcoming release, as well as previous stable releases.
|
||||
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status of each version.
|
||||
|
||||
v4.3.0 (development in progress)
|
||||
Unreleased
|
||||
---------
|
||||
|
||||
* **Lake:** Changed `postUpdate?` configuration option to a `post_update` declaration. See the `post_update` syntax docstring for more information on the new syntax.
|
||||
|
||||
* [Lake: A manifest is automatically created on workspace load if one does not exists.](https://github.com/leanprover/lean4/pull/2680).
|
||||
|
||||
* **Lake:** The `:=` syntax for configuration declarations (i.e., `package`, `lean_lib`, and `lean_exe`) has been deprecated. For example, `package foo := {...}` is deprecated.
|
||||
|
||||
v4.2.0
|
||||
---------
|
||||
|
||||
* [isDefEq cache for terms not containing metavariables.](https://github.com/leanprover/lean4/pull/2644).
|
||||
* [Cancel outstanding tasks on document edit in the language server](https://github.com/leanprover/lean4/pull/2648).
|
||||
* Make [`Environment.mk`](https://github.com/leanprover/lean4/pull/2604) and [`Environment.add`](https://github.com/leanprover/lean4/pull/2642) private, and add [`replay`](https://github.com/leanprover/lean4/pull/2617) as a safer alternative.
|
||||
* `IO.Process.output` no longer inherits the standard input of the caller.
|
||||
* [Do not inhibit caching](https://github.com/leanprover/lean4/pull/2612) of default-level `match` reduction.
|
||||
* [List the valid case tags](https://github.com/leanprover/lean4/pull/2629) when the user writes an invalid one.
|
||||
* The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types.
|
||||
* [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616).
|
||||
* [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598).
|
||||
* **Lake:** Add `postUpdate?` package configuration option. Used by a package to specify some code which should be run after a successful `lake update` of the package or one of its downstream dependencies. ([lake#185](https://github.com/leanprover/lake/issues/185))
|
||||
* Improvements to Lake startup time ([#2572](https://github.com/leanprover/lean4/pull/2572), [#2573](https://github.com/leanprover/lean4/pull/2573))
|
||||
* `refine e` now replaces the main goal with metavariables which were created during elaboration of `e` and no longer captures pre-existing metavariables that occur in `e` ([#2502](https://github.com/leanprover/lean4/pull/2502)).
|
||||
* This is accomplished via changes to `withCollectingNewGoalsFrom`, which also affects `elabTermWithHoles`, `refine'`, `calc` (tactic), and `specialize`. Likewise, all of these now only include newly-created metavariables in their output.
|
||||
* Previously, both newly-created and pre-existing metavariables occurring in `e` were returned inconsistently in different edge cases, causing duplicated goals in the infoview (issue [#2495](https://github.com/leanprover/lean4/issues/2495)), erroneously closed goals (issue [#2434](https://github.com/leanprover/lean4/issues/2434)), and unintuitive behavior due to `refine e` capturing previously-created goals appearing unexpectedly in `e` (no issue; see PR).
|
||||
|
||||
v4.1.0
|
||||
---------
|
||||
|
||||
* The error positioning on missing tokens has been [improved](https://github.com/leanprover/lean4/pull/2393). In particular, this should make it easier to spot errors in incomplete tactic proofs.
|
||||
|
||||
* After elaborating a configuration file, Lake will now cache the configuration to a `lakefile.olean`. Subsequent runs of Lake will import this OLean instead of elaborating the configuration file. This provides a significant performance improvement (benchmarks indicate that using the OLean cuts Lake's startup time in half), but there are some important details to keep in mind:
|
||||
+ Lake will regenerate this OLean after each modification to the `lakefile.lean` or `lean-toolchain`. You can also force a reconfigure by passing the new `--reconfigure` / `-R` option to `lake`.
|
||||
+ Lake configuration options (i.e., `-K`) will be fixed at the moment of elaboration. Setting these options when `lake` is using the cached configuration will have no effect. To change options, run `lake` with `-R` / `--reconfigure`.
|
||||
+ **The `lakefile.olean` is a local configuration and should not be committed to Git. Therefore, existing Lake packages need to add it to their `.gitignore`.**
|
||||
|
||||
* The signature of `Lake.buildO` has changed, `args` has been split into `weakArgs` and `traceArgs`. `traceArgs` are included in the input trace and `weakArgs` are not. See Lake's [FFI example](src/lake/examples/ffi/lib/lakefile.lean) for a demonstration of how to adapt to this change.
|
||||
|
||||
* The signatures of `Lean.importModules`, `Lean.Elab.headerToImports`, and `Lean.Elab.parseImports`
|
||||
have [changed](https://github.com/leanprover/lean4/pull/2480) from taking `List Import` to `Array Import`.
|
||||
|
||||
* There is now [an `occs` field](https://github.com/leanprover/lean4/pull/2470)
|
||||
in the configuration object for the `rewrite` tactic,
|
||||
allowing control of which occurrences of a pattern should be rewritten.
|
||||
This was previously a separate argument for `Lean.MVarId.rewrite`,
|
||||
and this has been removed in favour of an additional field of `Rewrite.Config`.
|
||||
It was not previously accessible from user tactics.
|
||||
|
||||
v4.0.0
|
||||
---------
|
||||
|
||||
* [`Lean.Meta.getConst?` has been renamed](https://github.com/leanprover/lean4/pull/2454).
|
||||
We have renamed `getConst?` to `getUnfoldableConst?` (and `getConstNoEx?` to `getUnfoldableConstNoEx?`).
|
||||
These were not intended to be part of the public API, but downstream projects had been using them
|
||||
(sometimes expecting different behaviour) incorrectly instead of `Lean.getConstInfo`.
|
||||
|
||||
* [`dsimp` / `simp` / `simp_all` now fail by default if they make no progress](https://github.com/leanprover/lean4/pull/2336).
|
||||
|
||||
This can be overridden with the `(config := { failIfUnchanged := false })` option.
|
||||
This change was made to ease manual use of `simp` (with complicated goals it can be hard to tell if it was effective)
|
||||
and to allow easier flow control in tactics internally using `simp`.
|
||||
See the [summary discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/simp.20fails.20if.20no.20progress/near/380153295)
|
||||
on zulip for more details.
|
||||
|
||||
* [`simp_all` now preserves order of hypotheses](https://github.com/leanprover/lean4/pull/2334).
|
||||
|
||||
In order to support the `failIfUnchanged` configuration option for `dsimp` / `simp` / `simp_all`
|
||||
the way `simp_all` replaces hypotheses has changed.
|
||||
In particular it is now more likely to preserve the order of hypotheses.
|
||||
See [`simp_all` reorders hypotheses unnecessarily](https://github.com/leanprover/lean4/pull/2334).
|
||||
(Previously all non-dependent propositional hypotheses were reverted and reintroduced.
|
||||
Now only such hypotheses which were changed, or which come after a changed hypothesis,
|
||||
are reverted and reintroduced.
|
||||
This has the effect of preserving the ordering amongst the non-dependent propositional hypotheses,
|
||||
but now any dependent or non-propositional hypotheses retain their position amongst the unchanged
|
||||
non-dependent propositional hypotheses.)
|
||||
This may affect proofs that use `rename_i`, `case ... =>`, or `next ... =>`.
|
||||
|
||||
* [New `have this` implementation](https://github.com/leanprover/lean4/pull/2247).
|
||||
|
||||
`this` is now a regular identifier again that is implicitly introduced by anonymous `have :=` for the remainder of the tactic block. It used to be a keyword that was visible in all scopes and led to unexpected behavior when explicitly used as a binder name.
|
||||
|
||||
* [Show typeclass and tactic names in profile output](https://github.com/leanprover/lean4/pull/2170).
|
||||
|
||||
* [Make `calc` require the sequence of relation/proof-s to have the same indentation](https://github.com/leanprover/lean4/pull/1844),
|
||||
and [add `calc` alternative syntax allowing underscores `_` in the first relation](https://github.com/leanprover/lean4/pull/1844).
|
||||
|
||||
The flexible indentation in `calc` was often used to align the relation symbols:
|
||||
```lean
|
||||
example (x y : Nat) : (x + y) * (x + y) = x * x + y * x + x * y + y * y :=
|
||||
calc
|
||||
(x + y) * (x + y) = (x + y) * x + (x + y) * y := by rw [Nat.mul_add]
|
||||
-- improper indentation
|
||||
_ = x * x + y * x + (x + y) * y := by rw [Nat.add_mul]
|
||||
_ = x * x + y * x + (x * y + y * y) := by rw [Nat.add_mul]
|
||||
_ = x * x + y * x + x * y + y * y := by rw [←Nat.add_assoc]
|
||||
```
|
||||
|
||||
This is no longer legal. The new syntax puts the first term right after the `calc` and each step has the same indentation:
|
||||
```lean
|
||||
example (x y : Nat) : (x + y) * (x + y) = x * x + y * x + x * y + y * y :=
|
||||
calc (x + y) * (x + y)
|
||||
_ = (x + y) * x + (x + y) * y := by rw [Nat.mul_add]
|
||||
_ = x * x + y * x + (x + y) * y := by rw [Nat.add_mul]
|
||||
_ = x * x + y * x + (x * y + y * y) := by rw [Nat.add_mul]
|
||||
_ = x * x + y * x + x * y + y * y := by rw [←Nat.add_assoc]
|
||||
```
|
||||
|
||||
|
||||
* Update Lake to latest prerelease.
|
||||
|
||||
* [Make go-to-definition on a typeclass projection application go to the instance(s)](https://github.com/leanprover/lean4/pull/1767).
|
||||
|
||||
* [Include timings in trace messages when `profiler` is true](https://github.com/leanprover/lean4/pull/1995).
|
||||
|
||||
* [Pretty-print signatures in hover and `#check <ident>`](https://github.com/leanprover/lean4/pull/1943).
|
||||
|
||||
* [Introduce parser memoization to avoid exponential behavior](https://github.com/leanprover/lean4/pull/1799).
|
||||
* [Introduce parser memoization to avoid exponentional behavior](https://github.com/leanprover/lean4/pull/1799).
|
||||
|
||||
* [feat: allow `doSeq` in `let x <- e | seq`](https://github.com/leanprover/lean4/pull/1809).
|
||||
|
||||
@@ -165,7 +41,7 @@ v4.0.0
|
||||
|
||||
* New [code generator](https://github.com/leanprover/lean4/tree/master/src/Lean/Compiler/LCNF) project has started.
|
||||
|
||||
* Remove description argument from `register_simp_attr`. [PR #1566](https://github.com/leanprover/lean4/pull/1566).
|
||||
* Remove description argument frome `register_simp_attr`. [PR #1566](https://github.com/leanprover/lean4/pull/1566).
|
||||
|
||||
* [Additional concurrency primitives](https://github.com/leanprover/lean4/pull/1555).
|
||||
|
||||
@@ -685,7 +561,7 @@ v4.0.0-m5 (07 August 2022)
|
||||
`Foo : {Foo : Type u} → List Foo → Type`.
|
||||
|
||||
|
||||
* Fix syntax highlighting for recursive declarations. Example
|
||||
* Fix syntax hightlighting for recursive declarations. Example
|
||||
```lean
|
||||
inductive List (α : Type u) where
|
||||
| nil : List α -- `List` is not highlighted as a variable anymore
|
||||
@@ -738,7 +614,7 @@ v4.0.0-m5 (07 August 2022)
|
||||
...
|
||||
```
|
||||
|
||||
* Remove support for `{}` annotation from inductive datatype constructors. This annotation was barely used, and we can control the binder information for parameter bindings using the new inductive family indices to parameter promotion. Example: the following declaration using `{}`
|
||||
* Remove support for `{}` annotation from inductive datatype contructors. This annotation was barely used, and we can control the binder information for parameter bindings using the new inductive family indices to parameter promotion. Example: the following declaration using `{}`
|
||||
```lean
|
||||
inductive LE' (n : Nat) : Nat → Prop where
|
||||
| refl {} : LE' n n -- Want `n` to be explicit
|
||||
@@ -903,7 +779,7 @@ v4.0.0-m4 (23 March 2022)
|
||||
|
||||
initialize my_ext : SimpExtension ← registerSimpAttr `my_simp "my own simp attribute"
|
||||
```
|
||||
If you don't need to access `my_ext`, you can also use the macro
|
||||
If you don't neet to acces `my_ext`, you can also use the macro
|
||||
```lean
|
||||
import Lean
|
||||
|
||||
@@ -994,7 +870,7 @@ For example, given `f : Nat → Nat` and `g : Nat → Nat`, `f.comp g` is now no
|
||||
|
||||
* Various improvements to go-to-definition & find-all-references accuracy.
|
||||
|
||||
* Auto generated congruence lemmas with support for casts on proofs and `Decidable` instances (see [wishlist](https://github.com/leanprover/lean4/issues/988)).
|
||||
* Auto generated congruence lemmas with support for casts on proofs and `Decidable` instances (see [whishlist](https://github.com/leanprover/lean4/issues/988)).
|
||||
|
||||
* Rename option `autoBoundImplicitLocal` => `autoImplicit`.
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
- [Tour of Lean](./tour.md)
|
||||
- [Setting Up Lean](./quickstart.md)
|
||||
- [Extended Setup Notes](./setup.md)
|
||||
- [Nix Setup](./setup/nix.md)
|
||||
- [Theorem Proving in Lean](./tpil.md)
|
||||
- [Functional Programming in Lean](fplean.md)
|
||||
- [Examples](./examples.md)
|
||||
|
||||
@@ -11,4 +11,4 @@ the following command executes a simple set of examples
|
||||
|
||||
% bin/lean examples/ex.lean
|
||||
|
||||
For more information on Lean and supported editors, please see https://lean-lang.org/documentation/.
|
||||
For more information on Lean and supported editors, please see https://leanprover.github.io/documentation/.
|
||||
|
||||
@@ -60,7 +60,7 @@ a b c : Nat
|
||||
|
||||
Here ``a b c : Nat`` indicates the local context, and the second ``Nat`` indicates the expected type of the result.
|
||||
|
||||
A *context* is sometimes called a *telescope*, but the latter is used more generally to include a sequence of declarations occurring relative to a given context. For example, relative to the context ``(a₁ : α₁) (a₂ : α₂) ... (aₙ : αₙ)``, the types ``βᵢ`` in a telescope ``(b₁ : β₁) (b₂ : β₂) ... (bₙ : βₙ)`` can refer to ``a₁, ..., aₙ``. Thus a context can be viewed as a telescope relative to the empty context.
|
||||
A *context* is sometimes called a *telescope*, but the latter is used more generally to include a sequence of declarations occuring relative to a given context. For example, relative to the context ``(a₁ : α₁) (a₂ : α₂) ... (aₙ : αₙ)``, the types ``βᵢ`` in a telescope ``(b₁ : β₁) (b₂ : β₂) ... (bₙ : βₙ)`` can refer to ``a₁, ..., aₙ``. Thus a context can be viewed as a telescope relative to the empty context.
|
||||
|
||||
Telescopes are often used to describe a list of arguments, or parameters, to a declaration. In such cases, it is often notationally convenient to let ``(a : α)`` stand for a telescope rather than just a single argument. In general, the annotations described in [Implicit Arguments](expressions.md#implicit_arguments) can be used to mark arguments as implicit.
|
||||
|
||||
@@ -76,7 +76,7 @@ Lean provides ways of adding new objects to the environment. The following provi
|
||||
* ``theorem c : p := v`` : similar to ``def``, but intended to be used when ``p`` is a proposition.
|
||||
* ``opaque c : α (:= v)?`` : declares a opaque constant named ``c`` of type ``α``, the optional value `v` is must have type `α`
|
||||
and can be viewed as a certificate that ``α`` is not an empty type. If the value is not provided, Lean tries to find one
|
||||
using a procedure based on type class resolution. The value `v` is hidden from the type checker. You can assume that
|
||||
using a proceture based on type class resolution. The value `v` is hidden from the type checker. You can assume that
|
||||
Lean "forgets" `v` after type checking this kind of declaration.
|
||||
|
||||
It is sometimes useful to be able to simulate a definition or theorem without naming it or adding it to the environment.
|
||||
|
||||
@@ -69,13 +69,6 @@ Finally, when we want to use new language features in the library, we need to
|
||||
update the stage 0 compiler, which can be done via `make -C stageN update-stage0`.
|
||||
`make update-stage0` without `-C` defaults to stage1.
|
||||
|
||||
Updates to `stage0` should be their own commits in the Git history. In
|
||||
other words, before running `make update-stage0`, please commit your
|
||||
work. Then, commit the updated `stage0` compiler code with the commit message:
|
||||
```
|
||||
chore: update stage0
|
||||
```
|
||||
|
||||
## Further Bootstrapping Complications
|
||||
|
||||
As written above, changes in meta code in the current stage usually will only
|
||||
|
||||
@@ -11,8 +11,6 @@ There are two primary attributes for interoperating with other languages:
|
||||
It can also be used with `def` to provide an internal definition, but ensuring consistency of both definitions is up to the user.
|
||||
* `@[export sym] def leanSym : ...` exports `leanSym` under the unmangled symbol name `sym`.
|
||||
|
||||
For simple examples of how to call foreign code from Lean and vice versa, see <https://github.com/leanprover/lean4/blob/master/src/lake/examples/ffi> and <https://github.com/leanprover/lean4/blob/master/src/lake/examples/reverse-ffi>, respectively.
|
||||
|
||||
## The Lean ABI
|
||||
|
||||
The Lean Application Binary Interface (ABI) describes how the signature of a Lean declaration is encoded as a native calling convention.
|
||||
|
||||
@@ -57,17 +57,3 @@ You might find that debugging through elan, e.g. via `gdb lean`, disables some
|
||||
things like symbol autocompletion because at first only the elan proxy binary
|
||||
is loaded. You can instead pass the explicit path to `bin/lean` in your build
|
||||
folder to gdb, or use `gdb $(elan which lean)`.
|
||||
|
||||
It is also possible to generate releases that others can use,
|
||||
simply by pushing a tag to your fork of the Lean 4 github repository
|
||||
(and waiting about an hour; check the `Actions` tab for completion).
|
||||
If you push `my-tag` to a fork in your github account `my_name`,
|
||||
you can then put `my_name/lean4:my-tag` in your `lean-toolchain` file in a project using `lake`.
|
||||
(You must use a tag name that does not start with a numeral, or contain `_`).
|
||||
|
||||
### `ccache`
|
||||
|
||||
Lean's build process uses [`ccache`](https://ccache.dev/) if it is
|
||||
installed to speed up recompilation of the generated C code. Without
|
||||
`ccache`, you'll likely spend more time than necessary waiting on
|
||||
rebuilds - it's a good idea to make sure it's installed.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Documentation
|
||||
|
||||
The Lean `doc` folder contains the [Lean Manual](https://lean-lang.org/lean4/doc/) and is
|
||||
The Lean `doc` folder contains the [Lean Manual](https://leanprover.github.io/lean4/doc/) and is
|
||||
authored in a combination of markdown (`*.md`) files and literate Lean files. The .lean files are
|
||||
preprocessed using a tool called [LeanInk](https://github.com/leanprover/leanink) and
|
||||
[Alectryon](https://github.com/Kha/alectryon) which produces a generated markdown file. We then run
|
||||
@@ -83,7 +83,7 @@ Then run the following:
|
||||
```
|
||||
|
||||
This will put the HTML in a `out` folder so you can load `out/index.html` in your web browser and
|
||||
it should look like https://lean-lang.org/lean4/doc/.
|
||||
it should look like https://leanprover.github.io/lean4/doc/.
|
||||
|
||||
1. It is also handy to use e.g. [`mdbook watch`](https://rust-lang.github.io/mdBook/cli/watch.html)
|
||||
in the `doc/` folder so that it keeps the html up to date while you are editing.
|
||||
|
||||
@@ -87,16 +87,6 @@ All these tests are included by [src/shell/CMakeLists.txt](https://github.com/le
|
||||
- `tests/plugin`: tests that compiled Lean code can be loaded into
|
||||
`lean` via the `--plugin` command line option.
|
||||
|
||||
## Writing Good Tests
|
||||
|
||||
Every test file should contain:
|
||||
* an initial `/-! -/` module docstring summarizing the test's purpose
|
||||
* a module docstring for each test section that describes what is tested
|
||||
and, if not 100% clear, why that is the desirable behavior
|
||||
|
||||
At the time of writing, most tests do not follow these new guidelines yet.
|
||||
For an example of a conforming test, see `tests/lean/1971.lean`.
|
||||
|
||||
## Fixing Tests
|
||||
|
||||
When the Lean source code or the standard library are modified, some of the
|
||||
@@ -111,7 +101,7 @@ First, we must install [meld](http://meldmerge.org/). On Ubuntu, we can do it by
|
||||
sudo apt-get install meld
|
||||
```
|
||||
|
||||
Now, suppose `bad_class.lean` test is broken. We can see the problem by going to `tests/lean` directory and
|
||||
Now, suppose `bad_class.lean` test is broken. We can see the problem by going to `test/lean` directory and
|
||||
executing
|
||||
|
||||
```
|
||||
|
||||
@@ -5,7 +5,7 @@ If the type of keys can be totally ordered -- that is, it supports a well-behave
|
||||
then maps can be implemented with binary search trees (BSTs). Insert and lookup operations on BSTs take time
|
||||
proportional to the height of the tree. If the tree is balanced, the operations therefore take logarithmic time.
|
||||
|
||||
This example is based on a similar example found in the ["Software Foundations"](https://softwarefoundations.cis.upenn.edu/vfa-current/SearchTree.html)
|
||||
This example is based on a similar example found in the ["Sofware Foundations"](https://softwarefoundations.cis.upenn.edu/vfa-current/SearchTree.html)
|
||||
book (volume 3).
|
||||
-/
|
||||
|
||||
@@ -81,9 +81,9 @@ def Tree.toList (t : Tree β) : List (Nat × β) :=
|
||||
|>.toList
|
||||
|
||||
/-!
|
||||
The implementation of `Tree.toList` is inefficient because of how it uses the `++` operator.
|
||||
The implemention of `Tree.toList` is inefficient because of how it uses the `++` operator.
|
||||
On a balanced tree its running time is linearithmic, because it does a linear number of
|
||||
concatenations at each level of the tree. On an unbalanced tree it's quadratic time.
|
||||
concatentations at each level of the tree. On an unbalanced tree it's quadratic time.
|
||||
Here's a tail-recursive implementation than runs in linear time, regardless of whether the tree is balanced:
|
||||
-/
|
||||
def Tree.toListTR (t : Tree β) : List (Nat × β) :=
|
||||
@@ -114,9 +114,9 @@ concatenating all goals produced by `tac'`. In this theorem, we use it to apply
|
||||
|
||||
The `simp` parameters `toListTR.go` and `toList` instruct the simplifier to try to reduce
|
||||
and/or apply auto generated equation theorems for these two functions.
|
||||
The parameter `*` instructs the simplifier to use any equation in a goal as rewriting rules.
|
||||
The parameter `*` intructs the simplifier to use any equation in a goal as rewriting rules.
|
||||
In this particular case, `simp` uses the induction hypotheses as rewriting rules.
|
||||
Finally, the parameter `List.append_assoc` instructs the simplifier to use the
|
||||
Finally, the parameter `List.append_assoc` intructs the simplifier to use the
|
||||
`List.append_assoc` theorem as a rewriting rule.
|
||||
-/
|
||||
theorem Tree.toList_eq_toListTR (t : Tree β)
|
||||
@@ -186,7 +186,7 @@ local macro "have_eq " lhs:term:max rhs:term:max : tactic =>
|
||||
The `by_cases' e` is just the regular `by_cases` followed by `simp` using all
|
||||
hypotheses in the current goal as rewriting rules.
|
||||
Recall that the `by_cases` tactic creates two goals. One where we have `h : e` and
|
||||
another one containing `h : ¬ e`. The simplifier uses the `h` to rewrite `e` to `True`
|
||||
another one containing `h : ¬ e`. The simplier uses the `h` to rewrite `e` to `True`
|
||||
in the first subgoal, and `e` to `False` in the second. This is particularly
|
||||
useful if `e` is the condition of an `if`-statement.
|
||||
-/
|
||||
@@ -282,7 +282,7 @@ theorem BinTree.find_insert_of_ne (b : BinTree β) (h : k ≠ k') (v : β)
|
||||
let ⟨t, h⟩ := b; simp
|
||||
induction t with simp
|
||||
| leaf =>
|
||||
split <;> (try simp) <;> split <;> (try simp)
|
||||
split <;> simp <;> split <;> simp
|
||||
have_eq k k'
|
||||
contradiction
|
||||
| node left key value right ihl ihr =>
|
||||
|
||||
@@ -152,7 +152,7 @@ We prove all cases but the one for `plus` using `simp [*]`. This tactic instruct
|
||||
use hypotheses such as `a = b` as rewriting/simplications rules.
|
||||
We use the `split` to break the nested `match` expression in the `plus` case into two cases.
|
||||
The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`.
|
||||
The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in
|
||||
The modifier `←` in a term simplifier argument instructs the term simplier to use the equation as a rewriting rule in
|
||||
the "reverse direction". That is, given `h : a = b`, `← h` instructs the term simplifier to rewrite `b` subterms to `a`.
|
||||
-/
|
||||
theorem Term.constFold_sound (e : Term ctx ty) : e.constFold.denote env = e.denote env := by
|
||||
|
||||
@@ -83,7 +83,7 @@ In practice, this means we use `stop` to refer to the most recently defined vari
|
||||
|
||||
A value `Expr.val` carries a concrete representation of an integer.
|
||||
|
||||
A lambda `Expr.lam` creates a function. In the scope of a function of type `Ty.fn a ty`, there is a
|
||||
A lambda `Expr.lam` creates a function. In the scope of a function ot type `Ty.fn a ty`, there is a
|
||||
new local variable of type `a`.
|
||||
|
||||
A function application `Expr.app` produces a value of type `ty` given a function from `a` to `ty` and a value of type `a`.
|
||||
@@ -139,7 +139,7 @@ def add : Expr ctx (Ty.fn Ty.int (Ty.fn Ty.int Ty.int)) :=
|
||||
More interestingly, a factorial function fact (e.g. `fun x => if (x == 0) then 1 else (fact (x-1) * x)`), can be written as.
|
||||
Note that this is a recursive (non-terminating) definition. For every input value, the interpreter terminates, but the
|
||||
definition itself is non-terminating. We use two tricks to make sure Lean accepts it. First, we use the auxiliary constructor
|
||||
`Expr.delay` to delay its unfolding. Second, we add the annotation `decreasing_by sorry` which can be viewed as
|
||||
`Expr.delay` to delay its unfolding. Second, we add the annotation `decreasing_by sorry` which can be viwed as
|
||||
"trust me, this recursive definition makes sense". Recall that `sorry` is an unsound axiom in Lean.
|
||||
-/
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ We prove all cases but the one for `plus` using `simp [*]`. This tactic instruct
|
||||
use hypotheses such as `a = b` as rewriting/simplications rules.
|
||||
We use the `split` to break the nested `match` expression in the `plus` case into two cases.
|
||||
The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`.
|
||||
The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in
|
||||
The modifier `←` in a term simplifier argument instructs the term simplier to use the equation as a rewriting rule in
|
||||
the "reverse direction. That is, given `h : a = b`, `← h` instructs the term simplifier to rewrite `b` subterms to `a`.
|
||||
-/
|
||||
theorem constFold_sound (e : Term' Ty.denote ty) : denote (constFold e) = denote e := by
|
||||
|
||||
@@ -38,7 +38,7 @@ theorem HasType.det (h₁ : HasType e t₁) (h₂ : HasType e t₂) : t₁ = t
|
||||
cases h₁ <;> cases h₂ <;> rfl
|
||||
|
||||
/-!
|
||||
The inductive type `Maybe p` has two constructors: `found a h` and `unknown`.
|
||||
The inductive type `Maybe p` has two contructors: `found a h` and `unknown`.
|
||||
The former contains an element `a : α` and a proof that `a` satisfies the predicate `p`.
|
||||
The constructor `unknown` is used to encode "failure".
|
||||
-/
|
||||
|
||||
@@ -111,8 +111,8 @@ def getType (params : GetTypeParams) : RequestM (RequestTask CodeWithInfos) :=
|
||||
withWaitFindSnapAtPos params.pos fun snap => do
|
||||
runTermElabM snap do
|
||||
let name ← resolveGlobalConstNoOverloadCore params.name
|
||||
let c ← try getConstInfo name
|
||||
catch _ => throwThe RequestError ⟨.invalidParams, s!"no constant named '{name}'"⟩
|
||||
let some c ← Meta.getConst? name
|
||||
| throwThe RequestError ⟨.invalidParams, s!"no constant named '{name}'"⟩
|
||||
Widget.ppExprTagged c.type
|
||||
|
||||
/-!
|
||||
@@ -126,10 +126,9 @@ as seen in the goal view. We will use it to implement our custom `#check` displa
|
||||
⚠️ WARNING: Like the other widget APIs, the infoview JS API is **unstable** and subject to breaking changes.
|
||||
|
||||
The code below demonstrates useful parts of the API. To make RPC method calls, we use the `RpcContext`.
|
||||
The `useAsync` helper packs the results of a call into an `AsyncState` structure which indicates
|
||||
whether the call has resolved successfully, has returned an error, or is still in-flight. Based
|
||||
on this we either display an `InteractiveCode` with the type, `mapRpcError` the error in order
|
||||
to turn it into a readable message, or show a `Loading..` message, respectively.
|
||||
The `useAsync` helper packs the results of a call into a `status` enum, the returned `val`ue in case
|
||||
the call was successful, and otherwise an `err`or. Based on the `status` we either display
|
||||
an `InteractiveCode`, or `mapRpcError` the error in order to turn it into a readable message.
|
||||
-/
|
||||
|
||||
@[widget]
|
||||
@@ -138,21 +137,21 @@ def checkWidget : UserWidgetDefinition where
|
||||
javascript := "
|
||||
import * as React from 'react';
|
||||
const e = React.createElement;
|
||||
import { RpcContext, InteractiveCode, useAsync, mapRpcError } from '@leanprover/infoview';
|
||||
import { RpcContext, InteractiveCode } from '@leanprover/infoview';
|
||||
|
||||
export default function(props) {
|
||||
const rs = React.useContext(RpcContext)
|
||||
const [name, setName] = React.useState('getType')
|
||||
const [value, setValue] = React.useState(undefined)
|
||||
|
||||
const st = useAsync(() =>
|
||||
rs.call('getType', { name, pos: props.pos }), [name, rs, props.pos])
|
||||
function run() {
|
||||
rs.call('getType', { name, pos: props.pos }).then(setValue)
|
||||
}
|
||||
|
||||
const type = st.state === 'resolved' ? st.value && e(InteractiveCode, {fmt: st.value})
|
||||
: st.state === 'rejected' ? e('p', null, mapRpcError(st.error).message)
|
||||
: e('p', null, 'Loading..')
|
||||
React.useEffect(() => run(), [name])
|
||||
const type = value && e(InteractiveCode, {fmt: value})
|
||||
const onChange = (event) => { setName(event.target.value) }
|
||||
return e('div', null,
|
||||
e('input', { value: name, onChange }), ' : ', type)
|
||||
return e('div', null, e('input', { value: name, onChange }), ' : ', type)
|
||||
}
|
||||
"
|
||||
|
||||
@@ -190,9 +189,11 @@ To do this, use the `React.useContext(EditorContext)` React context.
|
||||
This will return an `EditorConnection` whose `api` field contains a number of methods to
|
||||
interact with the text editor.
|
||||
|
||||
You can see the full API for this [here](https://github.com/leanprover/vscode-lean4/blob/master/lean4-infoview-api/src/infoviewApi.ts#L52)
|
||||
You can see the full API for this [here](https://github.com/leanprover/vscode-lean4/blob/1edd92230c7630627f18dbe76cd139903a4cbcee/lean4-infoview-api/src/infoviewApi.ts#L52)
|
||||
|
||||
-/
|
||||
|
||||
|
||||
@[widget]
|
||||
def insertTextWidget : UserWidgetDefinition where
|
||||
name := "textInserter"
|
||||
|
||||
@@ -406,7 +406,7 @@ The reduction relation is transitive, which is to say, is ``s`` reduces to ``s'`
|
||||
|
||||
This last fact reflects the intuition that once we have proved a proposition ``p``, we only care that is has been proved; the proof does nothing more than witness the fact that ``p`` is true.
|
||||
|
||||
Definitional equality is a strong notion of equality of values. Lean's logical foundations sanction treating definitionally equal terms as being the same when checking that a term is well-typed and/or that it has a given type.
|
||||
Definitional equality is a strong notion of equalty of values. Lean's logical foundations sanction treating definitionally equal terms as being the same when checking that a term is well-typed and/or that it has a given type.
|
||||
|
||||
The reduction relation is believed to be strongly normalizing, which is to say, every sequence of reductions applied to a term will eventually terminate. The property guarantees that Lean's type-checking algorithm terminates, at least in principle. The consistency of Lean and its soundness with respect to set-theoretic semantics do not depend on either of these properties.
|
||||
|
||||
|
||||
13
doc/faq.md
13
doc/faq.md
@@ -7,6 +7,15 @@ Lean is a new open source theorem prover being developed at Microsoft Research.
|
||||
It is a research project that aims to bridge the gap between interactive and automated theorem proving.
|
||||
Lean can be also used as a programming language. Actually, some Lean features are implemented in Lean itself.
|
||||
|
||||
### Are pull requests welcome?
|
||||
|
||||
In the past, we accepted most pull requests. This practice produced hard to maintain code, performance problems, and bugs.
|
||||
It takes time to review a pull request and make sure it is correct, useful and is not in conflict with our plans.
|
||||
Small bug fixes (few lines of code) are always welcome. Any other kind of unrequested pull request is not.
|
||||
Thus, before implementing a feature or modifying the system, please ask whether the change is welcome or not.
|
||||
We have issues tagged with ["help wanted"](https://github.com/leanprover/lean4/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22), if you want to contribute to the project, please take a look at them.
|
||||
If you are interested in one of them, post comments, ask questions, and engage with the core developers there.
|
||||
|
||||
### Should I use Lean?
|
||||
|
||||
Lean is under heavy development, and we are constantly trying new
|
||||
@@ -27,7 +36,7 @@ It is a good place to interact with other Lean users.
|
||||
### Should I use Lean to teach a course?
|
||||
|
||||
Lean has been used to teach courses on logic, type theory and programming languages at CMU and the University of Washington.
|
||||
The lecture notes for the CMU course [Logic and Proof](https://lean-lang.org/logic_and_proof) are available online,
|
||||
The lecture notes for the CMU course [Logic and Proof](https://leanprover.github.io/logic_and_proof) are available online,
|
||||
but they are for Lean 3.
|
||||
If you decide to teach a course using Lean, we suggest you prepare all material before the beginning of the course, and
|
||||
make sure that Lean attends all your needs. You should not expect we will fix bugs and/or add features needed for your course.
|
||||
@@ -47,7 +56,7 @@ We expect similar independent checkers will be built for Lean 4.
|
||||
|
||||
We use [GitHub](https://github.com/leanprover/lean4/issues) to track bugs and new features.
|
||||
Bug reports are always welcome, but nitpicking issues are not (e.g., the error message is confusing).
|
||||
See also our [contribution guidelines](https://github.com/leanprover/lean4/blob/master/CONTRIBUTING.md).
|
||||
See also our [contribution guidelines](../CONTRIBUTING.md).
|
||||
|
||||
### Is it Lean, LEAN, or L∃∀N?
|
||||
|
||||
|
||||
24
doc/flake.lock
generated
24
doc/flake.lock
generated
@@ -35,13 +35,14 @@
|
||||
"lean": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"lean-stage0": "lean-stage0",
|
||||
"lean4-mode": "lean4-mode",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 0,
|
||||
"narHash": "sha256-YnYbmG0oou1Q/GE4JbMNb8/yqUVXBPIvcdQQJHBqtPk=",
|
||||
"narHash": "sha256-18nUWebi3zAkP1uG27VrAJiO8vjnxnIKT4ibDx9CKYY=",
|
||||
"path": "../.",
|
||||
"type": "path"
|
||||
},
|
||||
@@ -50,14 +51,29 @@
|
||||
"type": "path"
|
||||
}
|
||||
},
|
||||
"lean-stage0": {
|
||||
"locked": {
|
||||
"lastModified": 0,
|
||||
"narHash": "sha256-3K/43lSW4WIHNG+HHVKCD1odS63mHuaQ4ueHyTIkcls=",
|
||||
"owner": "leanprover",
|
||||
"repo": "lean4",
|
||||
"rev": "0000000000000000000000000000000000000000",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "leanprover",
|
||||
"repo": "lean4",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lean4-mode": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1659020985,
|
||||
"narHash": "sha256-+dRaXB7uvN/weSZiKcfSKWhcdJVNg9Vg8k0pJkDNjpc=",
|
||||
"lastModified": 1656864638,
|
||||
"narHash": "sha256-Th+IOKGspSZEXJZMnoP9GqsuVZLt137JfgZg7Q0sHxQ=",
|
||||
"owner": "leanprover",
|
||||
"repo": "lean4-mode",
|
||||
"rev": "37d5c99b7b29c80ab78321edd6773200deb0bca6",
|
||||
"rev": "f23510741b3291d8f9797df9407b1e45d7f22b23",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
inputs.lean.url = path:../.;
|
||||
inputs.flake-utils.follows = "lean/flake-utils";
|
||||
inputs.mdBook = {
|
||||
url = "github:leanprover/mdBook";
|
||||
url = github:leanprover/mdBook;
|
||||
flake = false;
|
||||
};
|
||||
inputs.alectryon = {
|
||||
url = "github:Kha/alectryon/typeid";
|
||||
url = github:Kha/alectryon/typeid;
|
||||
flake = false;
|
||||
};
|
||||
inputs.leanInk = {
|
||||
url = "github:leanprover/LeanInk";
|
||||
url = github:leanprover/LeanInk;
|
||||
flake = false;
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
src = inputs.mdBook;
|
||||
cargoDeps = drv.cargoDeps.overrideAttrs (_: {
|
||||
inherit src;
|
||||
outputHash = "sha256-1YlPS6cqgxE4fjy9G8pWrpP27YrrbCDnfeyIsX81ZNw=";
|
||||
outputHash = "sha256-mhTWHs/bsmm3FH59SkUxBTl5lEH2Rlz/aF9CuBTu1TE=";
|
||||
});
|
||||
doCheck = false;
|
||||
});
|
||||
@@ -78,30 +78,22 @@
|
||||
(with python3Packages; [ pygments dominate beautifulsoup4 docutils ]);
|
||||
doCheck = false;
|
||||
};
|
||||
renderLeanMod = mod: mod.overrideAttrs (final: prev: {
|
||||
name = "${prev.name}.md";
|
||||
buildInputs = prev.buildInputs ++ [ alectryon ];
|
||||
outputs = [ "out" ];
|
||||
buildCommand = ''
|
||||
dir=$(dirname $relpath)
|
||||
mkdir -p $dir out/$dir
|
||||
if [ -d $src ]; then cp -r $src/. $dir/; else cp $src $leanPath; fi
|
||||
alectryon --frontend lean4+markup $leanPath --backend webpage -o $out/$leanPath.md
|
||||
'';
|
||||
});
|
||||
renderPackage = pkg: symlinkJoin {
|
||||
name = "${pkg.name}-mds";
|
||||
paths = map renderLeanMod (lib.attrValues pkg.mods);
|
||||
};
|
||||
literate = buildLeanPackage {
|
||||
name = "literate";
|
||||
src = ./.;
|
||||
roots = [
|
||||
{ mod = "examples"; glob = "submodules"; }
|
||||
{ mod = "monads"; glob = "submodules"; }
|
||||
];
|
||||
};
|
||||
inked = renderPackage literate;
|
||||
renderLean = name: file: runCommandNoCC "${name}.md" { buildInputs = [ alectryon ]; } ''
|
||||
mkdir -p $(basename $out/${name})
|
||||
alectryon --frontend lean4+markup ${file} --backend webpage -o $out/${name}.md
|
||||
'';
|
||||
listFilesRecursiveRel = root: dir: lib.flatten (lib.mapAttrsToList (name: type:
|
||||
if type == "directory" then
|
||||
listFilesRecursiveRel root ("${dir}/${name}")
|
||||
else
|
||||
dir + "/${name}"
|
||||
) (builtins.readDir "${root}/${dir}"));
|
||||
renderDir = dir: let
|
||||
inputs = builtins.filter (n: builtins.match ".*\.lean" n != null) (listFilesRecursiveRel dir ".");
|
||||
outputs = lib.genAttrs inputs (n: renderLean n "${dir}/${n}");
|
||||
in
|
||||
outputs // symlinkJoin { inherit name; paths = lib.attrValues outputs; };
|
||||
inked = renderDir ./.;
|
||||
doc = book;
|
||||
};
|
||||
defaultPackage = self.packages.${system}.doc;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Functional Programming in Lean
|
||||
=======================
|
||||
|
||||
The goal of [this book](https://lean-lang.org/functional_programming_in_lean/) is to be an accessible introduction to using Lean 4 as a programming language.
|
||||
The goal of [this book](https://leanprover.github.io/functional_programming_in_lean/) is to be an accessible introduction to using Lean 4 as a programming language.
|
||||
It should be useful both to people who want to use Lean as a general-purpose programming language and to mathematicians who want to develop larger-scale proof automation but do not have a background in functional programming.
|
||||
It does not assume any background with functional programming, though it's probably not a good first book on programming in general.
|
||||
New content will be added once per month until it's done.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 28 KiB |
@@ -1,3 +1,3 @@
|
||||
# Inductive Types
|
||||
|
||||
[Theorem Proving in Lean](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html) has a chapter about inductive datatypes.
|
||||
[Theorem Proving in Lean](https://leanprover.github.io/theorem_proving_in_lean4/inductive_types.html) has a chapter about inductive datatypes.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
\lstdefinelanguage{lean} {
|
||||
|
||||
% Anything between $ becomes LaTeX math mode
|
||||
% Anything betweeen $ becomes LaTeX math mode
|
||||
mathescape=false,
|
||||
% Comments may or not include Latex commands
|
||||
texcl=false,
|
||||
@@ -201,7 +201,6 @@ literate=
|
||||
|
||||
{ₙ}{{\ensuremath{_n}}}1
|
||||
{ₘ}{{\ensuremath{_m}}}1
|
||||
{ₚ}{{\ensuremath{_p}}}1
|
||||
{↑}{{\ensuremath{\uparrow}}}1
|
||||
{↓}{{\ensuremath{\downarrow}}}1
|
||||
|
||||
@@ -265,7 +264,7 @@ columns=[l]fullflexible,
|
||||
% Style for (listings') identifiers
|
||||
identifierstyle={\ttfamily\color{black}},
|
||||
% Note : highlighting of Coq identifiers is done through a new
|
||||
% delimiter definition through an lstset at the beginning of the
|
||||
% delimiter definition through an lstset at the begining of the
|
||||
% document. Don't know how to do better.
|
||||
|
||||
% Style for declaration keywords
|
||||
|
||||
@@ -85,7 +85,7 @@ def id5 : {α : Type} → α → α :=
|
||||
|
||||
## Sugar for simple functions
|
||||
|
||||
In Lean 3, we can create simple functions from infix operators by using parentheses. For example, `(+1)` is sugar for `fun x, x + 1`. In Lean 4, we generalize this notation using `·` as a placeholder. Here are a few examples:
|
||||
In Lean 3, we can create simple functions from infix operators by using parentheses. For example, `(+1)` is sugar for `fun x, x + 1`. In Lean 4, we generalize this notation using `·` As a placeholder. Here are a few examples:
|
||||
|
||||
```lean
|
||||
# namespace ex3
|
||||
@@ -196,8 +196,6 @@ example (f : Nat → Nat) (a b c : Nat) : f (a + b + c) = f (a + (b + c)) :=
|
||||
congrArg f (Nat.add_assoc ..)
|
||||
```
|
||||
|
||||
In Lean 4, writing `f(x)` in place of `f x` is no longer allowed, you must use whitespace between the function and its arguments (e.g., `f (x)`).
|
||||
|
||||
## Dependent function types
|
||||
|
||||
Given `α : Type` and `β : α → Type`, `(x : α) → β x` denotes the type of functions `f` with the property that,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# Macro Overview
|
||||
|
||||
The official paper describing the mechanics behind Lean 4's macro system can be
|
||||
The offical paper describing the mechanics behind Lean 4's macro system can be
|
||||
found in [Beyond Notations: Hygienic Macro Expansion for Theorem Proving
|
||||
Languages](https://arxiv.org/abs/2001.10490) by Sebastian Ullrich and Leonardo
|
||||
de Moura, and the accompanying repo with example code can be found in the
|
||||
@@ -257,7 +257,7 @@ pretty printed output.
|
||||
## Syntax expansions with `macro_rules`, and how it desugars.
|
||||
|
||||
`macro_rules` lets you declare expansions for a given `Syntax` element using a
|
||||
syntax similar to a `match` statement. The left-hand side of a match arm is a
|
||||
syntax simlar to a `match` statement. The left-hand side of a match arm is a
|
||||
quotation (with a leading `<cat>|` for categories other than `term` and
|
||||
`command`) in which users can specify the pattern they'd like to write an
|
||||
expansion for. The right-hand side returns a syntax quotation which is the
|
||||
|
||||
@@ -83,7 +83,7 @@ Work on two adjacent stages at the same time without the need for repeatedly upd
|
||||
```bash
|
||||
# open an editor that will use only committed changes (so first commit them when changing files)
|
||||
nix run .#HEAD-as-stage1.emacs-dev&
|
||||
# open a second editor that will use those committed changes as stage 0
|
||||
# open a second editor that will use those commited changes as stage 0
|
||||
# (so don't commit changes done here until you are done and ran a final `update-stage0-commit`)
|
||||
nix run .#HEAD-as-stage0.emacs-dev&
|
||||
```
|
||||
|
||||
@@ -212,7 +212,7 @@ so you get a nice zipped list like this:
|
||||
-- [(1, 4), (2, 5), (3, 6)]
|
||||
/-!
|
||||
|
||||
And of course, as you would expect, there is an `unzip` also:
|
||||
And of couse, as you would expect, there is an `unzip` also:
|
||||
|
||||
-/
|
||||
#eval List.unzip (List.zip [1, 2, 3] [4, 5, 6])
|
||||
@@ -286,7 +286,7 @@ But you will need to understand full Monads before this will make sense.
|
||||
Diving a bit deeper, (you can skip this and jump to the [Applicative
|
||||
Laws](laws.lean.md#what-are-the-applicative-laws) if don't want to dive into this implementation detail right
|
||||
now). But, if you write a simple `Option` example `(.*.) <$> some 4 <*> some 5` that produces `some 20`
|
||||
using `Seq.seq` you will see something interesting:
|
||||
using `Seq.seq` you will see somthing interesting:
|
||||
|
||||
-/
|
||||
#eval Seq.seq ((.*.) <$> some 4) (fun (_ : Unit) => some 5) -- some 20
|
||||
|
||||
@@ -32,7 +32,7 @@ Now that you have an intuition for how abstract structures work, you'll examine
|
||||
that functors and applicative functors don't help you solve. Then you'll learn the specifics of how
|
||||
to actually use monads with some examples using the `Option` monad and the all important `IO` monad.
|
||||
|
||||
## [Reader Monad](readers.lean.md)
|
||||
## [Reader Monads](readers.lean.md)
|
||||
Now that you understand the details of what makes a monadic structure work, in this section, you'll
|
||||
learn about one of the most useful built in monads `ReaderM`, which gives your programs a
|
||||
global read-only context.
|
||||
|
||||
@@ -113,7 +113,7 @@ the monadic container type.
|
||||
to write `(readerFunc3 args).run env` and this is a bit ugly, so Lean provides an infix operator
|
||||
`|>` that eliminates those parentheses so you can write `readerFunc3 args |>.run env` and then you can
|
||||
chain multiple monadic actions like this `m1 args1 |>.run args2 |>.run args3` and this is the
|
||||
recommended style. You will see this pattern used heavily in Lean code.
|
||||
recommended style. You will see this patten used heavily in Lean code.
|
||||
|
||||
The `let env ← read` expression in `readerFunc1` unwraps the environment from the `ReaderM` so we
|
||||
can use it. Each type of monad might provide one or more extra functions like this, functions that
|
||||
|
||||
@@ -17,12 +17,10 @@ See quick [walkthrough demo video](https://www.youtube.com/watch?v=yZo6k48L0VY).
|
||||
Click the "Install Lean using Elan" button. You should see some progress output like this:
|
||||
|
||||
```
|
||||
info: syncing channel updates for 'stable'
|
||||
info: latest update on stable, lean version v4.0.0
|
||||
info: syncing channel updates for 'nightly'
|
||||
info: latest update on nightly, lean version nightly-2021-12-05
|
||||
info: downloading component 'lean'
|
||||
```
|
||||
If there is no popup, you probably have Elan installed already.
|
||||
You may want to make sure that your default toolchain is Lean 4 in this case by running `elan default leanprover/lean4:stable` and reopen the file, as the next step will fail otherwise.
|
||||
|
||||
1. While it is installing, you can paste the following Lean program into the new file:
|
||||
|
||||
@@ -39,8 +37,6 @@ You are set up!
|
||||
|
||||
## Create a Lean Project
|
||||
|
||||
*If your goal is to contribute to [mathlib4](https://github.com/leanprover-community/mathlib4) or use it as a dependency, please see its readme for specific instructions on how to do that.*
|
||||
|
||||
You can now create a Lean project in a new folder. Run `lake init foo` from "View > Terminal" to create a package, followed by `lake build` to get an executable version of your Lean program.
|
||||
On Linux/macOS, you first have to follow the instructions printed by the Lean installation or log out and in again for the Lean executables to be available in you terminal.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Semantic Highlighting
|
||||
The Lean language server provides semantic highlighting information to editors. In order to benefit from this in VSCode, you may need to activate the "Editor > Semantic Highlighting" option in the preferences (this is translates to `"editor.semanticHighlighting.enabled": true,`
|
||||
in `settings.json`). The default option here is to let your color theme decides whether it activates semantic highlighting (the default themes Dark+ and Light+ do activate it for instance).
|
||||
|
||||
However this may be insufficient if your color theme does not distinguish enough syntax categories or distinguishes them very subtly. For instance the default Light+ theme uses color `#001080` for variables. This is awfully close to `#000000` that is used as the default text color. This makes it very easy to miss an accidental use of [auto bound implicit arguments](https://lean-lang.org/lean4/doc/autobound.html). For instance in
|
||||
However this may be insufficient if your color theme does not distinguish enough syntax categories or distinguishes them very subtly. For instance the default Light+ theme uses color `#001080` for variables. This is awfully close to `#000000` that is used as the default text color. This makes it very easy to miss an accidental use of [auto bound implicit arguments](https://leanprover.github.io/lean4/doc/autobound.html). For instance in
|
||||
```lean
|
||||
def my_id (n : nat) := n
|
||||
```
|
||||
|
||||
97
doc/setup.md
97
doc/setup.md
@@ -2,7 +2,7 @@
|
||||
|
||||
### Tier 1
|
||||
|
||||
Platforms built & tested by our CI, available as nightly releases via elan (see below)
|
||||
Platforms built & tested by our CI, available as nightly & stable releases via elan (see above)
|
||||
|
||||
* x86-64 Linux with glibc 2.27+
|
||||
* x86-64 macOS 10.15+
|
||||
@@ -10,13 +10,13 @@ Platforms built & tested by our CI, available as nightly releases via elan (see
|
||||
|
||||
### Tier 2
|
||||
|
||||
Platforms cross-compiled but not tested by our CI, available as nightly releases
|
||||
Platforms cross-compiled but not tested by our CI, available as nightly & stable releases
|
||||
|
||||
Releases may be silently broken due to the lack of automated testing.
|
||||
Issue reports and fixes are welcome.
|
||||
|
||||
* aarch64 Linux with glibc 2.27+
|
||||
* aarch64 (Apple Silicon) macOS
|
||||
* aarch64 (M1) macOS
|
||||
|
||||
<!--
|
||||
### Tier 3
|
||||
@@ -26,17 +26,28 @@ Platforms that are known to work from manual testing, but do not come with CI or
|
||||
|
||||
# Setting Up Lean
|
||||
|
||||
See also the [quickstart](./quickstart.md) instructions for a standard setup with VS Code as the editor.
|
||||
There are currently two ways to set up a Lean 4 development environment:
|
||||
|
||||
* [basic setup](./setup.md#basic-setup) (Linux/macOS/Windows): uses [`elan`](https://github.com/leanprover/elan) + your preinstalled editor
|
||||
* [Nix setup](./setup.md#nix-setup) (Linux/macOS/WSL): uses the [Nix](https://nixos.org/nix/) package manager for installing all dependencies localized to your project
|
||||
|
||||
See also the [quickstart](./quickstart.md) instructions for using the basic setup with VS Code as the editor.
|
||||
|
||||
## Basic Setup
|
||||
|
||||
Release builds for all supported platforms are available at <https://github.com/leanprover/lean4/releases>.
|
||||
Instead of downloading these and setting up the paths manually, however, it is recommended to use the Lean version manager [`elan`](https://github.com/leanprover/elan) instead:
|
||||
```sh
|
||||
$ elan self update # in case you haven't updated elan in a while
|
||||
# download & activate latest Lean 4 stable release (https://github.com/leanprover/lean4/releases)
|
||||
# download & activate latest Lean 4 release (https://github.com/leanprover/lean4/releases)
|
||||
$ elan default leanprover/lean4:stable
|
||||
# alternatively, use the latest nightly build (https://github.com/leanprover/lean4-nightly/releases)
|
||||
$ elan default leanprover/lean4:nightly
|
||||
# alternatively, activate Lean 4 in current directory only
|
||||
$ elan override set leanprover/lean4:stable
|
||||
```
|
||||
|
||||
## `lake`
|
||||
### `lake`
|
||||
|
||||
Lean 4 comes with a package manager named `lake`.
|
||||
Use `lake init foo` to initialize a Lean package `foo` in the current directory, and `lake build` to typecheck and build it as well as all its dependencies. Use `lake help` to learn about further commands.
|
||||
@@ -56,8 +67,80 @@ After running `lake build` you will see a binary named `./build/bin/foo` and whe
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
## Editing
|
||||
### Editing
|
||||
|
||||
Lean implements the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) that can be used for interactive development in [Emacs](https://github.com/leanprover/lean4-mode), [VS Code](https://github.com/leanprover-community/vscode-lean4), and possibly other editors.
|
||||
|
||||
Changes must be saved to be visible in other files, which must then be invalidated using an editor command (see links above).
|
||||
|
||||
## Nix Setup
|
||||
|
||||
The alternative setup based on Nix provides a perfectly reproducible development environment for your project from the Lean version down to the editor and Lean extension.
|
||||
However, it is still experimental and subject to change; in particular, it is heavily based on an unreleased version of Nix enabling [Nix Flakes](https://www.tweag.io/blog/2020-05-25-flakes/). The setup has been tested on NixOS, other Linux distributions, and macOS.
|
||||
|
||||
After installing (any version of) Nix (<https://nixos.org/download.html>), you can easily open a shell with the particular pre-release version of Nix needed by and tested with our setup (called the "Lean shell" from here on):
|
||||
```bash
|
||||
$ nix-shell https://github.com/leanprover/lean4/archive/master.tar.gz -A nix
|
||||
```
|
||||
While this shell is sufficient for executing the steps below, it is recommended to also set the following options in `/etc/nix/nix.conf` (`nix.extraOptions` in NixOS):
|
||||
```
|
||||
max-jobs = auto # Allow building multiple derivations in parallel
|
||||
keep-outputs = true # Do not garbage-collect build time-only dependencies (e.g. clang)
|
||||
# Allow fetching build results from the Lean Cachix cache
|
||||
trusted-substituters = https://lean4.cachix.org/
|
||||
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= lean4.cachix.org-1:mawtxSxcaiWE24xCXXgh3qnvlTkyU7evRRnGeAhD4Wk=
|
||||
```
|
||||
On a multi-user installation of Nix (the default), you need to restart the Nix daemon afterwards:
|
||||
```bash
|
||||
sudo pkill nix-daemon
|
||||
```
|
||||
|
||||
The [Cachix](https://cachix.org/) integration will magically beam any build steps already executed by the CI right onto your machine when calling Nix commands in the shell opened above.
|
||||
It can be set up analogously as a cache for your own project.
|
||||
|
||||
Note: Your system Nix might print warnings about not knowing some of the settings used by the Lean shell Nix, which can be ignored.
|
||||
|
||||
### Basic Commands
|
||||
|
||||
From a Lean shell, run
|
||||
```bash
|
||||
$ nix flake new mypkg -t github:leanprover/lean4
|
||||
```
|
||||
to create a new Lean package in directory `mypkg` using the latest commit of Lean 4.
|
||||
Such packages follow the same directory layout as described in the basic setup above, except for a `lakefile.lean` replaced by a `flake.nix` file set up so you can run Nix commands on it, for example:
|
||||
```bash
|
||||
$ nix build # build package and all dependencies
|
||||
$ nix build .#executable # compile `main` definition into executable (after you've added one)
|
||||
$ nix run .#emacs-dev # open a pinned version of Emacs with lean4-mode fully set up
|
||||
$ nix run .#emacs-dev MyPackage.lean # arguments can be passed as well, e.g. the file to open
|
||||
$ nix run .#vscode-dev MyPackage.lean # ditto, using VS Code
|
||||
```
|
||||
Note that if you rename `MyPackage.lean`, you also have to adjust the `name` attribute in `flake.nix` accordingly.
|
||||
Also note that if you turn the package into a Git repository, only tracked files will be visible to Nix.
|
||||
|
||||
As in the basic setup, changes need to be saved to be visible in other files, which have then to be invalidated via an editor command.
|
||||
|
||||
If you don't want to or cannot start the pinned editor from Nix, e.g. because you're running Lean inside WSL/a container/on a different machine, you can manually point your editor at the `lean` wrapper script the commands above use internally:
|
||||
```bash
|
||||
$ nix build .#lean-dev -o result-lean-dev
|
||||
```
|
||||
The resulting `./result-lean-dev/bin/lean` script essentially runs `nix run .#lean` in the current project's root directory when you open a Lean file or use the "refresh dependencies" command such that the correct Lean version for that project is executed.
|
||||
This includes selecting the correct stage of Lean (which it will compile on the fly, though without progress output) if you are [working on Lean itself](./make/nix.md#editor-integration).
|
||||
|
||||
Package dependencies can be added as further input flakes and passed to the `deps` list of `buildLeanPackage`. Example: <https://github.com/Kha/testpkg2/blob/master/flake.nix#L5>
|
||||
|
||||
For hacking, it can be useful to temporarily override an input with a local checkout/different version of a dependency:
|
||||
```bash
|
||||
$ nix build --override-input somedep path/to/somedep
|
||||
```
|
||||
|
||||
On a build error, Nix will show the last 10 lines of the output by default. You can pass `-L` to `nix build` to show all lines, or pass the shown `*.drv` path to `nix log` to show the full log after the fact.
|
||||
|
||||
Keeping all outputs ever built on a machine alive can accumulate to quite impressive amounts of disk space, so you might want to trigger the Nix GC when `/nix/store/` has grown too large:
|
||||
```bash
|
||||
nix-collect-garbage
|
||||
```
|
||||
This will remove everything not reachable from "GC roots" such as the `./result` symlink created by `nix build`.
|
||||
|
||||
Note that the package information in `flake.nix` is currently completely independent from `lakefile.lean` used in the basic setup.
|
||||
Unifying the two formats is TBD.
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# Nix Setup
|
||||
|
||||
An alternative setup based on Nix provides a perfectly reproducible development environment for your project from the Lean version down to the editor and Lean extension.
|
||||
However, it is still experimental and subject to change; in particular, it is heavily based on an unreleased version of Nix enabling [Nix Flakes](https://www.tweag.io/blog/2020-05-25-flakes/). The setup has been tested on NixOS, other Linux distributions, and macOS.
|
||||
|
||||
After installing (any version of) Nix (<https://nixos.org/download.html>), you can easily open a shell with the particular pre-release version of Nix needed by and tested with our setup (called the "Lean shell" from here on):
|
||||
```bash
|
||||
$ nix-shell https://github.com/leanprover/lean4/archive/master.tar.gz -A nix
|
||||
```
|
||||
While this shell is sufficient for executing the steps below, it is recommended to also set the following options in `/etc/nix/nix.conf` (`nix.extraOptions` in NixOS):
|
||||
```
|
||||
max-jobs = auto # Allow building multiple derivations in parallel
|
||||
keep-outputs = true # Do not garbage-collect build time-only dependencies (e.g. clang)
|
||||
# Allow fetching build results from the Lean Cachix cache
|
||||
trusted-substituters = https://lean4.cachix.org/
|
||||
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= lean4.cachix.org-1:mawtxSxcaiWE24xCXXgh3qnvlTkyU7evRRnGeAhD4Wk=
|
||||
```
|
||||
On a multi-user installation of Nix (the default), you need to restart the Nix daemon afterwards:
|
||||
```bash
|
||||
sudo pkill nix-daemon
|
||||
```
|
||||
|
||||
The [Cachix](https://cachix.org/) integration will magically beam any build steps already executed by the CI right onto your machine when calling Nix commands in the shell opened above.
|
||||
It can be set up analogously as a cache for your own project.
|
||||
|
||||
Note: Your system Nix might print warnings about not knowing some of the settings used by the Lean shell Nix, which can be ignored.
|
||||
|
||||
## Basic Commands
|
||||
|
||||
From a Lean shell, run
|
||||
```bash
|
||||
$ nix flake new mypkg -t github:leanprover/lean4
|
||||
```
|
||||
to create a new Lean package in directory `mypkg` using the latest commit of Lean 4.
|
||||
Such packages follow the same directory layout as described in the standard setup, except for a `lakefile.lean` replaced by a `flake.nix` file set up so you can run Nix commands on it, for example:
|
||||
```bash
|
||||
$ nix build # build package and all dependencies
|
||||
$ nix build .#executable # compile `main` definition into executable (after you've added one)
|
||||
$ nix run .#emacs-dev # open a pinned version of Emacs with lean4-mode fully set up
|
||||
$ nix run .#emacs-dev MyPackage.lean # arguments can be passed as well, e.g. the file to open
|
||||
$ nix run .#vscode-dev MyPackage.lean # ditto, using VS Code
|
||||
```
|
||||
Note that if you rename `MyPackage.lean`, you also have to adjust the `name` attribute in `flake.nix` accordingly.
|
||||
Also note that if you turn the package into a Git repository, only tracked files will be visible to Nix.
|
||||
|
||||
As in the standard setup, changes need to be saved to be visible in other files, which have then to be invalidated via an editor command.
|
||||
|
||||
If you don't want to or cannot start the pinned editor from Nix, e.g. because you're running Lean inside WSL/a container/on a different machine, you can manually point your editor at the `lean` wrapper script the commands above use internally:
|
||||
```bash
|
||||
$ nix build .#lean-dev -o result-lean-dev
|
||||
```
|
||||
The resulting `./result-lean-dev/bin/lean` script essentially runs `nix run .#lean` in the current project's root directory when you open a Lean file or use the "refresh dependencies" command such that the correct Lean version for that project is executed.
|
||||
This includes selecting the correct stage of Lean (which it will compile on the fly, though without progress output) if you are [working on Lean itself](./make/nix.md#editor-integration).
|
||||
|
||||
Package dependencies can be added as further input flakes and passed to the `deps` list of `buildLeanPackage`. Example: <https://github.com/Kha/testpkg2/blob/master/flake.nix#L5>
|
||||
|
||||
For hacking, it can be useful to temporarily override an input with a local checkout/different version of a dependency:
|
||||
```bash
|
||||
$ nix build --override-input somedep path/to/somedep
|
||||
```
|
||||
|
||||
On a build error, Nix will show the last 10 lines of the output by default. You can pass `-L` to `nix build` to show all lines, or pass the shown `*.drv` path to `nix log` to show the full log after the fact.
|
||||
|
||||
Keeping all outputs ever built on a machine alive can accumulate to quite impressive amounts of disk space, so you might want to trigger the Nix GC when `/nix/store/` has grown too large:
|
||||
```bash
|
||||
nix-collect-garbage
|
||||
```
|
||||
This will remove everything not reachable from "GC roots" such as the `./result` symlink created by `nix build`.
|
||||
|
||||
Note that the package information in `flake.nix` is currently completely independent from `lakefile.lean` used in the standard setup.
|
||||
Unifying the two formats is TBD.
|
||||
@@ -224,7 +224,7 @@ example (n : Nat) : (binToChar n).isSome -> n = 0 ∨ n = 1 := by
|
||||
next => exact fun _ => Or.inr rfl
|
||||
next => intro h; cases h
|
||||
|
||||
/- Hypotheses about previous cases can be accessed by assigning them a
|
||||
/- Hypotheses about previous cases can be accessesd by assigning them a
|
||||
name, like `ne_zero` below. Information about the matched term can also
|
||||
be preserved using the `generalizing` tactic: -/
|
||||
example (n : Nat) : (n = 0) -> (binToChar n = some '0') := by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Theorem Proving in Lean
|
||||
=======================
|
||||
|
||||
We strongly encourage you to read the book [Theorem Proving in Lean](https://lean-lang.org/theorem_proving_in_lean4/title_page.html).
|
||||
We strongly encourage you to read the book [Theorem Proving in Lean](https://leanprover.github.io/theorem_proving_in_lean4/title_page.html).
|
||||
Many Lean users consider it to be the Lean Bible.
|
||||
|
||||
@@ -36,7 +36,7 @@ Lean has numerous features, including:
|
||||
- [Monads](./monads/intro.md)
|
||||
- [Extensible syntax](./syntax.md)
|
||||
- Hygienic macros
|
||||
- [Dependent types](https://lean-lang.org/theorem_proving_in_lean4/dependent_type_theory.html)
|
||||
- [Dependent types](https://leanprover.github.io/theorem_proving_in_lean4/dependent_type_theory.html)
|
||||
- [Metaprogramming](./metaprogramming.md)
|
||||
- Multithreading
|
||||
- Verification: you can prove properties of your functions using Lean itself
|
||||
|
||||
12
flake.lock
generated
12
flake.lock
generated
@@ -18,11 +18,11 @@
|
||||
"lean4-mode": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1676498134,
|
||||
"narHash": "sha256-u3WvyKxOViZG53hkb8wd2/Og6muTecbh+NdflIgVeyk=",
|
||||
"lastModified": 1659020985,
|
||||
"narHash": "sha256-+dRaXB7uvN/weSZiKcfSKWhcdJVNg9Vg8k0pJkDNjpc=",
|
||||
"owner": "leanprover",
|
||||
"repo": "lean4-mode",
|
||||
"rev": "2c6ef33f476fdf5eb5e4fa4fa023ba8b11372440",
|
||||
"rev": "37d5c99b7b29c80ab78321edd6773200deb0bca6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -101,11 +101,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1686089707,
|
||||
"narHash": "sha256-LTNlJcru2qJ0XhlhG9Acp5KyjB774Pza3tRH0pKIb3o=",
|
||||
"lastModified": 1657208011,
|
||||
"narHash": "sha256-BlIFwopAykvdy1DYayEkj6ZZdkn+cVgPNX98QVLc0jM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "af21c31b2a1ec5d361ed8050edd0303c31306397",
|
||||
"rev": "2770cc0b1e8faa0e20eb2c6aea64c256a706d4f2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
14
flake.nix
14
flake.nix
@@ -1,11 +1,11 @@
|
||||
{
|
||||
description = "Lean interactive theorem prover";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.nix.url = "github:NixOS/nix";
|
||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixpkgs-unstable;
|
||||
inputs.flake-utils.url = github:numtide/flake-utils;
|
||||
inputs.nix.url = github:NixOS/nix;
|
||||
inputs.lean4-mode = {
|
||||
url = "github:leanprover/lean4-mode";
|
||||
url = github:leanprover/lean4-mode;
|
||||
flake = false;
|
||||
};
|
||||
# used *only* by `stage0-from-input` below
|
||||
@@ -24,13 +24,13 @@
|
||||
# for `vscode-with-extensions`
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; inherit nix lean4-mode; };
|
||||
lean-packages = pkgs.callPackage (./nix/packages.nix) { inherit nix lean4-mode; };
|
||||
in {
|
||||
packages = lean-packages // rec {
|
||||
debug = lean-packages.override { debug = true; };
|
||||
stage0debug = lean-packages.override { stage0debug = true; };
|
||||
asan = lean-packages.override { extraCMakeFlags = [ "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address" "-DLEANC_EXTRA_FLAGS=-fsanitize=address" "-DSMALL_ALLOCATOR=OFF" "-DSYMBOLIC=OFF" ]; };
|
||||
asandebug = asan.override { debug = true; };
|
||||
sanitized = lean-packages.override { extraCMakeFlags = [ "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address,undefined" "-DLEANC_EXTRA_FLAGS=-fsanitize=address,undefined" "-DSMALL_ALLOCATOR=OFF" "-DSYMBOLIC=OFF" ]; };
|
||||
sandebug = sanitized.override { debug = true; };
|
||||
tsan = lean-packages.override {
|
||||
extraCMakeFlags = [ "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=thread" "-DLEANC_EXTRA_FLAGS=-fsanitize=thread" "-DCOMPRESSED_OBJECT_HEADER=OFF" ];
|
||||
stage0 = (lean-packages.override {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
|
||||
stdenv, lib, cmake, gmp, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
|
||||
{ debug ? false, stage0debug ? false, extraCMakeFlags ? [],
|
||||
stdenv, lib, cmake, gmp, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages,
|
||||
... } @ args:
|
||||
with builtins;
|
||||
rec {
|
||||
inherit stdenv;
|
||||
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
|
||||
buildCMake = args: stdenv.mkDerivation ({
|
||||
nativeBuildInputs = [ cmake ];
|
||||
buildInputs = [ gmp llvmPackages.llvm ];
|
||||
@@ -16,8 +15,8 @@ rec {
|
||||
patchShebangs .
|
||||
'';
|
||||
} // args // {
|
||||
src = args.realSrc or (sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]);
|
||||
cmakeFlags = (args.cmakeFlags or [ "-DSTAGE=1" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ];
|
||||
src = args.realSrc or (lib.sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]);
|
||||
cmakeFlags = (args.cmakeFlags or [ "-DSTAGE=1" "-DLLVM=ON" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ];
|
||||
preConfigure = args.preConfigure or "" + ''
|
||||
# ignore absence of submodule
|
||||
sed -i 's!lake/Lake.lean!!' CMakeLists.txt
|
||||
@@ -26,7 +25,7 @@ rec {
|
||||
lean-bin-tools-unwrapped = buildCMake {
|
||||
name = "lean-bin-tools";
|
||||
outputs = [ "out" "leanc_src" ];
|
||||
realSrc = sourceByRegex (src + "/src") [ "CMakeLists\.txt" "cmake.*" "bin.*" "include.*" ".*\.in" "Leanc\.lean" ];
|
||||
realSrc = lib.sourceByRegex ../src [ "CMakeLists\.txt" "cmake.*" "bin.*" "include.*" ".*\.in" "Leanc\.lean" ];
|
||||
preConfigure = ''
|
||||
touch empty.cpp
|
||||
sed -i 's/add_subdirectory.*//;s/set(LEAN_OBJS.*/set(LEAN_OBJS empty.cpp)/' CMakeLists.txt
|
||||
@@ -44,7 +43,7 @@ rec {
|
||||
};
|
||||
leancpp = buildCMake {
|
||||
name = "leancpp";
|
||||
src = src + "/src";
|
||||
src = ../src;
|
||||
buildFlags = [ "leancpp" "leanrt" "leanrt_initial-exec" "shell" ];
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
@@ -53,14 +52,18 @@ rec {
|
||||
mv runtime/libleanrt_initial-exec.a $out/lib
|
||||
'';
|
||||
};
|
||||
stage0 = args.stage0 or (buildCMake {
|
||||
# rename derivation so `nix run` uses the right executable name but we still see the stage in the build log
|
||||
wrapStage = stage: runCommand "lean" {} ''
|
||||
ln -s ${stage} $out
|
||||
'';
|
||||
stage0 = wrapStage (args.stage0 or (buildCMake {
|
||||
name = "lean-stage0";
|
||||
realSrc = src + "/stage0/src";
|
||||
realSrc = ../stage0/src;
|
||||
debug = stage0debug;
|
||||
cmakeFlags = [ "-DSTAGE=0" ];
|
||||
extraCMakeFlags = [];
|
||||
preConfigure = ''
|
||||
ln -s ${src + "/stage0/stdlib"} ../stdlib
|
||||
ln -s ${../stage0/stdlib} ../stdlib
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin $out/lib/lean
|
||||
@@ -72,8 +75,7 @@ rec {
|
||||
done
|
||||
otool -L $out/bin/lean
|
||||
'';
|
||||
meta.mainProgram = "lean";
|
||||
});
|
||||
}));
|
||||
stage = { stage, prevStage, self }:
|
||||
let
|
||||
desc = "stage${toString stage}";
|
||||
@@ -85,10 +87,10 @@ rec {
|
||||
lean-final = self;
|
||||
leanFlags = [ "-DwarningAsError=true" ];
|
||||
} ({
|
||||
src = src + "/src";
|
||||
src = ../src;
|
||||
roots = [ { mod = args.name; glob = "andSubmodules"; } ];
|
||||
fullSrc = src;
|
||||
srcPath = "$PWD/src:$PWD/src/lake";
|
||||
fullSrc = ../.;
|
||||
srcPrefix = "src";
|
||||
inherit debug;
|
||||
} // args);
|
||||
Init' = build { name = "Init"; deps = []; };
|
||||
@@ -101,84 +103,64 @@ rec {
|
||||
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
|
||||
Init = attachSharedLib leanshared Init';
|
||||
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Init ]; };
|
||||
Lake = build {
|
||||
name = "Lake";
|
||||
src = src + "/src/lake";
|
||||
deps = [ Init Lean ];
|
||||
};
|
||||
Lake-Main = build {
|
||||
name = "Lake.Main";
|
||||
roots = [ "Lake.Main" ];
|
||||
executableName = "lake";
|
||||
deps = [ Lake ];
|
||||
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
|
||||
src = src + "/src/lake";
|
||||
};
|
||||
stdlib = [ Init Lean Lake ];
|
||||
stdlib = [ Init Lean ];
|
||||
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
|
||||
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
|
||||
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
|
||||
extlib = stdlib; # TODO: add Lake
|
||||
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
|
||||
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${Lake.staticLib} -L${leancpp}/lib/lean";
|
||||
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${leancpp}/lib/lean";
|
||||
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||
mkdir $out
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Bsymbolic"} \
|
||||
${if stdenv.isDarwin then "-Wl,-force_load,${Init.staticLib}/libInit.a -Wl,-force_load,${Lean.staticLib}/libLean.a -Wl,-force_load,${leancpp}/lib/lean/libleancpp.a ${leancpp}/lib/libleanrt_initial-exec.a -lc++"
|
||||
else "-Wl,--whole-archive -lInit -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++"} -lm ${stdlibLinkFlags} \
|
||||
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
||||
-o $out/$libName
|
||||
'';
|
||||
mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib;
|
||||
print-paths = Lean.makePrintPathsFor [] mods;
|
||||
mods = Init.mods // Lean.mods;
|
||||
leanc = writeShellScriptBin "leanc" ''
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${leanshared} "$@"
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable.override { withSharedStdlib = true; }}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${leanshared} "$@"
|
||||
'';
|
||||
lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } ''
|
||||
mkdir -p $out/bin
|
||||
${leanc}/bin/leanc ${leancpp}/lib/lean.cpp.o ${leanshared}/* -o $out/bin/lean
|
||||
'';
|
||||
# derivation following the directory layout of the "basic" setup, mostly useful for running tests
|
||||
lean-all = stdenv.mkDerivation {
|
||||
lean-all = wrapStage(stdenv.mkDerivation {
|
||||
name = "lean-${desc}";
|
||||
buildCommand = ''
|
||||
mkdir -p $out/bin $out/lib/lean
|
||||
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${leanshared}/* $out/lib/lean/
|
||||
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList extlib)} ${leanshared}/* $out/lib/lean/
|
||||
# put everything in a single final derivation so `IO.appDir` references work
|
||||
cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin
|
||||
cp ${lean}/bin/lean ${leanc}/bin/leanc $out/bin
|
||||
# NOTE: `lndir` will not override existing `bin/leanc`
|
||||
${lndir}/bin/lndir -silent ${lean-bin-tools-unwrapped} $out
|
||||
'';
|
||||
meta.mainProgram = "lean";
|
||||
};
|
||||
cacheRoots = linkFarmFromDrvs "cacheRoots" [
|
||||
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
|
||||
# .o files are not a runtime dependency on macOS because of lack of thin archives
|
||||
Lean.oTree Lake.oTree
|
||||
];
|
||||
});
|
||||
test = buildCMake {
|
||||
name = "lean-test-${desc}";
|
||||
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
|
||||
buildInputs = [ gmp perl git ];
|
||||
realSrc = lib.sourceByRegex ../. [ "src.*" "tests.*" ];
|
||||
buildInputs = [ gmp perl ];
|
||||
preConfigure = ''
|
||||
cd src
|
||||
'';
|
||||
extraCMakeFlags = [ "-DLLVM=OFF" ];
|
||||
postConfigure = ''
|
||||
patchShebangs ../../tests ../lake
|
||||
patchShebangs ../../tests
|
||||
rm -r bin lib include share
|
||||
ln -sf ${lean-all}/* .
|
||||
'';
|
||||
buildPhase = ''
|
||||
ctest --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
|
||||
ctest --output-on-failure -E 'leancomptest_(doc_example|foreign)|laketest|leanpkgtest' -j$NIX_BUILD_CORES
|
||||
'';
|
||||
installPhase = ''
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
update-stage0 =
|
||||
let cTree = symlinkJoin { name = "cs"; paths = [ Init.cTree Lean.cTree ]; }; in
|
||||
let cTree = symlinkJoin { name = "cs"; paths = map (l: l.cTree) stdlib; }; in
|
||||
writeShellScriptBin "update-stage0" ''
|
||||
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/update-stage0"}
|
||||
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${../script/update-stage0}
|
||||
'';
|
||||
update-stage0-commit = writeShellScriptBin "update-stage0-commit" ''
|
||||
set -euo pipefail
|
||||
@@ -193,11 +175,11 @@ rec {
|
||||
'';
|
||||
benchmarks =
|
||||
let
|
||||
entries = attrNames (readDir (src + "/tests/bench"));
|
||||
entries = attrNames (readDir ../tests/bench);
|
||||
leanFiles = map (n: elemAt n 0) (filter (n: n != null) (map (match "(.*)\.lean") entries));
|
||||
in lib.genAttrs leanFiles (n: (buildLeanPackage {
|
||||
name = n;
|
||||
src = filterSource (e: _: baseNameOf e == "${n}.lean") (src + "/tests/bench");
|
||||
src = filterSource (e: _: baseNameOf e == "${n}.lean") ../tests/bench;
|
||||
}).executable);
|
||||
};
|
||||
stage1 = stage { stage = 1; prevStage = stage0; self = stage1; };
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{ lean, lean-leanDeps ? lean, lean-final ? lean, leanc,
|
||||
stdenv, lib, coreutils, gnused, writeShellScriptBin, bash, lean-emacs, lean-vscode, nix, substituteAll, symlinkJoin, linkFarmFromDrvs,
|
||||
runCommand, darwin, mkShell, ... }:
|
||||
runCommand, gmp, darwin, mkShell, ... }:
|
||||
let lean-final' = lean-final; in
|
||||
lib.makeOverridable (
|
||||
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
|
||||
{ name, src, fullSrc ? src, srcPrefix ? "",
|
||||
# Lean dependencies. Each entry should be an output of buildLeanPackage.
|
||||
deps ? [ lean.Lean ],
|
||||
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
|
||||
@@ -28,18 +28,13 @@ lib.makeOverridable (
|
||||
precompilePackage ? precompileModules,
|
||||
# Lean plugin dependencies. Each derivation `plugin` should contain a plugin library at path `${plugin}/${plugin.name}`.
|
||||
pluginDeps ? [],
|
||||
# `overrideAttrs` for `buildMod`
|
||||
overrideBuildModAttrs ? null,
|
||||
debug ? false, leanFlags ? [], leancFlags ? [], linkFlags ? [], executableName ? lib.toLower name, libName ? name,
|
||||
srcTarget ? "..#stage0", srcArgs ? "(\${args[*]})", lean-final ? lean-final' }@args:
|
||||
with builtins; let
|
||||
# "Init.Core" ~> "Init/Core"
|
||||
modToPath = mod: replaceStrings ["."] ["/"] mod;
|
||||
modToAbsPath = mod: "${src}/${modToPath mod}";
|
||||
# sanitize file name before copying to store, except when already in store
|
||||
copyToStoreSafe = base: suffix: if lib.isDerivation base then base + suffix else
|
||||
builtins.path { name = lib.strings.sanitizeDerivationName (baseNameOf suffix); path = base + suffix; };
|
||||
modToLean = mod: copyToStoreSafe src "/${modToPath mod}.lean";
|
||||
modToLean = mod: "${modToAbsPath mod}.lean";
|
||||
bareStdenv = ./bareStdenv;
|
||||
mkBareDerivation = args: derivation (args // {
|
||||
name = lib.strings.sanitizeDerivationName args.name;
|
||||
@@ -52,7 +47,7 @@ with builtins; let
|
||||
set -u
|
||||
${args.buildCommand}
|
||||
'' ];
|
||||
}) // { overrideAttrs = f: mkBareDerivation (lib.fix (lib.extends f (_: args))); };
|
||||
});
|
||||
runBareCommand = name: args: buildCommand: mkBareDerivation (args // { inherit name buildCommand; });
|
||||
runBareCommandLocal = name: args: buildCommand: runBareCommand name (args // {
|
||||
preferLocalBuild = true;
|
||||
@@ -63,23 +58,24 @@ with builtins; let
|
||||
libName = "${name}${stdenv.hostPlatform.extensions.sharedLibrary}";
|
||||
} ''
|
||||
mkdir -p $out
|
||||
${leanc}/bin/leanc -shared ${args} -o $out/$libName
|
||||
${leanc}/bin/leanc -fPIC -shared ${lib.optionalString stdenv.isLinux "-Bsymbolic"} ${lib.optionalString stdenv.isDarwin "-Wl,-undefined,dynamic_lookup"} -L ${gmp}/lib \
|
||||
${args} -o $out/$libName
|
||||
'';
|
||||
depRoot = name: deps: mkBareDerivation {
|
||||
name = "${name}-depRoot";
|
||||
inherit deps;
|
||||
depRoots = map (drv: drv.LEAN_PATH) deps;
|
||||
|
||||
passAsFile = [ "deps" "depRoots" ];
|
||||
buildCommand = ''
|
||||
mkdir -p $out
|
||||
for i in $(cat $depRootsPath); do
|
||||
for i in $depRoots; do
|
||||
cp -dru --no-preserve=mode $i/. $out
|
||||
done
|
||||
for i in $(cat $depsPath); do
|
||||
for i in $deps; do
|
||||
cp -drsu --no-preserve=mode $i/. $out
|
||||
done
|
||||
'';
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
};
|
||||
srcRoot = src;
|
||||
|
||||
@@ -115,13 +111,13 @@ with builtins; let
|
||||
# we can't know the required files without parsing dependencies (which is what we want this
|
||||
# function for), so we approximate to the entire package.
|
||||
let root = (head (split "\\." g));
|
||||
in lib.optional (pathExists (src + "/${modToPath root}.lean")) root ++ lib.optionals (pathExists (modToAbsPath root)) (submodules root)
|
||||
in lib.optional (pathExists (modToLean root)) root ++ lib.optionals (pathExists (modToAbsPath root)) (submodules root)
|
||||
else if g.glob == "one" then expandGlobAllApprox g.mod
|
||||
else if g.glob == "submodules" then submodules g.mod
|
||||
else if g.glob == "andSubmodules" then [g.mod] ++ submodules g.mod
|
||||
else throw "unknown glob kind '${g}'";
|
||||
# list of modules that could potentially be involved in the build
|
||||
candidateMods = lib.unique (concatMap expandGlobAllApprox roots);
|
||||
candidateMods = filter (m: pathExists (modToLean m)) (lib.unique (concatMap expandGlobAllApprox roots));
|
||||
candidateFiles = map modToLean candidateMods;
|
||||
modDepsFile = args.modDepsFile or mkBareDerivation {
|
||||
name = "${name}-deps.json";
|
||||
@@ -135,20 +131,16 @@ with builtins; let
|
||||
modDeps = fromJSON (
|
||||
# the only possible references to store paths in the JSON should be inside errors, so no chance of missed dependencies from this
|
||||
unsafeDiscardStringContext (readFile "${modDepsFile}/${modDepsFile.name}"));
|
||||
# map from module name to list of imports
|
||||
modDepsMap = listToAttrs (lib.zipListsWith lib.nameValuePair candidateMods modDeps.imports);
|
||||
maybeOverrideAttrs = f: x: if f != null then x.overrideAttrs f else x;
|
||||
# build module (.olean and .c) given derivations of all (immediate) dependencies
|
||||
# TODO: make `rec` parts override-compatible?
|
||||
buildMod = mod: deps: maybeOverrideAttrs overrideBuildModAttrs (mkBareDerivation rec {
|
||||
buildMod = mod: deps: mkBareDerivation rec {
|
||||
name = "${mod}";
|
||||
LEAN_PATH = depRoot mod deps;
|
||||
LEAN_ABORT_ON_PANIC = "1";
|
||||
relpath = modToPath mod;
|
||||
buildInputs = [ lean ];
|
||||
leanPath = relpath + ".lean";
|
||||
# should be either single .lean file or directory directly containing .lean file plus dependencies
|
||||
src = copyToStoreSafe srcRoot ("/" + leanPath);
|
||||
src = srcRoot + ("/" + leanPath);
|
||||
outputs = [ "out" "ilean" "c" ];
|
||||
oleanPath = relpath + ".olean";
|
||||
ileanPath = relpath + ".ilean";
|
||||
@@ -158,10 +150,10 @@ with builtins; let
|
||||
buildCommand = ''
|
||||
dir=$(dirname $relpath)
|
||||
mkdir -p $dir $out/$dir $ilean/$dir $c/$dir
|
||||
if [ -d $src ]; then cp -r $src/. .; else cp $src $leanPath; fi
|
||||
cp $src $leanPath
|
||||
lean -o $out/$oleanPath -i $ilean/$ileanPath -c $c/$cPath $leanPath $leanFlags $leanPluginFlags $leanLoadDynlibFlags
|
||||
'';
|
||||
}) // {
|
||||
} // {
|
||||
inherit deps;
|
||||
propagatedLoadDynlibs = loadDynlibsOfDeps deps;
|
||||
};
|
||||
@@ -190,13 +182,17 @@ with builtins; let
|
||||
propagatedLoadDynlibs = [sharedLib];
|
||||
};
|
||||
externalModMap = lib.foldr (dep: depMap: depMap // dep.mods) {} allExternalDeps;
|
||||
# map from module name to derivation
|
||||
modCandidates = mapAttrs (mod: header:
|
||||
# Recursively build `mod` and its dependencies. `modMap` maps module names to
|
||||
# `{ deps, drv }` pairs of a derivation and its transitive dependencies (as a nested
|
||||
# mapping from module names to derivations). It is passed linearly through the
|
||||
# recursion to memoize common dependencies.
|
||||
buildModAndDeps = mod: modMap: if modMap ? ${mod} || externalModMap ? ${mod} then modMap else
|
||||
let
|
||||
deps = if header.errors == []
|
||||
then map (m: m.module) header.imports
|
||||
else abort "errors while parsing imports of ${mod}:\n${lib.concatStringsSep "\n" header.errors}";
|
||||
in mkMod mod (map (dep: if modDepsMap ? ${dep} then modCandidates.${dep} else externalModMap.${dep}) deps)) modDepsMap;
|
||||
deps = if modDepsMap.${mod}.errors == []
|
||||
then map (m: m.module) modDepsMap.${mod}.imports
|
||||
else abort "errors while parsing imports of ${mod}:\n${lib.concatStringsSep "\n" modDepsMap.${mod}.errors}";
|
||||
modMap' = lib.foldr buildModAndDeps modMap deps;
|
||||
in modMap' // { ${mod} = mkMod mod (map (dep: if modMap' ? ${dep} then modMap'.${dep} else externalModMap.${dep}) deps); };
|
||||
makeEmacsWrapper = name: emacs: lean: writeShellScriptBin name ''
|
||||
${emacs} --eval "(progn (setq lean4-rootdir \"${lean}\"))" "$@"
|
||||
'';
|
||||
@@ -210,17 +206,14 @@ with builtins; let
|
||||
loadDynlibPaths = map pathOfSharedLib (loadDynlibsOfDeps deps);
|
||||
}}'
|
||||
'';
|
||||
makePrintPathsFor = deps: mods: printPaths deps // mapAttrs (_: mod: makePrintPathsFor (deps ++ [mod]) mods) mods;
|
||||
expandGlob = g:
|
||||
if typeOf g == "string" then [g]
|
||||
else if g.glob == "one" then [g.mod]
|
||||
else if g.glob == "submodules" then submodules g.mod
|
||||
else if g.glob == "andSubmodules" then [g.mod] ++ submodules g.mod
|
||||
else throw "unknown glob kind '${g}'";
|
||||
# subset of `modCandidates` that is transitively reachable from `roots`
|
||||
mods' = listToAttrs (map (e: { name = e.key; value = modCandidates.${e.key}; }) (genericClosure {
|
||||
startSet = map (m: { key = m; }) (concatMap expandGlob roots);
|
||||
operator = e: if modDepsMap ? ${e.key} then map (m: { key = m.module; }) (filter (m: modCandidates ? ${m.module}) modDepsMap.${e.key}.imports) else [];
|
||||
}));
|
||||
mods' = lib.foldr buildModAndDeps {} (concatMap expandGlob roots);
|
||||
allLinkFlags = lib.foldr (shared: acc: acc ++ [ "-L${shared}" "-l${shared.linkName or shared.name}" ]) linkFlags allNativeSharedLibs;
|
||||
|
||||
objects = mapAttrs (_: m: m.obj) mods';
|
||||
@@ -241,14 +234,13 @@ in rec {
|
||||
lib.optionalAttrs precompilePackage { propagatedLoadDynlibs = [sharedLib]; })
|
||||
mods';
|
||||
modRoot = depRoot name (attrValues mods);
|
||||
depRoots = linkFarmFromDrvs "depRoots" (map (m: m.LEAN_PATH) (attrValues mods));
|
||||
cTree = symlinkJoin { name = "${name}-cTree"; paths = map (mod: mod.c) (attrValues mods); };
|
||||
oTree = symlinkJoin { name = "${name}-oTree"; paths = (attrValues objects); };
|
||||
iTree = symlinkJoin { name = "${name}-iTree"; paths = map (mod: mod.ilean) (attrValues mods); };
|
||||
sharedLib = mkSharedLib "lib${libName}" ''
|
||||
${if stdenv.isDarwin then "-Wl,-force_load,${staticLib}/lib${libName}.a" else "-Wl,--whole-archive ${staticLib}/lib${libName}.a -Wl,--no-whole-archive"} \
|
||||
${lib.concatStringsSep " " (map (d: "${d.sharedLib}/*") deps)}'';
|
||||
executable = lib.makeOverridable ({ withSharedStdlib ? true }: let
|
||||
executable = lib.makeOverridable ({ withSharedStdlib ? false }: let
|
||||
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.leanshared}/*";
|
||||
in runCommand executableName { buildInputs = [ stdenv.cc leanc ]; } ''
|
||||
mkdir -p $out/bin
|
||||
@@ -269,7 +261,6 @@ in rec {
|
||||
ln -sf ${iTree}/* $dest/build/lib
|
||||
'';
|
||||
|
||||
makePrintPathsFor = deps: mods: printPaths deps // mapAttrs (_: mod: makePrintPathsFor (deps ++ [mod]) mods) mods;
|
||||
print-paths = makePrintPathsFor [] (mods' // externalModMap);
|
||||
# `lean` wrapper that dynamically runs Nix for the actual `lean` executable so the same editor can be
|
||||
# used for multiple projects/after upgrading the `lean` input/for editing both stage 1 and the tests
|
||||
@@ -297,7 +288,7 @@ in rec {
|
||||
devShell = mkShell {
|
||||
buildInputs = [ nix ];
|
||||
shellHook = ''
|
||||
export LEAN_SRC_PATH="${srcPath}"
|
||||
export LEAN_SRC_PATH="$PWD/${srcPrefix}"
|
||||
'';
|
||||
};
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{ src, pkgs, nix, ... } @ args:
|
||||
{ pkgs, nix, ... } @ args:
|
||||
with pkgs;
|
||||
let
|
||||
nix-pinned = writeShellScriptBin "nix" ''
|
||||
${nix.packages.${system}.default}/bin/nix --experimental-features 'nix-command flakes' --extra-substituters https://lean4.cachix.org/ --option warn-dirty false "$@"
|
||||
'';
|
||||
# https://github.com/NixOS/nixpkgs/issues/130963
|
||||
llvmPackages = if stdenv.isDarwin then llvmPackages_11 else llvmPackages_15;
|
||||
llvmPackages = if stdenv.isDarwin then llvmPackages_11 else llvmPackages_14;
|
||||
cc = (ccacheWrapper.override rec {
|
||||
cc = llvmPackages.clang;
|
||||
extraConfig = ''
|
||||
@@ -29,7 +29,7 @@ let
|
||||
stdenv' = if stdenv.isLinux then useGoldLinker stdenv else stdenv;
|
||||
lean = callPackage (import ./bootstrap.nix) (args // {
|
||||
stdenv = overrideCC stdenv' cc;
|
||||
inherit src buildLeanPackage llvmPackages;
|
||||
inherit buildLeanPackage llvmPackages;
|
||||
});
|
||||
makeOverridableLeanPackage = f:
|
||||
let newF = origArgs: f origArgs // {
|
||||
@@ -52,10 +52,7 @@ let
|
||||
src = args.lean4-mode;
|
||||
packageRequires = with pkgs.emacsPackages.melpaPackages; [ dash f flycheck magit-section lsp-mode s ];
|
||||
recipe = pkgs.writeText "recipe" ''
|
||||
(lean4-mode
|
||||
:repo "leanprover/lean4-mode"
|
||||
:fetcher github
|
||||
:files ("*.el" "data"))
|
||||
(lean4-mode :repo "leanprover/lean4-mode" :fetcher github)
|
||||
'';
|
||||
};
|
||||
lean-emacs = emacsWithPackages [ lean4-mode ];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
description = "My Lean package";
|
||||
|
||||
inputs.lean.url = "github:leanprover/lean4";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.lean.url = github:leanprover/lean4;
|
||||
inputs.flake-utils.url = github:numtide/flake-utils;
|
||||
|
||||
outputs = { self, lean, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Author: Leonardo de Moura
|
||||
#
|
||||
# Given a text file containing constants defined in the Lean libraries,
|
||||
# this script generates .h and .cpp files for initialing/finalizing these constants
|
||||
# this script generates .h and .cpp files for initialing/finalizing theses constants
|
||||
# as C++ name objects.
|
||||
#
|
||||
# This script is used to generate src/library/constants.cpp and src/library/constants.h
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Author: Leonardo de Moura
|
||||
#
|
||||
# Given a text file containing id and token strings,
|
||||
# this script generates .h and .cpp files for initialing/finalizing these tokens
|
||||
# this script generates .h and .cpp files for initialing/finalizing theses tokens
|
||||
# as C++ name objects.
|
||||
#
|
||||
# This script is used to generate src/frontends/lean/tokens.cpp and src/frontends/lean/tokens.h
|
||||
|
||||
@@ -25,9 +25,6 @@ cp -L llvm/bin/llvm-ar stage1/bin/
|
||||
# dependencies of the above
|
||||
$CP llvm/lib/lib{clang-cpp,LLVM}*.so* stage1/lib/
|
||||
$CP $ZLIB/lib/libz.so* stage1/lib/
|
||||
# bundle libatomic (referenced by LLVM >= 15, and required by the lean executable to run)
|
||||
$CP $GCC_LIB/lib/libatomic.so* stage1/lib/
|
||||
|
||||
find stage1 -type f -exec strip --strip-unneeded '{}' \; 2> /dev/null
|
||||
# lean.h dependencies
|
||||
$CP llvm/lib/clang/*/include/{std*,__std*,limits}.h stage1/include/clang
|
||||
@@ -48,6 +45,7 @@ $CP -r llvm/include/*-*-* llvm-host/include/
|
||||
$CP $GLIBC/lib/libc_nonshared.a stage1/lib/glibc
|
||||
for f in $GLIBC/lib/lib{c,dl,m,rt,pthread}-*; do b=$(basename $f); cp $f stage1/lib/glibc/${b%-*}.so; done
|
||||
OPTIONS=()
|
||||
echo -n " -DLLVM=ON -DLLVM_CONFIG=$PWD/llvm-host/bin/llvm-config" # manually point to `llvm-config` location
|
||||
echo -n " -DLEAN_STANDALONE=ON"
|
||||
echo -n " -DCMAKE_CXX_COMPILER=$PWD/llvm-host/bin/clang++ -DLEAN_CXX_STDLIB='-Wl,-Bstatic -lc++ -lc++abi -Wl,-Bdynamic'"
|
||||
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter $GLIBC_DEV/include ${EXTRA_FLAGS:-}'"
|
||||
|
||||
@@ -34,11 +34,9 @@ $CP llvm/lib/clang/*/include/{std*,__std*,limits}.h stage1/include/clang
|
||||
(cd llvm; $CP --parents lib/clang/*/lib/*/libclang_rt.osx.a ../stage1)
|
||||
# libSystem stub, includes libc
|
||||
cp $SDK/usr/lib/libSystem.tbd stage1/lib/libc
|
||||
# use for linking, use system lib for running
|
||||
gcp llvm/lib/libc++.dylib stage1/lib/libc
|
||||
# make sure we search for the library in /usr/lib instead of the rpath, which should not contain `/usr/lib`
|
||||
# and apparently since Sonoma does not do so implicitly either
|
||||
install_name_tool -id /usr/lib/libc++.dylib stage1/lib/libc/libc++.dylib
|
||||
# use for linking, use system libs for running
|
||||
gcp llvm/lib/lib{c++,c++abi,unwind}.dylib stage1/lib/libc
|
||||
echo -n " -DLLVM=ON -DLLVM_CONFIG=$PWD/llvm-host/bin/llvm-config" # manually point to `llvm-config` location
|
||||
echo -n " -DLEAN_STANDALONE=ON"
|
||||
# do not change C++ compiler; libc++ etc. being system libraries means there's no danger of conflicts,
|
||||
# and the custom clang++ outputs a myriad of warnings when consuming the SDK
|
||||
|
||||
@@ -32,6 +32,7 @@ cp /clang64/lib/{crtbegin,crtend,crt2,dllcrt2}.o stage1/lib/
|
||||
(cd llvm; cp --parents lib/clang/*/lib/*/libclang_rt.builtins* ../stage1)
|
||||
# further dependencies
|
||||
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase}.* /clang64/lib/libgmp.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
|
||||
echo -n " -DLLVM=ON -DLLVM_CONFIG=$PWD/llvm/bin/llvm-config" # manually point to `llvm-config` location
|
||||
echo -n " -DLEAN_STANDALONE=ON"
|
||||
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang.exe -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER=$PWD/llvm/bin/clang++.exe -DCMAKE_CXX_COMPILER_WORKS=1 -DLEAN_CXX_STDLIB='-lc++ -lc++abi'"
|
||||
echo -n " -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_CXX_COMPILER=clang++"
|
||||
|
||||
@@ -17,7 +17,7 @@ partial def reprintCore : Syntax → Option Format
|
||||
| Syntax.missing => none
|
||||
| Syntax.atom _ val => val.trim
|
||||
| Syntax.ident _ rawVal _ _ => rawVal.toString
|
||||
| Syntax.node _ _ args =>
|
||||
| Syntax.node _ kind args =>
|
||||
match args.toList.filterMap reprintCore with
|
||||
| [] => none
|
||||
| [arg] => arg
|
||||
@@ -29,7 +29,7 @@ def reprint (stx : Syntax) : Format :=
|
||||
def printCommands (cmds : Syntax) : CoreM Unit := do
|
||||
for cmd in getCommands cmds |>.run #[] |>.2 do
|
||||
try
|
||||
IO.println (← ppCommand ⟨cmd⟩).pretty
|
||||
IO.println (← ppCommand cmd).pretty
|
||||
catch e =>
|
||||
IO.println f!"/-\ncannot print: {← e.toMessageData.format}\n{reprint cmd}\n-/"
|
||||
|
||||
@@ -70,4 +70,4 @@ unsafe def main (args : List String) : IO Unit := do
|
||||
let mut first := true
|
||||
for {env, currNamespace, openDecls, ..} in moduleStx, stx in leadingUpdated do
|
||||
if first then first := false else IO.print "\n"
|
||||
let _ ← printCommands stx |>.toIO {fileName, fileMap := FileMap.ofString input, currNamespace, openDecls} {env}
|
||||
let _ ← printCommands stx |>.toIO {currNamespace, openDecls} {env}
|
||||
|
||||
@@ -3,8 +3,8 @@ set -euo pipefail
|
||||
|
||||
rm -r stage0 || true
|
||||
# don't copy untracked files
|
||||
# `:!` is git glob flavor for exclude patterns
|
||||
for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
|
||||
for f in $(git ls-files src); do
|
||||
[[ $f != src/lake && $f != src/Leanc.lean ]] || continue
|
||||
if [[ $f == *.lean ]]; then
|
||||
f=${f#src/}
|
||||
f=${f%.lean}.c
|
||||
|
||||
@@ -9,7 +9,7 @@ in { pkgs ? flakePkgs.nixpkgs, pkgsDist ? pkgs }:
|
||||
} (rec {
|
||||
buildInputs = with pkgs; [
|
||||
cmake gmp ccache
|
||||
flakePkgs.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
];
|
||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||
hardeningDisable = [ "all" ];
|
||||
@@ -19,9 +19,7 @@ in { pkgs ? flakePkgs.nixpkgs, pkgsDist ? pkgs }:
|
||||
GMP = pkgsDist.gmp.override { withStatic = true; };
|
||||
GLIBC = pkgsDist.glibc;
|
||||
GLIBC_DEV = pkgsDist.glibc.dev;
|
||||
GCC_LIB = pkgsDist.gcc.cc.lib;
|
||||
ZLIB = pkgsDist.zlib;
|
||||
GDB = pkgsDist.gdb;
|
||||
});
|
||||
nix = flake.devShell.${builtins.currentSystem};
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 3)
|
||||
set(LEAN_VERSION_MINOR 0)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
@@ -57,7 +57,6 @@ option(CUSTOM_ALLOCATORS "CUSTOM_ALLOCATORS" ON)
|
||||
option(SAVE_SNAPSHOT "SAVE_SNAPSHOT" ON)
|
||||
option(SAVE_INFO "SAVE_INFO" ON)
|
||||
option(SMALL_ALLOCATOR "SMALL_ALLOCATOR" ON)
|
||||
option(MMAP "MMAP" ON)
|
||||
option(LAZY_RC "LAZY_RC" OFF)
|
||||
option(RUNTIME_STATS "RUNTIME_STATS" OFF)
|
||||
option(BSYMBOLIC "Link with -Bsymbolic to reduce call overhead in shared libraries (Linux)" ON)
|
||||
@@ -85,10 +84,6 @@ else()
|
||||
set(NumBits 32)
|
||||
endif()
|
||||
|
||||
if ("${MMAP}" MATCHES "ON")
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_MMAP")
|
||||
endif()
|
||||
|
||||
if ("${RUNTIME_STATS}" MATCHES "ON")
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_RUNTIME_STATS")
|
||||
endif()
|
||||
@@ -98,19 +93,29 @@ if (NOT("${CHECK_OLEAN_VERSION}" MATCHES "ON"))
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
set(MULTI_THREAD OFF)
|
||||
# TODO(WN): code size/performance tradeoffs
|
||||
# - we're using -O3; it's /okay/
|
||||
# - -flto crashes at runtime
|
||||
# - -Oz produces quite slow code
|
||||
# - system libraries such as OpenGL are included in the JS but shouldn't be
|
||||
# - we need EMSCRIPTEN_KEEPALIVE annotations on exports to run meta-dce (-s MAIN_MODULE=2)
|
||||
# - -fexceptions is a slow JS blob, remove when more runtimes support the WASM exceptions spec
|
||||
|
||||
# From https://emscripten.org/docs/compiling/WebAssembly.html#backends:
|
||||
# > The simple and safe thing is to pass all -s flags at both compile and link time.
|
||||
set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -pthread")
|
||||
set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -s DISABLE_EXCEPTION_CATCHING=0 -s MAIN_MODULE=1 -fexceptions")
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
|
||||
endif()
|
||||
if (CMAKE_CROSSCOMPILING_EMULATOR)
|
||||
# emscripten likes to quote "node"
|
||||
string(REPLACE "\"" "" CMAKE_CROSSCOMPILING_EMULATOR ${CMAKE_CROSSCOMPILING_EMULATOR})
|
||||
# HACK(WN): lazy compilation makes Node.js startup time a bad but tolerable ~4s
|
||||
string(APPEND CMAKE_CROSSCOMPILING_EMULATOR " --wasm-lazy-compilation")
|
||||
else()
|
||||
set(CMAKE_CROSSCOMPILING_EMULATOR)
|
||||
endif()
|
||||
|
||||
# Added for CTest
|
||||
include(CTest)
|
||||
@@ -138,12 +143,9 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/lean")
|
||||
|
||||
# OSX default thread stack size is very small. Moreover, in Debug mode, each new stack frame consumes a lot of extra memory.
|
||||
if ((${MULTI_THREAD} MATCHES "ON") AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
||||
string(APPEND LEAN_EXTRA_MAKE_OPTS " -s40000")
|
||||
set(LEAN_EXTRA_MAKE_OPTS -s40000 ${LEAN_EXTRA_MAKE_OPTS})
|
||||
endif ()
|
||||
|
||||
# We want explicit stack probes in huge Lean stack frames for robust stack overflow detection
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fstack-clash-protection")
|
||||
|
||||
if(NOT MULTI_THREAD)
|
||||
message(STATUS "Disabled multi-thread support, it will not be safe to run multiple threads in parallel")
|
||||
set(AUTO_THREAD_FINALIZATION OFF)
|
||||
@@ -259,14 +261,10 @@ if(LLVM)
|
||||
endif()
|
||||
# check that we have 'llvm-config' version.
|
||||
message(STATUS "Executing 'llvm-config --version' at '${LLVM_CONFIG}' to check configuration.")
|
||||
execute_process(COMMAND ${LLVM_CONFIG} --version COMMAND_ERROR_IS_FATAL ANY OUTPUT_VARIABLE LLVM_CONFIG_VERSION ECHO_OUTPUT_VARIABLE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX MATCH "^[0-9]*" LLVM_CONFIG_MAJOR_VERSION ${LLVM_CONFIG_VERSION})
|
||||
message(STATUS "Found 'llvm-config' at '${LLVM_CONFIG}' with version '${LLVM_CONFIG_VERSION}', major version '${LLVM_CONFIG_MAJOR_VERSION}'")
|
||||
if (NOT LLVM_CONFIG_MAJOR_VERSION STREQUAL "15")
|
||||
message(FATAL_ERROR "Unable to find llvm-config version 15. Found invalid version '${LLVM_CONFIG_MAJOR_VERSION}'")
|
||||
endif()
|
||||
execute_process(COMMAND ${LLVM_CONFIG} --version COMMAND_ERROR_IS_FATAL ANY)
|
||||
message(STATUS "Found 'llvm-config' as ${LLVM_CONFIG}")
|
||||
# -DLEAN_LLVM is used to conditionally compile Lean features that depend on LLVM
|
||||
string(APPEND CMAKE_CXX_FLAGS " -D LEAN_LLVM")
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_LLVM")
|
||||
|
||||
execute_process(COMMAND ${LLVM_CONFIG} --ldflags OUTPUT_VARIABLE LLVM_CONFIG_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${LLVM_CONFIG} --libs OUTPUT_VARIABLE LLVM_CONFIG_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
@@ -288,7 +286,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
find_package(ZLIB REQUIRED)
|
||||
message(STATUS "ZLIB_LIBRARY: ${ZLIB_LIBRARY}")
|
||||
cmake_path(GET ZLIB_LIBRARY PARENT_PATH ZLIB_LIBRARY_PARENT_PATH)
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
|
||||
endif()
|
||||
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lleanrt")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
@@ -296,7 +294,6 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
else()
|
||||
string(APPEND LEANC_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
|
||||
endif()
|
||||
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lLake")
|
||||
|
||||
set(LEAN_CXX_STDLIB "-lstdc++" CACHE STRING "C++ stdlib linker flags")
|
||||
|
||||
@@ -307,26 +304,23 @@ endif()
|
||||
string(APPEND LEANC_STATIC_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
|
||||
|
||||
if (LLVM)
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -L${LLVM_CONFIG_LIBDIR} ${LLVM_CONFIG_LDFLAGS} ${LLVM_CONFIG_LIBS} ${LLVM_CONFIG_SYSTEM_LIBS}")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -I${LLVM_CONFIG_INCLUDEDIR}")
|
||||
endif()
|
||||
|
||||
if(LLVM AND ${STAGE} GREATER 0)
|
||||
if(LLVM)
|
||||
# Here, we perform a replacement of `llvm-host` with `llvm`. This is necessary for our cross-compile
|
||||
# builds in `script/prepare-llvm-*.sh`.
|
||||
# builds in `script/prepare-llvm-*.sh`.
|
||||
# - Recall that the host's copy of LLVM binaries and libraries is at
|
||||
# `llvm-host`, and the target's copy of LLVM binaries and libraries is at
|
||||
# `llvm`.
|
||||
# - In an ideal world, we would run the target's `llvm/bin/llvm-config` and get the correct link options for the target
|
||||
# - In an ideal world, we would run the target's `llvm/bin/llvm-config` and get the corrct link options for the target
|
||||
# (e.g. `-Lllvm/lib/libLLVM`.)
|
||||
# - However, the target's `llvm/bin/llvm-config` has a different target
|
||||
# triple from the host, and thus cannot be run on the host.
|
||||
# - So, we run the host `llvm-host/bin/llvm-config` from which we pick up
|
||||
# compiler options, and change the output of the host to point to the target.
|
||||
# - In particular, `host/bin/llvm-config` produces flags like `-Lllvm-host/lib/libLLVM`, while
|
||||
# - In particular, `host/bin/llvm-config` produces flags like `-Lllvm-host/lib/libLLVM`, while
|
||||
# we need the path to be `-Lllvm/lib/libLLVM`. Thus, we perform this replacement here.
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -L${LLVM_CONFIG_LIBDIR} ${LLVM_CONFIG_LDFLAGS} ${LLVM_CONFIG_LIBS} ${LLVM_CONFIG_SYSTEM_LIBS}")
|
||||
string(REPLACE "llvm-host" "llvm" LEANSHARED_LINKER_FLAGS ${LEANSHARED_LINKER_FLAGS})
|
||||
set(APPEND LEAN_EXTRA_CXX_FLAGS " -I${LLVM_CONFIG_INCLUDEDIR}")
|
||||
string(REPLACE "llvm-host" "llvm" LEAN_EXTRA_CXX_FLAGS ${LEAN_EXTRA_CXX_FLAGS})
|
||||
message(VERBOSE "leanshared linker flags: '${LEANSHARED_LINKER_FLAGS}' | lean extra cxx flags '${LEAN_EXTR_CXX_FLAGS}'")
|
||||
endif()
|
||||
@@ -334,12 +328,13 @@ endif()
|
||||
# get rid of unused parts of C++ stdlib
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-dead_strip")
|
||||
elseif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
else()
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,--gc-sections")
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " -lm")
|
||||
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lm")
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -lm")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
@@ -350,28 +345,18 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec")
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
|
||||
# We do not use dynamic linking via leanshared for Emscripten to keep things
|
||||
# simple. (And we are not interested in `Lake` anyway.) To use dynamic
|
||||
# linking, we would probably have to set MAIN_MODULE=2 on `leanshared`,
|
||||
# SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js".
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--whole-archive -lInit -lLean -lleancpp -lleanrt ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " -ldl")
|
||||
endif()
|
||||
|
||||
if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten"))
|
||||
if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows"))
|
||||
# export symbols for the interpreter (done via `LEAN_EXPORT` for Windows)
|
||||
string(APPEND LEAN_DYN_EXE_LINKER_FLAGS " -rdynamic")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic")
|
||||
@@ -454,6 +439,9 @@ string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
|
||||
if(CMAKE_OSX_SYSROOT AND NOT LEAN_STANDALONE)
|
||||
string(APPEND LEANC_OPTS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
endif()
|
||||
if(CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
string(APPEND LEANC_OPTS " ${CMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif()
|
||||
|
||||
if(${STAGE} GREATER 1)
|
||||
# reuse C++ parts, which don't change
|
||||
@@ -471,11 +459,6 @@ if(${STAGE} GREATER 1)
|
||||
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/libleanrt.a" "${CMAKE_BINARY_DIR}/lib/lean/libleanrt.a"
|
||||
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/libleancpp.a" "${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a")
|
||||
add_dependencies(leancpp copy-leancpp)
|
||||
if(LLVM)
|
||||
add_custom_target(copy-lean-h-bc
|
||||
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/lean.h.bc" "${CMAKE_BINARY_DIR}/lib/lean/lean.h.bc")
|
||||
add_dependencies(leancpp copy-lean-h-bc)
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(runtime)
|
||||
|
||||
@@ -513,12 +496,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build the compiler using the bootstrapped C sources for stage0, and use
|
||||
# the LLVM build for stage1 and further.
|
||||
if (LLVM AND ${STAGE} GREATER 0)
|
||||
set(EXTRA_LEANMAKE_OPTS "LLVM=1")
|
||||
endif()
|
||||
|
||||
# Escape for `make`. Yes, twice.
|
||||
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
|
||||
@@ -531,12 +508,6 @@ add_custom_target(make_stdlib ALL
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Lean
|
||||
VERBATIM)
|
||||
|
||||
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
|
||||
# of Lean runtime to be built.
|
||||
if (LLVM AND ${STAGE} EQUAL 1)
|
||||
add_dependencies(make_stdlib runtime_bc)
|
||||
endif()
|
||||
|
||||
# We declare these as separate custom targets so they use separate `make` invocations, which makes `make` recompute which dependencies
|
||||
# (e.g. `libLean.a`) are now newer than the target file
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ which is not a type error anymore.
|
||||
|
||||
You can also use the `↑` operator to explicitly indicate a coercion. Using `↑x`
|
||||
instead of `x` in the example will result in the same output.
|
||||
|
||||
Because there are many polymorphic functions in Lean, it is often ambiguous where
|
||||
the coercion can go. For example:
|
||||
```
|
||||
@@ -48,44 +47,10 @@ between these possibilities, but generally Lean will elaborate working from the
|
||||
and assign the `+` to be the one for `Int`, and then need to insert coercions
|
||||
for the subterms `↑x : Int` and `↑y : Int`, resulting in the `↑x + ↑y` version.
|
||||
|
||||
Note that unlike most operators like `+`, `↑` is always eagerly unfolded at
|
||||
parse time into its definition. So if we look at the definition of `f` from
|
||||
before, we see no trace of the `CoeT.coe` function:
|
||||
```
|
||||
def f (x : Nat) : Int := x
|
||||
#print f
|
||||
-- def f : Nat → Int :=
|
||||
-- fun (x : Nat) => Int.ofNat x
|
||||
```
|
||||
|
||||
## Important typeclasses
|
||||
|
||||
Lean resolves a coercion by either inserting a `CoeDep` instance
|
||||
or chaining `CoeHead? CoeOut* Coe* CoeTail?` instances.
|
||||
(That is, zero or one `CoeHead` instances, an arbitrary number of `CoeOut`
|
||||
instances, etc.)
|
||||
|
||||
The `CoeHead? CoeOut*` instances are chained from the "left" side.
|
||||
So if Lean looks for a coercion from `Nat` to `Int`, it starts by trying coerce
|
||||
`Nat` using `CoeHead` by looking for a `CoeHead Nat ?α` instance, and then
|
||||
continuing with `CoeOut`. Similarly `Coe* CoeTail?` are chained from the "right".
|
||||
|
||||
These classes should be implemented for coercions:
|
||||
|
||||
* `Coe α β` is the most basic class, and the usual one you will want to use
|
||||
when implementing a coercion for your own types.
|
||||
The variables in the type `α` must be a subset of the variables in `β`
|
||||
(or out-params of type class parameters),
|
||||
because `Coe` is chained right-to-left.
|
||||
|
||||
* `CoeOut α β` is like `Coe α β` but chained left-to-right.
|
||||
Use this if the variables in the type `α` are a superset of the variables in `β`.
|
||||
|
||||
* `CoeTail α β` is like `Coe α β`, but only applied once.
|
||||
Use this for coercions that would cause loops, like `[Ring R] → CoeTail Nat R`.
|
||||
|
||||
* `CoeHead α β` is similar to `CoeOut α β`, but only applied once.
|
||||
Use this for coercions that would cause loops, like `[SetLike S α] → CoeHead S (Set α)`.
|
||||
|
||||
* `CoeDep α (x : α) β` allows `β` to depend not only on `α` but on the value
|
||||
`x : α` itself. This is useful when the coercion function is dependent.
|
||||
@@ -98,21 +63,32 @@ These classes should be implemented for coercions:
|
||||
* `CoeFun α (γ : α → Sort v)` is a coercion to a function. `γ a` should be a
|
||||
(coercion-to-)function type, and this is triggered whenever an element
|
||||
`f : α` appears in an application like `f x` which would not make sense since
|
||||
`f` does not have a function type.
|
||||
`CoeFun` instances apply to `CoeOut` as well.
|
||||
`f` does not have a function type. This is automatically turned into `CoeFun.coe f x`.
|
||||
|
||||
* `CoeSort α β` is a coercion to a sort. `β` must be a universe, and this is
|
||||
triggered when `a : α` appears in a place where a type is expected, like
|
||||
`(x : a)` or `a → a`.
|
||||
`CoeSort` instances apply to `CoeOut` as well.
|
||||
* `CoeSort α β` is a coercion to a sort. `β` must be a universe, and if
|
||||
`a : α` appears in a place where a type is expected, like `(x : a)` or `a → a`,
|
||||
then it will be turned into `(x : CoeSort.coe a)`.
|
||||
|
||||
On top of these instances this file defines several auxiliary type classes:
|
||||
* `CoeTC := Coe*`
|
||||
* `CoeOTC := CoeOut* Coe*`
|
||||
* `CoeHTC := CoeHead? CoeOut* Coe*`
|
||||
* `CoeHTCT := CoeHead? CoeOut* Coe* CoeTail?`
|
||||
* `CoeDep := CoeHead? CoeOut* Coe* CoeTail? | CoeDep`
|
||||
* `CoeHead` is like `Coe`, but while `Coe` can be transitively chained in the
|
||||
`CoeT` class, `CoeHead` can only appear once and only at the start of such a
|
||||
chain. This is useful when the transitive instances are not well behaved.
|
||||
|
||||
* `CoeTail` is similar: it can only appear at the end of a chain of coercions.
|
||||
|
||||
* `CoeT α (x : α) β` itself is the combination of all the aforementioned classes
|
||||
(except `CoeSort` and `CoeFun` which have different triggers). You can
|
||||
implement `CoeT` if you do not want this coercion to be transitively composed
|
||||
with any other coercions.
|
||||
|
||||
Note that unlike most operators like `+`, `↑` is always eagerly unfolded at
|
||||
parse time into its definition. So if we look at the definition of `f` from
|
||||
before, we see no trace of the `CoeT.coe` function:
|
||||
```
|
||||
def f (x : Nat) : Int := x
|
||||
#print f
|
||||
-- def f : Nat → Int :=
|
||||
-- fun (x : Nat) => Int.ofNat x
|
||||
```
|
||||
-/
|
||||
|
||||
universe u v w w'
|
||||
@@ -123,101 +99,50 @@ chained with other `Coe` instances, and coercion is automatically used when
|
||||
`x` has type `α` but it is used in a context where `β` is expected.
|
||||
You can use the `↑x` operator to explicitly trigger coercion.
|
||||
-/
|
||||
class Coe (α : semiOutParam (Sort u)) (β : Sort v) where
|
||||
class Coe (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] Coe.coe
|
||||
|
||||
/--
|
||||
Auxiliary class implementing `Coe*`.
|
||||
Auxiliary class that contains the transitive closure of `Coe`.
|
||||
Users should generally not implement this directly.
|
||||
-/
|
||||
class CoeTC (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeTC.coe
|
||||
|
||||
instance [Coe β γ] [CoeTC α β] : CoeTC α γ where coe a := Coe.coe (CoeTC.coe a : β)
|
||||
instance [Coe α β] : CoeTC α β where coe a := Coe.coe a
|
||||
instance : CoeTC α α where coe a := a
|
||||
|
||||
/--
|
||||
`CoeOut α β` is for coercions that are applied from left-to-right.
|
||||
`CoeHead α β` is for coercions that can only appear at the beginning of a
|
||||
sequence of coercions. That is, `β` can be further coerced via `Coe β γ` and
|
||||
`CoeTail γ δ` instances but `α` will only be the inferred type of the input.
|
||||
-/
|
||||
class CoeOut (α : Sort u) (β : semiOutParam (Sort v)) where
|
||||
class CoeHead (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeOut.coe
|
||||
|
||||
/--
|
||||
Auxiliary class implementing `CoeOut* Coe*`.
|
||||
Users should generally not implement this directly.
|
||||
-/
|
||||
class CoeOTC (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeOTC.coe
|
||||
|
||||
instance [CoeOut α β] [CoeOTC β γ] : CoeOTC α γ where coe a := CoeOTC.coe (CoeOut.coe a : β)
|
||||
instance [CoeTC α β] : CoeOTC α β where coe a := CoeTC.coe a
|
||||
instance : CoeOTC α α where coe a := a
|
||||
|
||||
-- Note: ^^ We add reflexivity instances for CoeOTC/etc. so that we avoid going
|
||||
-- through a user-defined CoeTC/etc. instance. (Instances like
|
||||
-- `CoeTC F (A →+ B)` apply even when the two sides are defeq.)
|
||||
|
||||
/--
|
||||
`CoeHead α β` is for coercions that are applied from left-to-right at most once
|
||||
at beginning of the coercion chain.
|
||||
-/
|
||||
class CoeHead (α : Sort u) (β : semiOutParam (Sort v)) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeHead.coe
|
||||
|
||||
/--
|
||||
Auxiliary class implementing `CoeHead CoeOut* Coe*`.
|
||||
Users should generally not implement this directly.
|
||||
-/
|
||||
class CoeHTC (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeHTC.coe
|
||||
|
||||
instance [CoeHead α β] [CoeOTC β γ] : CoeHTC α γ where coe a := CoeOTC.coe (CoeHead.coe a : β)
|
||||
instance [CoeOTC α β] : CoeHTC α β where coe a := CoeOTC.coe a
|
||||
instance : CoeHTC α α where coe a := a
|
||||
|
||||
/--
|
||||
`CoeTail α β` is for coercions that can only appear at the end of a
|
||||
sequence of coercions. That is, `α` can be further coerced via `Coe σ α` and
|
||||
`CoeHead τ σ` instances but `β` will only be the expected type of the expression.
|
||||
-/
|
||||
class CoeTail (α : semiOutParam (Sort u)) (β : Sort v) where
|
||||
class CoeTail (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeTail.coe
|
||||
|
||||
/--
|
||||
Auxiliary class implementing `CoeHead* Coe* CoeTail?`.
|
||||
Users should generally not implement this directly.
|
||||
Auxiliary class that contains `CoeHead` + `CoeTC` + `CoeTail`.
|
||||
|
||||
A `CoeHTCT` chain has the "grammar" `(CoeHead)? (Coe)* (CoeTail)?`, except that
|
||||
the empty sequence is not allowed.
|
||||
-/
|
||||
class CoeHTCT (α : Sort u) (β : Sort v) where
|
||||
/-- Coerces a value of type `α` to type `β`. Accessible by the notation `↑x`,
|
||||
or by double type ascription `((x : α) : β)`. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeHTCT.coe
|
||||
|
||||
instance [CoeTail β γ] [CoeHTC α β] : CoeHTCT α γ where coe a := CoeTail.coe (CoeHTC.coe a : β)
|
||||
instance [CoeHTC α β] : CoeHTCT α β where coe a := CoeHTC.coe a
|
||||
instance : CoeHTCT α α where coe a := a
|
||||
|
||||
/--
|
||||
`CoeDep α (x : α) β` is a typeclass for dependent coercions, that is, the type `β`
|
||||
@@ -232,54 +157,43 @@ class CoeDep (α : Sort u) (_ : α) (β : Sort v) where
|
||||
the type class, so the value of type `β` may possibly depend on additional
|
||||
typeclasses on `x`. -/
|
||||
coe : β
|
||||
attribute [coe_decl] CoeDep.coe
|
||||
|
||||
/--
|
||||
`CoeT` is the core typeclass which is invoked by Lean to resolve a type error.
|
||||
It can also be triggered explicitly with the notation `↑x` or by double type
|
||||
ascription `((x : α) : β)`.
|
||||
|
||||
A `CoeT` chain has the grammar `CoeHead? CoeOut* Coe* CoeTail? | CoeDep`.
|
||||
A `CoeT` chain has the "grammar" `(CoeHead)? (Coe)* (CoeTail)? | CoeDep`,
|
||||
except that the empty sequence is not allowed (identity coercions don't need
|
||||
the coercion system at all).
|
||||
-/
|
||||
class CoeT (α : Sort u) (_ : α) (β : Sort v) where
|
||||
/-- The resulting value of type `β`. The input `x : α` is a parameter to
|
||||
the type class, so the value of type `β` may possibly depend on additional
|
||||
typeclasses on `x`. -/
|
||||
coe : β
|
||||
attribute [coe_decl] CoeT.coe
|
||||
|
||||
instance [CoeHTCT α β] : CoeT α a β where coe := CoeHTCT.coe a
|
||||
instance [CoeDep α a β] : CoeT α a β where coe := CoeDep.coe a
|
||||
instance : CoeT α a α where coe := a
|
||||
|
||||
/--
|
||||
`CoeFun α (γ : α → Sort v)` is a coercion to a function. `γ a` should be a
|
||||
(coercion-to-)function type, and this is triggered whenever an element
|
||||
`f : α` appears in an application like `f x`, which would not make sense since
|
||||
`f` does not have a function type.
|
||||
`CoeFun` instances apply to `CoeOut` as well.
|
||||
`f : α` appears in an application like `f x` which would not make sense since
|
||||
`f` does not have a function type. This is automatically turned into `CoeFun.coe f x`.
|
||||
-/
|
||||
class CoeFun (α : Sort u) (γ : outParam (α → Sort v)) where
|
||||
/-- Coerces a value `f : α` to type `γ f`, which should be either be a
|
||||
function type or another `CoeFun` type, in order to resolve a mistyped
|
||||
application `f x`. -/
|
||||
coe : (f : α) → γ f
|
||||
attribute [coe_decl] CoeFun.coe
|
||||
|
||||
instance [CoeFun α fun _ => β] : CoeOut α β where coe a := CoeFun.coe a
|
||||
|
||||
/--
|
||||
`CoeSort α β` is a coercion to a sort. `β` must be a universe, and this is
|
||||
triggered when `a : α` appears in a place where a type is expected, like
|
||||
`(x : a)` or `a → a`.
|
||||
`CoeSort` instances apply to `CoeOut` as well.
|
||||
`CoeSort α β` is a coercion to a sort. `β` must be a universe, and if
|
||||
`a : α` appears in a place where a type is expected, like `(x : a)` or `a → a`,
|
||||
then it will be turned into `(x : CoeSort.coe a)`.
|
||||
-/
|
||||
class CoeSort (α : Sort u) (β : outParam (Sort v)) where
|
||||
/-- Coerces a value of type `α` to `β`, which must be a universe. -/
|
||||
coe : α → β
|
||||
attribute [coe_decl] CoeSort.coe
|
||||
|
||||
instance [CoeSort α β] : CoeOut α β where coe a := CoeSort.coe a
|
||||
|
||||
/--
|
||||
`↑x` represents a coercion, which converts `x` of type `α` to type `β`, using
|
||||
@@ -290,21 +204,60 @@ between e.g. `↑x + ↑y` and `↑(x + y)`.
|
||||
-/
|
||||
syntax:1024 (name := coeNotation) "↑" term:1024 : term
|
||||
|
||||
instance coeTrans {α : Sort u} {β : Sort v} {δ : Sort w} [Coe β δ] [CoeTC α β] : CoeTC α δ where
|
||||
coe a := Coe.coe (CoeTC.coe a : β)
|
||||
|
||||
instance coeBase {α : Sort u} {β : Sort v} [Coe α β] : CoeTC α β where
|
||||
coe a := Coe.coe a
|
||||
|
||||
instance coeOfHeafOfTCOfTail {α : Sort u} {β : Sort v} {δ : Sort w} {γ : Sort w'} [CoeHead α β] [CoeTail δ γ] [CoeTC β δ] : CoeHTCT α γ where
|
||||
coe a := CoeTail.coe (CoeTC.coe (CoeHead.coe a : β) : δ)
|
||||
|
||||
instance coeOfHeadOfTC {α : Sort u} {β : Sort v} {δ : Sort w} [CoeHead α β] [CoeTC β δ] : CoeHTCT α δ where
|
||||
coe a := CoeTC.coe (CoeHead.coe a : β)
|
||||
|
||||
instance coeOfTCOfTail {α : Sort u} {β : Sort v} {δ : Sort w} [CoeTail β δ] [CoeTC α β] : CoeHTCT α δ where
|
||||
coe a := CoeTail.coe (CoeTC.coe a : β)
|
||||
|
||||
instance coeOfHeadOfTail {α : Sort u} {β : Sort v} {γ : Sort w} [CoeHead α β] [CoeTail β γ] : CoeHTCT α γ where
|
||||
coe a := CoeTail.coe (CoeHead.coe a : β)
|
||||
|
||||
instance coeOfHead {α : Sort u} {β : Sort v} [CoeHead α β] : CoeHTCT α β where
|
||||
coe a := CoeHead.coe a
|
||||
|
||||
instance coeOfTail {α : Sort u} {β : Sort v} [CoeTail α β] : CoeHTCT α β where
|
||||
coe a := CoeTail.coe a
|
||||
|
||||
instance coeOfTC {α : Sort u} {β : Sort v} [CoeTC α β] : CoeHTCT α β where
|
||||
coe a := CoeTC.coe a
|
||||
|
||||
instance coeOfHTCT {α : Sort u} {β : Sort v} [CoeHTCT α β] (a : α) : CoeT α a β where
|
||||
coe := CoeHTCT.coe a
|
||||
|
||||
instance coeOfDep {α : Sort u} {β : Sort v} (a : α) [CoeDep α a β] : CoeT α a β where
|
||||
coe := CoeDep.coe a
|
||||
|
||||
instance coeId {α : Sort u} (a : α) : CoeT α a α where
|
||||
coe := a
|
||||
|
||||
instance coeSortToCoeTail [inst : CoeSort α β] : CoeTail α β where
|
||||
coe := inst.coe
|
||||
|
||||
/-! # Basic instances -/
|
||||
|
||||
instance boolToProp : Coe Bool Prop where
|
||||
coe b := Eq b true
|
||||
|
||||
instance boolToSort : CoeSort Bool Prop where
|
||||
coe b := b
|
||||
coe b := Eq b true
|
||||
|
||||
instance decPropToBool (p : Prop) [Decidable p] : CoeDep Prop p Bool where
|
||||
coe := decide p
|
||||
|
||||
instance optionCoe {α : Type u} : Coe α (Option α) where
|
||||
instance optionCoe {α : Type u} : CoeTail α (Option α) where
|
||||
coe := some
|
||||
|
||||
instance subtypeCoe {α : Sort u} {p : α → Prop} : CoeOut (Subtype p) α where
|
||||
instance subtypeCoe {α : Sort u} {p : α → Prop} : CoeHead (Subtype p) α where
|
||||
coe v := v.val
|
||||
|
||||
/-! # Coe bridge -/
|
||||
@@ -315,7 +268,7 @@ Helper definition used by the elaborator. It is not meant to be used directly by
|
||||
This is used for coercions between monads, in the case where we want to apply
|
||||
a monad lift and a coercion on the result type at the same time.
|
||||
-/
|
||||
@[inline, coe_decl] def Lean.Internal.liftCoeM {m : Type u → Type v} {n : Type u → Type w} {α β : Type u}
|
||||
@[inline] def Lean.Internal.liftCoeM {m : Type u → Type v} {n : Type u → Type w} {α β : Type u}
|
||||
[MonadLiftT m n] [∀ a, CoeT α a β] [Monad n] (x : m α) : n β := do
|
||||
let a ← liftM x
|
||||
pure (CoeT.coe a)
|
||||
@@ -325,7 +278,16 @@ Helper definition used by the elaborator. It is not meant to be used directly by
|
||||
|
||||
This is used for coercing the result type under a monad.
|
||||
-/
|
||||
@[inline, coe_decl] def Lean.Internal.coeM {m : Type u → Type v} {α β : Type u}
|
||||
@[inline] def Lean.Internal.coeM {m : Type u → Type v} {α β : Type u}
|
||||
[∀ a, CoeT α a β] [Monad m] (x : m α) : m β := do
|
||||
let a ← x
|
||||
pure (CoeT.coe a)
|
||||
|
||||
instance [CoeFun α β] (a : α) : CoeDep α a (β a) where
|
||||
coe := CoeFun.coe a
|
||||
|
||||
instance [CoeFun α (fun _ => β)] : CoeTail α β where
|
||||
coe a := CoeFun.coe a
|
||||
|
||||
instance [CoeSort α β] : CoeTail α β where
|
||||
coe a := CoeSort.coe a
|
||||
|
||||
@@ -186,7 +186,7 @@ This is the same as [`MonadBaseControl`](https://hackage.haskell.org/package/mon
|
||||
To learn about `MonadControl`, see the comment above this docstring.
|
||||
|
||||
-/
|
||||
class MonadControl (m : semiOutParam (Type u → Type v)) (n : Type u → Type w) where
|
||||
class MonadControl (m : Type u → Type v) (n : Type u → Type w) where
|
||||
stM : Type u → Type u
|
||||
liftWith : {α : Type u} → (({β : Type u} → n β → m (stM β)) → m α) → n α
|
||||
restoreM : {α : Type u} → m (stM α) → n α
|
||||
|
||||
@@ -289,14 +289,14 @@ theorem seqRight_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT
|
||||
apply ext; intro s
|
||||
simp [map_eq_pure_bind, const]
|
||||
apply bind_congr; intro p; cases p
|
||||
simp [Prod.eta]
|
||||
simp [Prod.ext]
|
||||
|
||||
theorem seqLeft_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x <* y = const β <$> x <*> y := by
|
||||
apply ext; intro s
|
||||
simp [map_eq_pure_bind]
|
||||
|
||||
instance [Monad m] [LawfulMonad m] : LawfulMonad (StateT σ m) where
|
||||
id_map := by intros; apply ext; intros; simp[Prod.eta]
|
||||
id_map := by intros; apply ext; intros; simp[Prod.ext]
|
||||
map_const := by intros; rfl
|
||||
seqLeft_eq := seqLeft_eq
|
||||
seqRight_eq := seqRight_eq
|
||||
|
||||
@@ -33,7 +33,7 @@ occurrence of the pattern.
|
||||
syntax occsIndexed := num+
|
||||
|
||||
/-- An occurrence specification, either `*` or a list of numbers. The default is `[1]`. -/
|
||||
syntax occs := atomic("(" &"occs") " := " (occsWildcard <|> occsIndexed) ") "
|
||||
syntax occs := atomic(" (" &"occs") " := " (occsWildcard <|> occsIndexed) ")"
|
||||
|
||||
/--
|
||||
`with_annotate_state stx t` annotates the lexical range of `stx : Syntax` with
|
||||
@@ -79,7 +79,7 @@ syntax (name := arg) "arg " "@"? num : conv
|
||||
|
||||
/-- `ext x` traverses into a binder (a `fun x => e` or `∀ x, e` expression)
|
||||
to target `e`, introducing name `x` in the process. -/
|
||||
syntax (name := ext) "ext" (ppSpace colGt ident)* : conv
|
||||
syntax (name := ext) "ext" (colGt ident)* : conv
|
||||
|
||||
/-- `change t'` replaces the target `t` with `t'`,
|
||||
assuming `t` and `t'` are definitionally equal. -/
|
||||
@@ -89,7 +89,7 @@ syntax (name := change) "change " term : conv
|
||||
Like the `delta` tactic, this ignores any definitional equations and uses
|
||||
primitive delta-reduction instead, which may result in leaking implementation details.
|
||||
Users should prefer `unfold` for unfolding definitions. -/
|
||||
syntax (name := delta) "delta" (ppSpace colGt ident)+ : conv
|
||||
syntax (name := delta) "delta " (colGt ident)+ : conv
|
||||
|
||||
/--
|
||||
* `unfold foo` unfolds all occurrences of `foo` in the target.
|
||||
@@ -97,7 +97,7 @@ syntax (name := delta) "delta" (ppSpace colGt ident)+ : conv
|
||||
Like the `unfold` tactic, this uses equational lemmas for the chosen definition
|
||||
to rewrite the target. For recursive definitions,
|
||||
only one layer of unfolding is performed. -/
|
||||
syntax (name := unfold) "unfold" (ppSpace colGt ident)+ : conv
|
||||
syntax (name := unfold) "unfold " (colGt ident)+ : conv
|
||||
|
||||
/--
|
||||
* `pattern pat` traverses to the first subterm of the target that matches `pat`.
|
||||
@@ -139,8 +139,8 @@ example (a : Nat): (0 + 0) = a - a := by
|
||||
rw [← Nat.sub_self a]
|
||||
```
|
||||
-/
|
||||
syntax (name := dsimp) "dsimp" (config)? (discharger)? (&" only")?
|
||||
(" [" withoutPosition((simpErase <|> simpLemma),*) "]")? : conv
|
||||
syntax (name := dsimp) "dsimp " (config)? (discharger)? (&"only ")?
|
||||
("[" withoutPosition((simpErase <|> simpLemma),*) "]")? : conv
|
||||
|
||||
/-- `simp_match` simplifies match expressions. For example,
|
||||
```
|
||||
@@ -214,7 +214,7 @@ macro (name := case') tk:"case' " args:sepBy1(caseArg, " | ") arr:" => " s:convS
|
||||
`next x₁ ... xₙ => tac` additionally renames the `n` most recent hypotheses with
|
||||
inaccessible names to the given names.
|
||||
-/
|
||||
macro "next" args:(ppSpace binderIdent)* " => " tac:convSeq : conv => `(conv| case _ $args* => $tac)
|
||||
macro "next " args:binderIdent* " => " tac:convSeq : conv => `(conv| case _ $args* => $tac)
|
||||
|
||||
/--
|
||||
`focus tac` focuses on the main goal, suppressing all other goals, and runs `tac` on it.
|
||||
@@ -250,7 +250,7 @@ macro "left" : conv => `(conv| lhs)
|
||||
/-- `right` traverses into the right argument. Synonym for `rhs`. -/
|
||||
macro "right" : conv => `(conv| rhs)
|
||||
/-- `intro` traverses into binders. Synonym for `ext`. -/
|
||||
macro "intro" xs:(ppSpace colGt ident)* : conv => `(conv| ext $xs*)
|
||||
macro "intro" xs:(colGt ident)* : conv => `(conv| ext $xs*)
|
||||
|
||||
syntax enterArg := ident <|> ("@"? num)
|
||||
|
||||
@@ -261,7 +261,7 @@ It is a shorthand for other conv tactics as follows:
|
||||
* `enter [x]` (where `x` is an identifier) is equivalent to `ext x`.
|
||||
For example, given the target `f (g a (fun x => x b))`, `enter [1, 2, x, 1]`
|
||||
will traverse to the subterm `b`. -/
|
||||
syntax "enter" " [" withoutPosition(enterArg,+) "]" : conv
|
||||
syntax "enter" " [" (colGt enterArg),+ "]": conv
|
||||
macro_rules
|
||||
| `(conv| enter [$i:num]) => `(conv| arg $i)
|
||||
| `(conv| enter [@$i]) => `(conv| arg @$i)
|
||||
@@ -275,7 +275,7 @@ cannot be reasonably interpreted as proving one equality from a list of others.
|
||||
macro "apply " e:term : conv => `(conv| tactic => apply $e)
|
||||
|
||||
/-- `first | conv | ...` runs each `conv` until one succeeds, or else fails. -/
|
||||
syntax (name := first) "first " withPosition((ppDedent(ppLine) colGe "| " convSeq)+) : conv
|
||||
syntax (name := first) "first " withPosition((colGe "|" convSeq)+) : conv
|
||||
|
||||
/-- `try tac` runs `tac` and succeeds even if `tac` failed. -/
|
||||
macro "try " t:convSeq : conv => `(conv| first | $t | skip)
|
||||
@@ -284,15 +284,15 @@ macro:1 x:conv tk:" <;> " y:conv:0 : conv =>
|
||||
`(conv| tactic' => (conv' => $x:conv) <;>%$tk (conv' => $y:conv))
|
||||
|
||||
/-- `repeat convs` runs the sequence `convs` repeatedly until it fails to apply. -/
|
||||
syntax "repeat " convSeq : conv
|
||||
syntax "repeat" convSeq : conv
|
||||
macro_rules
|
||||
| `(conv| repeat $seq) => `(conv| first | ($seq); repeat $seq | skip)
|
||||
| `(conv| repeat $seq) => `(conv| first | ($seq); repeat $seq | rfl)
|
||||
|
||||
/--
|
||||
`conv => ...` allows the user to perform targeted rewriting on a goal or hypothesis,
|
||||
by focusing on particular subexpressions.
|
||||
|
||||
See <https://lean-lang.org/theorem_proving_in_lean4/conv.html> for more details.
|
||||
See <https://leanprover.github.io/theorem_proving_in_lean4/conv.html> for more details.
|
||||
|
||||
Basic forms:
|
||||
* `conv => cs` will rewrite the goal with conv tactics `cs`.
|
||||
@@ -301,6 +301,6 @@ Basic forms:
|
||||
-/
|
||||
-- HACK: put this at the end so that references to `conv` above
|
||||
-- refer to the syntax category instead of this syntax
|
||||
syntax (name := conv) "conv" (" at " ident)? (" in " (occs)? term)? " => " convSeq : tactic
|
||||
syntax (name := conv) "conv " (" at " ident)? (" in " (occs)? term)? " => " convSeq : tactic
|
||||
|
||||
end Lean.Parser.Tactic.Conv
|
||||
|
||||
@@ -365,11 +365,14 @@ structure Task (α : Type u) : Type u where
|
||||
/-- If `task : Task α` then `task.get : α` blocks the current thread until the
|
||||
value is available, and then returns the result of the task. -/
|
||||
get : α
|
||||
deriving Inhabited, Nonempty
|
||||
deriving Inhabited
|
||||
|
||||
attribute [extern "lean_task_pure"] Task.pure
|
||||
attribute [extern "lean_task_get_own"] Task.get
|
||||
|
||||
instance : [Nonempty α] → Nonempty (Task α)
|
||||
| ⟨x⟩ => ⟨.pure x⟩
|
||||
|
||||
namespace Task
|
||||
/-- Task priority. Tasks with higher priority will always be scheduled before ones with lower priority. -/
|
||||
abbrev Priority := Nat
|
||||
@@ -464,13 +467,13 @@ theorem optParam_eq (α : Sort u) (default : α) : optParam α default = α := r
|
||||
`strictOr` is the same as `or`, but it does not use short-circuit evaluation semantics:
|
||||
both sides are evaluated, even if the first value is `true`.
|
||||
-/
|
||||
@[extern "lean_strict_or"] def strictOr (b₁ b₂ : Bool) := b₁ || b₂
|
||||
@[extern c inline "#1 || #2"] def strictOr (b₁ b₂ : Bool) := b₁ || b₂
|
||||
|
||||
/--
|
||||
`strictAnd` is the same as `and`, but it does not use short-circuit evaluation semantics:
|
||||
both sides are evaluated, even if the first value is `false`.
|
||||
-/
|
||||
@[extern "lean_strict_and"] def strictAnd (b₁ b₂ : Bool) := b₁ && b₂
|
||||
@[extern c inline "#1 && #2"] def strictAnd (b₁ b₂ : Bool) := b₁ && b₂
|
||||
|
||||
/--
|
||||
`x != y` is boolean not-equal. It is the negation of `x == y` which is supplied by
|
||||
@@ -797,13 +800,6 @@ theorem if_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t e : α}
|
||||
| isTrue hc => absurd hc hnc
|
||||
| isFalse _ => rfl
|
||||
|
||||
/-- Split an if-then-else into cases. The `split` tactic is generally easier to use than this theorem. -/
|
||||
def iteInduction {c} [inst : Decidable c] {motive : α → Sort _} {t e : α}
|
||||
(hpos : c → motive t) (hneg : ¬c → motive e) : motive (ite c t e) :=
|
||||
match inst with
|
||||
| isTrue h => hpos h
|
||||
| isFalse h => hneg h
|
||||
|
||||
theorem dif_pos {c : Prop} {h : Decidable c} (hc : c) {α : Sort u} {t : c → α} {e : ¬ c → α} : (dite c t e) = t hc :=
|
||||
match h with
|
||||
| isTrue _ => rfl
|
||||
@@ -1034,7 +1030,8 @@ instance Prod.lexLtDec
|
||||
theorem Prod.lexLt_def [LT α] [LT β] (s t : α × β) : (Prod.lexLt s t) = (s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2)) :=
|
||||
rfl
|
||||
|
||||
theorem Prod.eta (p : α × β) : (p.1, p.2) = p := rfl
|
||||
theorem Prod.ext (p : α × β) : (p.1, p.2) = p := by
|
||||
cases p; rfl
|
||||
|
||||
/--
|
||||
`Prod.map f g : α₁ × β₁ → α₂ × β₂` maps across a pair
|
||||
@@ -1351,8 +1348,7 @@ then it lifts to a function on `Quotient s` such that `lift f h (mk a) = f a`.
|
||||
protected abbrev lift {α : Sort u} {β : Sort v} {s : Setoid α} (f : α → β) : ((a b : α) → a ≈ b → f a = f b) → Quotient s → β :=
|
||||
Quot.lift f
|
||||
|
||||
/-- The analogue of `Quot.ind`: every element of `Quotient s` is of the form `Quotient.mk s a`. -/
|
||||
protected theorem ind {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop} : ((a : α) → motive (Quotient.mk s a)) → (q : Quotient s) → motive q :=
|
||||
protected theorem ind {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop} : ((a : α) → motive (Quotient.mk s a)) → (q : Quot Setoid.r) → motive q :=
|
||||
Quot.ind
|
||||
|
||||
/--
|
||||
@@ -1362,7 +1358,6 @@ then it lifts to a function on `Quotient s` such that `lift (mk a) f h = f a`.
|
||||
protected abbrev liftOn {α : Sort u} {β : Sort v} {s : Setoid α} (q : Quotient s) (f : α → β) (c : (a b : α) → a ≈ b → f a = f b) : β :=
|
||||
Quot.liftOn q f c
|
||||
|
||||
/-- The analogue of `Quot.inductionOn`: every element of `Quotient s` is of the form `Quotient.mk s a`. -/
|
||||
@[elab_as_elim]
|
||||
protected theorem inductionOn {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop}
|
||||
(q : Quotient s)
|
||||
@@ -1480,7 +1475,7 @@ end
|
||||
|
||||
section Exact
|
||||
|
||||
variable {α : Sort u}
|
||||
variable {α : Sort u}
|
||||
|
||||
private def rel {s : Setoid α} (q₁ q₂ : Quotient s) : Prop :=
|
||||
Quotient.liftOn₂ q₁ q₂
|
||||
@@ -1612,11 +1607,6 @@ class Antisymm {α : Sort u} (r : α → α → Prop) where
|
||||
namespace Lean
|
||||
/-! # Kernel reduction hints -/
|
||||
|
||||
/--
|
||||
Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations.
|
||||
-/
|
||||
axiom trustCompiler : True
|
||||
|
||||
/--
|
||||
When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`.
|
||||
The kernel will not use the interpreter if `c` is not a constant.
|
||||
@@ -1636,10 +1626,7 @@ Recall that the compiler trusts the correctness of all `[implemented_by ...]` an
|
||||
If an extern function is executed, then the trusted code base will also include the implementation of the associated
|
||||
foreign function.
|
||||
-/
|
||||
opaque reduceBool (b : Bool) : Bool :=
|
||||
-- This ensures that `#print axioms` will track use of `reduceBool`.
|
||||
have := trustCompiler
|
||||
b
|
||||
opaque reduceBool (b : Bool) : Bool := b
|
||||
|
||||
/--
|
||||
Similar to `Lean.reduceBool` for closed `Nat` terms.
|
||||
@@ -1648,11 +1635,7 @@ Remark: we do not have plans for supporting a generic `reduceValue {α} (a : α)
|
||||
The main issue is that it is non-trivial to convert an arbitrary runtime object back into a Lean expression.
|
||||
We believe `Lean.reduceBool` enables most interesting applications (e.g., proof by reflection).
|
||||
-/
|
||||
opaque reduceNat (n : Nat) : Nat :=
|
||||
-- This ensures that `#print axioms` will track use of `reduceNat`.
|
||||
have := trustCompiler
|
||||
n
|
||||
|
||||
opaque reduceNat (n : Nat) : Nat := n
|
||||
|
||||
/--
|
||||
The axiom `ofReduceBool` is used to perform proofs by reflection. See `reduceBool`.
|
||||
|
||||
@@ -7,7 +7,7 @@ prelude
|
||||
import Init.WFTactics
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.Fin.Basic
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt
|
||||
import Init.Data.Repr
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.Util
|
||||
@@ -269,15 +269,7 @@ unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad
|
||||
/-- Reference implementation for `mapM` -/
|
||||
@[implemented_by mapMUnsafe]
|
||||
def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
|
||||
-- Note: we cannot use `foldlM` here for the reference implementation because this calls
|
||||
-- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
|
||||
let rec map (i : Nat) (r : Array β) : m (Array β) := do
|
||||
if hlt : i < as.size then
|
||||
map (i+1) (r.push (← f as[i]))
|
||||
else
|
||||
pure r
|
||||
map 0 (mkEmpty as.size)
|
||||
termination_by map => as.size - i
|
||||
as.foldlM (fun bs a => do let b ← f a; pure (bs.push b)) (mkEmpty as.size)
|
||||
|
||||
@[inline]
|
||||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : Fin as.size → α → m β) : m (Array β) :=
|
||||
@@ -328,9 +320,8 @@ unsafe def anyMUnsafe {α : Type u} {m : Type → Type w} [Monad m] (p : α →
|
||||
else
|
||||
any (i+1) stop
|
||||
if start < stop then
|
||||
let stop' := min stop as.size
|
||||
if start < stop' then
|
||||
any (USize.ofNat start) (USize.ofNat stop')
|
||||
if stop ≤ as.size then
|
||||
any (USize.ofNat start) (USize.ofNat stop)
|
||||
else
|
||||
pure false
|
||||
else
|
||||
@@ -592,7 +583,7 @@ theorem ext (a b : Array α)
|
||||
have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
|
||||
have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
|
||||
have headEq : a = b := h₂ 0 hz₁ hz₂
|
||||
have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
|
||||
have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁; assumption
|
||||
have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as.get ⟨i, hi₁⟩ = bs.get ⟨i, hi₂⟩ := by
|
||||
intro i hi₁ hi₂
|
||||
have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
|
||||
|
||||
@@ -8,9 +8,9 @@ import Init.Data.Array.Basic
|
||||
|
||||
namespace Array
|
||||
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
|
||||
-- TODO: remove `partial` using well-founded recursion
|
||||
|
||||
def qpartition (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat × Array α :=
|
||||
if h : as.size = 0 then (0, as) else have : Inhabited α := ⟨as[0]'(by revert h; cases as.size <;> simp [Nat.zero_lt_succ])⟩ -- TODO: remove
|
||||
@[inline] def qpartition {α : Type} [Inhabited α] (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat × Array α :=
|
||||
let mid := (lo + hi) / 2
|
||||
let as := if lt (as.get! mid) (as.get! lo) then as.swap! lo mid else as
|
||||
let as := if lt (as.get! hi) (as.get! lo) then as.swap! lo hi else as
|
||||
@@ -29,7 +29,7 @@ def qpartition (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat ×
|
||||
loop as lo lo
|
||||
termination_by _ => hi - j
|
||||
|
||||
@[inline] partial def qsort (as : Array α) (lt : α → α → Bool) (low := 0) (high := as.size - 1) : Array α :=
|
||||
@[inline] partial def qsort {α : Type} [Inhabited α] (as : Array α) (lt : α → α → Bool) (low := 0) (high := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort (as : Array α) (low high : Nat) :=
|
||||
if low < high then
|
||||
let p := qpartition as lt low high;
|
||||
|
||||
@@ -149,6 +149,9 @@ def ofSubarray (s : Subarray α) : Array α := Id.run do
|
||||
as := as.push a
|
||||
return as
|
||||
|
||||
def extract (as : Array α) (start stop : Nat) : Array α :=
|
||||
ofSubarray (as.toSubarray start stop)
|
||||
|
||||
instance : Coe (Subarray α) (Array α) := ⟨ofSubarray⟩
|
||||
|
||||
syntax:max term noWs "[" withoutPosition(term ":" term) "]" : term
|
||||
|
||||
@@ -6,7 +6,7 @@ Author: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Array.Subarray
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt
|
||||
import Init.Data.Option.Basic
|
||||
universe u
|
||||
|
||||
@@ -67,12 +67,6 @@ def set : (a : ByteArray) → (@& Fin a.size) → UInt8 → ByteArray
|
||||
def uset : (a : ByteArray) → (i : USize) → UInt8 → i.toNat < a.size → ByteArray
|
||||
| ⟨bs⟩, i, v, h => ⟨bs.uset i v h⟩
|
||||
|
||||
@[extern "lean_byte_array_hash"]
|
||||
protected opaque hash (a : @& ByteArray) : UInt64
|
||||
|
||||
instance : Hashable ByteArray where
|
||||
hash := ByteArray.hash
|
||||
|
||||
def isEmpty (s : ByteArray) : Bool :=
|
||||
s.size == 0
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt
|
||||
|
||||
/-- Determines if the given integer is a valid [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value).
|
||||
|
||||
|
||||
@@ -5,4 +5,3 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Fin.Basic
|
||||
import Init.Data.Fin.Log2
|
||||
|
||||
@@ -12,7 +12,7 @@ open Nat
|
||||
|
||||
namespace Fin
|
||||
|
||||
instance coeToNat : CoeOut (Fin n) Nat :=
|
||||
instance coeToNat {n} : Coe (Fin n) Nat :=
|
||||
⟨fun v => v.val⟩
|
||||
|
||||
def elim0.{u} {α : Sort u} : Fin 0 → α
|
||||
@@ -45,19 +45,19 @@ protected def sub : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
|
||||
|
||||
/-!
|
||||
Remark: land/lor can be defined without using (% n), but
|
||||
Remark: mod/div/modn/land/lor can be defined without using (% n), but
|
||||
we are trying to minimize the number of Nat theorems
|
||||
needed to bootstrap Lean.
|
||||
needed to boostrap Lean.
|
||||
-/
|
||||
|
||||
protected def mod : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨a % b, Nat.lt_of_le_of_lt (Nat.mod_le _ _) h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a % b) % n, mlt h⟩
|
||||
|
||||
protected def div : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨a / b, Nat.lt_of_le_of_lt (Nat.div_le_self _ _) h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a / b) % n, mlt h⟩
|
||||
|
||||
def modn : Fin n → Nat → Fin n
|
||||
| ⟨a, h⟩, m => ⟨a % m, Nat.lt_of_le_of_lt (Nat.mod_le _ _) h⟩
|
||||
| ⟨a, h⟩, m => ⟨(a % m) % n, mlt h⟩
|
||||
|
||||
def land : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.land a b) % n, mlt h⟩
|
||||
@@ -110,7 +110,7 @@ theorem val_ne_of_ne {i j : Fin n} (h : i ≠ j) : val i ≠ val j :=
|
||||
fun h' => absurd (eq_of_val_eq h') h
|
||||
|
||||
theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
|
||||
| _, ⟨_, _⟩, hp => by simp [modn]; apply Nat.mod_lt; assumption
|
||||
| _, ⟨_, _⟩, hp => Nat.lt_of_le_of_lt (mod_le _ _) (mod_lt _ hp)
|
||||
|
||||
theorem val_lt_of_le (i : Fin b) (h : b ≤ n) : i.val < n :=
|
||||
Nat.lt_of_lt_of_le i.isLt h
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2022 Henrik Böving. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Log2
|
||||
|
||||
def Fin.log2 (n : Fin m) : Fin m := ⟨Nat.log2 n.val, Nat.lt_of_le_of_lt (Nat.log2_le_self n.val) n.isLt⟩
|
||||
@@ -41,19 +41,6 @@ inductive Format where
|
||||
/-- A position where a newline may be inserted
|
||||
if the current group does not fit within the allotted column width. -/
|
||||
| line : Format
|
||||
/-- `align` tells the formatter to pad with spaces to the current indent,
|
||||
or else add a newline if we are already at or past the indent. For example:
|
||||
```
|
||||
nest 2 <| "." ++ align ++ "a" ++ line ++ "b"
|
||||
```
|
||||
results in:
|
||||
```
|
||||
. a
|
||||
b
|
||||
```
|
||||
If `force` is true, then it will pad to the indent even if it is in a flattened group.
|
||||
-/
|
||||
| align (force : Bool) : Format
|
||||
/-- A node containing a plain string. -/
|
||||
| text : String → Format
|
||||
/-- `nest n f` tells the formatter that `f` is nested inside something with length `n`
|
||||
@@ -83,7 +70,6 @@ namespace Format
|
||||
def isEmpty : Format → Bool
|
||||
| nil => true
|
||||
| line => false
|
||||
| align _ => true
|
||||
| text msg => msg == ""
|
||||
| nest _ f => f.isEmpty
|
||||
| append f₁ f₂ => f₁.isEmpty && f₂.isEmpty
|
||||
@@ -117,23 +103,17 @@ private structure SpaceResult where
|
||||
let r₂ := r₂ (w - r₁.space);
|
||||
{ r₂ with space := r₁.space + r₂.space }
|
||||
|
||||
private def spaceUptoLine : Format → Bool → Int → Nat → SpaceResult
|
||||
| nil, _, _, _ => {}
|
||||
| line, flatten, _, _ => if flatten then { space := 1 } else { foundLine := true }
|
||||
| align force, flatten, m, w =>
|
||||
if flatten && !force then {}
|
||||
else if w < m then
|
||||
{ space := (m - w).toNat }
|
||||
else
|
||||
{ foundLine := true }
|
||||
| text s, flatten, _, _ =>
|
||||
let p := s.posOf '\n'
|
||||
let off := s.offsetOfPos p
|
||||
private def spaceUptoLine : Format → Bool → Nat → SpaceResult
|
||||
| nil, _, _ => {}
|
||||
| line, flatten, _ => if flatten then { space := 1 } else { foundLine := true }
|
||||
| text s, flatten, _ =>
|
||||
let p := s.posOf '\n';
|
||||
let off := s.offsetOfPos p;
|
||||
{ foundLine := p != s.endPos, foundFlattenedHardLine := flatten && p != s.endPos, space := off }
|
||||
| append f₁ f₂, flatten, m, w => merge w (spaceUptoLine f₁ flatten m w) (spaceUptoLine f₂ flatten m)
|
||||
| nest n f, flatten, m, w => spaceUptoLine f flatten (m - n) w
|
||||
| group f _, _, m, w => spaceUptoLine f true m w
|
||||
| tag _ f, flatten, m, w => spaceUptoLine f flatten m w
|
||||
| append f₁ f₂, flatten, w => merge w (spaceUptoLine f₁ flatten w) (spaceUptoLine f₂ flatten)
|
||||
| nest _ f, flatten, w => spaceUptoLine f flatten w
|
||||
| group f _, _, w => spaceUptoLine f true w
|
||||
| tag _ f, flatten, w => spaceUptoLine f flatten w
|
||||
|
||||
private structure WorkItem where
|
||||
f : Format
|
||||
@@ -145,13 +125,10 @@ private structure WorkGroup where
|
||||
flb : FlattenBehavior
|
||||
items : List WorkItem
|
||||
|
||||
private partial def spaceUptoLine' : List WorkGroup → Nat → Nat → SpaceResult
|
||||
| [], _, _ => {}
|
||||
| { items := [], .. }::gs, col, w => spaceUptoLine' gs col w
|
||||
| g@{ items := i::is, .. }::gs, col, w =>
|
||||
merge w
|
||||
(spaceUptoLine i.f g.flatten (w + col - i.indent) w)
|
||||
(spaceUptoLine' ({ g with items := is }::gs) col)
|
||||
private partial def spaceUptoLine' : List WorkGroup → Nat → SpaceResult
|
||||
| [], _ => {}
|
||||
| { items := [], .. }::gs, w => spaceUptoLine' gs w
|
||||
| g@{ items := i::is, .. }::gs, w => merge w (spaceUptoLine i.f g.flatten w) (spaceUptoLine' ({ g with items := is }::gs))
|
||||
|
||||
/-- A monad in which we can pretty-print `Format` objects. -/
|
||||
class MonadPrettyFormat (m : Type → Type) where
|
||||
@@ -168,8 +145,8 @@ private def pushGroup (flb : FlattenBehavior) (items : List WorkItem) (gs : List
|
||||
let k ← currColumn
|
||||
-- Flatten group if it + the remainder (gs) fits in the remaining space. For `fill`, measure only up to the next (ungrouped) line break.
|
||||
let g := { flatten := flb == FlattenBehavior.allOrNone, flb := flb, items := items : WorkGroup }
|
||||
let r := spaceUptoLine' [g] k (w-k)
|
||||
let r' := merge (w-k) r (spaceUptoLine' gs k)
|
||||
let r := spaceUptoLine' [g] (w-k)
|
||||
let r' := merge (w-k) r (spaceUptoLine' gs);
|
||||
-- Prevent flattening if any item contains a hard line break, except within `fill` if it is ungrouped (=> unflattened)
|
||||
return { g with flatten := !r.foundFlattenedHardLine && r'.space <= w-k }::gs
|
||||
|
||||
@@ -222,28 +199,13 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - " ".length)
|
||||
| panic "unreachable"
|
||||
if g'.flatten then
|
||||
pushOutput " "
|
||||
pushOutput " ";
|
||||
endTags i.activeTags
|
||||
be w gs' -- TODO: use `return`
|
||||
else
|
||||
breakHere
|
||||
else
|
||||
breakHere
|
||||
| align force =>
|
||||
if g.flatten && !force then
|
||||
-- flatten (align false) = nil
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
let k ← currColumn
|
||||
if k < i.indent then
|
||||
pushOutput ("".pushn ' ' (i.indent - k).toNat)
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
pushNewline i.indent.toNat
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
| group f flb =>
|
||||
if g.flatten then
|
||||
-- flatten (group f) = flatten f
|
||||
@@ -315,7 +277,7 @@ class ToFormat (α : Type u) where
|
||||
|
||||
export ToFormat (format)
|
||||
|
||||
-- note: must take precedence over the above instance to avoid premature formatting
|
||||
-- note: must take precendence over the above instance to avoid premature formatting
|
||||
instance : ToFormat Format where
|
||||
format f := f
|
||||
|
||||
@@ -326,16 +288,16 @@ instance : ToFormat String where
|
||||
def Format.joinSep {α : Type u} [ToFormat α] : List α → Format → Format
|
||||
| [], _ => nil
|
||||
| [a], _ => format a
|
||||
| a::as, sep => as.foldl (· ++ sep ++ format ·) (format a)
|
||||
| a::as, sep => format a ++ sep ++ joinSep as sep
|
||||
|
||||
/-- Format each item in `items` and prepend prefix `pre`. -/
|
||||
def Format.prefixJoin {α : Type u} [ToFormat α] (pre : Format) : List α → Format
|
||||
| [] => nil
|
||||
| a::as => as.foldl (· ++ pre ++ format ·) (pre ++ format a)
|
||||
| a::as => pre ++ format a ++ prefixJoin pre as
|
||||
|
||||
/-- Format each item in `items` and append `suffix`. -/
|
||||
def Format.joinSuffix {α : Type u} [ToFormat α] : List α → Format → Format
|
||||
| [], _ => nil
|
||||
| a::as, suffix => as.foldl (· ++ format · ++ suffix) (format a ++ suffix)
|
||||
| a::as, suffix => format a ++ suffix ++ joinSuffix as suffix
|
||||
|
||||
end Std
|
||||
|
||||
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt
|
||||
import Init.Data.String
|
||||
universe u
|
||||
|
||||
@@ -58,7 +58,3 @@ instance : Hashable Int where
|
||||
|
||||
instance (P : Prop) : Hashable P where
|
||||
hash _ := 0
|
||||
|
||||
/-- An opaque (low-level) hash operation used to implement hashing for pointers. -/
|
||||
@[always_inline, inline] def hash64 (u : UInt64) : UInt64 :=
|
||||
mixHash u 11
|
||||
|
||||
@@ -9,39 +9,12 @@ prelude
|
||||
import Init.Coe
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.List.Basic
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
open Nat
|
||||
|
||||
/-! # Integer Type, Coercions, and Notation
|
||||
/-! # the Type, coercions, and notation -/
|
||||
|
||||
This file defines the `Int` type as well as
|
||||
|
||||
* coercions, conversions, and compatibility with numeric literals,
|
||||
* basic arithmetic operations add/sub/mul/div/mod/pow,
|
||||
* a few `Nat`-related operations such as `negOfNat` and `subNatNat`,
|
||||
* relations `<`/`≤`/`≥`/`>`, the `NonNeg` property and `min`/`max`,
|
||||
* decidability of equality, relations and `NonNeg`.
|
||||
-/
|
||||
|
||||
/--
|
||||
The type of integers. It is defined as an inductive type based on the
|
||||
natural number type `Nat` featuring two constructors: "a natural
|
||||
number is an integer", and "the negation of a successor of a natural
|
||||
number is an integer". The former represents integers between `0`
|
||||
(inclusive) and `∞`, and the latter integers between `-∞` and `-1`
|
||||
(inclusive).
|
||||
|
||||
This type is special-cased by the compiler. The runtime has a special
|
||||
representation for `Int` which stores "small" signed numbers directly,
|
||||
and larger numbers use an arbitrary precision "bignum" library
|
||||
(usually [GMP](https://gmplib.org/)). A "small number" is an integer
|
||||
that can be encoded with 63 bits (31 bits on 32-bits architectures).
|
||||
-/
|
||||
inductive Int : Type where
|
||||
/-- A natural number is an integer (`0` to `∞`). -/
|
||||
| ofNat : Nat → Int
|
||||
/-- The negation of the successor of a natural number is an integer
|
||||
(`-1` to `-∞`). -/
|
||||
| negSucc : Nat → Int
|
||||
|
||||
attribute [extern "lean_nat_to_int"] Int.ofNat
|
||||
@@ -55,69 +28,32 @@ instance : OfNat Int n where
|
||||
namespace Int
|
||||
instance : Inhabited Int := ⟨ofNat 0⟩
|
||||
|
||||
/-- Negation of a natural number. -/
|
||||
def negOfNat : Nat → Int
|
||||
| 0 => 0
|
||||
| succ m => negSucc m
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/-- Negation of an integer.
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_neg"]
|
||||
protected def neg (n : @& Int) : Int :=
|
||||
match n with
|
||||
| ofNat n => negOfNat n
|
||||
| negSucc n => succ n
|
||||
|
||||
/-
|
||||
The `Neg Int` default instance must have priority higher than `low`
|
||||
since the default instance `OfNat Nat n` has `low` priority.
|
||||
|
||||
```
|
||||
#check -42
|
||||
```
|
||||
-/
|
||||
@[default_instance mid]
|
||||
instance : Neg Int where
|
||||
neg := Int.neg
|
||||
|
||||
/-- Subtraction of two natural numbers. -/
|
||||
def subNatNat (m n : Nat) : Int :=
|
||||
match (n - m : Nat) with
|
||||
| 0 => ofNat (m - n) -- m ≥ n
|
||||
| (succ k) => negSucc k
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/-- Addition of two integers.
|
||||
|
||||
```
|
||||
#eval (7 : Int) + (6 : Int) -- 13
|
||||
#eval (6 : Int) + (-6 : Int) -- 0
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_add"]
|
||||
protected def add (m n : @& Int) : Int :=
|
||||
protected def add (m n : @& Int) : Int :=
|
||||
match m, n with
|
||||
| ofNat m, ofNat n => ofNat (m + n)
|
||||
| ofNat m, negSucc n => subNatNat m (succ n)
|
||||
| negSucc m, ofNat n => subNatNat n (succ m)
|
||||
| negSucc m, negSucc n => negSucc (succ (m + n))
|
||||
|
||||
instance : Add Int where
|
||||
add := Int.add
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/-- Multiplication of two integers.
|
||||
|
||||
```
|
||||
#eval (63 : Int) * (6 : Int) -- 378
|
||||
#eval (6 : Int) * (-6 : Int) -- -36
|
||||
#eval (7 : Int) * (0 : Int) -- 0
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_mul"]
|
||||
protected def mul (m n : @& Int) : Int :=
|
||||
match m, n with
|
||||
@@ -126,18 +62,21 @@ protected def mul (m n : @& Int) : Int :=
|
||||
| negSucc m, ofNat n => negOfNat (succ m * n)
|
||||
| negSucc m, negSucc n => ofNat (succ m * succ n)
|
||||
|
||||
/--
|
||||
The `Neg Int` default instance must have priority higher than `low` since
|
||||
the default instance `OfNat Nat n` has `low` priority.
|
||||
```
|
||||
#check -42
|
||||
```
|
||||
-/
|
||||
@[default_instance mid]
|
||||
instance : Neg Int where
|
||||
neg := Int.neg
|
||||
instance : Add Int where
|
||||
add := Int.add
|
||||
instance : Mul Int where
|
||||
mul := Int.mul
|
||||
|
||||
/-- Subtraction of two integers.
|
||||
|
||||
```
|
||||
#eval (63 : Int) - (6 : Int) -- 57
|
||||
#eval (7 : Int) - (0 : Int) -- 7
|
||||
#eval (0 : Int) - (7 : Int) -- -7
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_sub"]
|
||||
protected def sub (m n : @& Int) : Int :=
|
||||
m + (- n)
|
||||
@@ -145,33 +84,20 @@ protected def sub (m n : @& Int) : Int :=
|
||||
instance : Sub Int where
|
||||
sub := Int.sub
|
||||
|
||||
/-- A proof that an `Int` is non-negative. -/
|
||||
inductive NonNeg : Int → Prop where
|
||||
/-- Sole constructor, proving that `ofNat n` is positive. -/
|
||||
| mk (n : Nat) : NonNeg (ofNat n)
|
||||
|
||||
/-- Definition of `a ≤ b`, encoded as `b - a ≥ 0`. -/
|
||||
protected def le (a b : Int) : Prop := NonNeg (b - a)
|
||||
|
||||
instance : LE Int where
|
||||
le := Int.le
|
||||
|
||||
/-- Definition of `a < b`, encoded as `a + 1 ≤ b`. -/
|
||||
protected def lt (a b : Int) : Prop := (a + 1) ≤ b
|
||||
|
||||
instance : LT Int where
|
||||
lt := Int.lt
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/-- Decides equality between two `Int`s.
|
||||
|
||||
```
|
||||
#eval (7 : Int) = (3 : Int) + (4 : Int) -- true
|
||||
#eval (6 : Int) = (3 : Int) * (2 : Int) -- true
|
||||
#eval ¬ (6 : Int) = (3 : Int) -- true
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_dec_eq"]
|
||||
protected def decEq (a b : @& Int) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
@@ -187,93 +113,27 @@ protected def decEq (a b : @& Int) : Decidable (a = b) :=
|
||||
instance : DecidableEq Int := Int.decEq
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/-- Decides whether an integer is negative.
|
||||
|
||||
```
|
||||
#eval (7 : Int).decNonneg.decide -- true
|
||||
#eval (0 : Int).decNonneg.decide -- true
|
||||
#eval ¬ (-7 : Int).decNonneg.decide -- true
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_dec_nonneg"]
|
||||
private def decNonneg (m : @& Int) : Decidable (NonNeg m) :=
|
||||
match m with
|
||||
| ofNat m => isTrue <| NonNeg.mk m
|
||||
| negSucc _ => isFalse <| fun h => nomatch h
|
||||
|
||||
/-- Decides whether `a ≤ b`.
|
||||
|
||||
```
|
||||
#eval ¬ ( (7 : Int) ≤ (0 : Int) ) -- true
|
||||
#eval (0 : Int) ≤ (0 : Int) -- true
|
||||
#eval (7 : Int) ≤ (10 : Int) -- true
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_dec_le"]
|
||||
instance decLe (a b : @& Int) : Decidable (a ≤ b) :=
|
||||
decNonneg _
|
||||
|
||||
/-- Decides whether `a < b`.
|
||||
|
||||
```
|
||||
#eval `¬ ( (7 : Int) < 0 )` -- true
|
||||
#eval `¬ ( (0 : Int) < 0 )` -- true
|
||||
#eval `(7 : Int) < 10` -- true
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_dec_lt"]
|
||||
instance decLt (a b : @& Int) : Decidable (a < b) :=
|
||||
decNonneg _
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
/-- Absolute value (`Nat`) of an integer.
|
||||
|
||||
```
|
||||
#eval (7 : Int).natAbs -- 7
|
||||
#eval (0 : Int).natAbs -- 0
|
||||
#eval (-11 : Int).natAbs -- 11
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_nat_abs"]
|
||||
def natAbs (m : @& Int) : Nat :=
|
||||
match m with
|
||||
| ofNat m => m
|
||||
| negSucc m => m.succ
|
||||
|
||||
/-- Integer division. This function uses the
|
||||
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention,
|
||||
meaning that it rounds toward zero. Also note that division by zero
|
||||
is defined to equal zero.
|
||||
|
||||
The relation between integer division and modulo is found in [the
|
||||
`Int.mod_add_div` theorem in std][theo mod_add_div] which states
|
||||
that `a % b + b * (a / b) = a`, unconditionally.
|
||||
|
||||
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
|
||||
[theo mod_add_div]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.mod_add_div#doc
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
#eval (7 : Int) / (0 : Int) -- 0
|
||||
#eval (0 : Int) / (7 : Int) -- 0
|
||||
|
||||
#eval (12 : Int) / (6 : Int) -- 2
|
||||
#eval (12 : Int) / (-6 : Int) -- -2
|
||||
#eval (-12 : Int) / (6 : Int) -- -2
|
||||
#eval (-12 : Int) / (-6 : Int) -- 2
|
||||
|
||||
#eval (12 : Int) / (7 : Int) -- 1
|
||||
#eval (12 : Int) / (-7 : Int) -- -1
|
||||
#eval (-12 : Int) / (7 : Int) -- -1
|
||||
#eval (-12 : Int) / (-7 : Int) -- 1
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_div"]
|
||||
def div : (@& Int) → (@& Int) → Int
|
||||
| ofNat m, ofNat n => ofNat (m / n)
|
||||
@@ -281,36 +141,6 @@ def div : (@& Int) → (@& Int) → Int
|
||||
| negSucc m, ofNat n => -ofNat (succ m / n)
|
||||
| negSucc m, negSucc n => ofNat (succ m / succ n)
|
||||
|
||||
instance : Div Int where
|
||||
div := Int.div
|
||||
|
||||
/-- Integer modulo. This function uses the
|
||||
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
||||
to pair with `Int.div`, meaning that `a % b + b * (a / b) = a`
|
||||
unconditionally (see [`Int.mod_add_div`][theo mod_add_div]). In
|
||||
particular, `a % 0 = a`.
|
||||
|
||||
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862
|
||||
[theo mod_add_div]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.mod_add_div#doc
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
#eval (7 : Int) % (0 : Int) -- 7
|
||||
#eval (0 : Int) % (7 : Int) -- 0
|
||||
|
||||
#eval (12 : Int) % (6 : Int) -- 0
|
||||
#eval (12 : Int) % (-6 : Int) -- 0
|
||||
#eval (-12 : Int) % (6 : Int) -- 0
|
||||
#eval (-12 : Int) % (-6 : Int) -- 0
|
||||
|
||||
#eval (12 : Int) % (7 : Int) -- 5
|
||||
#eval (12 : Int) % (-7 : Int) -- 5
|
||||
#eval (-12 : Int) % (7 : Int) -- 2
|
||||
#eval (-12 : Int) % (-7 : Int) -- 2
|
||||
```
|
||||
|
||||
Implemented by efficient native code. -/
|
||||
@[extern "lean_int_mod"]
|
||||
def mod : (@& Int) → (@& Int) → Int
|
||||
| ofNat m, ofNat n => ofNat (m % n)
|
||||
@@ -318,31 +148,16 @@ def mod : (@& Int) → (@& Int) → Int
|
||||
| negSucc m, ofNat n => -ofNat (succ m % n)
|
||||
| negSucc m, negSucc n => -ofNat (succ m % succ n)
|
||||
|
||||
instance : Div Int where
|
||||
div := Int.div
|
||||
|
||||
instance : Mod Int where
|
||||
mod := Int.mod
|
||||
|
||||
/-- Turns an integer into a natural number, negative numbers become
|
||||
`0`.
|
||||
|
||||
```
|
||||
#eval (7 : Int).toNat -- 7
|
||||
#eval (0 : Int).toNat -- 0
|
||||
#eval (-7 : Int).toNat -- 0
|
||||
```
|
||||
-/
|
||||
def toNat : Int → Nat
|
||||
| ofNat n => n
|
||||
| negSucc _ => 0
|
||||
|
||||
/-- Power of an integer to some natural number.
|
||||
|
||||
```
|
||||
#eval (2 : Int) ^ 4 -- 16
|
||||
#eval (10 : Int) ^ 0 -- 1
|
||||
#eval (0 : Int) ^ 10 -- 0
|
||||
#eval (-7 : Int) ^ 3 -- -343
|
||||
```
|
||||
-/
|
||||
protected def pow (m : Int) : Nat → Int
|
||||
| 0 => 1
|
||||
| succ n => Int.pow m n * m
|
||||
|
||||
@@ -98,7 +98,7 @@ instance : Append (List α) := ⟨List.append⟩
|
||||
|
||||
@[simp] theorem cons_append (a : α) (as bs : List α) : (a::as) ++ bs = a::(as ++ bs) := rfl
|
||||
|
||||
@[simp] theorem append_eq (as bs : List α) : List.append as bs = as ++ bs := rfl
|
||||
@[simp] theorem List.append_eq (as bs : List α) : List.append as bs = as ++ bs := rfl
|
||||
|
||||
theorem append_assoc (as bs cs : List α) : (as ++ bs) ++ cs = as ++ (bs ++ cs) := by
|
||||
induction as with
|
||||
@@ -285,7 +285,7 @@ def dropWhile (p : α → Bool) : List α → List α
|
||||
| [] => []
|
||||
| a::l => match p a with
|
||||
| true => dropWhile p l
|
||||
| false => a::l
|
||||
| false => a::l
|
||||
|
||||
/--
|
||||
`O(|l|)`. `find? p l` returns the first element for which `p` returns true,
|
||||
@@ -434,17 +434,17 @@ where
|
||||
such that adjacent elements are related by `R`.
|
||||
|
||||
* `groupBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
|
||||
* `groupBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
|
||||
* `groupBy (·<·) [1, 2, 5, 4, 5, 4, 1] = [[1, 2, 5], [4, 5], [4], [1]]`
|
||||
-/
|
||||
@[specialize] def groupBy (R : α → α → Bool) : List α → List (List α)
|
||||
| [] => []
|
||||
| a::as => loop as a [] []
|
||||
| a::as => loop as [[a]]
|
||||
where
|
||||
@[specialize] loop : List α → α → List α → List (List α) → List (List α)
|
||||
| a::as, ag, g, gs => match R ag a with
|
||||
| true => loop as a (ag::g) gs
|
||||
| false => loop as a [] ((ag::g).reverse::gs)
|
||||
| [], ag, g, gs => ((ag::g).reverse::gs).reverse
|
||||
@[specialize] loop : List α → List (List α) → List (List α)
|
||||
| a::as, (ag::g)::gs => match R ag a with
|
||||
| true => loop as ((a::ag::g)::gs)
|
||||
| false => loop as ([a]::(ag::g).reverse::gs)
|
||||
| _, gs => gs.reverse
|
||||
|
||||
/--
|
||||
`O(|l|)`. `lookup a l` treats `l : List (α × β)` like an association list,
|
||||
@@ -524,7 +524,7 @@ def takeWhile (p : α → Bool) : (xs : List α) → List α
|
||||
|
||||
/--
|
||||
`O(|l|)`. Returns true if `p` is true for every element of `l`.
|
||||
* `all p [a, b, c] = p a && p b && p c`
|
||||
* `any p [a, b, c] = p a && p b && p c`
|
||||
-/
|
||||
@[inline] def all (l : List α) (p : α → Bool) : Bool :=
|
||||
foldr (fun a r => p a && r) true l
|
||||
@@ -814,9 +814,9 @@ def maximum? [Max α] : List α → Option α
|
||||
|
||||
/--
|
||||
Returns the smallest element of the list, if it is not empty.
|
||||
* `[].minimum? = none`
|
||||
* `[4].minimum? = some 4`
|
||||
* `[1, 4, 2, 10, 6].minimum? = some 1`
|
||||
* `[].maximum? = none`
|
||||
* `[4].maximum? = some 4`
|
||||
* `[1, 4, 2, 10, 6].maximum? = some 1`
|
||||
-/
|
||||
def minimum? [Min α] : List α → Option α
|
||||
| [] => none
|
||||
|
||||
@@ -102,7 +102,7 @@ def foldrM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} (f : α
|
||||
l.reverse.foldlM (fun s a => f a s) init
|
||||
|
||||
@[specialize]
|
||||
def firstM {m : Type u → Type v} [Alternative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m β
|
||||
def firstM {m : Type u → Type v} [Monad m] [Alternative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m β
|
||||
| [] => failure
|
||||
| a::as => f a <|> firstM f as
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ attribute [simp] Nat.lt_irrefl
|
||||
theorem ne_of_lt {a b : Nat} (h : a < b) : a ≠ b :=
|
||||
fun he => absurd (he ▸ h) (Nat.lt_irrefl a)
|
||||
|
||||
theorem le_or_eq_of_le_succ {m n : Nat} (h : m ≤ succ n) : m ≤ n ∨ m = succ n :=
|
||||
theorem le_or_eq_or_le_succ {m n : Nat} (h : m ≤ succ n) : m ≤ n ∨ m = succ n :=
|
||||
Decidable.byCases
|
||||
(fun (h' : m = succ n) => Or.inr h')
|
||||
(fun (h' : m ≠ succ n) =>
|
||||
@@ -484,7 +484,7 @@ theorem pow_le_pow_of_le_right {n : Nat} (hx : n > 0) {i : Nat} : ∀ {j}, i ≤
|
||||
have : i = 0 := eq_zero_of_le_zero h
|
||||
this.symm ▸ Nat.le_refl _
|
||||
| succ j, h =>
|
||||
match le_or_eq_of_le_succ h with
|
||||
match le_or_eq_or_le_succ h with
|
||||
| Or.inl h => show n^i ≤ n^j * n from
|
||||
have : n^i * 1 ≤ n^j * n := Nat.mul_le_mul (pow_le_pow_of_le_right hx h) hx
|
||||
Nat.mul_one (n^i) ▸ this
|
||||
@@ -496,6 +496,8 @@ theorem pos_pow_of_pos {n : Nat} (m : Nat) (h : 0 < n) : 0 < n^m :=
|
||||
|
||||
/-! # min/max -/
|
||||
|
||||
instance : Min Nat := minOfLe
|
||||
|
||||
/--
|
||||
`Nat.min a b` is the minimum of `a` and `b`:
|
||||
* if `a ≤ b` then `Nat.min a b = a`
|
||||
@@ -620,12 +622,6 @@ theorem le_add_of_sub_le {a b c : Nat} (h : a - b ≤ c) : a ≤ c + b := by
|
||||
have hd := Nat.eq_add_of_sub_eq (Nat.le_trans hge (Nat.le_add_left ..)) hd
|
||||
rw [Nat.add_comm, hd]
|
||||
|
||||
protected theorem sub_lt_sub_left : ∀ {k m n : Nat}, k < m → k < n → m - n < m - k
|
||||
| 0, m+1, n+1, _, _ => by rw [Nat.add_sub_add_right]; exact lt_succ_of_le (Nat.sub_le _ _)
|
||||
| k+1, m+1, n+1, h1, h2 => by
|
||||
rw [Nat.add_sub_add_right, Nat.add_sub_add_right]
|
||||
exact Nat.sub_lt_sub_left (Nat.lt_of_succ_lt_succ h1) (Nat.lt_of_succ_lt_succ h2)
|
||||
|
||||
@[simp] protected theorem zero_sub (n : Nat) : 0 - n = 0 := by
|
||||
induction n with
|
||||
| zero => rfl
|
||||
|
||||
@@ -65,34 +65,19 @@ theorem div_lt_self {n k : Nat} (hLtN : 0 < n) (hLtK : 1 < k) : n / k < n := by
|
||||
exact Nat.lt_of_lt_of_le (Nat.add_lt_add_left hLtK _) this
|
||||
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def modCore (x y : @& Nat) : Nat :=
|
||||
protected def mod (x y : @& Nat) : Nat :=
|
||||
if 0 < y ∧ y ≤ x then
|
||||
Nat.modCore (x - y) y
|
||||
Nat.mod (x - y) y
|
||||
else
|
||||
x
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def mod : @& Nat → @& Nat → Nat
|
||||
/- This case is not needed mathematically as the case below is equal to it; however, it makes
|
||||
`0 % n = 0` true definitionally rather than just propositionally.
|
||||
This property is desirable for `Fin n`, as it means `(ofNat 0 : Fin n).val = 0` by definition.
|
||||
Primarily, this is valuable because mathlib in Lean3 assumed this was true definitionally, and so
|
||||
keeping this definitional equality makes mathlib easier to port to mathlib4. -/
|
||||
| 0, _ => 0
|
||||
| x@(_ + 1), y => Nat.modCore x y
|
||||
|
||||
instance : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (x y : Nat) : Nat.modCore x y = x % y := by
|
||||
cases x with
|
||||
| zero =>
|
||||
rw [Nat.modCore]
|
||||
exact if_neg fun ⟨hlt, hle⟩ => Nat.lt_irrefl _ (Nat.lt_of_lt_of_le hlt hle)
|
||||
| succ x => rfl
|
||||
|
||||
theorem mod_eq (x y : Nat) : x % y = if 0 < y ∧ y ≤ x then (x - y) % y else x := by
|
||||
rw [←Nat.modCore_eq_mod, ←Nat.modCore_eq_mod, Nat.modCore]
|
||||
show Nat.mod x y = _
|
||||
rw [Nat.mod]
|
||||
rfl
|
||||
|
||||
theorem mod.inductionOn.{u}
|
||||
{motive : Nat → Nat → Sort u}
|
||||
@@ -102,7 +87,7 @@ theorem mod.inductionOn.{u}
|
||||
: motive x y :=
|
||||
div.inductionOn x y ind base
|
||||
|
||||
@[simp] theorem mod_zero (a : Nat) : a % 0 = a :=
|
||||
theorem mod_zero (a : Nat) : a % 0 = a :=
|
||||
have : (if 0 < 0 ∧ 0 ≤ a then (a - 0) % 0 else a) = a :=
|
||||
have h : ¬ (0 < 0 ∧ 0 ≤ a) := fun ⟨h₁, _⟩ => absurd h₁ (Nat.lt_irrefl _)
|
||||
if_neg h
|
||||
|
||||
@@ -28,12 +28,7 @@ theorem gcd_succ (x y : Nat) : gcd (succ x) y = gcd (y % succ x) (succ x) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem gcd_zero_right (n : Nat) : gcd n 0 = n := by
|
||||
cases n with
|
||||
| zero => simp [gcd_succ]
|
||||
| succ n =>
|
||||
-- `simp [gcd_succ]` produces an invalid term unless `gcd_succ` is proved with `id rfl` instead
|
||||
rw [gcd_succ]
|
||||
exact gcd_zero_left _
|
||||
cases n <;> simp [gcd_succ]
|
||||
|
||||
@[simp] theorem gcd_self (n : Nat) : gcd n n = n := by
|
||||
cases n <;> simp [gcd_succ]
|
||||
|
||||
@@ -353,7 +353,7 @@ theorem Poly.denote_eq_cancelAux (ctx : Context) (fuel : Nat) (m₁ m₂ r₁ r
|
||||
| zero => assumption
|
||||
| succ fuel ih =>
|
||||
simp
|
||||
split <;> try (simp at h; try assumption)
|
||||
split <;> simp at h <;> try assumption
|
||||
rename_i k₁ v₁ m₁ k₂ v₂ m₂
|
||||
by_cases hltv : Nat.blt v₁ v₂ <;> simp [hltv]
|
||||
· apply ih; simp [denote_eq] at h |-; assumption
|
||||
@@ -387,7 +387,7 @@ theorem Poly.of_denote_eq_cancelAux (ctx : Context) (fuel : Nat) (m₁ m₂ r₁
|
||||
| zero => assumption
|
||||
| succ fuel ih =>
|
||||
simp at h
|
||||
split at h <;> (try simp; assumption)
|
||||
split at h <;> simp <;> try assumption
|
||||
rename_i k₁ v₁ m₁ k₂ v₂ m₂
|
||||
by_cases hltv : Nat.blt v₁ v₂ <;> simp [hltv] at h
|
||||
· have ih := ih (h := h); simp [denote_eq] at ih ⊢; assumption
|
||||
@@ -413,9 +413,10 @@ theorem Poly.of_denote_eq_cancelAux (ctx : Context) (fuel : Nat) (m₁ m₂ r₁
|
||||
rw [← Nat.add_assoc, ih, Nat.add_assoc]
|
||||
|
||||
theorem Poly.denote_eq_cancel {ctx : Context} {m₁ m₂ : Poly} (h : denote_eq ctx (m₁, m₂)) : denote_eq ctx (cancel m₁ m₂) := by
|
||||
apply denote_eq_cancelAux; simp [h]
|
||||
simp; apply denote_eq_cancelAux; simp [h]
|
||||
|
||||
theorem Poly.of_denote_eq_cancel {ctx : Context} {m₁ m₂ : Poly} (h : denote_eq ctx (cancel m₁ m₂)) : denote_eq ctx (m₁, m₂) := by
|
||||
simp at h
|
||||
have := Poly.of_denote_eq_cancelAux (h := h)
|
||||
simp at this
|
||||
assumption
|
||||
@@ -431,7 +432,7 @@ theorem Poly.denote_le_cancelAux (ctx : Context) (fuel : Nat) (m₁ m₂ r₁ r
|
||||
| zero => assumption
|
||||
| succ fuel ih =>
|
||||
simp
|
||||
split <;> try (simp at h; assumption)
|
||||
split <;> simp at h <;> try assumption
|
||||
rename_i k₁ v₁ m₁ k₂ v₂ m₂
|
||||
by_cases hltv : Nat.blt v₁ v₂ <;> simp [hltv]
|
||||
· apply ih; simp [denote_le] at h |-; assumption
|
||||
@@ -465,7 +466,7 @@ theorem Poly.of_denote_le_cancelAux (ctx : Context) (fuel : Nat) (m₁ m₂ r₁
|
||||
| zero => assumption
|
||||
| succ fuel ih =>
|
||||
simp at h
|
||||
split at h <;> try (simp; assumption)
|
||||
split at h <;> simp <;> try assumption
|
||||
rename_i k₁ v₁ m₁ k₂ v₂ m₂
|
||||
by_cases hltv : Nat.blt v₁ v₂ <;> simp [hltv] at h
|
||||
· have ih := ih (h := h); simp [denote_le] at ih ⊢; assumption
|
||||
@@ -493,9 +494,10 @@ theorem Poly.of_denote_le_cancelAux (ctx : Context) (fuel : Nat) (m₁ m₂ r₁
|
||||
exact this
|
||||
|
||||
theorem Poly.denote_le_cancel {ctx : Context} {m₁ m₂ : Poly} (h : denote_le ctx (m₁, m₂)) : denote_le ctx (cancel m₁ m₂) := by
|
||||
apply denote_le_cancelAux; simp [h]
|
||||
simp; apply denote_le_cancelAux; simp [h]
|
||||
|
||||
theorem Poly.of_denote_le_cancel {ctx : Context} {m₁ m₂ : Poly} (h : denote_le ctx (cancel m₁ m₂)) : denote_le ctx (m₁, m₂) := by
|
||||
simp at h
|
||||
have := Poly.of_denote_le_cancelAux (h := h)
|
||||
simp at this
|
||||
assumption
|
||||
@@ -615,7 +617,7 @@ attribute [local simp] PolyCnstr.denote_combine
|
||||
theorem Poly.isNum?_eq_some (ctx : Context) {p : Poly} {k : Nat} : p.isNum? = some k → p.denote ctx = k := by
|
||||
simp [isNum?]
|
||||
split
|
||||
next => intro h; injection h
|
||||
next => intro h; injection h; subst k; simp
|
||||
next k v => by_cases h : v == fixedVar <;> simp [h]; intros; simp [Var.denote, eq_of_beq h]; assumption
|
||||
next => intros; contradiction
|
||||
|
||||
|
||||
@@ -27,11 +27,3 @@ Computes `⌊max 0 (log₂ n)⌋`.
|
||||
def log2 (n : @& Nat) : Nat :=
|
||||
if n ≥ 2 then log2 (n / 2) + 1 else 0
|
||||
decreasing_by exact log2_terminates _ ‹_›
|
||||
|
||||
theorem log2_le_self (n : Nat) : Nat.log2 n ≤ n := by
|
||||
unfold Nat.log2; split
|
||||
· next h =>
|
||||
have := log2_le_self (n / 2)
|
||||
exact Nat.lt_of_le_of_lt this (Nat.div_lt_self (Nat.le_of_lt h) (by decide))
|
||||
· apply Nat.zero_le
|
||||
decreasing_by exact Nat.log2_terminates _ ‹_›
|
||||
|
||||
@@ -7,7 +7,7 @@ prelude
|
||||
import Init.Data.Format.Basic
|
||||
import Init.Data.Int.Basic
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt
|
||||
import Init.Control.Id
|
||||
open Sum Subtype Nat
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ def append : String → (@& String) → String
|
||||
def toList (s : String) : List Char :=
|
||||
s.data
|
||||
|
||||
def utf8GetAux : List Char → Pos → Pos → Char
|
||||
private def utf8GetAux : List Char → Pos → Pos → Char
|
||||
| [], _, _ => default
|
||||
| c::cs, i, p => if i = p then c else utf8GetAux cs (i + c) p
|
||||
|
||||
@@ -58,9 +58,9 @@ def get (s : @& String) (p : @& Pos) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
|
||||
def utf8GetAux? : List Char → Pos → Pos → Option Char
|
||||
private def utf8GetAux? : List Char → Pos → Pos → Option Char
|
||||
| [], _, _ => none
|
||||
| c::cs, i, p => if i = p then c else utf8GetAux? cs (i + c) p
|
||||
| c::cs, i, p => if i = p then c else utf8GetAux cs (i + c) p
|
||||
|
||||
@[extern "lean_string_utf8_get_opt"]
|
||||
def get? : (@& String) → (@& Pos) → Option Char
|
||||
@@ -74,7 +74,7 @@ def get! (s : @& String) (p : @& Pos) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
|
||||
def utf8SetAux (c' : Char) : List Char → Pos → Pos → List Char
|
||||
private def utf8SetAux (c' : Char) : List Char → Pos → Pos → List Char
|
||||
| [], _, _ => []
|
||||
| c::cs, i, p =>
|
||||
if i = p then (c'::cs) else c::(utf8SetAux c' cs (i + c) p)
|
||||
@@ -91,7 +91,7 @@ def next (s : @& String) (p : @& Pos) : Pos :=
|
||||
let c := get s p
|
||||
p + c
|
||||
|
||||
def utf8PrevAux : List Char → Pos → Pos → Pos
|
||||
private def utf8PrevAux : List Char → Pos → Pos → Pos
|
||||
| [], _, _ => 0
|
||||
| c::cs, i, p =>
|
||||
let i' := i + c
|
||||
@@ -119,106 +119,62 @@ def get' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
|
||||
/--
|
||||
Similar to `next` but runtime does not perform bounds check.
|
||||
-/
|
||||
@[extern "lean_string_utf8_next_fast"]
|
||||
def next' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Pos :=
|
||||
let c := get s p
|
||||
p + c
|
||||
|
||||
theorem one_le_csize (c : Char) : 1 ≤ csize c := by
|
||||
repeat first | apply iteInduction (motive := (1 ≤ UInt32.toNat ·)) <;> intros | decide
|
||||
/- TODO: remove `partial` keywords after we restore the tactic
|
||||
framework and wellfounded recursion support -/
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
|
||||
@[simp] theorem pos_add_char (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + csize c := rfl
|
||||
|
||||
theorem lt_next (s : String) (i : Pos) : i.1 < (s.next i).1 :=
|
||||
Nat.add_lt_add_left (one_le_csize _) _
|
||||
|
||||
theorem utf8PrevAux_lt_of_pos : ∀ (cs : List Char) (i p : Pos), p ≠ 0 →
|
||||
(utf8PrevAux cs i p).1 < p.1
|
||||
| [], i, p, h =>
|
||||
Nat.lt_of_le_of_lt (Nat.zero_le _)
|
||||
(Nat.zero_lt_of_ne_zero (mt (congrArg Pos.mk) h))
|
||||
| c::cs, i, p, h => by
|
||||
simp [utf8PrevAux]
|
||||
apply iteInduction (motive := (Pos.byteIdx · < _)) <;> intro h'
|
||||
next => exact h' ▸ Nat.add_lt_add_left (one_le_csize _) _
|
||||
next => exact utf8PrevAux_lt_of_pos _ _ _ h
|
||||
|
||||
theorem prev_lt_of_pos (s : String) (i : Pos) (h : i ≠ 0) : (s.prev i).1 < i.1 := by
|
||||
simp [prev, h]
|
||||
exact utf8PrevAux_lt_of_pos _ _ _ h
|
||||
|
||||
def posOfAux (s : String) (c : Char) (stopPos : Pos) (pos : Pos) : Pos :=
|
||||
if h : pos < stopPos then
|
||||
if s.get pos == c then pos
|
||||
else
|
||||
have := Nat.sub_lt_sub_left h (lt_next s pos)
|
||||
posOfAux s c stopPos (s.next pos)
|
||||
else pos
|
||||
termination_by _ => stopPos.1 - pos.1
|
||||
partial def posOfAux (s : String) (c : Char) (stopPos : Pos) (pos : Pos) : Pos :=
|
||||
if pos >= stopPos then pos
|
||||
else if s.get pos == c then pos
|
||||
else posOfAux s c stopPos (s.next pos)
|
||||
|
||||
@[inline] def posOf (s : String) (c : Char) : Pos :=
|
||||
posOfAux s c s.endPos 0
|
||||
|
||||
def revPosOfAux (s : String) (c : Char) (pos : Pos) : Option Pos :=
|
||||
if h : pos = 0 then none
|
||||
else
|
||||
have := prev_lt_of_pos s pos h
|
||||
let pos := s.prev pos
|
||||
if s.get pos == c then some pos
|
||||
else revPosOfAux s c pos
|
||||
termination_by _ => pos.1
|
||||
partial def revPosOfAux (s : String) (c : Char) (pos : Pos) : Option Pos :=
|
||||
if s.get pos == c then some pos
|
||||
else if pos == 0 then none
|
||||
else revPosOfAux s c (s.prev pos)
|
||||
|
||||
def revPosOf (s : String) (c : Char) : Option Pos :=
|
||||
revPosOfAux s c s.endPos
|
||||
if s.endPos == 0 then none
|
||||
else revPosOfAux s c (s.prev s.endPos)
|
||||
|
||||
def findAux (s : String) (p : Char → Bool) (stopPos : Pos) (pos : Pos) : Pos :=
|
||||
if h : pos < stopPos then
|
||||
if p (s.get pos) then pos
|
||||
else
|
||||
have := Nat.sub_lt_sub_left h (lt_next s pos)
|
||||
findAux s p stopPos (s.next pos)
|
||||
else pos
|
||||
termination_by _ => stopPos.1 - pos.1
|
||||
partial def findAux (s : String) (p : Char → Bool) (stopPos : Pos) (pos : Pos) : Pos :=
|
||||
if pos >= stopPos then pos
|
||||
else if p (s.get pos) then pos
|
||||
else findAux s p stopPos (s.next pos)
|
||||
|
||||
@[inline] def find (s : String) (p : Char → Bool) : Pos :=
|
||||
findAux s p s.endPos 0
|
||||
|
||||
def revFindAux (s : String) (p : Char → Bool) (pos : Pos) : Option Pos :=
|
||||
if h : pos = 0 then none
|
||||
else
|
||||
have := prev_lt_of_pos s pos h
|
||||
let pos := s.prev pos
|
||||
if p (s.get pos) then some pos
|
||||
else revFindAux s p pos
|
||||
termination_by _ => pos.1
|
||||
partial def revFindAux (s : String) (p : Char → Bool) (pos : Pos) : Option Pos :=
|
||||
if p (s.get pos) then some pos
|
||||
else if pos == 0 then none
|
||||
else revFindAux s p (s.prev pos)
|
||||
|
||||
def revFind (s : String) (p : Char → Bool) : Option Pos :=
|
||||
revFindAux s p s.endPos
|
||||
if s.endPos == 0 then none
|
||||
else revFindAux s p (s.prev s.endPos)
|
||||
|
||||
abbrev Pos.min (p₁ p₂ : Pos) : Pos :=
|
||||
{ byteIdx := p₁.byteIdx.min p₂.byteIdx }
|
||||
|
||||
/-- Returns the first position where the two strings differ. -/
|
||||
def firstDiffPos (a b : String) : Pos :=
|
||||
partial def firstDiffPos (a b : String) : Pos :=
|
||||
let stopPos := a.endPos.min b.endPos
|
||||
let rec loop (i : Pos) : Pos :=
|
||||
if h : i < stopPos then
|
||||
if a.get i != b.get i then i
|
||||
else
|
||||
have := Nat.sub_lt_sub_left h (lt_next a i)
|
||||
loop (a.next i)
|
||||
else i
|
||||
if i >= stopPos || a.get i != b.get i then i
|
||||
else loop (a.next i)
|
||||
loop 0
|
||||
termination_by loop => stopPos.1 - i.1
|
||||
|
||||
@[extern "lean_string_utf8_extract"]
|
||||
def extract : (@& String) → (@& Pos) → (@& Pos) → String
|
||||
| ⟨s⟩, b, e => if b.byteIdx ≥ e.byteIdx then "" else ⟨go₁ s 0 b e⟩
|
||||
| ⟨s⟩, b, e => if b.byteIdx ≥ e.byteIdx then ⟨[]⟩ else ⟨go₁ s 0 b e⟩
|
||||
where
|
||||
go₁ : List Char → Pos → Pos → Pos → List Char
|
||||
| [], _, _, _ => []
|
||||
@@ -229,38 +185,32 @@ where
|
||||
| c::cs, i, e => if i = e then [] else c :: go₂ cs (i + c) e
|
||||
|
||||
|
||||
@[specialize] def splitAux (s : String) (p : Char → Bool) (b : Pos) (i : Pos) (r : List String) : List String :=
|
||||
if h : s.atEnd i then
|
||||
@[specialize] partial def splitAux (s : String) (p : Char → Bool) (b : Pos) (i : Pos) (r : List String) : List String :=
|
||||
if s.atEnd i then
|
||||
let r := (s.extract b i)::r
|
||||
r.reverse
|
||||
else if p (s.get i) then
|
||||
let i := s.next i
|
||||
splitAux s p i i (s.extract b { byteIdx := i.byteIdx - 1 } :: r)
|
||||
else
|
||||
have := Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next s _)
|
||||
if p (s.get i) then
|
||||
let i' := s.next i
|
||||
splitAux s p i' i' (s.extract b i :: r)
|
||||
else
|
||||
splitAux s p b (s.next i) r
|
||||
termination_by _ => s.endPos.1 - i.1
|
||||
splitAux s p b (s.next i) r
|
||||
|
||||
@[specialize] def split (s : String) (p : Char → Bool) : List String :=
|
||||
splitAux s p 0 0 []
|
||||
|
||||
def splitOnAux (s sep : String) (b : Pos) (i : Pos) (j : Pos) (r : List String) : List String :=
|
||||
if h : s.atEnd i then
|
||||
let r := (s.extract b i)::r
|
||||
partial def splitOnAux (s sep : String) (b : Pos) (i : Pos) (j : Pos) (r : List String) : List String :=
|
||||
if s.atEnd i then
|
||||
let r := if sep.atEnd j then ""::(s.extract b (i - j))::r else (s.extract b i)::r
|
||||
r.reverse
|
||||
else
|
||||
have := Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next s _)
|
||||
if s.get i == sep.get j then
|
||||
let i := s.next i
|
||||
let j := sep.next j
|
||||
if sep.atEnd j then
|
||||
splitOnAux s sep i i 0 (s.extract b (i - j)::r)
|
||||
else
|
||||
splitOnAux s sep b i j r
|
||||
else if s.get i == sep.get j then
|
||||
let i := s.next i
|
||||
let j := sep.next j
|
||||
if sep.atEnd j then
|
||||
splitOnAux s sep i i 0 (s.extract b (i - j)::r)
|
||||
else
|
||||
splitOnAux s sep b (s.next i) 0 r
|
||||
termination_by _ => s.endPos.1 - i.1
|
||||
splitOnAux s sep b i j r
|
||||
else
|
||||
splitOnAux s sep b (s.next i) 0 r
|
||||
|
||||
def splitOn (s : String) (sep : String := " ") : List String :=
|
||||
if sep == "" then [s] else splitOnAux s sep 0 0 0 []
|
||||
@@ -362,108 +312,55 @@ def prevn : Iterator → Nat → Iterator
|
||||
| it, i+1 => prevn it.prev i
|
||||
end Iterator
|
||||
|
||||
def offsetOfPosAux (s : String) (pos : Pos) (i : Pos) (offset : Nat) : Nat :=
|
||||
if i >= pos then offset
|
||||
else if h : s.atEnd i then
|
||||
partial def offsetOfPosAux (s : String) (pos : Pos) (i : Pos) (offset : Nat) : Nat :=
|
||||
if i >= pos || s.atEnd i then
|
||||
offset
|
||||
else
|
||||
have := Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next s _)
|
||||
offsetOfPosAux s pos (s.next i) (offset+1)
|
||||
termination_by _ => s.endPos.1 - i.1
|
||||
|
||||
def offsetOfPos (s : String) (pos : Pos) : Nat :=
|
||||
offsetOfPosAux s pos 0 0
|
||||
|
||||
@[specialize] def foldlAux {α : Type u} (f : α → Char → α) (s : String) (stopPos : Pos) (i : Pos) (a : α) : α :=
|
||||
if h : i < stopPos then
|
||||
have := Nat.sub_lt_sub_left h (lt_next s i)
|
||||
foldlAux f s stopPos (s.next i) (f a (s.get i))
|
||||
else a
|
||||
termination_by _ => stopPos.1 - i.1
|
||||
@[specialize] partial def foldlAux {α : Type u} (f : α → Char → α) (s : String) (stopPos : Pos) (i : Pos) (a : α) : α :=
|
||||
let rec loop (i : Pos) (a : α) :=
|
||||
if i >= stopPos then a
|
||||
else loop (s.next i) (f a (s.get i))
|
||||
loop i a
|
||||
|
||||
@[inline] def foldl {α : Type u} (f : α → Char → α) (init : α) (s : String) : α :=
|
||||
foldlAux f s s.endPos 0 init
|
||||
|
||||
@[specialize] def foldrAux {α : Type u} (f : Char → α → α) (a : α) (s : String) (i begPos : Pos) : α :=
|
||||
if h : begPos < i then
|
||||
have := String.prev_lt_of_pos s i <| mt (congrArg String.Pos.byteIdx) <|
|
||||
Ne.symm <| Nat.ne_of_lt <| Nat.lt_of_le_of_lt (Nat.zero_le _) h
|
||||
let i := s.prev i
|
||||
let a := f (s.get i) a
|
||||
foldrAux f a s i begPos
|
||||
else a
|
||||
termination_by _ => i.1
|
||||
@[specialize] partial def foldrAux {α : Type u} (f : Char → α → α) (a : α) (s : String) (stopPos : Pos) (i : Pos) : α :=
|
||||
let rec loop (i : Pos) :=
|
||||
if i >= stopPos then a
|
||||
else f (s.get i) (loop (s.next i))
|
||||
loop i
|
||||
|
||||
@[inline] def foldr {α : Type u} (f : Char → α → α) (init : α) (s : String) : α :=
|
||||
foldrAux f init s s.endPos 0
|
||||
|
||||
@[specialize] def anyAux (s : String) (stopPos : Pos) (p : Char → Bool) (i : Pos) : Bool :=
|
||||
if h : i < stopPos then
|
||||
if p (s.get i) then true
|
||||
else
|
||||
have := Nat.sub_lt_sub_left h (lt_next s i)
|
||||
anyAux s stopPos p (s.next i)
|
||||
else false
|
||||
termination_by _ => stopPos.1 - i.1
|
||||
@[specialize] partial def anyAux (s : String) (stopPos : Pos) (p : Char → Bool) (i : Pos) : Bool :=
|
||||
let rec loop (i : Pos) :=
|
||||
if i >= stopPos then false
|
||||
else if p (s.get i) then true
|
||||
else loop (s.next i)
|
||||
loop i
|
||||
|
||||
@[inline] def any (s : String) (p : Char → Bool) : Bool :=
|
||||
anyAux s s.endPos p 0
|
||||
anyAux s s.endPos p 0
|
||||
|
||||
@[inline] def all (s : String) (p : Char → Bool) : Bool :=
|
||||
!s.any (fun c => !p c)
|
||||
!s.any (fun c => !p c)
|
||||
|
||||
def contains (s : String) (c : Char) : Bool :=
|
||||
s.any (fun a => a == c)
|
||||
|
||||
theorem utf8SetAux_of_gt (c' : Char) : ∀ (cs : List Char) {i p : Pos}, i > p → utf8SetAux c' cs i p = cs
|
||||
| [], _, _, _ => rfl
|
||||
| c::cs, i, p, h => by
|
||||
rw [utf8SetAux, if_neg (mt (congrArg (·.1)) (Ne.symm <| Nat.ne_of_lt h)), utf8SetAux_of_gt c' cs]
|
||||
exact Nat.lt_of_lt_of_le h (Nat.le_add_right ..)
|
||||
|
||||
theorem set_next_add (s : String) (i : Pos) (c : Char) (b₁ b₂)
|
||||
(h : (s.next i).1 + b₁ = s.endPos.1 + b₂) :
|
||||
((s.set i c).next i).1 + b₁ = (s.set i c).endPos.1 + b₂ := by
|
||||
simp [next, get, set, endPos, utf8ByteSize] at h ⊢
|
||||
rw [Nat.add_comm i.1, Nat.add_assoc] at h ⊢
|
||||
let rec foo : ∀ cs a b₁ b₂,
|
||||
csize (utf8GetAux cs a i) + b₁ = utf8ByteSize.go cs + b₂ →
|
||||
csize (utf8GetAux (utf8SetAux c cs a i) a i) + b₁ = utf8ByteSize.go (utf8SetAux c cs a i) + b₂
|
||||
| [], _, _, _, h => h
|
||||
| c'::cs, a, b₁, b₂, h => by
|
||||
unfold utf8SetAux
|
||||
apply iteInduction (motive := fun p => csize (utf8GetAux p a i) + b₁ = utf8ByteSize.go p + b₂) <;>
|
||||
intro h' <;> simp [utf8GetAux, h', utf8ByteSize.go] at h ⊢
|
||||
next =>
|
||||
rw [Nat.add_assoc, Nat.add_left_comm] at h ⊢; rw [Nat.add_left_cancel h]
|
||||
next =>
|
||||
rw [Nat.add_assoc] at h ⊢
|
||||
refine foo cs (a + c') b₁ (csize c' + b₂) h
|
||||
exact foo s.1 0 _ _ h
|
||||
|
||||
theorem mapAux_lemma (s : String) (i : Pos) (c : Char) (h : ¬s.atEnd i) :
|
||||
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 :=
|
||||
suffices (s.set i c).endPos.1 - ((s.set i c).next i).1 = s.endPos.1 - (s.next i).1 by
|
||||
rw [this]
|
||||
apply Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next ..)
|
||||
Nat.sub.elim (motive := (_ = ·)) _ _
|
||||
(fun _ k e =>
|
||||
have := set_next_add _ _ _ k 0 e.symm
|
||||
Nat.sub_eq_of_eq_add <| this.symm.trans <| Nat.add_comm ..)
|
||||
(fun h => by
|
||||
have ⟨k, e⟩ := Nat.le.dest h
|
||||
rw [Nat.succ_add] at e
|
||||
have : ((s.set i c).next i).1 = _ := set_next_add _ _ c 0 k.succ e.symm
|
||||
exact Nat.sub_eq_zero_of_le (this ▸ Nat.le_add_right ..))
|
||||
|
||||
@[specialize] def mapAux (f : Char → Char) (i : Pos) (s : String) : String :=
|
||||
if h : s.atEnd i then s
|
||||
@[specialize] partial def mapAux (f : Char → Char) (i : Pos) (s : String) : String :=
|
||||
if s.atEnd i then s
|
||||
else
|
||||
let c := f (s.get i)
|
||||
have := mapAux_lemma s i c h
|
||||
let s := s.set i c
|
||||
mapAux f (s.next i) s
|
||||
termination_by _ => s.endPos.1 - i.1
|
||||
|
||||
@[inline] def map (f : Char → Char) (s : String) : String :=
|
||||
mapAux f 0 s
|
||||
@@ -480,40 +377,32 @@ def toNat? (s : String) : Option Nat :=
|
||||
/--
|
||||
Return `true` iff the substring of byte size `sz` starting at position `off1` in `s1` is equal to that starting at `off2` in `s2.`.
|
||||
False if either substring of that byte size does not exist. -/
|
||||
def substrEq (s1 : String) (off1 : String.Pos) (s2 : String) (off2 : String.Pos) (sz : Nat) : Bool :=
|
||||
partial def substrEq (s1 : String) (off1 : String.Pos) (s2 : String) (off2 : String.Pos) (sz : Nat) : Bool :=
|
||||
off1.byteIdx + sz ≤ s1.endPos.byteIdx && off2.byteIdx + sz ≤ s2.endPos.byteIdx && loop off1 off2 { byteIdx := off1.byteIdx + sz }
|
||||
where
|
||||
loop (off1 off2 stop1 : Pos) :=
|
||||
if h : off1.byteIdx < stop1.byteIdx then
|
||||
if off1.byteIdx >= stop1.byteIdx then
|
||||
true
|
||||
else
|
||||
let c₁ := s1.get off1
|
||||
let c₂ := s2.get off2
|
||||
have := Nat.sub_lt_sub_left h (Nat.add_lt_add_left (one_le_csize c₁) off1.1)
|
||||
c₁ == c₂ && loop (off1 + c₁) (off2 + c₂) stop1
|
||||
else true
|
||||
termination_by loop => stop1.1 - off1.1
|
||||
|
||||
/-- Return true iff `p` is a prefix of `s` -/
|
||||
def isPrefixOf (p : String) (s : String) : Bool :=
|
||||
substrEq p 0 s 0 p.endPos.byteIdx
|
||||
|
||||
/-- Replace all occurrences of `pattern` in `s` with `replacement`. -/
|
||||
def replace (s pattern replacement : String) : String :=
|
||||
if h : pattern.endPos.1 = 0 then s
|
||||
else
|
||||
have hPatt := Nat.zero_lt_of_ne_zero h
|
||||
let rec loop (acc : String) (accStop pos : String.Pos) :=
|
||||
if h : pos.byteIdx + pattern.endPos.byteIdx > s.endPos.byteIdx then
|
||||
acc ++ s.extract accStop s.endPos
|
||||
else
|
||||
have := Nat.lt_of_lt_of_le (Nat.add_lt_add_left hPatt _) (Nat.ge_of_not_lt h)
|
||||
if s.substrEq pos pattern 0 pattern.endPos.byteIdx then
|
||||
have := Nat.sub_lt_sub_left this (Nat.add_lt_add_left hPatt _)
|
||||
loop (acc ++ s.extract accStop pos ++ replacement) (pos + pattern) (pos + pattern)
|
||||
else
|
||||
have := Nat.sub_lt_sub_left this (lt_next s pos)
|
||||
loop acc accStop (s.next pos)
|
||||
loop "" 0 0
|
||||
termination_by loop => s.endPos.1 - pos.1
|
||||
/-- Replace all occurrences of `pattern` in `s` with `replacment`. -/
|
||||
partial def replace (s pattern replacement : String) : String :=
|
||||
loop "" 0 0
|
||||
where
|
||||
loop (acc : String) (accStop pos : String.Pos) :=
|
||||
if pos.byteIdx + pattern.endPos.byteIdx > s.endPos.byteIdx then
|
||||
acc ++ s.extract accStop s.endPos
|
||||
else if s.substrEq pos pattern 0 pattern.endPos.byteIdx then
|
||||
loop (acc ++ s.extract accStop pos ++ replacement) (pos + pattern) (pos + pattern)
|
||||
else
|
||||
loop acc accStop (s.next pos)
|
||||
|
||||
end String
|
||||
|
||||
@@ -539,15 +428,6 @@ return the offset there of the next codepoint. -/
|
||||
let absP := b+p
|
||||
if absP = e then p else { byteIdx := (s.next absP).byteIdx - b.byteIdx }
|
||||
|
||||
theorem lt_next (s : Substring) (i : String.Pos) (h : i.1 < s.bsize) :
|
||||
i.1 < (s.next i).1 := by
|
||||
simp [next]; rw [if_neg ?a]
|
||||
case a =>
|
||||
refine mt (congrArg String.Pos.byteIdx) (Nat.ne_of_lt ?_)
|
||||
exact (Nat.add_comm .. ▸ Nat.add_lt_of_lt_sub h :)
|
||||
apply Nat.lt_sub_of_add_lt
|
||||
rw [Nat.add_comm]; apply String.lt_next
|
||||
|
||||
/-- Given an offset of a codepoint into the substring,
|
||||
return the offset there of the previous codepoint. -/
|
||||
@[inline] def prev : Substring → String.Pos → String.Pos
|
||||
@@ -566,7 +446,7 @@ def prevn : Substring → Nat → String.Pos → String.Pos
|
||||
@[inline] def front (s : Substring) : Char :=
|
||||
s.get 0
|
||||
|
||||
/-- Return the offset into `s` of the first occurrence of `c` in `s`,
|
||||
/-- Return the offset into `s` of the first occurence of `c` in `s`,
|
||||
or `s.bsize` if `c` doesn't occur. -/
|
||||
@[inline] def posOf (s : Substring) (c : Char) : String.Pos :=
|
||||
match s with
|
||||
@@ -590,30 +470,27 @@ or `s.bsize` if `c` doesn't occur. -/
|
||||
@[inline] def extract : Substring → String.Pos → String.Pos → Substring
|
||||
| ⟨s, b, e⟩, b', e' => if b' ≥ e' then ⟨"", 0, 0⟩ else ⟨s, e.min (b+b'), e.min (b+e')⟩
|
||||
|
||||
def splitOn (s : Substring) (sep : String := " ") : List Substring :=
|
||||
partial def splitOn (s : Substring) (sep : String := " ") : List Substring :=
|
||||
if sep == "" then
|
||||
[s]
|
||||
else
|
||||
let rec loop (b i j : String.Pos) (r : List Substring) : List Substring :=
|
||||
if h : i.byteIdx < s.bsize then
|
||||
have := Nat.sub_lt_sub_left h (lt_next s i h)
|
||||
if s.get i == sep.get j then
|
||||
let i := s.next i
|
||||
let j := sep.next j
|
||||
if sep.atEnd j then
|
||||
loop i i 0 (s.extract b (i-j) :: r)
|
||||
else
|
||||
loop b i j r
|
||||
else
|
||||
loop b (s.next i) 0 r
|
||||
else
|
||||
if i.byteIdx == s.bsize then
|
||||
let r := if sep.atEnd j then
|
||||
"".toSubstring :: s.extract b (i-j) :: r
|
||||
else
|
||||
s.extract b i :: r
|
||||
r.reverse
|
||||
else if s.get i == sep.get j then
|
||||
let i := s.next i
|
||||
let j := sep.next j
|
||||
if sep.atEnd j then
|
||||
loop i i 0 (s.extract b (i-j) :: r)
|
||||
else
|
||||
loop b i j r
|
||||
else
|
||||
loop b (s.next i) 0 r
|
||||
loop 0 0 0 []
|
||||
termination_by loop => s.bsize - i.1
|
||||
|
||||
@[inline] def foldl {α : Type u} (f : α → Char → α) (init : α) (s : Substring) : α :=
|
||||
match s with
|
||||
@@ -633,14 +510,10 @@ termination_by loop => s.bsize - i.1
|
||||
def contains (s : Substring) (c : Char) : Bool :=
|
||||
s.any (fun a => a == c)
|
||||
|
||||
@[specialize] def takeWhileAux (s : String) (stopPos : String.Pos) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
if h : i < stopPos then
|
||||
if p (s.get i) then
|
||||
have := Nat.sub_lt_sub_left h (String.lt_next s i)
|
||||
takeWhileAux s stopPos p (s.next i)
|
||||
else i
|
||||
@[specialize] private partial def takeWhileAux (s : String) (stopPos : String.Pos) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
if i >= stopPos then i
|
||||
else if p (s.get i) then takeWhileAux s stopPos p (s.next i)
|
||||
else i
|
||||
termination_by _ => stopPos.1 - i.1
|
||||
|
||||
@[inline] def takeWhile : Substring → (Char → Bool) → Substring
|
||||
| ⟨s, b, e⟩, p =>
|
||||
@@ -652,16 +525,13 @@ termination_by _ => stopPos.1 - i.1
|
||||
let b := takeWhileAux s e p b;
|
||||
⟨s, b, e⟩
|
||||
|
||||
@[specialize] def takeRightWhileAux (s : String) (begPos : String.Pos) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
if h : begPos < i then
|
||||
have := String.prev_lt_of_pos s i <| mt (congrArg String.Pos.byteIdx) <|
|
||||
Ne.symm <| Nat.ne_of_lt <| Nat.lt_of_le_of_lt (Nat.zero_le _) h
|
||||
@[specialize] private partial def takeRightWhileAux (s : String) (begPos : String.Pos) (p : Char → Bool) (i : String.Pos) : String.Pos :=
|
||||
if i == begPos then i
|
||||
else
|
||||
let i' := s.prev i
|
||||
let c := s.get i'
|
||||
if !p c then i
|
||||
else takeRightWhileAux s begPos p i'
|
||||
else i
|
||||
termination_by _ => i.1
|
||||
|
||||
@[inline] def takeRightWhile : Substring → (Char → Bool) → Substring
|
||||
| ⟨s, b, e⟩, p =>
|
||||
|
||||
@@ -33,18 +33,40 @@ opaque fromUTF8Unchecked (a : @& ByteArray) : String
|
||||
@[extern "lean_string_to_utf8"]
|
||||
opaque toUTF8 (a : @& String) : ByteArray
|
||||
|
||||
/-- Accesses a byte in the UTF-8 encoding of the `String`. O(1) -/
|
||||
@[extern "lean_string_get_byte_fast"]
|
||||
opaque getUtf8Byte (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8
|
||||
theorem one_le_csize (c : Char) : 1 ≤ csize c := by
|
||||
simp [csize, Char.utf8Size]
|
||||
repeat (first | split | decide)
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
|
||||
@[simp] theorem pos_add_char (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + csize c := rfl
|
||||
|
||||
theorem eq_empty_of_bsize_eq_zero (h : s.endPos = {}) : s = "" := by
|
||||
match s with
|
||||
| ⟨[]⟩ => rfl
|
||||
| ⟨c::cs⟩ =>
|
||||
injection h with h
|
||||
simp [endPos, utf8ByteSize, utf8ByteSize.go] at h
|
||||
have : utf8ByteSize.go cs + 1 ≤ utf8ByteSize.go cs + csize c := Nat.add_le_add_left (one_le_csize c) _
|
||||
simp_arith [h] at this
|
||||
|
||||
theorem lt_next (s : String) (i : String.Pos) : i.1 < (s.next i).1 := by
|
||||
simp_arith [next]; apply one_le_csize
|
||||
|
||||
theorem Iterator.sizeOf_next_lt_of_hasNext (i : String.Iterator) (h : i.hasNext) : sizeOf i.next < sizeOf i := by
|
||||
cases i; rename_i s pos; simp [Iterator.next, Iterator.sizeOf_eq]; simp [Iterator.hasNext] at h
|
||||
exact Nat.sub_lt_sub_left h (String.lt_next s pos)
|
||||
have := String.lt_next s pos
|
||||
apply Nat.sub.elim (motive := fun k => k < _) (utf8ByteSize s) (String.next s pos).1
|
||||
. intro _ k he
|
||||
simp [he]; rw [Nat.add_comm, Nat.add_sub_assoc (Nat.le_of_lt this)]
|
||||
have := Nat.zero_lt_sub_of_lt this
|
||||
simp_all_arith
|
||||
. intro; apply Nat.zero_lt_sub_of_lt h
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply String.Iterator.sizeOf_next_lt_of_hasNext; assumption)
|
||||
|
||||
theorem Iterator.sizeOf_next_lt_of_atEnd (i : String.Iterator) (h : ¬ i.atEnd = true) : sizeOf i.next < sizeOf i :=
|
||||
have h : i.hasNext := decide_eq_true <| Nat.gt_of_not_le <| mt decide_eq_true h
|
||||
have h : i.hasNext = true := by simp_arith [atEnd] at h; simp_arith [hasNext, h]
|
||||
sizeOf_next_lt_of_hasNext i h
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| apply String.Iterator.sizeOf_next_lt_of_atEnd; assumption)
|
||||
|
||||
@@ -5,7 +5,7 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt
|
||||
import Init.Data.Nat.Div
|
||||
import Init.Data.Repr
|
||||
import Init.Data.Int.Basic
|
||||
@@ -45,10 +45,14 @@ instance {p : Prop} : ToString (Decidable p) := ⟨fun h =>
|
||||
| Decidable.isTrue _ => "true"
|
||||
| Decidable.isFalse _ => "false"⟩
|
||||
|
||||
protected def List.toString [ToString α] : List α → String
|
||||
| [] => "[]"
|
||||
| [x] => "[" ++ toString x ++ "]"
|
||||
| x::xs => xs.foldl (· ++ ", " ++ toString ·) ("[" ++ toString x) |>.push ']'
|
||||
protected def List.toStringAux {α : Type u} [ToString α] : Bool → List α → String
|
||||
| _, [] => ""
|
||||
| true, x::xs => toString x ++ List.toStringAux false xs
|
||||
| false, x::xs => ", " ++ toString x ++ List.toStringAux false xs
|
||||
|
||||
protected def List.toString {α : Type u} [ToString α] : List α → String
|
||||
| [] => "[]"
|
||||
| x::xs => "[" ++ List.toStringAux true (x::xs) ++ "]"
|
||||
|
||||
instance {α : Type u} [ToString α] : ToString (List α) :=
|
||||
⟨List.toString⟩
|
||||
|
||||
@@ -1,8 +1,363 @@
|
||||
/-
|
||||
Copyright (c) 2022 Henrik Böving. All rights reserved.
|
||||
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt.Log2
|
||||
import Init.Data.Fin.Basic
|
||||
import Init.System.Platform
|
||||
|
||||
open Nat
|
||||
|
||||
@[extern "lean_uint8_of_nat"]
|
||||
def UInt8.ofNat (n : @& Nat) : UInt8 := ⟨Fin.ofNat n⟩
|
||||
abbrev Nat.toUInt8 := UInt8.ofNat
|
||||
@[extern "lean_uint8_to_nat"]
|
||||
def UInt8.toNat (n : UInt8) : Nat := n.val.val
|
||||
@[extern "lean_uint8_add"]
|
||||
def UInt8.add (a b : UInt8) : UInt8 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint8_sub"]
|
||||
def UInt8.sub (a b : UInt8) : UInt8 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint8_mul"]
|
||||
def UInt8.mul (a b : UInt8) : UInt8 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint8_div"]
|
||||
def UInt8.div (a b : UInt8) : UInt8 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint8_mod"]
|
||||
def UInt8.mod (a b : UInt8) : UInt8 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint8_modn"]
|
||||
def UInt8.modn (a : UInt8) (n : @& Nat) : UInt8 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint8_land"]
|
||||
def UInt8.land (a b : UInt8) : UInt8 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint8_lor"]
|
||||
def UInt8.lor (a b : UInt8) : UInt8 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint8_xor"]
|
||||
def UInt8.xor (a b : UInt8) : UInt8 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint8_shift_left"]
|
||||
def UInt8.shiftLeft (a b : UInt8) : UInt8 := ⟨a.val <<< (modn b 8).val⟩
|
||||
@[extern "lean_uint8_shift_right"]
|
||||
def UInt8.shiftRight (a b : UInt8) : UInt8 := ⟨a.val >>> (modn b 8).val⟩
|
||||
def UInt8.lt (a b : UInt8) : Prop := a.val < b.val
|
||||
def UInt8.le (a b : UInt8) : Prop := a.val ≤ b.val
|
||||
|
||||
instance : OfNat UInt8 n := ⟨UInt8.ofNat n⟩
|
||||
instance : Add UInt8 := ⟨UInt8.add⟩
|
||||
instance : Sub UInt8 := ⟨UInt8.sub⟩
|
||||
instance : Mul UInt8 := ⟨UInt8.mul⟩
|
||||
instance : Mod UInt8 := ⟨UInt8.mod⟩
|
||||
instance : HMod UInt8 Nat UInt8 := ⟨UInt8.modn⟩
|
||||
instance : Div UInt8 := ⟨UInt8.div⟩
|
||||
instance : LT UInt8 := ⟨UInt8.lt⟩
|
||||
instance : LE UInt8 := ⟨UInt8.le⟩
|
||||
|
||||
@[extern "lean_uint8_complement"]
|
||||
def UInt8.complement (a:UInt8) : UInt8 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt8 := ⟨UInt8.complement⟩
|
||||
instance : AndOp UInt8 := ⟨UInt8.land⟩
|
||||
instance : OrOp UInt8 := ⟨UInt8.lor⟩
|
||||
instance : Xor UInt8 := ⟨UInt8.xor⟩
|
||||
instance : ShiftLeft UInt8 := ⟨UInt8.shiftLeft⟩
|
||||
instance : ShiftRight UInt8 := ⟨UInt8.shiftRight⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint8_dec_le"]
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : UInt8) : Decidable (a < b) := UInt8.decLt a b
|
||||
instance (a b : UInt8) : Decidable (a ≤ b) := UInt8.decLe a b
|
||||
instance : Max UInt8 := maxOfLe
|
||||
instance : Min UInt8 := minOfLe
|
||||
|
||||
@[extern "lean_uint16_of_nat"]
|
||||
def UInt16.ofNat (n : @& Nat) : UInt16 := ⟨Fin.ofNat n⟩
|
||||
abbrev Nat.toUInt16 := UInt16.ofNat
|
||||
@[extern "lean_uint16_to_nat"]
|
||||
def UInt16.toNat (n : UInt16) : Nat := n.val.val
|
||||
@[extern "lean_uint16_add"]
|
||||
def UInt16.add (a b : UInt16) : UInt16 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint16_sub"]
|
||||
def UInt16.sub (a b : UInt16) : UInt16 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint16_mul"]
|
||||
def UInt16.mul (a b : UInt16) : UInt16 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint16_div"]
|
||||
def UInt16.div (a b : UInt16) : UInt16 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint16_mod"]
|
||||
def UInt16.mod (a b : UInt16) : UInt16 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint16_modn"]
|
||||
def UInt16.modn (a : UInt16) (n : @& Nat) : UInt16 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint16_land"]
|
||||
def UInt16.land (a b : UInt16) : UInt16 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint16_lor"]
|
||||
def UInt16.lor (a b : UInt16) : UInt16 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint16_xor"]
|
||||
def UInt16.xor (a b : UInt16) : UInt16 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint16_shift_left"]
|
||||
def UInt16.shiftLeft (a b : UInt16) : UInt16 := ⟨a.val <<< (modn b 16).val⟩
|
||||
@[extern "lean_uint16_to_uint8"]
|
||||
def UInt16.toUInt8 (a : UInt16) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint8_to_uint16"]
|
||||
def UInt8.toUInt16 (a : UInt8) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint16_shift_right"]
|
||||
def UInt16.shiftRight (a b : UInt16) : UInt16 := ⟨a.val >>> (modn b 16).val⟩
|
||||
def UInt16.lt (a b : UInt16) : Prop := a.val < b.val
|
||||
def UInt16.le (a b : UInt16) : Prop := a.val ≤ b.val
|
||||
|
||||
|
||||
instance : OfNat UInt16 n := ⟨UInt16.ofNat n⟩
|
||||
instance : Add UInt16 := ⟨UInt16.add⟩
|
||||
instance : Sub UInt16 := ⟨UInt16.sub⟩
|
||||
instance : Mul UInt16 := ⟨UInt16.mul⟩
|
||||
instance : Mod UInt16 := ⟨UInt16.mod⟩
|
||||
instance : HMod UInt16 Nat UInt16 := ⟨UInt16.modn⟩
|
||||
instance : Div UInt16 := ⟨UInt16.div⟩
|
||||
instance : LT UInt16 := ⟨UInt16.lt⟩
|
||||
instance : LE UInt16 := ⟨UInt16.le⟩
|
||||
|
||||
@[extern "lean_uint16_complement"]
|
||||
def UInt16.complement (a:UInt16) : UInt16 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt16 := ⟨UInt16.complement⟩
|
||||
instance : AndOp UInt16 := ⟨UInt16.land⟩
|
||||
instance : OrOp UInt16 := ⟨UInt16.lor⟩
|
||||
instance : Xor UInt16 := ⟨UInt16.xor⟩
|
||||
instance : ShiftLeft UInt16 := ⟨UInt16.shiftLeft⟩
|
||||
instance : ShiftRight UInt16 := ⟨UInt16.shiftRight⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint16_dec_lt"]
|
||||
def UInt16.decLt (a b : UInt16) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint16_dec_le"]
|
||||
def UInt16.decLe (a b : UInt16) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : UInt16) : Decidable (a < b) := UInt16.decLt a b
|
||||
instance (a b : UInt16) : Decidable (a ≤ b) := UInt16.decLe a b
|
||||
instance : Max UInt16 := maxOfLe
|
||||
instance : Min UInt16 := minOfLe
|
||||
|
||||
@[extern "lean_uint32_of_nat"]
|
||||
def UInt32.ofNat (n : @& Nat) : UInt32 := ⟨Fin.ofNat n⟩
|
||||
@[extern "lean_uint32_of_nat"]
|
||||
def UInt32.ofNat' (n : Nat) (h : n < UInt32.size) : UInt32 := ⟨⟨n, h⟩⟩
|
||||
abbrev Nat.toUInt32 := UInt32.ofNat
|
||||
@[extern "lean_uint32_add"]
|
||||
def UInt32.add (a b : UInt32) : UInt32 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint32_sub"]
|
||||
def UInt32.sub (a b : UInt32) : UInt32 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint32_mul"]
|
||||
def UInt32.mul (a b : UInt32) : UInt32 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint32_div"]
|
||||
def UInt32.div (a b : UInt32) : UInt32 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint32_mod"]
|
||||
def UInt32.mod (a b : UInt32) : UInt32 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint32_modn"]
|
||||
def UInt32.modn (a : UInt32) (n : @& Nat) : UInt32 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint32_land"]
|
||||
def UInt32.land (a b : UInt32) : UInt32 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint32_lor"]
|
||||
def UInt32.lor (a b : UInt32) : UInt32 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint32_xor"]
|
||||
def UInt32.xor (a b : UInt32) : UInt32 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint32_shift_left"]
|
||||
def UInt32.shiftLeft (a b : UInt32) : UInt32 := ⟨a.val <<< (modn b 32).val⟩
|
||||
@[extern "lean_uint32_shift_right"]
|
||||
def UInt32.shiftRight (a b : UInt32) : UInt32 := ⟨a.val >>> (modn b 32).val⟩
|
||||
@[extern "lean_uint32_to_uint8"]
|
||||
def UInt32.toUInt8 (a : UInt32) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint32_to_uint16"]
|
||||
def UInt32.toUInt16 (a : UInt32) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint8_to_uint32"]
|
||||
def UInt8.toUInt32 (a : UInt8) : UInt32 := a.toNat.toUInt32
|
||||
@[extern "lean_uint16_to_uint32"]
|
||||
def UInt16.toUInt32 (a : UInt16) : UInt32 := a.toNat.toUInt32
|
||||
|
||||
instance : OfNat UInt32 n := ⟨UInt32.ofNat n⟩
|
||||
instance : Add UInt32 := ⟨UInt32.add⟩
|
||||
instance : Sub UInt32 := ⟨UInt32.sub⟩
|
||||
instance : Mul UInt32 := ⟨UInt32.mul⟩
|
||||
instance : Mod UInt32 := ⟨UInt32.mod⟩
|
||||
instance : HMod UInt32 Nat UInt32 := ⟨UInt32.modn⟩
|
||||
instance : Div UInt32 := ⟨UInt32.div⟩
|
||||
|
||||
@[extern "lean_uint32_complement"]
|
||||
def UInt32.complement (a:UInt32) : UInt32 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt32 := ⟨UInt32.complement⟩
|
||||
instance : AndOp UInt32 := ⟨UInt32.land⟩
|
||||
instance : OrOp UInt32 := ⟨UInt32.lor⟩
|
||||
instance : Xor UInt32 := ⟨UInt32.xor⟩
|
||||
instance : ShiftLeft UInt32 := ⟨UInt32.shiftLeft⟩
|
||||
instance : ShiftRight UInt32 := ⟨UInt32.shiftRight⟩
|
||||
|
||||
@[extern "lean_uint64_of_nat"]
|
||||
def UInt64.ofNat (n : @& Nat) : UInt64 := ⟨Fin.ofNat n⟩
|
||||
abbrev Nat.toUInt64 := UInt64.ofNat
|
||||
@[extern "lean_uint64_to_nat"]
|
||||
def UInt64.toNat (n : UInt64) : Nat := n.val.val
|
||||
@[extern "lean_uint64_add"]
|
||||
def UInt64.add (a b : UInt64) : UInt64 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint64_sub"]
|
||||
def UInt64.sub (a b : UInt64) : UInt64 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint64_mul"]
|
||||
def UInt64.mul (a b : UInt64) : UInt64 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint64_div"]
|
||||
def UInt64.div (a b : UInt64) : UInt64 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint64_mod"]
|
||||
def UInt64.mod (a b : UInt64) : UInt64 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint64_modn"]
|
||||
def UInt64.modn (a : UInt64) (n : @& Nat) : UInt64 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint64_land"]
|
||||
def UInt64.land (a b : UInt64) : UInt64 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint64_lor"]
|
||||
def UInt64.lor (a b : UInt64) : UInt64 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint64_xor"]
|
||||
def UInt64.xor (a b : UInt64) : UInt64 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint64_shift_left"]
|
||||
def UInt64.shiftLeft (a b : UInt64) : UInt64 := ⟨a.val <<< (modn b 64).val⟩
|
||||
@[extern "lean_uint64_shift_right"]
|
||||
def UInt64.shiftRight (a b : UInt64) : UInt64 := ⟨a.val >>> (modn b 64).val⟩
|
||||
def UInt64.lt (a b : UInt64) : Prop := a.val < b.val
|
||||
def UInt64.le (a b : UInt64) : Prop := a.val ≤ b.val
|
||||
@[extern "lean_uint64_to_uint8"]
|
||||
def UInt64.toUInt8 (a : UInt64) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint64_to_uint16"]
|
||||
def UInt64.toUInt16 (a : UInt64) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint64_to_uint32"]
|
||||
def UInt64.toUInt32 (a : UInt64) : UInt32 := a.toNat.toUInt32
|
||||
@[extern "lean_uint8_to_uint64"]
|
||||
def UInt8.toUInt64 (a : UInt8) : UInt64 := a.toNat.toUInt64
|
||||
@[extern "lean_uint16_to_uint64"]
|
||||
def UInt16.toUInt64 (a : UInt16) : UInt64 := a.toNat.toUInt64
|
||||
@[extern "lean_uint32_to_uint64"]
|
||||
def UInt32.toUInt64 (a : UInt32) : UInt64 := a.toNat.toUInt64
|
||||
|
||||
instance : OfNat UInt64 n := ⟨UInt64.ofNat n⟩
|
||||
instance : Add UInt64 := ⟨UInt64.add⟩
|
||||
instance : Sub UInt64 := ⟨UInt64.sub⟩
|
||||
instance : Mul UInt64 := ⟨UInt64.mul⟩
|
||||
instance : Mod UInt64 := ⟨UInt64.mod⟩
|
||||
instance : HMod UInt64 Nat UInt64 := ⟨UInt64.modn⟩
|
||||
instance : Div UInt64 := ⟨UInt64.div⟩
|
||||
instance : LT UInt64 := ⟨UInt64.lt⟩
|
||||
instance : LE UInt64 := ⟨UInt64.le⟩
|
||||
|
||||
@[extern "lean_uint64_complement"]
|
||||
def UInt64.complement (a:UInt64) : UInt64 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt64 := ⟨UInt64.complement⟩
|
||||
instance : AndOp UInt64 := ⟨UInt64.land⟩
|
||||
instance : OrOp UInt64 := ⟨UInt64.lor⟩
|
||||
instance : Xor UInt64 := ⟨UInt64.xor⟩
|
||||
instance : ShiftLeft UInt64 := ⟨UInt64.shiftLeft⟩
|
||||
instance : ShiftRight UInt64 := ⟨UInt64.shiftRight⟩
|
||||
|
||||
@[extern "lean_bool_to_uint64"]
|
||||
def Bool.toUInt64 (b : Bool) : UInt64 := if b then 1 else 0
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint64_dec_lt"]
|
||||
def UInt64.decLt (a b : UInt64) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint64_dec_le"]
|
||||
def UInt64.decLe (a b : UInt64) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : UInt64) : Decidable (a < b) := UInt64.decLt a b
|
||||
instance (a b : UInt64) : Decidable (a ≤ b) := UInt64.decLe a b
|
||||
instance : Max UInt64 := maxOfLe
|
||||
instance : Min UInt64 := minOfLe
|
||||
|
||||
theorem usize_size_gt_zero : USize.size > 0 :=
|
||||
Nat.pos_pow_of_pos System.Platform.numBits (Nat.zero_lt_succ _)
|
||||
|
||||
@[extern "lean_usize_of_nat"]
|
||||
def USize.ofNat (n : @& Nat) : USize := ⟨Fin.ofNat' n usize_size_gt_zero⟩
|
||||
abbrev Nat.toUSize := USize.ofNat
|
||||
@[extern "lean_usize_to_nat"]
|
||||
def USize.toNat (n : USize) : Nat := n.val.val
|
||||
@[extern "lean_usize_add"]
|
||||
def USize.add (a b : USize) : USize := ⟨a.val + b.val⟩
|
||||
@[extern "lean_usize_sub"]
|
||||
def USize.sub (a b : USize) : USize := ⟨a.val - b.val⟩
|
||||
@[extern "lean_usize_mul"]
|
||||
def USize.mul (a b : USize) : USize := ⟨a.val * b.val⟩
|
||||
@[extern "lean_usize_div"]
|
||||
def USize.div (a b : USize) : USize := ⟨a.val / b.val⟩
|
||||
@[extern "lean_usize_mod"]
|
||||
def USize.mod (a b : USize) : USize := ⟨a.val % b.val⟩
|
||||
@[extern "lean_usize_modn"]
|
||||
def USize.modn (a : USize) (n : @& Nat) : USize := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_usize_land"]
|
||||
def USize.land (a b : USize) : USize := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_usize_lor"]
|
||||
def USize.lor (a b : USize) : USize := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_usize_xor"]
|
||||
def USize.xor (a b : USize) : USize := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_usize_shift_left"]
|
||||
def USize.shiftLeft (a b : USize) : USize := ⟨a.val <<< (modn b System.Platform.numBits).val⟩
|
||||
@[extern "lean_usize_shift_right"]
|
||||
def USize.shiftRight (a b : USize) : USize := ⟨a.val >>> (modn b System.Platform.numBits).val⟩
|
||||
@[extern "lean_uint32_to_usize"]
|
||||
def UInt32.toUSize (a : UInt32) : USize := a.toNat.toUSize
|
||||
@[extern "lean_usize_to_uint32"]
|
||||
def USize.toUInt32 (a : USize) : UInt32 := a.toNat.toUInt32
|
||||
|
||||
def USize.lt (a b : USize) : Prop := a.val < b.val
|
||||
def USize.le (a b : USize) : Prop := a.val ≤ b.val
|
||||
|
||||
instance : OfNat USize n := ⟨USize.ofNat n⟩
|
||||
instance : Add USize := ⟨USize.add⟩
|
||||
instance : Sub USize := ⟨USize.sub⟩
|
||||
instance : Mul USize := ⟨USize.mul⟩
|
||||
instance : Mod USize := ⟨USize.mod⟩
|
||||
instance : HMod USize Nat USize := ⟨USize.modn⟩
|
||||
instance : Div USize := ⟨USize.div⟩
|
||||
instance : LT USize := ⟨USize.lt⟩
|
||||
instance : LE USize := ⟨USize.le⟩
|
||||
|
||||
@[extern "lean_usize_complement"]
|
||||
def USize.complement (a:USize) : USize := 0-(a+1)
|
||||
|
||||
instance : Complement USize := ⟨USize.complement⟩
|
||||
instance : AndOp USize := ⟨USize.land⟩
|
||||
instance : OrOp USize := ⟨USize.lor⟩
|
||||
instance : Xor USize := ⟨USize.xor⟩
|
||||
instance : ShiftLeft USize := ⟨USize.shiftLeft⟩
|
||||
instance : ShiftRight USize := ⟨USize.shiftRight⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_usize_dec_lt"]
|
||||
def USize.decLt (a b : USize) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_usize_dec_le"]
|
||||
def USize.decLe (a b : USize) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : USize) : Decidable (a < b) := USize.decLt a b
|
||||
instance (a b : USize) : Decidable (a ≤ b) := USize.decLe a b
|
||||
instance : Max USize := maxOfLe
|
||||
instance : Min USize := minOfLe
|
||||
|
||||
theorem USize.modn_lt {m : Nat} : ∀ (u : USize), m > 0 → USize.toNat (u % m) < m
|
||||
| ⟨u⟩, h => Fin.modn_lt u h
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Fin.Basic
|
||||
import Init.System.Platform
|
||||
|
||||
open Nat
|
||||
|
||||
@[extern "lean_uint8_of_nat"]
|
||||
def UInt8.ofNat (n : @& Nat) : UInt8 := ⟨Fin.ofNat n⟩
|
||||
abbrev Nat.toUInt8 := UInt8.ofNat
|
||||
@[extern "lean_uint8_to_nat"]
|
||||
def UInt8.toNat (n : UInt8) : Nat := n.val.val
|
||||
@[extern "lean_uint8_add"]
|
||||
def UInt8.add (a b : UInt8) : UInt8 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint8_sub"]
|
||||
def UInt8.sub (a b : UInt8) : UInt8 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint8_mul"]
|
||||
def UInt8.mul (a b : UInt8) : UInt8 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint8_div"]
|
||||
def UInt8.div (a b : UInt8) : UInt8 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint8_mod"]
|
||||
def UInt8.mod (a b : UInt8) : UInt8 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint8_modn"]
|
||||
def UInt8.modn (a : UInt8) (n : @& Nat) : UInt8 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint8_land"]
|
||||
def UInt8.land (a b : UInt8) : UInt8 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint8_lor"]
|
||||
def UInt8.lor (a b : UInt8) : UInt8 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint8_xor"]
|
||||
def UInt8.xor (a b : UInt8) : UInt8 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint8_shift_left"]
|
||||
def UInt8.shiftLeft (a b : UInt8) : UInt8 := ⟨a.val <<< (modn b 8).val⟩
|
||||
@[extern "lean_uint8_shift_right"]
|
||||
def UInt8.shiftRight (a b : UInt8) : UInt8 := ⟨a.val >>> (modn b 8).val⟩
|
||||
def UInt8.lt (a b : UInt8) : Prop := a.val < b.val
|
||||
def UInt8.le (a b : UInt8) : Prop := a.val ≤ b.val
|
||||
|
||||
instance : OfNat UInt8 n := ⟨UInt8.ofNat n⟩
|
||||
instance : Add UInt8 := ⟨UInt8.add⟩
|
||||
instance : Sub UInt8 := ⟨UInt8.sub⟩
|
||||
instance : Mul UInt8 := ⟨UInt8.mul⟩
|
||||
instance : Mod UInt8 := ⟨UInt8.mod⟩
|
||||
instance : HMod UInt8 Nat UInt8 := ⟨UInt8.modn⟩
|
||||
instance : Div UInt8 := ⟨UInt8.div⟩
|
||||
instance : LT UInt8 := ⟨UInt8.lt⟩
|
||||
instance : LE UInt8 := ⟨UInt8.le⟩
|
||||
|
||||
@[extern "lean_uint8_complement"]
|
||||
def UInt8.complement (a:UInt8) : UInt8 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt8 := ⟨UInt8.complement⟩
|
||||
instance : AndOp UInt8 := ⟨UInt8.land⟩
|
||||
instance : OrOp UInt8 := ⟨UInt8.lor⟩
|
||||
instance : Xor UInt8 := ⟨UInt8.xor⟩
|
||||
instance : ShiftLeft UInt8 := ⟨UInt8.shiftLeft⟩
|
||||
instance : ShiftRight UInt8 := ⟨UInt8.shiftRight⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint8_dec_le"]
|
||||
def UInt8.decLe (a b : UInt8) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : UInt8) : Decidable (a < b) := UInt8.decLt a b
|
||||
instance (a b : UInt8) : Decidable (a ≤ b) := UInt8.decLe a b
|
||||
instance : Max UInt8 := maxOfLe
|
||||
instance : Min UInt8 := minOfLe
|
||||
|
||||
@[extern "lean_uint16_of_nat"]
|
||||
def UInt16.ofNat (n : @& Nat) : UInt16 := ⟨Fin.ofNat n⟩
|
||||
abbrev Nat.toUInt16 := UInt16.ofNat
|
||||
@[extern "lean_uint16_to_nat"]
|
||||
def UInt16.toNat (n : UInt16) : Nat := n.val.val
|
||||
@[extern "lean_uint16_add"]
|
||||
def UInt16.add (a b : UInt16) : UInt16 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint16_sub"]
|
||||
def UInt16.sub (a b : UInt16) : UInt16 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint16_mul"]
|
||||
def UInt16.mul (a b : UInt16) : UInt16 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint16_div"]
|
||||
def UInt16.div (a b : UInt16) : UInt16 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint16_mod"]
|
||||
def UInt16.mod (a b : UInt16) : UInt16 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint16_modn"]
|
||||
def UInt16.modn (a : UInt16) (n : @& Nat) : UInt16 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint16_land"]
|
||||
def UInt16.land (a b : UInt16) : UInt16 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint16_lor"]
|
||||
def UInt16.lor (a b : UInt16) : UInt16 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint16_xor"]
|
||||
def UInt16.xor (a b : UInt16) : UInt16 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint16_shift_left"]
|
||||
def UInt16.shiftLeft (a b : UInt16) : UInt16 := ⟨a.val <<< (modn b 16).val⟩
|
||||
@[extern "lean_uint16_to_uint8"]
|
||||
def UInt16.toUInt8 (a : UInt16) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint8_to_uint16"]
|
||||
def UInt8.toUInt16 (a : UInt8) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint16_shift_right"]
|
||||
def UInt16.shiftRight (a b : UInt16) : UInt16 := ⟨a.val >>> (modn b 16).val⟩
|
||||
def UInt16.lt (a b : UInt16) : Prop := a.val < b.val
|
||||
def UInt16.le (a b : UInt16) : Prop := a.val ≤ b.val
|
||||
|
||||
|
||||
instance : OfNat UInt16 n := ⟨UInt16.ofNat n⟩
|
||||
instance : Add UInt16 := ⟨UInt16.add⟩
|
||||
instance : Sub UInt16 := ⟨UInt16.sub⟩
|
||||
instance : Mul UInt16 := ⟨UInt16.mul⟩
|
||||
instance : Mod UInt16 := ⟨UInt16.mod⟩
|
||||
instance : HMod UInt16 Nat UInt16 := ⟨UInt16.modn⟩
|
||||
instance : Div UInt16 := ⟨UInt16.div⟩
|
||||
instance : LT UInt16 := ⟨UInt16.lt⟩
|
||||
instance : LE UInt16 := ⟨UInt16.le⟩
|
||||
|
||||
@[extern "lean_uint16_complement"]
|
||||
def UInt16.complement (a:UInt16) : UInt16 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt16 := ⟨UInt16.complement⟩
|
||||
instance : AndOp UInt16 := ⟨UInt16.land⟩
|
||||
instance : OrOp UInt16 := ⟨UInt16.lor⟩
|
||||
instance : Xor UInt16 := ⟨UInt16.xor⟩
|
||||
instance : ShiftLeft UInt16 := ⟨UInt16.shiftLeft⟩
|
||||
instance : ShiftRight UInt16 := ⟨UInt16.shiftRight⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint16_dec_lt"]
|
||||
def UInt16.decLt (a b : UInt16) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint16_dec_le"]
|
||||
def UInt16.decLe (a b : UInt16) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : UInt16) : Decidable (a < b) := UInt16.decLt a b
|
||||
instance (a b : UInt16) : Decidable (a ≤ b) := UInt16.decLe a b
|
||||
instance : Max UInt16 := maxOfLe
|
||||
instance : Min UInt16 := minOfLe
|
||||
|
||||
@[extern "lean_uint32_of_nat"]
|
||||
def UInt32.ofNat (n : @& Nat) : UInt32 := ⟨Fin.ofNat n⟩
|
||||
@[extern "lean_uint32_of_nat"]
|
||||
def UInt32.ofNat' (n : Nat) (h : n < UInt32.size) : UInt32 := ⟨⟨n, h⟩⟩
|
||||
abbrev Nat.toUInt32 := UInt32.ofNat
|
||||
@[extern "lean_uint32_add"]
|
||||
def UInt32.add (a b : UInt32) : UInt32 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint32_sub"]
|
||||
def UInt32.sub (a b : UInt32) : UInt32 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint32_mul"]
|
||||
def UInt32.mul (a b : UInt32) : UInt32 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint32_div"]
|
||||
def UInt32.div (a b : UInt32) : UInt32 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint32_mod"]
|
||||
def UInt32.mod (a b : UInt32) : UInt32 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint32_modn"]
|
||||
def UInt32.modn (a : UInt32) (n : @& Nat) : UInt32 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint32_land"]
|
||||
def UInt32.land (a b : UInt32) : UInt32 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint32_lor"]
|
||||
def UInt32.lor (a b : UInt32) : UInt32 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint32_xor"]
|
||||
def UInt32.xor (a b : UInt32) : UInt32 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint32_shift_left"]
|
||||
def UInt32.shiftLeft (a b : UInt32) : UInt32 := ⟨a.val <<< (modn b 32).val⟩
|
||||
@[extern "lean_uint32_shift_right"]
|
||||
def UInt32.shiftRight (a b : UInt32) : UInt32 := ⟨a.val >>> (modn b 32).val⟩
|
||||
@[extern "lean_uint32_to_uint8"]
|
||||
def UInt32.toUInt8 (a : UInt32) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint32_to_uint16"]
|
||||
def UInt32.toUInt16 (a : UInt32) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint8_to_uint32"]
|
||||
def UInt8.toUInt32 (a : UInt8) : UInt32 := a.toNat.toUInt32
|
||||
@[extern "lean_uint16_to_uint32"]
|
||||
def UInt16.toUInt32 (a : UInt16) : UInt32 := a.toNat.toUInt32
|
||||
|
||||
instance : OfNat UInt32 n := ⟨UInt32.ofNat n⟩
|
||||
instance : Add UInt32 := ⟨UInt32.add⟩
|
||||
instance : Sub UInt32 := ⟨UInt32.sub⟩
|
||||
instance : Mul UInt32 := ⟨UInt32.mul⟩
|
||||
instance : Mod UInt32 := ⟨UInt32.mod⟩
|
||||
instance : HMod UInt32 Nat UInt32 := ⟨UInt32.modn⟩
|
||||
instance : Div UInt32 := ⟨UInt32.div⟩
|
||||
|
||||
@[extern "lean_uint32_complement"]
|
||||
def UInt32.complement (a:UInt32) : UInt32 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt32 := ⟨UInt32.complement⟩
|
||||
instance : AndOp UInt32 := ⟨UInt32.land⟩
|
||||
instance : OrOp UInt32 := ⟨UInt32.lor⟩
|
||||
instance : Xor UInt32 := ⟨UInt32.xor⟩
|
||||
instance : ShiftLeft UInt32 := ⟨UInt32.shiftLeft⟩
|
||||
instance : ShiftRight UInt32 := ⟨UInt32.shiftRight⟩
|
||||
|
||||
@[extern "lean_uint64_of_nat"]
|
||||
def UInt64.ofNat (n : @& Nat) : UInt64 := ⟨Fin.ofNat n⟩
|
||||
abbrev Nat.toUInt64 := UInt64.ofNat
|
||||
@[extern "lean_uint64_to_nat"]
|
||||
def UInt64.toNat (n : UInt64) : Nat := n.val.val
|
||||
@[extern "lean_uint64_add"]
|
||||
def UInt64.add (a b : UInt64) : UInt64 := ⟨a.val + b.val⟩
|
||||
@[extern "lean_uint64_sub"]
|
||||
def UInt64.sub (a b : UInt64) : UInt64 := ⟨a.val - b.val⟩
|
||||
@[extern "lean_uint64_mul"]
|
||||
def UInt64.mul (a b : UInt64) : UInt64 := ⟨a.val * b.val⟩
|
||||
@[extern "lean_uint64_div"]
|
||||
def UInt64.div (a b : UInt64) : UInt64 := ⟨a.val / b.val⟩
|
||||
@[extern "lean_uint64_mod"]
|
||||
def UInt64.mod (a b : UInt64) : UInt64 := ⟨a.val % b.val⟩
|
||||
@[extern "lean_uint64_modn"]
|
||||
def UInt64.modn (a : UInt64) (n : @& Nat) : UInt64 := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_uint64_land"]
|
||||
def UInt64.land (a b : UInt64) : UInt64 := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_uint64_lor"]
|
||||
def UInt64.lor (a b : UInt64) : UInt64 := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_uint64_xor"]
|
||||
def UInt64.xor (a b : UInt64) : UInt64 := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_uint64_shift_left"]
|
||||
def UInt64.shiftLeft (a b : UInt64) : UInt64 := ⟨a.val <<< (modn b 64).val⟩
|
||||
@[extern "lean_uint64_shift_right"]
|
||||
def UInt64.shiftRight (a b : UInt64) : UInt64 := ⟨a.val >>> (modn b 64).val⟩
|
||||
def UInt64.lt (a b : UInt64) : Prop := a.val < b.val
|
||||
def UInt64.le (a b : UInt64) : Prop := a.val ≤ b.val
|
||||
@[extern "lean_uint64_to_uint8"]
|
||||
def UInt64.toUInt8 (a : UInt64) : UInt8 := a.toNat.toUInt8
|
||||
@[extern "lean_uint64_to_uint16"]
|
||||
def UInt64.toUInt16 (a : UInt64) : UInt16 := a.toNat.toUInt16
|
||||
@[extern "lean_uint64_to_uint32"]
|
||||
def UInt64.toUInt32 (a : UInt64) : UInt32 := a.toNat.toUInt32
|
||||
@[extern "lean_uint8_to_uint64"]
|
||||
def UInt8.toUInt64 (a : UInt8) : UInt64 := a.toNat.toUInt64
|
||||
@[extern "lean_uint16_to_uint64"]
|
||||
def UInt16.toUInt64 (a : UInt16) : UInt64 := a.toNat.toUInt64
|
||||
@[extern "lean_uint32_to_uint64"]
|
||||
def UInt32.toUInt64 (a : UInt32) : UInt64 := a.toNat.toUInt64
|
||||
|
||||
instance : OfNat UInt64 n := ⟨UInt64.ofNat n⟩
|
||||
instance : Add UInt64 := ⟨UInt64.add⟩
|
||||
instance : Sub UInt64 := ⟨UInt64.sub⟩
|
||||
instance : Mul UInt64 := ⟨UInt64.mul⟩
|
||||
instance : Mod UInt64 := ⟨UInt64.mod⟩
|
||||
instance : HMod UInt64 Nat UInt64 := ⟨UInt64.modn⟩
|
||||
instance : Div UInt64 := ⟨UInt64.div⟩
|
||||
instance : LT UInt64 := ⟨UInt64.lt⟩
|
||||
instance : LE UInt64 := ⟨UInt64.le⟩
|
||||
|
||||
@[extern "lean_uint64_complement"]
|
||||
def UInt64.complement (a:UInt64) : UInt64 := 0-(a+1)
|
||||
|
||||
instance : Complement UInt64 := ⟨UInt64.complement⟩
|
||||
instance : AndOp UInt64 := ⟨UInt64.land⟩
|
||||
instance : OrOp UInt64 := ⟨UInt64.lor⟩
|
||||
instance : Xor UInt64 := ⟨UInt64.xor⟩
|
||||
instance : ShiftLeft UInt64 := ⟨UInt64.shiftLeft⟩
|
||||
instance : ShiftRight UInt64 := ⟨UInt64.shiftRight⟩
|
||||
|
||||
@[extern "lean_bool_to_uint64"]
|
||||
def Bool.toUInt64 (b : Bool) : UInt64 := if b then 1 else 0
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint64_dec_lt"]
|
||||
def UInt64.decLt (a b : UInt64) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint64_dec_le"]
|
||||
def UInt64.decLe (a b : UInt64) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : UInt64) : Decidable (a < b) := UInt64.decLt a b
|
||||
instance (a b : UInt64) : Decidable (a ≤ b) := UInt64.decLe a b
|
||||
instance : Max UInt64 := maxOfLe
|
||||
instance : Min UInt64 := minOfLe
|
||||
|
||||
theorem usize_size_gt_zero : USize.size > 0 :=
|
||||
Nat.zero_lt_succ ..
|
||||
|
||||
@[extern "lean_usize_of_nat"]
|
||||
def USize.ofNat (n : @& Nat) : USize := ⟨Fin.ofNat' n usize_size_gt_zero⟩
|
||||
abbrev Nat.toUSize := USize.ofNat
|
||||
@[extern "lean_usize_to_nat"]
|
||||
def USize.toNat (n : USize) : Nat := n.val.val
|
||||
@[extern "lean_usize_add"]
|
||||
def USize.add (a b : USize) : USize := ⟨a.val + b.val⟩
|
||||
@[extern "lean_usize_sub"]
|
||||
def USize.sub (a b : USize) : USize := ⟨a.val - b.val⟩
|
||||
@[extern "lean_usize_mul"]
|
||||
def USize.mul (a b : USize) : USize := ⟨a.val * b.val⟩
|
||||
@[extern "lean_usize_div"]
|
||||
def USize.div (a b : USize) : USize := ⟨a.val / b.val⟩
|
||||
@[extern "lean_usize_mod"]
|
||||
def USize.mod (a b : USize) : USize := ⟨a.val % b.val⟩
|
||||
@[extern "lean_usize_modn"]
|
||||
def USize.modn (a : USize) (n : @& Nat) : USize := ⟨Fin.modn a.val n⟩
|
||||
@[extern "lean_usize_land"]
|
||||
def USize.land (a b : USize) : USize := ⟨Fin.land a.val b.val⟩
|
||||
@[extern "lean_usize_lor"]
|
||||
def USize.lor (a b : USize) : USize := ⟨Fin.lor a.val b.val⟩
|
||||
@[extern "lean_usize_xor"]
|
||||
def USize.xor (a b : USize) : USize := ⟨Fin.xor a.val b.val⟩
|
||||
@[extern "lean_usize_shift_left"]
|
||||
def USize.shiftLeft (a b : USize) : USize := ⟨a.val <<< (modn b System.Platform.numBits).val⟩
|
||||
@[extern "lean_usize_shift_right"]
|
||||
def USize.shiftRight (a b : USize) : USize := ⟨a.val >>> (modn b System.Platform.numBits).val⟩
|
||||
@[extern "lean_uint32_to_usize"]
|
||||
def UInt32.toUSize (a : UInt32) : USize := a.toNat.toUSize
|
||||
@[extern "lean_usize_to_uint32"]
|
||||
def USize.toUInt32 (a : USize) : UInt32 := a.toNat.toUInt32
|
||||
|
||||
def USize.lt (a b : USize) : Prop := a.val < b.val
|
||||
def USize.le (a b : USize) : Prop := a.val ≤ b.val
|
||||
|
||||
instance : OfNat USize n := ⟨USize.ofNat n⟩
|
||||
instance : Add USize := ⟨USize.add⟩
|
||||
instance : Sub USize := ⟨USize.sub⟩
|
||||
instance : Mul USize := ⟨USize.mul⟩
|
||||
instance : Mod USize := ⟨USize.mod⟩
|
||||
instance : HMod USize Nat USize := ⟨USize.modn⟩
|
||||
instance : Div USize := ⟨USize.div⟩
|
||||
instance : LT USize := ⟨USize.lt⟩
|
||||
instance : LE USize := ⟨USize.le⟩
|
||||
|
||||
@[extern "lean_usize_complement"]
|
||||
def USize.complement (a:USize) : USize := 0-(a+1)
|
||||
|
||||
instance : Complement USize := ⟨USize.complement⟩
|
||||
instance : AndOp USize := ⟨USize.land⟩
|
||||
instance : OrOp USize := ⟨USize.lor⟩
|
||||
instance : Xor USize := ⟨USize.xor⟩
|
||||
instance : ShiftLeft USize := ⟨USize.shiftLeft⟩
|
||||
instance : ShiftRight USize := ⟨USize.shiftRight⟩
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_usize_dec_lt"]
|
||||
def USize.decLt (a b : USize) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n < m))
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_usize_dec_le"]
|
||||
def USize.decLe (a b : USize) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ => inferInstanceAs (Decidable (n <= m))
|
||||
|
||||
instance (a b : USize) : Decidable (a < b) := USize.decLt a b
|
||||
instance (a b : USize) : Decidable (a ≤ b) := USize.decLe a b
|
||||
instance : Max USize := maxOfLe
|
||||
instance : Min USize := minOfLe
|
||||
|
||||
theorem USize.modn_lt {m : Nat} : ∀ (u : USize), m > 0 → USize.toNat (u % m) < m
|
||||
| ⟨u⟩, h => Fin.modn_lt u h
|
||||
@@ -1,22 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2022 Henrik Böving. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Fin.Log2
|
||||
|
||||
@[extern "lean_uint8_log2"]
|
||||
def UInt8.log2 (a : UInt8) : UInt8 := ⟨Fin.log2 a.val⟩
|
||||
|
||||
@[extern "lean_uint16_log2"]
|
||||
def UInt16.log2 (a : UInt16) : UInt16 := ⟨Fin.log2 a.val⟩
|
||||
|
||||
@[extern "lean_uint32_log2"]
|
||||
def UInt32.log2 (a : UInt32) : UInt32 := ⟨Fin.log2 a.val⟩
|
||||
|
||||
@[extern "lean_uint64_log2"]
|
||||
def UInt64.log2 (a : UInt64) : UInt64 := ⟨Fin.log2 a.val⟩
|
||||
|
||||
@[extern "lean_usize_log2"]
|
||||
def USize.log2 (a : USize) : USize := ⟨Fin.log2 a.val⟩
|
||||
@@ -11,15 +11,15 @@ import Init.Data.Option.BasicAux
|
||||
|
||||
namespace Lean
|
||||
|
||||
@[extern "lean_version_get_major"]
|
||||
@[extern c inline "lean_box(LEAN_VERSION_MAJOR)"]
|
||||
private opaque version.getMajor (u : Unit) : Nat
|
||||
def version.major : Nat := version.getMajor ()
|
||||
|
||||
@[extern "lean_version_get_minor"]
|
||||
@[extern c inline "lean_box(LEAN_VERSION_MINOR)"]
|
||||
private opaque version.getMinor (u : Unit) : Nat
|
||||
def version.minor : Nat := version.getMinor ()
|
||||
|
||||
@[extern "lean_version_get_patch"]
|
||||
@[extern c inline "lean_box(LEAN_VERSION_PATCH)"]
|
||||
private opaque version.getPatch (u : Unit) : Nat
|
||||
def version.patch : Nat := version.getPatch ()
|
||||
|
||||
@@ -27,12 +27,12 @@ def version.patch : Nat := version.getPatch ()
|
||||
opaque getGithash (u : Unit) : String
|
||||
def githash : String := getGithash ()
|
||||
|
||||
@[extern "lean_version_get_is_release"]
|
||||
@[extern c inline "LEAN_VERSION_IS_RELEASE"]
|
||||
opaque version.getIsRelease (u : Unit) : Bool
|
||||
def version.isRelease : Bool := version.getIsRelease ()
|
||||
|
||||
/-- Additional version description like "nightly-2018-03-11" -/
|
||||
@[extern "lean_version_get_special_desc"]
|
||||
@[extern c inline "lean_mk_string(LEAN_SPECIAL_VERSION_DESC)"]
|
||||
opaque version.getSpecialDesc (u : Unit) : String
|
||||
def version.specialDesc : String := version.getSpecialDesc ()
|
||||
|
||||
@@ -61,7 +61,7 @@ def toolchain :=
|
||||
else
|
||||
""
|
||||
|
||||
@[extern "lean_internal_is_stage0"]
|
||||
@[extern c inline "LEAN_IS_STAGE0"]
|
||||
opaque Internal.isStage0 (u : Unit) : Bool
|
||||
|
||||
/-- Valid identifier names -/
|
||||
@@ -271,11 +271,10 @@ abbrev CharLit := TSyntax charLitKind
|
||||
abbrev NameLit := TSyntax nameLitKind
|
||||
abbrev ScientificLit := TSyntax scientificLitKind
|
||||
abbrev NumLit := TSyntax numLitKind
|
||||
abbrev HygieneInfo := TSyntax hygieneInfoKind
|
||||
|
||||
end Syntax
|
||||
|
||||
export Syntax (Term Command Prec Prio Ident StrLit CharLit NameLit ScientificLit NumLit HygieneInfo)
|
||||
export Syntax (Term Command Prec Prio Ident StrLit CharLit NameLit ScientificLit NumLit)
|
||||
|
||||
namespace TSyntax
|
||||
|
||||
@@ -452,6 +451,9 @@ end Syntax
|
||||
| none => x
|
||||
| some ref => withRef ref x
|
||||
|
||||
@[inline] def mkNode (k : SyntaxNodeKind) (args : Array Syntax) : TSyntax k :=
|
||||
⟨Syntax.node SourceInfo.none k args⟩
|
||||
|
||||
/-- Syntax objects for a Lean module. -/
|
||||
structure Module where
|
||||
header : Syntax
|
||||
@@ -480,7 +482,7 @@ structure Module where
|
||||
1- A proper extensible tactic feature that does not rely on the macro system.
|
||||
|
||||
2- Typed macros that know the syntax categories they're working in. Then, we would be able to select which
|
||||
syntactic categories are expanded by `expandMacros`.
|
||||
syntatic categories are expanded by `expandMacros`.
|
||||
-/
|
||||
partial def expandMacros (stx : Syntax) (p : SyntaxNodeKind → Bool := fun k => k != `Lean.Parser.Term.byTactic) : MacroM Syntax :=
|
||||
withRef stx do
|
||||
@@ -526,6 +528,9 @@ def mkCIdent (c : Name) : Ident :=
|
||||
def mkIdent (val : Name) : Ident :=
|
||||
⟨Syntax.ident SourceInfo.none (toString val).toSubstring val []⟩
|
||||
|
||||
@[inline] def mkNullNode (args : Array Syntax := #[]) : Syntax :=
|
||||
mkNode nullKind args
|
||||
|
||||
@[inline] def mkGroupNode (args : Array Syntax := #[]) : Syntax :=
|
||||
mkNode groupKind args
|
||||
|
||||
@@ -837,30 +842,22 @@ private partial def splitNameLitAux (ss : Substring) (acc : List Substring) : Li
|
||||
def splitNameLit (ss : Substring) : List Substring :=
|
||||
splitNameLitAux ss [] |>.reverse
|
||||
|
||||
def _root_.Substring.toName (s : Substring) : Name :=
|
||||
match splitNameLitAux s [] with
|
||||
| [] => .anonymous
|
||||
| comps => comps.foldr (init := Name.anonymous)
|
||||
fun comp n =>
|
||||
let comp := comp.toString
|
||||
if isIdBeginEscape comp.front then
|
||||
Name.mkStr n (comp.drop 1 |>.dropRight 1)
|
||||
else if comp.front.isDigit then
|
||||
if let some k := decodeNatLitVal? comp then
|
||||
Name.mkNum n k
|
||||
else
|
||||
unreachable!
|
||||
else
|
||||
Name.mkStr n comp
|
||||
|
||||
def _root_.String.toName (s : String) : Name :=
|
||||
s.toSubstring.toName
|
||||
|
||||
def decodeNameLit (s : String) : Option Name :=
|
||||
if s.get 0 == '`' then
|
||||
match (s.toSubstring.drop 1).toName with
|
||||
| .anonymous => none
|
||||
| name => some name
|
||||
match splitNameLitAux (s.toSubstring.drop 1) [] with
|
||||
| [] => none
|
||||
| comps => some <| comps.foldr (init := Name.anonymous)
|
||||
fun comp n =>
|
||||
let comp := comp.toString
|
||||
if isIdBeginEscape comp.front then
|
||||
Name.mkStr n (comp.drop 1 |>.dropRight 1)
|
||||
else if comp.front.isDigit then
|
||||
if let some k := decodeNatLitVal? comp then
|
||||
Name.mkNum n k
|
||||
else
|
||||
unreachable!
|
||||
else
|
||||
Name.mkStr n comp
|
||||
else
|
||||
none
|
||||
|
||||
@@ -922,9 +919,6 @@ def getChar (s : CharLit) : Char :=
|
||||
def getName (s : NameLit) : Name :=
|
||||
s.raw.isNameLit?.getD .anonymous
|
||||
|
||||
def getHygieneInfo (s : HygieneInfo) : Name :=
|
||||
s.raw[0].getId
|
||||
|
||||
namespace Compat
|
||||
|
||||
scoped instance : CoeTail (Array Syntax) (Syntax.TSepArray k sep) where
|
||||
@@ -934,18 +928,12 @@ end Compat
|
||||
|
||||
end TSyntax
|
||||
|
||||
def HygieneInfo.mkIdent (s : HygieneInfo) (val : Name) (canonical := false) : Ident :=
|
||||
let src := s.raw[0]
|
||||
let id := { extractMacroScopes src.getId with name := val.eraseMacroScopes }.review
|
||||
⟨Syntax.ident (SourceInfo.fromRef src canonical) (toString val).toSubstring id []⟩
|
||||
|
||||
/-- Reflect a runtime datum back to surface syntax (best-effort). -/
|
||||
class Quote (α : Type) (k : SyntaxNodeKind := `term) where
|
||||
quote : α → TSyntax k
|
||||
|
||||
export Quote (quote)
|
||||
|
||||
set_option synthInstance.checkSynthOrder false in
|
||||
instance [Quote α k] [CoeHTCT (TSyntax k) (TSyntax [k'])] : Quote α k' := ⟨fun a => quote (k := k) a⟩
|
||||
|
||||
instance : Quote Term := ⟨id⟩
|
||||
@@ -1112,16 +1100,21 @@ instance : EmptyCollection (SepArray sep) where
|
||||
instance : EmptyCollection (TSepArray sep k) where
|
||||
emptyCollection := ⟨∅⟩
|
||||
|
||||
instance : CoeOut (SepArray sep) (Array Syntax) where
|
||||
/-
|
||||
We use `CoeTail` here instead of `Coe` to avoid a "loop" when computing `CoeTC`.
|
||||
The "loop" is interrupted using the maximum instance size threshold, but it is a performance bottleneck.
|
||||
The loop occurs because the predicate `isNewAnswer` is too imprecise.
|
||||
-/
|
||||
instance : CoeTail (SepArray sep) (Array Syntax) where
|
||||
coe := SepArray.getElems
|
||||
|
||||
instance : CoeOut (TSepArray k sep) (TSyntaxArray k) where
|
||||
instance : Coe (TSepArray k sep) (TSyntaxArray k) where
|
||||
coe := TSepArray.getElems
|
||||
|
||||
instance [Coe (TSyntax k) (TSyntax k')] : Coe (TSyntaxArray k) (TSyntaxArray k') where
|
||||
coe a := a.map Coe.coe
|
||||
|
||||
instance : CoeOut (TSyntaxArray k) (Array Syntax) where
|
||||
instance : Coe (TSyntaxArray k) (Array Syntax) where
|
||||
coe a := a.raw
|
||||
|
||||
instance : Coe Ident (TSyntax `Lean.Parser.Command.declId) where
|
||||
@@ -1225,11 +1218,8 @@ structure Config where
|
||||
etaStruct : EtaStructMode := .all
|
||||
iota : Bool := true
|
||||
proj : Bool := true
|
||||
decide : Bool := false
|
||||
decide : Bool := true
|
||||
autoUnfold : Bool := false
|
||||
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress. -/
|
||||
failIfUnchanged : Bool := true
|
||||
deriving Inhabited, BEq, Repr
|
||||
|
||||
end DSimp
|
||||
@@ -1258,13 +1248,6 @@ structure Config where
|
||||
`simp` to visit them. If `dsimp := false`, then argument is not visited.
|
||||
-/
|
||||
dsimp : Bool := true
|
||||
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress. -/
|
||||
failIfUnchanged : Bool := true
|
||||
/-- If `ground := true`, then ground terms are reduced. A term is ground when
|
||||
it does not contain free or meta variables. Reduction is interrupted at a function application `f ...`
|
||||
if `f` is marked to not be unfolded. -/
|
||||
ground : Bool := false
|
||||
deriving Inhabited, BEq, Repr
|
||||
|
||||
-- Configuration object for `simp_all`
|
||||
@@ -1280,32 +1263,15 @@ def neutralConfig : Simp.Config := {
|
||||
decide := false
|
||||
arith := false
|
||||
autoUnfold := false
|
||||
ground := false
|
||||
}
|
||||
|
||||
end Simp
|
||||
|
||||
inductive Occurrences where
|
||||
| all
|
||||
| pos (idxs : List Nat)
|
||||
| neg (idxs : List Nat)
|
||||
deriving Inhabited, BEq
|
||||
|
||||
def Occurrences.contains : Occurrences → Nat → Bool
|
||||
| all, _ => true
|
||||
| pos idxs, idx => idxs.contains idx
|
||||
| neg idxs, idx => !idxs.contains idx
|
||||
|
||||
def Occurrences.isAll : Occurrences → Bool
|
||||
| all => true
|
||||
| _ => false
|
||||
|
||||
namespace Rewrite
|
||||
|
||||
structure Config where
|
||||
transparency : TransparencyMode := TransparencyMode.reducible
|
||||
offsetCnstrs : Bool := true
|
||||
occs : Occurrences := Occurrences.all
|
||||
|
||||
end Rewrite
|
||||
|
||||
@@ -1316,15 +1282,13 @@ namespace Parser.Tactic
|
||||
/-- `erw [rules]` is a shorthand for `rw (config := { transparency := .default }) [rules]`.
|
||||
This does rewriting up to unfolding of regular definitions (by comparison to regular `rw`
|
||||
which only unfolds `@[reducible]` definitions). -/
|
||||
macro "erw" s:rwRuleSeq loc:(location)? : tactic =>
|
||||
macro "erw " s:rwRuleSeq loc:(location)? : tactic =>
|
||||
`(tactic| rw (config := { transparency := .default }) $s $(loc)?)
|
||||
|
||||
syntax simpAllKind := atomic(" (" &"all") " := " &"true" ")"
|
||||
syntax dsimpKind := atomic(" (" &"dsimp") " := " &"true" ")"
|
||||
syntax simpAllKind := atomic("(" &"all") " := " &"true" ")"
|
||||
syntax dsimpKind := atomic("(" &"dsimp") " := " &"true" ")"
|
||||
|
||||
macro (name := declareSimpLikeTactic) doc?:(docComment)?
|
||||
"declare_simp_like_tactic" opt:((simpAllKind <|> dsimpKind)?)
|
||||
ppSpace tacName:ident ppSpace tacToken:str ppSpace updateCfg:term : command => do
|
||||
macro (name := declareSimpLikeTactic) doc?:(docComment)? "declare_simp_like_tactic" opt:((simpAllKind <|> dsimpKind)?) tacName:ident tacToken:str updateCfg:term : command => do
|
||||
let (kind, tkn, stx) ←
|
||||
if opt.raw.isNone then
|
||||
pure (← `(``simp), ← `("simp"), ← `($[$doc?:docComment]? syntax (name := $tacName) $tacToken:str (config)? (discharger)? (&" only")? (" [" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic))
|
||||
|
||||
@@ -86,19 +86,19 @@ namespace Parser.Syntax
|
||||
|
||||
/-! DSL for specifying parser precedences and priorities -/
|
||||
|
||||
/-- Addition of precedences. This is normally used only for offsetting, e.g. `max + 1`. -/
|
||||
/-- Addition of precedences. This is normally used only for offseting, e.g. `max + 1`. -/
|
||||
syntax:65 (name := addPrec) prec " + " prec:66 : prec
|
||||
/-- Subtraction of precedences. This is normally used only for offsetting, e.g. `max - 1`. -/
|
||||
/-- Subtraction of precedences. This is normally used only for offseting, e.g. `max - 1`. -/
|
||||
syntax:65 (name := subPrec) prec " - " prec:66 : prec
|
||||
|
||||
/-- Addition of priorities. This is normally used only for offsetting, e.g. `default + 1`. -/
|
||||
/-- Addition of priorities. This is normally used only for offseting, e.g. `default + 1`. -/
|
||||
syntax:65 (name := addPrio) prio " + " prio:66 : prio
|
||||
/-- Subtraction of priorities. This is normally used only for offsetting, e.g. `default - 1`. -/
|
||||
/-- Subtraction of priorities. This is normally used only for offseting, e.g. `default - 1`. -/
|
||||
syntax:65 (name := subPrio) prio " - " prio:66 : prio
|
||||
|
||||
end Parser.Syntax
|
||||
|
||||
instance : CoeOut (TSyntax ks) Syntax where
|
||||
instance : CoeHead (TSyntax ks) Syntax where
|
||||
coe stx := stx.raw
|
||||
|
||||
instance : Coe SyntaxNodeKind SyntaxNodeKinds where
|
||||
@@ -132,7 +132,7 @@ macro "default" : prio => `(prio| 1000)
|
||||
/-- The standardized "low" priority `low = 100`, for things that should be lower than default priority. -/
|
||||
macro "low" : prio => `(prio| 100)
|
||||
/--
|
||||
The standardized "medium" priority `mid = 500`. This is lower than `default`, and higher than `low`.
|
||||
The standardized "medium" priority `med = 1000`. This is lower than `default`, and higher than `low`.
|
||||
-/
|
||||
macro "mid" : prio => `(prio| 500)
|
||||
/-- The standardized "high" priority `high = 10000`, for things that should be higher than default priority. -/
|
||||
@@ -363,7 +363,7 @@ namespace Parser.Tactic
|
||||
A case tag argument has the form `tag x₁ ... xₙ`; it refers to tag `tag` and renames
|
||||
the last `n` hypotheses to `x₁ ... xₙ`.
|
||||
-/
|
||||
syntax caseArg := binderIdent (ppSpace binderIdent)*
|
||||
syntax caseArg := binderIdent binderIdent*
|
||||
|
||||
end Parser.Tactic
|
||||
end Lean
|
||||
@@ -479,7 +479,7 @@ The syntax `%[a,b,c|tail]` constructs a value equivalent to `a::b::c::tail`.
|
||||
It uses binary partitioning to construct a tree of intermediate let bindings as in
|
||||
`let left := [d, e, f]; a :: b :: c :: left` to avoid creating very deep expressions.
|
||||
-/
|
||||
syntax "%[" withoutPosition(term,* " | " term) "]" : term
|
||||
syntax "%[" withoutPosition(term,* "|" term) "]" : term
|
||||
|
||||
namespace Lean
|
||||
|
||||
@@ -496,6 +496,12 @@ macro_rules
|
||||
else
|
||||
`(%[ $elems,* | List.nil ])
|
||||
|
||||
-- Declare `this` as a keyword that unhygienically binds to a scope-less `this` assumption (or other binding).
|
||||
-- The keyword prevents declaring a `this` binding except through metaprogramming, as is done by `have`/`show`.
|
||||
/-- Special identifier introduced by "anonymous" `have : ...`, `suffices p ...` etc. -/
|
||||
macro tk:"this" : term =>
|
||||
return (⟨(Syntax.ident tk.getHeadInfo "this".toSubstring `this [])⟩ : TSyntax `term)
|
||||
|
||||
/--
|
||||
Category for carrying raw syntax trees between macros; any content is printed as is by the pretty printer.
|
||||
The only accepted parser for this category is an antiquotation.
|
||||
@@ -515,11 +521,11 @@ existing code. It may be removed in a future version of the library.
|
||||
|
||||
`@[deprecated myBetterDef]` means that `myBetterDef` is the suggested replacement.
|
||||
-/
|
||||
syntax (name := deprecated) "deprecated" (ppSpace ident)? : attr
|
||||
syntax (name := deprecated) "deprecated " (ident)? : attr
|
||||
|
||||
/--
|
||||
When `parent_dir` contains the current Lean file, `include_str "path" / "to" / "file"` becomes
|
||||
a string literal with the contents of the file at `"parent_dir" / "path" / "to" / "file"`. If this
|
||||
file cannot be read, elaboration fails.
|
||||
-/
|
||||
syntax (name := includeStr) "include_str " term : term
|
||||
syntax (name := includeStr) "include_str" term : term
|
||||
|
||||
@@ -16,9 +16,9 @@ macro "Macro.trace[" id:ident "]" s:interpolatedStr(term) : term =>
|
||||
|
||||
-- Auxiliary parsers and functions for declaring notation with binders
|
||||
|
||||
syntax unbracketedExplicitBinders := (ppSpace binderIdent)+ (" : " term)?
|
||||
syntax bracketedExplicitBinders := "(" withoutPosition((binderIdent ppSpace)+ ": " term) ")"
|
||||
syntax explicitBinders := (ppSpace bracketedExplicitBinders)+ <|> unbracketedExplicitBinders
|
||||
syntax unbracketedExplicitBinders := binderIdent+ (" : " term)?
|
||||
syntax bracketedExplicitBinders := "(" withoutPosition(binderIdent+ " : " term) ")"
|
||||
syntax explicitBinders := bracketedExplicitBinders+ <|> unbracketedExplicitBinders
|
||||
|
||||
open TSyntax.Compat in
|
||||
def expandExplicitBindersAux (combinator : Syntax) (idents : Array Syntax) (type? : Option Syntax) (body : Syntax) : MacroM Syntax :=
|
||||
@@ -46,7 +46,7 @@ def expandBrackedBindersAux (combinator : Syntax) (binders : Array Syntax) (body
|
||||
loop binders.size body
|
||||
|
||||
def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
|
||||
let combinator := mkCIdentFrom (← getRef) combinatorDeclName
|
||||
let combinator := mkIdentFrom (← getRef) combinatorDeclName
|
||||
let explicitBinders := explicitBinders[0]
|
||||
if explicitBinders.getKind == ``Lean.unbracketedExplicitBinders then
|
||||
let idents := explicitBinders[0].getArgs
|
||||
@@ -58,14 +58,13 @@ def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Syntax)
|
||||
Macro.throwError "unexpected explicit binder"
|
||||
|
||||
def expandBrackedBinders (combinatorDeclName : Name) (bracketedExplicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
|
||||
let combinator := mkCIdentFrom (← getRef) combinatorDeclName
|
||||
let combinator := mkIdentFrom (← getRef) combinatorDeclName
|
||||
expandBrackedBindersAux combinator #[bracketedExplicitBinders] body
|
||||
|
||||
syntax unifConstraint := term patternIgnore(" =?= " <|> " ≟ ") term
|
||||
syntax unifConstraintElem := colGe unifConstraint ", "?
|
||||
|
||||
syntax (docComment)? attrKind "unif_hint" (ppSpace ident)? (ppSpace bracketedBinder)*
|
||||
" where " withPosition(unifConstraintElem*) patternIgnore(atomic("|" noWs "-") <|> "⊢") unifConstraint : command
|
||||
syntax (docComment)? attrKind "unif_hint " (ident)? bracketedBinder* " where " withPosition(unifConstraintElem*) patternIgnore("|-" <|> "⊢ ") unifConstraint : command
|
||||
|
||||
macro_rules
|
||||
| `($[$doc?:docComment]? $kind:attrKind unif_hint $(n)? $bs* where $[$cs₁ ≟ $cs₂]* |- $t₁ ≟ $t₂) => do
|
||||
@@ -80,7 +79,7 @@ open Lean
|
||||
|
||||
section
|
||||
open TSyntax.Compat
|
||||
macro "∃" xs:explicitBinders ", " b:term : term => expandExplicitBinders ``Exists xs b
|
||||
macro "∃ " xs:explicitBinders ", " b:term : term => expandExplicitBinders ``Exists xs b
|
||||
macro "exists" xs:explicitBinders ", " b:term : term => expandExplicitBinders ``Exists xs b
|
||||
macro "Σ" xs:explicitBinders ", " b:term : term => expandExplicitBinders ``Sigma xs b
|
||||
macro "Σ'" xs:explicitBinders ", " b:term : term => expandExplicitBinders ``PSigma xs b
|
||||
@@ -88,11 +87,8 @@ macro:35 xs:bracketedExplicitBinders " × " b:term:35 : term => expandBrackedBi
|
||||
macro:35 xs:bracketedExplicitBinders " ×' " b:term:35 : term => expandBrackedBinders ``PSigma xs b
|
||||
end
|
||||
|
||||
-- first step of a `calc` block
|
||||
syntax calcFirstStep := ppIndent(colGe term (" := " term)?)
|
||||
-- enforce indentation of calc steps so we know when to stop parsing them
|
||||
syntax calcStep := ppIndent(colGe term " := " term)
|
||||
syntax calcSteps := ppLine withPosition(calcFirstStep) withPosition((ppLine linebreak calcStep)*)
|
||||
syntax calcStep := ppIndent(colGe term " := " withPosition(term))
|
||||
|
||||
/-- Step-wise reasoning over transitive relations.
|
||||
```
|
||||
@@ -105,31 +101,14 @@ calc
|
||||
proves `a = z` from the given step-wise proofs. `=` can be replaced with any
|
||||
relation implementing the typeclass `Trans`. Instead of repeating the right-
|
||||
hand sides, subsequent left-hand sides can be replaced with `_`.
|
||||
```
|
||||
calc
|
||||
a = b := pab
|
||||
_ = c := pbc
|
||||
...
|
||||
_ = z := pyz
|
||||
```
|
||||
It is also possible to write the *first* relation as `<lhs>\n _ = <rhs> :=
|
||||
<proof>`. This is useful for aligning relation symbols, especially on longer:
|
||||
identifiers:
|
||||
```
|
||||
calc abc
|
||||
_ = bce := pabce
|
||||
_ = cef := pbcef
|
||||
...
|
||||
_ = xyz := pwxyz
|
||||
```
|
||||
|
||||
`calc` has term mode and tactic mode variants. This is the term mode variant.
|
||||
|
||||
See [Theorem Proving in Lean 4][tpil4] for more information.
|
||||
|
||||
[tpil4]: https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#calculational-proofs
|
||||
[tpil4]: https://leanprover.github.io/theorem_proving_in_lean4/quantifiers_and_equality.html#calculational-proofs
|
||||
-/
|
||||
syntax (name := calc) "calc" calcSteps : term
|
||||
syntax (name := calc) "calc" ppLine withPosition(calcStep) ppLine withPosition((calcStep ppLine)*) : term
|
||||
|
||||
/-- Step-wise reasoning over transitive relations.
|
||||
```
|
||||
@@ -142,22 +121,6 @@ calc
|
||||
proves `a = z` from the given step-wise proofs. `=` can be replaced with any
|
||||
relation implementing the typeclass `Trans`. Instead of repeating the right-
|
||||
hand sides, subsequent left-hand sides can be replaced with `_`.
|
||||
```
|
||||
calc
|
||||
a = b := pab
|
||||
_ = c := pbc
|
||||
...
|
||||
_ = z := pyz
|
||||
```
|
||||
It is also possible to write the *first* relation as `<lhs>\n _ = <rhs> :=
|
||||
<proof>`. This is useful for aligning relation symbols:
|
||||
```
|
||||
calc abc
|
||||
_ = bce := pabce
|
||||
_ = cef := pbcef
|
||||
...
|
||||
_ = xyz := pwxyz
|
||||
```
|
||||
|
||||
`calc` has term mode and tactic mode variants. This is the tactic mode variant,
|
||||
which supports an additional feature: it works even if the goal is `a = z'`
|
||||
@@ -166,9 +129,9 @@ leave a subgoal proving `z = z'`.
|
||||
|
||||
See [Theorem Proving in Lean 4][tpil4] for more information.
|
||||
|
||||
[tpil4]: https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#calculational-proofs
|
||||
[tpil4]: https://leanprover.github.io/theorem_proving_in_lean4/quantifiers_and_equality.html#calculational-proofs
|
||||
-/
|
||||
syntax (name := calcTactic) "calc" calcSteps : tactic
|
||||
syntax (name := calcTactic) "calc" ppLine withPosition(calcStep) ppLine withPosition((calcStep ppLine)*) : tactic
|
||||
|
||||
@[app_unexpander Unit.unit] def unexpandUnit : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_)) => `(())
|
||||
@@ -322,7 +285,7 @@ syntax (name := calcTactic) "calc" calcSteps : tactic
|
||||
|
||||
/--
|
||||
Apply function extensionality and introduce new hypotheses.
|
||||
The tactic `funext` will keep applying the `funext` lemma until the goal target is not reducible to
|
||||
The tactic `funext` will keep applying new the `funext` lemma until the goal target is not reducible to
|
||||
```
|
||||
|- ((fun x => ...) = (fun x => ...))
|
||||
```
|
||||
@@ -333,10 +296,9 @@ Patterns can be used like in the `intro` tactic. Example, given a goal
|
||||
```
|
||||
`funext (a, b)` applies `funext` once and performs pattern matching on the newly introduced pair.
|
||||
-/
|
||||
syntax "funext" (ppSpace colGt term:max)* : tactic
|
||||
syntax "funext " (colGt term:max)+ : tactic
|
||||
|
||||
macro_rules
|
||||
| `(tactic|funext) => `(tactic| repeat (apply funext; intro))
|
||||
| `(tactic|funext $x) => `(tactic| apply funext; intro $x:term)
|
||||
| `(tactic|funext $x $xs*) => `(tactic| apply funext; intro $x:term; funext $xs*)
|
||||
|
||||
@@ -373,14 +335,23 @@ macro_rules
|
||||
`($mods:declModifiers class $id $params* extends $parents,* $[: $ty]?
|
||||
attribute [instance] $ctor)
|
||||
|
||||
syntax cdotTk := patternIgnore("· " <|> ". ")
|
||||
section
|
||||
open Lean.Parser.Tactic
|
||||
syntax cdotTk := patternIgnore("·" <|> ".")
|
||||
/-- `· tac` focuses on the main goal and tries to solve it using `tac`, or else fails. -/
|
||||
syntax (name := cdot) cdotTk tacticSeqIndentGt : tactic
|
||||
syntax cdotTk ppHardSpace many1Indent(tactic ";"? ppLine) : tactic
|
||||
macro_rules
|
||||
| `(tactic| $cdot:cdotTk $[$tacs $[;%$sc]?]*) => do
|
||||
let tacs ← tacs.zip sc |>.mapM fun
|
||||
| (tac, none) => pure tac
|
||||
| (tac, some sc) => `(tactic| ($tac; with_annotate_state $sc skip))
|
||||
`(tactic| { with_annotate_state $cdot skip; $[$tacs]* })
|
||||
end
|
||||
|
||||
/--
|
||||
Similar to `first`, but succeeds only if one the given tactics solves the current goal.
|
||||
-/
|
||||
syntax (name := solve) "solve" withPosition((ppDedent(ppLine) colGe "| " tacticSeq)+) : tactic
|
||||
syntax (name := solve) "solve " withPosition((colGe "|" tacticSeq)+) : tactic
|
||||
|
||||
macro_rules
|
||||
| `(tactic| solve $[| $ts]* ) => `(tactic| focus first $[| ($ts); done]*)
|
||||
@@ -417,12 +388,12 @@ syntax "while " termBeforeDo " do " doSeq : doElem
|
||||
macro_rules
|
||||
| `(doElem| while $cond do $seq) => `(doElem| repeat if $cond then $seq else break)
|
||||
|
||||
syntax "repeat " doSeq ppDedent(ppLine) "until " term : doElem
|
||||
syntax "repeat " doSeq " until " term : doElem
|
||||
|
||||
macro_rules
|
||||
| `(doElem| repeat $seq until $cond) => `(doElem| repeat do $seq:doSeq; if $cond then break)
|
||||
|
||||
macro:50 e:term:51 " matches " p:sepBy1(term:51, " | ") : term =>
|
||||
macro:50 e:term:51 " matches " p:sepBy1(term:51, "|") : term =>
|
||||
`(((match $e:term with | $[$p:term]|* => true | _ => false) : Bool))
|
||||
|
||||
end Lean
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user