forked from libre-chip/fayalite
Compare commits
228 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb34aeb7f1 | |||
| 7ddb4780fa | |||
| b0e7873a17 | |||
| 1b16118ce5 | |||
| e2ca80af97 | |||
| 30ffd009f6 | |||
| 4bd6db3de8 | |||
| 98e7e91fc9 | |||
| ffca1a279d | |||
| d4d9706798 | |||
| 5d68885eaf | |||
| 31353862ce | |||
| b1116c4a1a | |||
| 6902aea3a6 | |||
| 1880ed682f | |||
| cf3e6cfc6b | |||
| ea183eac87 | |||
| 26224abe1c | |||
| 2266315944 | |||
| 7e9d7739fb | |||
| 7516ec3c24 | |||
| 8e4eeef723 | |||
| 402f457c68 | |||
| 8cff3687f7 | |||
| 80b92c7dd3 | |||
| 2aa41137d4 | |||
| a0b2dc085c | |||
| a8a541b357 | |||
| 52c41bb5db | |||
| a93e66d8ab | |||
| eb3ca59053 | |||
| dbed947408 | |||
| cb4e1f42c0 | |||
| 8c270b0e35 | |||
| c632e5d570 | |||
| 1bc835803b | |||
| 9db3240644 | |||
| caa097db0b | |||
| a96efa9696 | |||
| 4ac1bcbc0a | |||
| 39810043ea | |||
| 26b0dc3fd8 | |||
| 11281a9842 | |||
| e366793204 | |||
| a398f8f185 | |||
| 4fd4371054 | |||
| c97b44d9d6 | |||
| fbe4585578 | |||
| e4210a672f | |||
| e54558d848 | |||
| 46f3519c76 | |||
| 9e803223d0 | |||
| 2a65aa2bd5 | |||
| 2817cd3d58 | |||
| 053c1b2b10 | |||
| 17b58e8edb | |||
| df020e9c9b | |||
| 45fea70c18 | |||
| fbc8ffa5ae | |||
| 26a7090178 | |||
| 0b77d1bea0 | |||
| 840c5e1895 | |||
| c11a1743f9 | |||
| 0be9f9ce23 | |||
| 0b82178740 | |||
| 4b24a88641 | |||
| 094c77e26e | |||
| d2c8b023bf | |||
| c043ee54d0 | |||
| edcc5927a5 | |||
| 7dc4417874 | |||
| 838bd469ce | |||
| b6e4cd0614 | |||
| 3e5b2f126a | |||
| 040cefea21 | |||
| 3267cb38c4 | |||
| b3cc28e2b6 | |||
| 26840daf13 | |||
| 4d9e8d3b47 | |||
| c6feea6d51 | |||
| 409992961c | |||
| 2bdc8a7c72 | |||
| 477a1f2d29 | |||
| 4d54f903be | |||
| 3f5dd61e46 | |||
| def406ab52 | |||
| a565be1b09 | |||
| 676c1e3b7d | |||
| 169be960f8 | |||
| 2b52799f5c | |||
| 35f98f3229 | |||
| 8a63ea89d0 | |||
| 84c5978eaf | |||
| 42e3179a60 | |||
| 53ae3ff670 | |||
| 7af9abfb6f | |||
| aacd05378f | |||
| 908ccef674 | |||
| 057670c12a | |||
| f8ac78abd6 | |||
| 64ec6c0dcc | |||
| c06ef56482 | |||
| db9b1c202c | |||
| d3dd66cbf0 | |||
| b5b1ee866c | |||
| f0e3aef061 | |||
| 6d36698adf | |||
| e7e831cf00 | |||
| 4008c311bf | |||
| ef85d11327 | |||
| ae7c4be9dc | |||
| 65f9ab32f4 | |||
| 67e66ac3bd | |||
| 668e714dc9 | |||
| 88323a8c16 | |||
| 91e1b619e8 | |||
| e2d2d4110b | |||
| b1f9706e4e | |||
| 4eda4366c8 | |||
| 122c08d3cf | |||
| b08a747e20 | |||
| e0c9939147 | |||
| 07725ab489 | |||
| 36f1b9bbb6 | |||
| 9a1b047d2f | |||
| 5967e812a2 | |||
| 001fd31451 | |||
| 57aae7b7fb | |||
| 6929352be7 | |||
| 62058dc141 | |||
| c4b6a0fee6 | |||
| 9092e45447 | |||
| a40eaaa2da | |||
| 5028401a5a | |||
| e0f978fbb6 | |||
| ec3a61513b | |||
| fdc73b5f3b | |||
| a115585d5a | |||
| ab9ff4f2db | |||
| d1bd176b28 | |||
| 920d8d875f | |||
| d453755bb2 | |||
| 450e1004b6 | |||
| c0c5b550bc | |||
| 2fa0ea6192 | |||
| bd75fdfefd | |||
| 50c86e18dc | |||
| 60734cc9d1 | |||
| 3458c21f44 | |||
| 43797db36e | |||
| cdd84953d0 | |||
| 86a1bb46be | |||
| 209d5b5fe1 | |||
| d4ea826051 | |||
| 404a2ee043 | |||
| e3a2ccd41c | |||
| 3771cea78e | |||
| dcf865caec | |||
| 31d01046a8 | |||
| c16726cee6 | |||
| b63676d0ca | |||
| 7005fa3330 | |||
| 2ab8428062 | |||
| 9b06019bf5 | |||
| 36bad52978 | |||
| 21c73051ec | |||
| 304d8da0e8 | |||
| 2af38de900 | |||
| c756aeec70 | |||
| 903ca1bf30 | |||
| 8d030ac65d | |||
| 562c479b62 | |||
| 393f78a14d | |||
| 8616ee4737 | |||
| 5087f16099 | |||
| 6b31e6d515 | |||
| 564ccb30bc | |||
| ca759168ff | |||
| e4cf66adf8 | |||
| cd0dd7b7ee | |||
|
|
2e7d685dc7 | ||
| 9654167ca3 | |||
| 3ed7827485 | |||
| e504cfebfe | |||
| 9f42cab471 | |||
| 259bee39c2 | |||
| 643816d5b5 | |||
| 42afd2da0e | |||
| 15bc304bb6 | |||
| 4422157db8 | |||
| d3f52292a1 | |||
| fd45465d35 | |||
| 5e0548db26 | |||
| 12b3ba57f1 | |||
| 965fe53077 | |||
| 3abba7f9eb | |||
| 6446b71afd | |||
| d36cf92d7f | |||
| d744d85c66 | |||
| 358cdd10c8 | |||
| 9128a84284 | |||
| 546010739a | |||
| 9b5f1218fd | |||
| 89d84551f8 | |||
| c45624e3c2 | |||
| 7851bf545c | |||
| 3e3da53bd2 | |||
| fa50930ff8 | |||
| 9516fe03a1 | |||
| 52ab134673 | |||
| 698b8adc23 | |||
| 59be3bd645 | |||
| 913baa37e9 | |||
| 11ddbc43c7 | |||
| c4b5d00419 | |||
| 09aa9fbc78 | |||
| 288a6b71b9 | |||
| 0095570f19 | |||
| f54e55a143 | |||
| a6e40839ac | |||
| 3106a6fff6 | |||
| f338f37d3e | |||
| 277d3e0d4d | |||
| b288d6f8f2 | |||
| 479d59b287 | |||
| 6f904148c4 | |||
| 3ea0d98924 | |||
|
|
c1f1a8b749 |
208 changed files with 193295 additions and 4023 deletions
|
|
@ -1,77 +0,0 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
# See Notices.txt for copyright information
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
cache-primary-key:
|
||||
value: ${{ jobs.deps.outputs.cache-primary-key }}
|
||||
|
||||
jobs:
|
||||
deps:
|
||||
runs-on: debian-12
|
||||
outputs:
|
||||
cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||
steps:
|
||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: https://code.forgejo.org/actions/cache/restore@v3
|
||||
id: restore-deps
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }}
|
||||
lookup-only: true
|
||||
- name: Install Apt packages
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -qq \
|
||||
bison \
|
||||
build-essential \
|
||||
ccache \
|
||||
clang \
|
||||
cvc5 \
|
||||
flex \
|
||||
gawk \
|
||||
g++ \
|
||||
git \
|
||||
libboost-filesystem-dev \
|
||||
libboost-python-dev \
|
||||
libboost-system-dev \
|
||||
libffi-dev \
|
||||
libreadline-dev \
|
||||
lld \
|
||||
pkg-config \
|
||||
python3 \
|
||||
python3-click \
|
||||
tcl-dev \
|
||||
zlib1g-dev
|
||||
- name: Install Firtool
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p deps
|
||||
wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz
|
||||
sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz'
|
||||
tar -C deps -xvaf deps/firrtl.tar.gz
|
||||
rm -rf deps/firtool
|
||||
mv deps/firtool-1.86.0 deps/firtool
|
||||
- name: Get SymbiYosys
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --depth=1 --branch=yosys-0.45 https://github.com/YosysHQ/sby.git deps/sby
|
||||
- name: Build Z3
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --depth=1 --recursive --branch=z3-4.13.3 https://github.com/Z3Prover/z3.git deps/z3
|
||||
(cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local)
|
||||
make -C deps/z3/build -j"$(nproc)"
|
||||
- name: Build Yosys
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --depth=1 --recursive --branch=0.45 https://github.com/YosysHQ/yosys.git deps/yosys
|
||||
make -C deps/yosys -j"$(nproc)"
|
||||
- uses: https://code.forgejo.org/actions/cache/save@v3
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||
|
|
@ -3,58 +3,26 @@
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
deps:
|
||||
uses: ./.forgejo/workflows/deps.yml
|
||||
test:
|
||||
runs-on: debian-12
|
||||
needs: deps
|
||||
container:
|
||||
image: git.libre-chip.org/libre-chip/fayalite-deps:latest
|
||||
steps:
|
||||
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
scripts/check-copyright.sh
|
||||
- run: |
|
||||
apt-get update -qq
|
||||
apt-get install -qq \
|
||||
bison \
|
||||
build-essential \
|
||||
ccache \
|
||||
clang \
|
||||
cvc5 \
|
||||
flex \
|
||||
gawk \
|
||||
git \
|
||||
libboost-filesystem-dev \
|
||||
libboost-python-dev \
|
||||
libboost-system-dev \
|
||||
libffi-dev \
|
||||
libreadline-dev \
|
||||
lld \
|
||||
pkg-config \
|
||||
python3 \
|
||||
python3-click \
|
||||
tcl-dev \
|
||||
z3 \
|
||||
zlib1g-dev
|
||||
- run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.80.1
|
||||
source "$HOME/.cargo/env"
|
||||
echo "$PATH" >> "$GITHUB_PATH"
|
||||
- uses: https://code.forgejo.org/actions/cache/restore@v3
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ needs.deps.outputs.cache-primary-key }}
|
||||
fail-on-cache-miss: true
|
||||
- run: |
|
||||
make -C deps/z3/build install
|
||||
make -C deps/sby install
|
||||
make -C deps/yosys install
|
||||
export PATH="$(realpath deps/firtool/bin):$PATH"
|
||||
echo "$PATH" >> "$GITHUB_PATH"
|
||||
- uses: https://github.com/Swatinem/rust-cache@v2
|
||||
- uses: https://git.libre-chip.org/mirrors/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/master' }}
|
||||
- run: rustup override set 1.93.0
|
||||
- run: rustup component add rust-src
|
||||
- run: make -C rocq-demo
|
||||
- run: cargo test
|
||||
- run: cargo build --tests --features=unstable-doc
|
||||
- run: cargo test --doc --features=unstable-doc
|
||||
- run: cargo doc --features=unstable-doc
|
||||
- run: FAYALITE_TEST_HASHER=always_zero cargo test --test=module --features=unstable-doc,unstable-test-hasher
|
||||
- run: cargo run --example blinky yosys-nextpnr-xray --platform=arty-a7-100t --nextpnr-xilinx-chipdb-dir /opt/fayalite-deps/nextpnr-xilinx/xilinx --prjxray-db-dir /opt/fayalite-deps/prjxray-db -o target/blinky-out
|
||||
- run: cargo run --example tx_only_uart yosys-nextpnr-xray --platform=arty-a7-100t --nextpnr-xilinx-chipdb-dir /opt/fayalite-deps/nextpnr-xilinx/xilinx --prjxray-db-dir /opt/fayalite-deps/prjxray-db -o target/tx_only_uart-out
|
||||
|
|
|
|||
230
Cargo.lock
generated
230
Cargo.lock
generated
|
|
@ -1,18 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
|
|
@ -37,9 +25,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.7"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
|
|
@ -93,6 +81,12 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.8"
|
||||
|
|
@ -161,9 +155,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.9"
|
||||
version = "4.5.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
|
||||
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -171,9 +165,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.9"
|
||||
version = "4.5.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
|
||||
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -182,10 +176,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.8"
|
||||
name = "clap_complete"
|
||||
version = "4.5.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||
checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
|
@ -195,9 +198,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.1"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
|
|
@ -301,11 +304,13 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
|||
|
||||
[[package]]
|
||||
name = "fayalite"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitvec",
|
||||
"blake3",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"ctor",
|
||||
"eyre",
|
||||
"fayalite-proc-macros",
|
||||
|
|
@ -314,24 +319,28 @@ dependencies = [
|
|||
"jobslot",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"os_pipe",
|
||||
"once_cell",
|
||||
"ordered-float",
|
||||
"petgraph",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"trybuild",
|
||||
"vec_map",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fayalite-proc-macros"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"fayalite-proc-macros-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fayalite-proc-macros-impl"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"num-bigint",
|
||||
|
|
@ -345,7 +354,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fayalite-visit-gen"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
|
|
@ -357,6 +366,18 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
|
|
@ -375,12 +396,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.14"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
|
|
@ -392,12 +414,13 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -423,9 +446,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
|
@ -446,23 +469,23 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
|||
|
||||
[[package]]
|
||||
name = "jobslot"
|
||||
version = "0.2.19"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d"
|
||||
checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"derive_destructure2",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"scopeguard",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
version = "0.2.176"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
|
|
@ -472,11 +495,10 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
|||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.4"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
|
@ -501,18 +523,31 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.1"
|
||||
name = "ordered-float"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -527,9 +562,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.83"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -543,12 +578,37 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
|
|
@ -631,9 +691,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
version = "2.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -720,6 +780,12 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
|
@ -728,9 +794,21 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
version = "0.14.7+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
|
||||
dependencies = [
|
||||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.1+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
|
|
@ -775,6 +853,12 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
@ -786,11 +870,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -863,6 +947,12 @@ version = "0.0.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
|
|
@ -871,23 +961,3 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
|||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
|||
29
Cargo.toml
29
Cargo.toml
|
|
@ -5,38 +5,43 @@ resolver = "2"
|
|||
members = ["crates/*"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
license = "LGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
repository = "https://git.libre-chip.org/libre-chip/fayalite"
|
||||
keywords = ["hdl", "hardware", "semiconductors", "firrtl", "fpga"]
|
||||
categories = ["simulation", "development-tools", "compilers"]
|
||||
rust-version = "1.80.1"
|
||||
rust-version = "1.93.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
fayalite-proc-macros = { version = "=0.2.1", path = "crates/fayalite-proc-macros" }
|
||||
fayalite-proc-macros-impl = { version = "=0.2.1", path = "crates/fayalite-proc-macros-impl" }
|
||||
fayalite-visit-gen = { version = "=0.2.1", path = "crates/fayalite-visit-gen" }
|
||||
fayalite-proc-macros = { version = "=0.3.0", path = "crates/fayalite-proc-macros" }
|
||||
fayalite-proc-macros-impl = { version = "=0.3.0", path = "crates/fayalite-proc-macros-impl" }
|
||||
fayalite-visit-gen = { version = "=0.3.0", path = "crates/fayalite-visit-gen" }
|
||||
base16ct = "0.2.0"
|
||||
base64 = "0.22.1"
|
||||
bitvec = { version = "1.0.1", features = ["serde"] }
|
||||
blake3 = { version = "1.5.4", features = ["serde"] }
|
||||
clap = { version = "4.5.9", features = ["derive", "env", "string"] }
|
||||
clap_complete = "4.5.58"
|
||||
ctor = "0.2.8"
|
||||
eyre = "0.6.12"
|
||||
hashbrown = "0.14.3"
|
||||
indexmap = { version = "2.2.6", features = ["serde"] }
|
||||
jobslot = "0.2.19"
|
||||
num-bigint = "0.4.4"
|
||||
hashbrown = "0.15.2"
|
||||
indexmap = { version = "2.5.0", features = ["serde"] }
|
||||
jobslot = "0.2.23"
|
||||
num-bigint = "0.4.6"
|
||||
num-traits = "0.2.16"
|
||||
os_pipe = "1.2.1"
|
||||
once_cell = "1.21.3"
|
||||
ordered-float = { version = "5.1.0", features = ["serde"] }
|
||||
petgraph = "0.8.1"
|
||||
prettyplease = "0.2.20"
|
||||
proc-macro2 = "1.0.83"
|
||||
quote = "1.0.36"
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
serde_json = { version = "1.0.117", features = ["preserve_order"] }
|
||||
sha2 = "0.10.8"
|
||||
syn = { version = "2.0.66", features = ["full", "fold", "visit", "extra-traits"] }
|
||||
syn = { version = "2.0.93", features = ["full", "fold", "visit", "extra-traits"] }
|
||||
tempfile = "3.10.1"
|
||||
thiserror = "1.0.61"
|
||||
trybuild = "1.0"
|
||||
vec_map = "0.8.2"
|
||||
which = "6.0.1"
|
||||
|
|
|
|||
75
README.md
75
README.md
|
|
@ -7,3 +7,78 @@ See Notices.txt for copyright information
|
|||
Fayalite is a library for designing digital hardware -- a hardware description language (HDL) embedded in the Rust programming language. Fayalite's semantics are based on [FIRRTL] as interpreted by [LLVM CIRCT](https://circt.llvm.org/docs/Dialects/FIRRTL/FIRRTLAnnotations/).
|
||||
|
||||
[FIRRTL]: https://github.com/chipsalliance/firrtl-spec
|
||||
|
||||
# Building the [Blinky example] for the Arty A7 100T on Linux
|
||||
|
||||
[Blinky example]: crates/fayalite/examples/blinky.rs
|
||||
|
||||
This uses the container image containing all the external programs and files that Fayalite needs to build for FPGAs, the sources for the container image are in <https://git.libre-chip.org/libre-chip/fayalite-deps>
|
||||
|
||||
Steps:
|
||||
|
||||
Install podman (or docker).
|
||||
|
||||
Run:
|
||||
```bash
|
||||
podman run --rm --security-opt label=disable --volume="$(pwd):$(pwd)" -w="$(pwd)" -it git.libre-chip.org/libre-chip/fayalite-deps:latest cargo run --example blinky yosys-nextpnr-xray --nextpnr-xilinx-chipdb-dir /opt/fayalite-deps/nextpnr-xilinx/xilinx --prjxray-db-dir /opt/fayalite-deps/prjxray-db --platform arty-a7-100t -o target/blinky-out
|
||||
```
|
||||
|
||||
To actually program the FPGA, you'll need to install [openFPGALoader] on your host OS:
|
||||
|
||||
[openFPGALoader]: https://github.com/trabucayre/openFPGALoader
|
||||
|
||||
On Debian 12:
|
||||
```bash
|
||||
sudo apt update && sudo apt install openfpgaloader
|
||||
```
|
||||
|
||||
Then program the FPGA:
|
||||
```bash
|
||||
sudo openFPGALoader --board arty_a7_100t target/blinky-out/blinky.bit
|
||||
```
|
||||
|
||||
This will program the FPGA but leave the Flash chip unmodified, so the FPGA will revert when the board is power-cycled.
|
||||
|
||||
To program the Flash also, so it stays programmed when power-cycling the board:
|
||||
|
||||
```bash
|
||||
sudo openFPGALoader --board arty_a7_100t -f target/blinky-out/blinky.bit
|
||||
```
|
||||
|
||||
# Building the [Transmit-only UART example] for the Arty A7 100T on Linux
|
||||
|
||||
[Transmit-only UART example]: crates/fayalite/examples/tx_only_uart.rs
|
||||
|
||||
Follow the steps above of building the Blinky example, but replace `blinky` with `tx_only_uart`.
|
||||
|
||||
View the output using [tio](https://github.com/tio/tio) which you can install in Debian using `apt`.
|
||||
|
||||
Find the correct USB device:
|
||||
```bash
|
||||
sudo tio --list
|
||||
```
|
||||
|
||||
You want the device with a name like (note the `if01`, `if00` is presumably the JTAG port):
|
||||
`/dev/serial/by-id/usb-Digilent_Digilent_USB_Device_210319B4A51E-if01-port0`
|
||||
|
||||
Connect to the serial port:
|
||||
```bash
|
||||
sudo tio -b115200 /dev/serial/by-id/put-your-device-id-here
|
||||
```
|
||||
|
||||
You'll see (repeating endlessly):
|
||||
```text
|
||||
Hello World from Fayalite!!!
|
||||
Hello World from Fayalite!!!
|
||||
Hello World from Fayalite!!!
|
||||
```
|
||||
|
||||
Press Ctrl+T then `q` to exit tio.
|
||||
|
||||
# Funding
|
||||
|
||||
## NLnet Grants
|
||||
|
||||
* [Libre-Chip CPU with proof of No Spectre bugs](https://nlnet.nl/project/Libre-Chip-proof/) 2024-12-324 [(progress)](https://git.libre-chip.org/libre-chip/grant-tracking/src/branch/master/nlnet-2024-12-324/progress.md)
|
||||
|
||||
This project was funded through the [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement № [101135429](https://cordis.europa.eu/project/id/101135429). Additional funding is made available by the [Swiss State Secretariat for Education, Research and Innovation](https://www.sbfi.admin.ch/sbfi/en/home.html) (SERI).
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ forward_fold!(syn::ExprArray => fold_expr_array);
|
|||
forward_fold!(syn::ExprCall => fold_expr_call);
|
||||
forward_fold!(syn::ExprIf => fold_expr_if);
|
||||
forward_fold!(syn::ExprMatch => fold_expr_match);
|
||||
forward_fold!(syn::ExprMethodCall => fold_expr_method_call);
|
||||
forward_fold!(syn::ExprPath => fold_expr_path);
|
||||
forward_fold!(syn::ExprRepeat => fold_expr_repeat);
|
||||
forward_fold!(syn::ExprStruct => fold_expr_struct);
|
||||
|
|
@ -256,5 +257,6 @@ no_op_fold!(syn::Token![let]);
|
|||
no_op_fold!(syn::Token![mut]);
|
||||
no_op_fold!(syn::Token![static]);
|
||||
no_op_fold!(syn::Token![struct]);
|
||||
no_op_fold!(syn::Token![type]);
|
||||
no_op_fold!(syn::Token![where]);
|
||||
no_op_fold!(usize);
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
hdl_type_common::{
|
||||
common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField,
|
||||
ParsedFieldsNamed, ParsedGenerics, SplitForImpl, TypesParser, WrappedInConst,
|
||||
CustomDebugOptions, CustomDebugTrait, ItemOptions, MakeHdlTypeExpr, MaybeParsed,
|
||||
ParsedField, ParsedFieldsNamed, ParsedGenerics, SplitForImpl, TypesParser, WrappedInConst,
|
||||
common_derives, create_struct_debug_impl, get_target,
|
||||
},
|
||||
kw, Errors, HdlAttr, PairsIterExt,
|
||||
kw,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote_spanned, ToTokens};
|
||||
use quote::{ToTokens, format_ident, quote_spanned};
|
||||
use syn::{
|
||||
parse_quote, parse_quote_spanned,
|
||||
AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed,
|
||||
GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility, parse_quote,
|
||||
parse_quote_spanned,
|
||||
punctuated::{Pair, Punctuated},
|
||||
spanned::Spanned,
|
||||
token::Brace,
|
||||
AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed,
|
||||
GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -29,8 +31,11 @@ pub(crate) struct ParsedBundle {
|
|||
pub(crate) fields: MaybeParsed<ParsedFieldsNamed, FieldsNamed>,
|
||||
pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip, kw::hdl>>>,
|
||||
pub(crate) mask_type_ident: Ident,
|
||||
pub(crate) mask_type_name: String,
|
||||
pub(crate) mask_type_match_variant_ident: Ident,
|
||||
pub(crate) mask_type_sim_value_ident: Ident,
|
||||
pub(crate) match_variant_ident: Ident,
|
||||
pub(crate) sim_value_ident: Ident,
|
||||
pub(crate) builder_ident: Ident,
|
||||
pub(crate) mask_type_builder_ident: Ident,
|
||||
}
|
||||
|
|
@ -83,7 +88,14 @@ impl ParsedBundle {
|
|||
custom_bounds,
|
||||
no_static: _,
|
||||
no_runtime_generics: _,
|
||||
cmp_eq: _,
|
||||
ref get,
|
||||
custom_debug: _,
|
||||
custom_sim_display: _,
|
||||
} = options.body;
|
||||
if let Some((get, ..)) = get {
|
||||
errors.error(get, "#[hdl(get(...))] is not allowed on structs");
|
||||
}
|
||||
let mut fields = match fields {
|
||||
syn::Fields::Named(fields) => fields,
|
||||
syn::Fields::Unnamed(fields) => {
|
||||
|
|
@ -123,8 +135,11 @@ impl ParsedBundle {
|
|||
fields,
|
||||
field_flips,
|
||||
mask_type_ident: format_ident!("__{}__MaskType", ident),
|
||||
mask_type_name: format!("MaskType<{}>", ident),
|
||||
mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident),
|
||||
mask_type_sim_value_ident: format_ident!("__{}__MaskType__SimValue", ident),
|
||||
match_variant_ident: format_ident!("__{}__MatchVariant", ident),
|
||||
sim_value_ident: format_ident!("__{}__SimValue", ident),
|
||||
mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident),
|
||||
builder_ident: format_ident!("__{}__Builder", ident),
|
||||
ident,
|
||||
|
|
@ -214,7 +229,7 @@ impl Builder {
|
|||
.args
|
||||
.push_value(match get_field_state(field_index) {
|
||||
BuilderFieldState::Unfilled => parse_quote_spanned! {self.ident.span()=>
|
||||
::fayalite::bundle::Unfilled<#ty>
|
||||
()
|
||||
},
|
||||
BuilderFieldState::Generic => {
|
||||
let type_var = type_var_for_field_name(ident);
|
||||
|
|
@ -339,7 +354,6 @@ impl ToTokens for Builder {
|
|||
}
|
||||
}));
|
||||
quote_spanned! {self.ident.span()=>
|
||||
#[automatically_derived]
|
||||
#[allow(non_camel_case_types, non_snake_case, dead_code)]
|
||||
impl #impl_generics #unfilled_ty
|
||||
#where_clause
|
||||
|
|
@ -374,7 +388,7 @@ impl ToTokens for Builder {
|
|||
fn default() -> Self {
|
||||
#ident {
|
||||
#phantom_field_name: ::fayalite::__std::marker::PhantomData,
|
||||
#(#field_idents: ::fayalite::__std::default::Default::default(),)*
|
||||
#(#field_idents: (),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -386,16 +400,30 @@ impl ToTokens for Builder {
|
|||
let type_generics = self.generics.split_for_impl().1;
|
||||
quote_spanned! {self.ident.span()=>
|
||||
#[automatically_derived]
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty
|
||||
#[allow(non_camel_case_types, dead_code, private_interfaces)]
|
||||
impl #filled_impl_generics ::fayalite::expr::ValueType for #filled_ty
|
||||
#filled_where_clause
|
||||
{
|
||||
type Type = #target #type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
#target {
|
||||
#(#field_idents: ::fayalite::expr::ValueType::ty(&self.#field_idents),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
#[allow(non_camel_case_types, dead_code, private_interfaces)]
|
||||
impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty
|
||||
#filled_where_clause
|
||||
{
|
||||
fn to_expr(
|
||||
&self,
|
||||
) -> ::fayalite::expr::Expr<<Self as ::fayalite::expr::ToExpr>::Type> {
|
||||
) -> ::fayalite::expr::Expr<<Self as ::fayalite::expr::ValueType>::Type> {
|
||||
let __ty = #target {
|
||||
#(#field_idents: ::fayalite::expr::Expr::ty(self.#field_idents),)*
|
||||
#(#field_idents: ::fayalite::expr::ValueType::ty(&self.#field_idents),)*
|
||||
};
|
||||
let __field_values = [
|
||||
#(::fayalite::expr::Expr::canonical(self.#field_idents),)*
|
||||
|
|
@ -425,8 +453,11 @@ impl ToTokens for ParsedBundle {
|
|||
fields,
|
||||
field_flips,
|
||||
mask_type_ident,
|
||||
mask_type_name,
|
||||
mask_type_match_variant_ident,
|
||||
mask_type_sim_value_ident,
|
||||
match_variant_ident,
|
||||
sim_value_ident,
|
||||
builder_ident,
|
||||
mask_type_builder_ident,
|
||||
} = self;
|
||||
|
|
@ -437,11 +468,22 @@ impl ToTokens for ParsedBundle {
|
|||
custom_bounds: _,
|
||||
no_static,
|
||||
no_runtime_generics,
|
||||
cmp_eq,
|
||||
get: _,
|
||||
custom_debug: _,
|
||||
custom_sim_display,
|
||||
} = &options.body;
|
||||
let CustomDebugOptions {
|
||||
type_: custom_debug_type,
|
||||
sim: custom_debug_sim,
|
||||
mask_type: custom_debug_mask_type,
|
||||
mask_sim: custom_debug_mask_sim,
|
||||
} = options.body.custom_debug();
|
||||
let target = get_target(target, ident);
|
||||
let struct_name = ident.to_string();
|
||||
let mut item_attrs = attrs.clone();
|
||||
item_attrs.push(common_derives(span));
|
||||
ItemStruct {
|
||||
item_attrs.push(common_derives(span, false));
|
||||
let type_struct = ItemStruct {
|
||||
attrs: item_attrs,
|
||||
vis: vis.clone(),
|
||||
struct_token: *struct_token,
|
||||
|
|
@ -449,8 +491,8 @@ impl ToTokens for ParsedBundle {
|
|||
generics: generics.into(),
|
||||
fields: Fields::Named(fields.clone().into()),
|
||||
semi_token: None,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
};
|
||||
type_struct.to_tokens(tokens);
|
||||
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
||||
if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(fields), None) =
|
||||
(generics, fields, no_runtime_generics)
|
||||
|
|
@ -476,6 +518,9 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
let mut wrapped_in_const = WrappedInConst::new(tokens, span);
|
||||
let tokens = wrapped_in_const.inner();
|
||||
if custom_debug_type.is_none() {
|
||||
create_struct_debug_impl(&type_struct, &struct_name, None).to_tokens(tokens);
|
||||
}
|
||||
let builder = Builder {
|
||||
vis: vis.clone(),
|
||||
struct_token: *struct_token,
|
||||
|
|
@ -486,7 +531,6 @@ impl ToTokens for ParsedBundle {
|
|||
};
|
||||
builder.to_tokens(tokens);
|
||||
let unfilled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
|
||||
let filled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Filled);
|
||||
let mut mask_type_fields = FieldsNamed::from(fields.clone());
|
||||
for Field { ty, .. } in &mut mask_type_fields.named {
|
||||
*ty = parse_quote_spanned! {span=>
|
||||
|
|
@ -504,11 +548,9 @@ impl ToTokens for ParsedBundle {
|
|||
mask_type_builder.to_tokens(tokens);
|
||||
let unfilled_mask_type_builder_ty =
|
||||
mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
|
||||
let filled_mask_type_builder_ty =
|
||||
mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Filled);
|
||||
ItemStruct {
|
||||
let mask_type_struct = ItemStruct {
|
||||
attrs: vec![
|
||||
common_derives(span),
|
||||
common_derives(span, false),
|
||||
parse_quote_spanned! {span=>
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
},
|
||||
|
|
@ -519,17 +561,20 @@ impl ToTokens for ParsedBundle {
|
|||
generics: generics.into(),
|
||||
fields: Fields::Named(mask_type_fields.clone()),
|
||||
semi_token: None,
|
||||
};
|
||||
mask_type_struct.to_tokens(tokens);
|
||||
if custom_debug_mask_type.is_none() {
|
||||
create_struct_debug_impl(&mask_type_struct, mask_type_name, None).to_tokens(tokens);
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let mut mask_type_match_variant_fields = mask_type_fields;
|
||||
let mut mask_type_match_variant_fields = mask_type_fields.clone();
|
||||
for Field { ty, .. } in &mut mask_type_match_variant_fields.named {
|
||||
*ty = parse_quote_spanned! {span=>
|
||||
::fayalite::expr::Expr<#ty>
|
||||
};
|
||||
}
|
||||
ItemStruct {
|
||||
let mask_type_match_variant_struct = ItemStruct {
|
||||
attrs: vec![
|
||||
common_derives(span),
|
||||
common_derives(span, false),
|
||||
parse_quote_spanned! {span=>
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
},
|
||||
|
|
@ -540,17 +585,19 @@ impl ToTokens for ParsedBundle {
|
|||
generics: generics.into(),
|
||||
fields: Fields::Named(mask_type_match_variant_fields),
|
||||
semi_token: None,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
};
|
||||
mask_type_match_variant_struct.to_tokens(tokens);
|
||||
create_struct_debug_impl(&mask_type_match_variant_struct, mask_type_name, None)
|
||||
.to_tokens(tokens);
|
||||
let mut match_variant_fields = FieldsNamed::from(fields.clone());
|
||||
for Field { ty, .. } in &mut match_variant_fields.named {
|
||||
*ty = parse_quote_spanned! {span=>
|
||||
::fayalite::expr::Expr<#ty>
|
||||
};
|
||||
}
|
||||
ItemStruct {
|
||||
let match_variant_struct = ItemStruct {
|
||||
attrs: vec![
|
||||
common_derives(span),
|
||||
common_derives(span, false),
|
||||
parse_quote_spanned! {span=>
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
},
|
||||
|
|
@ -561,8 +608,103 @@ impl ToTokens for ParsedBundle {
|
|||
generics: generics.into(),
|
||||
fields: Fields::Named(match_variant_fields),
|
||||
semi_token: None,
|
||||
};
|
||||
match_variant_struct.to_tokens(tokens);
|
||||
create_struct_debug_impl(&match_variant_struct, &struct_name, None).to_tokens(tokens);
|
||||
let mut mask_type_sim_value_fields = mask_type_fields;
|
||||
for Field { ty, .. } in &mut mask_type_sim_value_fields.named {
|
||||
*ty = parse_quote_spanned! {span=>
|
||||
::fayalite::sim::value::SimValue<#ty>
|
||||
};
|
||||
}
|
||||
let mask_type_sim_value_struct = ItemStruct {
|
||||
attrs: vec![
|
||||
parse_quote_spanned! {span=>
|
||||
#[::fayalite::__std::prelude::v1::derive(
|
||||
::fayalite::__std::clone::Clone,
|
||||
)]
|
||||
},
|
||||
parse_quote_spanned! {span=>
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
},
|
||||
],
|
||||
vis: vis.clone(),
|
||||
struct_token: *struct_token,
|
||||
ident: mask_type_sim_value_ident.clone(),
|
||||
generics: generics.into(),
|
||||
fields: Fields::Named(mask_type_sim_value_fields),
|
||||
semi_token: None,
|
||||
};
|
||||
mask_type_sim_value_struct.to_tokens(tokens);
|
||||
if custom_debug_mask_sim.is_none() {
|
||||
create_struct_debug_impl(
|
||||
&mask_type_struct,
|
||||
mask_type_name,
|
||||
Some(CustomDebugTrait {
|
||||
trait_path: &parse_quote_spanned! {span=>
|
||||
::fayalite::ty::SimValueDebug
|
||||
},
|
||||
fn_name: &format_ident!("sim_value_debug", span = span),
|
||||
this_arg: &parse_quote_spanned! {span=>
|
||||
value: &<Self as ::fayalite::ty::Type>::SimValue
|
||||
},
|
||||
}),
|
||||
)
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
let mut sim_value_fields = FieldsNamed::from(fields.clone());
|
||||
for Field { ty, .. } in &mut sim_value_fields.named {
|
||||
*ty = parse_quote_spanned! {span=>
|
||||
::fayalite::sim::value::SimValue<#ty>
|
||||
};
|
||||
}
|
||||
let sim_value_struct = ItemStruct {
|
||||
attrs: vec![
|
||||
parse_quote_spanned! {span=>
|
||||
#[::fayalite::__std::prelude::v1::derive(
|
||||
::fayalite::__std::clone::Clone,
|
||||
)]
|
||||
},
|
||||
parse_quote_spanned! {span=>
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
},
|
||||
],
|
||||
vis: vis.clone(),
|
||||
struct_token: *struct_token,
|
||||
ident: sim_value_ident.clone(),
|
||||
generics: generics.into(),
|
||||
fields: Fields::Named(sim_value_fields),
|
||||
semi_token: None,
|
||||
};
|
||||
sim_value_struct.to_tokens(tokens);
|
||||
if custom_debug_sim.is_none() {
|
||||
create_struct_debug_impl(
|
||||
&type_struct,
|
||||
&struct_name,
|
||||
Some(CustomDebugTrait {
|
||||
trait_path: &parse_quote_spanned! {span=>
|
||||
::fayalite::ty::SimValueDebug
|
||||
},
|
||||
fn_name: &format_ident!("sim_value_debug", span = span),
|
||||
this_arg: &parse_quote_spanned! {span=>
|
||||
value: &<Self as ::fayalite::ty::Type>::SimValue
|
||||
},
|
||||
}),
|
||||
)
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
if custom_sim_display.is_some() {
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
|
||||
}
|
||||
}
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let this_token = Ident::new("__this", span);
|
||||
let fields_token = Ident::new("__fields", span);
|
||||
let self_token = Token;
|
||||
|
|
@ -613,6 +755,32 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
},
|
||||
));
|
||||
let sim_value_from_opaque_fields =
|
||||
Vec::from_iter(fields.named().into_iter().map(|field| {
|
||||
let ident: &Ident = field.ident().as_ref().unwrap();
|
||||
quote_spanned! {span=>
|
||||
#ident: v.field_from_opaque(),
|
||||
}
|
||||
}));
|
||||
let sim_value_clone_from_opaque_fields =
|
||||
Vec::from_iter(fields.named().into_iter().map(|field| {
|
||||
let ident: &Ident = field.ident().as_ref().unwrap();
|
||||
quote_spanned! {span=>
|
||||
v.field_clone_from_opaque(&mut value.#ident);
|
||||
}
|
||||
}));
|
||||
let sim_value_to_opaque_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
|
||||
let ident: &Ident = field.ident().as_ref().unwrap();
|
||||
quote_spanned! {span=>
|
||||
v.field(&value.#ident);
|
||||
}
|
||||
}));
|
||||
let value_type_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
|
||||
let ident: &Ident = field.ident().as_ref().unwrap();
|
||||
quote_spanned! {span=>
|
||||
#ident: ::fayalite::expr::ValueType::ty(&self.#ident),
|
||||
}
|
||||
}));
|
||||
let fields_len = fields.named().into_iter().len();
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
|
|
@ -621,6 +789,7 @@ impl ToTokens for ParsedBundle {
|
|||
{
|
||||
type BaseType = ::fayalite::bundle::Bundle;
|
||||
type MaskType = #mask_type_ident #type_generics;
|
||||
type SimValue = #mask_type_sim_value_ident #type_generics;
|
||||
type MatchVariant = #mask_type_match_variant_ident #type_generics;
|
||||
type MatchActiveScope = ();
|
||||
type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
|
||||
|
|
@ -658,13 +827,41 @@ impl ToTokens for ParsedBundle {
|
|||
fn source_location() -> ::fayalite::source_location::SourceLocation {
|
||||
::fayalite::source_location::SourceLocation::caller()
|
||||
}
|
||||
fn sim_value_from_opaque(
|
||||
&self,
|
||||
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
|
||||
) -> <Self as ::fayalite::ty::Type>::SimValue {
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
|
||||
#mask_type_sim_value_ident {
|
||||
#(#sim_value_from_opaque_fields)*
|
||||
}
|
||||
}
|
||||
fn sim_value_clone_from_opaque(
|
||||
&self,
|
||||
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
|
||||
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
|
||||
) {
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
|
||||
#(#sim_value_clone_from_opaque_fields)*
|
||||
}
|
||||
fn sim_value_to_opaque<'__w>(
|
||||
&self,
|
||||
value: &<Self as ::fayalite::ty::Type>::SimValue,
|
||||
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
|
||||
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
|
||||
#(#sim_value_to_opaque_fields)*
|
||||
v.finish()
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type Builder = #unfilled_mask_type_builder_ty;
|
||||
type FilledBuilder = #filled_mask_type_builder_ty;
|
||||
fn fields(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> {
|
||||
::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..])
|
||||
}
|
||||
|
|
@ -689,11 +886,76 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::fmt::Debug for #mask_type_sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||
<#mask_type_ident #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::ValueType for #mask_type_sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type Type = #mask_type_ident #type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
#mask_type_ident {
|
||||
#(#value_type_fields)*
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #mask_type_ident {
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
}
|
||||
fn into_sim_value(
|
||||
self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #mask_type_ident {
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#mask_type_ident #type_generics>
|
||||
for #mask_type_sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value_with_type(
|
||||
&self,
|
||||
ty: #mask_type_ident #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
}
|
||||
fn into_sim_value_with_type(
|
||||
self,
|
||||
ty: #mask_type_ident #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::ty::Type for #target #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type BaseType = ::fayalite::bundle::Bundle;
|
||||
type MaskType = #mask_type_ident #type_generics;
|
||||
type SimValue = #sim_value_ident #type_generics;
|
||||
type MatchVariant = #match_variant_ident #type_generics;
|
||||
type MatchActiveScope = ();
|
||||
type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
|
||||
|
|
@ -733,13 +995,41 @@ impl ToTokens for ParsedBundle {
|
|||
fn source_location() -> ::fayalite::source_location::SourceLocation {
|
||||
::fayalite::source_location::SourceLocation::caller()
|
||||
}
|
||||
fn sim_value_from_opaque(
|
||||
&self,
|
||||
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
|
||||
) -> <Self as ::fayalite::ty::Type>::SimValue {
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
|
||||
#sim_value_ident {
|
||||
#(#sim_value_from_opaque_fields)*
|
||||
}
|
||||
}
|
||||
fn sim_value_clone_from_opaque(
|
||||
&self,
|
||||
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
|
||||
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
|
||||
) {
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
|
||||
#(#sim_value_clone_from_opaque_fields)*
|
||||
}
|
||||
fn sim_value_to_opaque<'__w>(
|
||||
&self,
|
||||
value: &<Self as ::fayalite::ty::Type>::SimValue,
|
||||
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
|
||||
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
|
||||
#(#sim_value_to_opaque_fields)*
|
||||
v.finish()
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type Builder = #unfilled_builder_ty;
|
||||
type FilledBuilder = #filled_builder_ty;
|
||||
fn fields(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> {
|
||||
::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..])
|
||||
}
|
||||
|
|
@ -763,8 +1053,275 @@ impl ToTokens for ParsedBundle {
|
|||
::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval))
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::ValueType for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type Type = #target #type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
#target {
|
||||
#(#value_type_fields)*
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #target {
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
}
|
||||
fn into_sim_value(
|
||||
self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #target {
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics>
|
||||
for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value_with_type(
|
||||
&self,
|
||||
ty: #target #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
}
|
||||
fn into_sim_value_with_type(
|
||||
self,
|
||||
ty: #target #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
if let Some((cmp_eq,)) = cmp_eq {
|
||||
let mut cmp_eq_where_clause =
|
||||
Generics::from(generics)
|
||||
.where_clause
|
||||
.unwrap_or_else(|| syn::WhereClause {
|
||||
where_token: Token,
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
let mut fields_value_eq = vec![];
|
||||
let mut fields_value_ne = vec![];
|
||||
let mut fields_expr_eq = vec![];
|
||||
let mut fields_expr_ne = vec![];
|
||||
let mut fields_valueless_eq = vec![];
|
||||
let mut fields_valueless_ne = vec![];
|
||||
let mut fields_structural_eq = vec![];
|
||||
for field in fields.named() {
|
||||
let field_ident = field.ident();
|
||||
let field_ty = field.ty();
|
||||
cmp_eq_where_clause
|
||||
.predicates
|
||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||
});
|
||||
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
|
||||
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||
});
|
||||
fields_value_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||
__lhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__lhs_value.#field_ident),
|
||||
__rhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__rhs_value.#field_ident),
|
||||
)
|
||||
});
|
||||
fields_value_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_ne(
|
||||
__lhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__lhs_value.#field_ident),
|
||||
__rhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__rhs_value.#field_ident),
|
||||
)
|
||||
});
|
||||
fields_expr_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(
|
||||
__lhs.#field_ident,
|
||||
__rhs.#field_ident,
|
||||
)
|
||||
});
|
||||
fields_expr_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_ne(
|
||||
__lhs.#field_ident,
|
||||
__rhs.#field_ident,
|
||||
)
|
||||
});
|
||||
fields_valueless_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_valueless_eq(
|
||||
::fayalite::expr::Valueless::new(__lhs.#field_ident),
|
||||
::fayalite::expr::Valueless::new(__rhs.#field_ident),
|
||||
)
|
||||
});
|
||||
fields_valueless_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_valueless_ne(
|
||||
::fayalite::expr::Valueless::new(__lhs.#field_ident),
|
||||
::fayalite::expr::Valueless::new(__rhs.#field_ident),
|
||||
)
|
||||
});
|
||||
}
|
||||
let value_eq_body;
|
||||
let value_ne_body;
|
||||
let expr_eq_body;
|
||||
let expr_ne_body;
|
||||
let valueless_eq_body;
|
||||
let valueless_ne_body;
|
||||
let structural_eq;
|
||||
if fields_len == 0 {
|
||||
value_eq_body = quote_spanned! {span=>
|
||||
true
|
||||
};
|
||||
value_ne_body = quote_spanned! {span=>
|
||||
false
|
||||
};
|
||||
expr_eq_body = quote_spanned! {span=>
|
||||
::fayalite::expr::ToExpr::to_expr(&true)
|
||||
};
|
||||
expr_ne_body = quote_spanned! {span=>
|
||||
::fayalite::expr::ToExpr::to_expr(&false)
|
||||
};
|
||||
valueless_eq_body = quote_spanned! {span=>
|
||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||
};
|
||||
valueless_ne_body = quote_spanned! {span=>
|
||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||
};
|
||||
structural_eq = quote_spanned! {span=>
|
||||
true
|
||||
};
|
||||
} else {
|
||||
value_eq_body = quote_spanned! {span=>
|
||||
#(#fields_value_eq)&*
|
||||
};
|
||||
value_ne_body = quote_spanned! {span=>
|
||||
#(#fields_value_ne)|*
|
||||
};
|
||||
expr_eq_body = quote_spanned! {span=>
|
||||
#(#fields_expr_eq)&*
|
||||
};
|
||||
expr_ne_body = quote_spanned! {span=>
|
||||
#(#fields_expr_ne)|*
|
||||
};
|
||||
valueless_eq_body = quote_spanned! {span=>
|
||||
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
|
||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||
#(#fields_valueless_eq)&*
|
||||
};
|
||||
valueless_ne_body = quote_spanned! {span=>
|
||||
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
|
||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||
#(#fields_valueless_ne)|*
|
||||
};
|
||||
structural_eq = quote_spanned! {span=>
|
||||
#(#fields_structural_eq)&&*
|
||||
};
|
||||
};
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||
#cmp_eq_where_clause
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
__lhs: Self,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs: Self,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
) -> ::fayalite::__std::primitive::bool {
|
||||
#value_eq_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_ne(
|
||||
__lhs: Self,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs: Self,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
) -> ::fayalite::__std::primitive::bool {
|
||||
#value_ne_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(
|
||||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
||||
::fayalite::expr::ops::StructuralEq::try_new(
|
||||
::fayalite::expr::Expr::canonical(__lhs),
|
||||
::fayalite::expr::Expr::canonical(__rhs),
|
||||
)
|
||||
{
|
||||
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
||||
}
|
||||
}
|
||||
#expr_eq_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_ne(
|
||||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||
return !::fayalite::expr::ToExpr::to_expr(
|
||||
&::fayalite::expr::ops::StructuralEq::new(
|
||||
::fayalite::expr::Expr::canonical(__lhs),
|
||||
::fayalite::expr::Expr::canonical(__rhs),
|
||||
),
|
||||
);
|
||||
}
|
||||
#expr_ne_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_eq(
|
||||
__lhs: ::fayalite::expr::Valueless<Self>,
|
||||
__rhs: ::fayalite::expr::Valueless<Self>,
|
||||
) -> ::fayalite::expr::Valueless<::fayalite::int::Bool> {
|
||||
#valueless_eq_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_ne(
|
||||
__lhs: ::fayalite::expr::Valueless<Self>,
|
||||
__rhs: ::fayalite::expr::Valueless<Self>,
|
||||
) -> ::fayalite::expr::Valueless<::fayalite::int::Bool> {
|
||||
#valueless_ne_body
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
|
||||
let static_generics = generics.clone().for_static_type();
|
||||
let (static_impl_generics, static_type_generics, static_where_clause) =
|
||||
|
|
@ -800,6 +1357,14 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
}));
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::__std::default::Default for #mask_type_ident #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
fn default() -> Self {
|
||||
<Self as ::fayalite::ty::StaticType>::TYPE
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics
|
||||
#static_where_clause
|
||||
|
|
@ -822,6 +1387,15 @@ impl ToTokens for ParsedBundle {
|
|||
};
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::__std::default::Default
|
||||
for #target #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
fn default() -> Self {
|
||||
<Self as ::fayalite::ty::StaticType>::TYPE
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
hdl_type_common::{
|
||||
common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics,
|
||||
ParsedType, SplitForImpl, TypesParser, WrappedInConst,
|
||||
CustomDebugOptions, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType,
|
||||
SplitForImpl, TypesParser, WrappedInConst, common_derives, create_struct_debug_impl,
|
||||
get_target,
|
||||
},
|
||||
kw, Errors, HdlAttr, PairsIterExt,
|
||||
kw,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote_spanned, ToTokens};
|
||||
use quote::{ToTokens, format_ident, quote_spanned};
|
||||
use syn::{
|
||||
parse_quote_spanned,
|
||||
Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident,
|
||||
ItemEnum, ItemStruct, Token, Type, Variant, Visibility, parse_quote_spanned,
|
||||
punctuated::{Pair, Punctuated},
|
||||
token::{Brace, Paren},
|
||||
Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident,
|
||||
ItemEnum, ItemStruct, Token, Type, Variant, Visibility,
|
||||
};
|
||||
|
||||
crate::options! {
|
||||
|
|
@ -129,6 +130,9 @@ pub(crate) struct ParsedEnum {
|
|||
pub(crate) brace_token: Brace,
|
||||
pub(crate) variants: Punctuated<ParsedVariant, Token![,]>,
|
||||
pub(crate) match_variant_ident: Ident,
|
||||
pub(crate) sim_value_ident: Ident,
|
||||
pub(crate) sim_builder_ident: Ident,
|
||||
pub(crate) sim_builder_ty_field_ident: Ident,
|
||||
}
|
||||
|
||||
impl ParsedEnum {
|
||||
|
|
@ -155,7 +159,32 @@ impl ParsedEnum {
|
|||
custom_bounds,
|
||||
no_static: _,
|
||||
no_runtime_generics: _,
|
||||
cmp_eq: _,
|
||||
ref get,
|
||||
custom_debug: _,
|
||||
custom_sim_display: _,
|
||||
} = options.body;
|
||||
if let Some((get, ..)) = get {
|
||||
errors.error(get, "#[hdl(get(...))] is not allowed on enums");
|
||||
}
|
||||
let CustomDebugOptions {
|
||||
type_: _,
|
||||
sim: _,
|
||||
mask_type,
|
||||
mask_sim,
|
||||
} = options.body.custom_debug();
|
||||
if let Some((mask_type,)) = mask_type {
|
||||
errors.error(
|
||||
mask_type,
|
||||
"#[hdl(custom_debug(mask_type)] is not allowed on enums",
|
||||
);
|
||||
}
|
||||
if let Some((mask_sim,)) = mask_sim {
|
||||
errors.error(
|
||||
mask_sim,
|
||||
"#[hdl(custom_debug(mask_sim)] is not allowed on enums",
|
||||
);
|
||||
}
|
||||
attrs.retain(|attr| {
|
||||
if attr.path().is_ident("repr") {
|
||||
errors.error(attr, "#[repr] is not supported on #[hdl] enums");
|
||||
|
|
@ -186,6 +215,9 @@ impl ParsedEnum {
|
|||
brace_token,
|
||||
variants,
|
||||
match_variant_ident: format_ident!("__{}__MatchVariant", ident),
|
||||
sim_value_ident: format_ident!("__{}__SimValue", ident),
|
||||
sim_builder_ident: format_ident!("__{}__SimBuilder", ident),
|
||||
sim_builder_ty_field_ident: format_ident!("__ty", span = ident.span()),
|
||||
ident,
|
||||
})
|
||||
}
|
||||
|
|
@ -203,6 +235,9 @@ impl ToTokens for ParsedEnum {
|
|||
brace_token,
|
||||
variants,
|
||||
match_variant_ident,
|
||||
sim_value_ident,
|
||||
sim_builder_ident,
|
||||
sim_builder_ty_field_ident,
|
||||
} = self;
|
||||
let span = ident.span();
|
||||
let ItemOptions {
|
||||
|
|
@ -211,10 +246,21 @@ impl ToTokens for ParsedEnum {
|
|||
custom_bounds: _,
|
||||
no_static,
|
||||
no_runtime_generics,
|
||||
cmp_eq,
|
||||
get: _,
|
||||
custom_debug: _,
|
||||
custom_sim_display,
|
||||
} = &options.body;
|
||||
let CustomDebugOptions {
|
||||
type_: custom_debug_type,
|
||||
sim: custom_debug_sim,
|
||||
mask_type: _,
|
||||
mask_sim: _,
|
||||
} = options.body.custom_debug();
|
||||
let target = get_target(target, ident);
|
||||
let enum_name = ident.to_string();
|
||||
let mut struct_attrs = attrs.clone();
|
||||
struct_attrs.push(common_derives(span));
|
||||
struct_attrs.push(common_derives(span, false));
|
||||
struct_attrs.push(parse_quote_spanned! {span=>
|
||||
#[allow(non_snake_case)]
|
||||
});
|
||||
|
|
@ -254,7 +300,7 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
},
|
||||
));
|
||||
ItemStruct {
|
||||
let type_struct = ItemStruct {
|
||||
attrs: struct_attrs,
|
||||
vis: vis.clone(),
|
||||
struct_token: Token,
|
||||
|
|
@ -269,8 +315,8 @@ impl ToTokens for ParsedEnum {
|
|||
})
|
||||
},
|
||||
semi_token: None,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
};
|
||||
type_struct.to_tokens(tokens);
|
||||
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
||||
if let (MaybeParsed::Parsed(generics), None) = (generics, no_runtime_generics) {
|
||||
generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
|
||||
|
|
@ -354,6 +400,9 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
if custom_debug_type.is_none() {
|
||||
create_struct_debug_impl(&type_struct, &enum_name, None).to_tokens(tokens);
|
||||
}
|
||||
let mut enum_attrs = attrs.clone();
|
||||
enum_attrs.push(parse_quote_spanned! {span=>
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
|
|
@ -404,11 +453,136 @@ impl ToTokens for ParsedEnum {
|
|||
)),
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let mut struct_attrs = attrs.clone();
|
||||
struct_attrs.push(parse_quote_spanned! {span=>
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
});
|
||||
ItemStruct {
|
||||
attrs: struct_attrs,
|
||||
vis: vis.clone(),
|
||||
struct_token: Token,
|
||||
ident: sim_builder_ident.clone(),
|
||||
generics: generics.into(),
|
||||
fields: FieldsNamed {
|
||||
brace_token: *brace_token,
|
||||
named: Punctuated::from_iter([Field {
|
||||
attrs: vec![],
|
||||
vis: Visibility::Inherited,
|
||||
mutability: FieldMutability::None,
|
||||
ident: Some(sim_builder_ty_field_ident.clone()),
|
||||
colon_token: Some(Token),
|
||||
ty: parse_quote_spanned! {span=>
|
||||
#target #type_generics
|
||||
},
|
||||
}]),
|
||||
}
|
||||
.into(),
|
||||
semi_token: None,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let mut enum_attrs = attrs.clone();
|
||||
enum_attrs.push(parse_quote_spanned! {span=>
|
||||
#[::fayalite::__std::prelude::v1::derive(
|
||||
::fayalite::__std::clone::Clone,
|
||||
)]
|
||||
});
|
||||
enum_attrs.push(parse_quote_spanned! {span=>
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
});
|
||||
let sim_value_has_unknown_variant = !variants.len().is_power_of_two();
|
||||
let sim_value_unknown_variant_name = sim_value_has_unknown_variant.then(|| {
|
||||
let mut name = String::new();
|
||||
let unknown = "Unknown";
|
||||
loop {
|
||||
let orig_len = name.len();
|
||||
name.push_str(unknown);
|
||||
if variants.iter().all(|v| v.ident != name) {
|
||||
break Ident::new(&name, span);
|
||||
}
|
||||
name.truncate(orig_len);
|
||||
name.push('_');
|
||||
}
|
||||
});
|
||||
let sim_value_unknown_variant =
|
||||
sim_value_unknown_variant_name
|
||||
.as_ref()
|
||||
.map(|unknown_variant_name| {
|
||||
Pair::End(parse_quote_spanned! {span=>
|
||||
#unknown_variant_name(::fayalite::enum_::UnknownVariantSimValue)
|
||||
})
|
||||
});
|
||||
ItemEnum {
|
||||
attrs: enum_attrs,
|
||||
vis: vis.clone(),
|
||||
enum_token: *enum_token,
|
||||
ident: sim_value_ident.clone(),
|
||||
generics: generics.into(),
|
||||
brace_token: *brace_token,
|
||||
variants: Punctuated::from_iter(
|
||||
variants
|
||||
.pairs()
|
||||
.map_pair_value_ref(
|
||||
|ParsedVariant {
|
||||
attrs,
|
||||
options: _,
|
||||
ident,
|
||||
field,
|
||||
}| Variant {
|
||||
attrs: attrs.clone(),
|
||||
ident: ident.clone(),
|
||||
fields: match field {
|
||||
Some(ParsedVariantField {
|
||||
paren_token,
|
||||
attrs,
|
||||
options: _,
|
||||
ty,
|
||||
comma_token,
|
||||
}) => Fields::Unnamed(FieldsUnnamed {
|
||||
paren_token: *paren_token,
|
||||
unnamed: Punctuated::from_iter([
|
||||
Pair::new(
|
||||
Field {
|
||||
attrs: attrs.clone(),
|
||||
vis: Visibility::Inherited,
|
||||
mutability: FieldMutability::None,
|
||||
ident: None,
|
||||
colon_token: None,
|
||||
ty: parse_quote_spanned! {span=>
|
||||
::fayalite::sim::value::SimValue<#ty>
|
||||
},
|
||||
},
|
||||
Some(comma_token.unwrap_or(Token))),
|
||||
),
|
||||
Pair::new(
|
||||
Field {
|
||||
attrs: vec![],
|
||||
vis: Visibility::Inherited,
|
||||
mutability: FieldMutability::None,
|
||||
ident: None,
|
||||
colon_token: None,
|
||||
ty: parse_quote_spanned! {span=>
|
||||
::fayalite::enum_::EnumPaddingSimValue
|
||||
},
|
||||
},
|
||||
None,
|
||||
),
|
||||
]),
|
||||
}),
|
||||
None => Fields::Unnamed(parse_quote_spanned! {span=>
|
||||
(::fayalite::enum_::EnumPaddingSimValue)
|
||||
}),
|
||||
},
|
||||
discriminant: None,
|
||||
},
|
||||
)
|
||||
.chain(sim_value_unknown_variant),
|
||||
),
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let self_token = Token;
|
||||
for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() {
|
||||
if let Some(ParsedVariantField { ty, .. }) = field {
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #target #type_generics
|
||||
#where_clause
|
||||
{
|
||||
|
|
@ -430,10 +604,27 @@ impl ToTokens for ParsedEnum {
|
|||
)
|
||||
}
|
||||
}
|
||||
impl #impl_generics #sim_builder_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
#[allow(non_snake_case, dead_code)]
|
||||
#vis fn #ident<__V: ::fayalite::sim::value::ToSimValueWithType<#ty>>(
|
||||
#self_token,
|
||||
v: __V,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
let v = ::fayalite::sim::value::ToSimValueWithType::into_sim_value_with_type(
|
||||
v,
|
||||
#self_token.#sim_builder_ty_field_ident.#ident,
|
||||
);
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
#self_token.#sim_builder_ty_field_ident,
|
||||
#sim_value_ident::#ident(v, ::fayalite::enum_::EnumPaddingSimValue::new()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #target #type_generics
|
||||
#where_clause
|
||||
{
|
||||
|
|
@ -448,6 +639,19 @@ impl ToTokens for ParsedEnum {
|
|||
)
|
||||
}
|
||||
}
|
||||
impl #impl_generics #sim_builder_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
#[allow(non_snake_case, dead_code)]
|
||||
#vis fn #ident(
|
||||
#self_token,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
#self_token.#sim_builder_ty_field_ident,
|
||||
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
|
|
@ -529,6 +733,426 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
},
|
||||
));
|
||||
let sim_value_from_opaque_unknown_match_arm = if let Some(sim_value_unknown_variant_name) =
|
||||
&sim_value_unknown_variant_name
|
||||
{
|
||||
quote_spanned! {span=>
|
||||
_ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_opaque()),
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
_ => ::fayalite::__std::unreachable!(),
|
||||
}
|
||||
};
|
||||
let sim_value_from_opaque_match_arms = Vec::from_iter(
|
||||
variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(
|
||||
index,
|
||||
ParsedVariant {
|
||||
attrs: _,
|
||||
options: _,
|
||||
ident,
|
||||
field,
|
||||
},
|
||||
)| {
|
||||
if let Some(_) = field {
|
||||
quote_spanned! {span=>
|
||||
#index => {
|
||||
let (field, padding) = v.variant_with_field_from_opaque();
|
||||
#sim_value_ident::#ident(field, padding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
#index => #sim_value_ident::#ident(
|
||||
v.variant_no_field_from_opaque(),
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.chain([sim_value_from_opaque_unknown_match_arm]),
|
||||
);
|
||||
let sim_value_clone_from_opaque_unknown_match_arm =
|
||||
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
||||
quote_spanned! {span=>
|
||||
_ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value {
|
||||
v.unknown_variant_clone_from_opaque(value);
|
||||
} else {
|
||||
*value = #sim_value_ident::#sim_value_unknown_variant_name(
|
||||
v.unknown_variant_from_opaque(),
|
||||
);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
_ => ::fayalite::__std::unreachable!(),
|
||||
}
|
||||
};
|
||||
let sim_value_clone_from_opaque_match_arms = Vec::from_iter(
|
||||
variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(
|
||||
index,
|
||||
ParsedVariant {
|
||||
attrs: _,
|
||||
options: _,
|
||||
ident,
|
||||
field,
|
||||
},
|
||||
)| {
|
||||
if let Some(_) = field {
|
||||
quote_spanned! {span=>
|
||||
#index => if let #sim_value_ident::#ident(field, padding) = value {
|
||||
v.variant_with_field_clone_from_opaque(field, padding);
|
||||
} else {
|
||||
let (field, padding) = v.variant_with_field_from_opaque();
|
||||
*value = #sim_value_ident::#ident(field, padding);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
#index => if let #sim_value_ident::#ident(padding) = value {
|
||||
v.variant_no_field_clone_from_opaque(padding);
|
||||
} else {
|
||||
*value = #sim_value_ident::#ident(
|
||||
v.variant_no_field_from_opaque(),
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.chain([sim_value_clone_from_opaque_unknown_match_arm]),
|
||||
);
|
||||
let sim_value_to_opaque_match_arms = Vec::from_iter(
|
||||
variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(
|
||||
index,
|
||||
ParsedVariant {
|
||||
attrs: _,
|
||||
options: _,
|
||||
ident,
|
||||
field,
|
||||
},
|
||||
)| {
|
||||
if let Some(_) = field {
|
||||
quote_spanned! {span=>
|
||||
#sim_value_ident::#ident(field, padding) => {
|
||||
v.variant_with_field_to_opaque(#index, field, padding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
#sim_value_ident::#ident(padding) => {
|
||||
v.variant_no_field_to_opaque(#index, padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.chain(sim_value_unknown_variant_name.as_ref().map(
|
||||
|sim_value_unknown_variant_name| {
|
||||
quote_spanned! {span=>
|
||||
#sim_value_ident::#sim_value_unknown_variant_name(value) => {
|
||||
v.unknown_variant_to_opaque(value)
|
||||
}
|
||||
}
|
||||
},
|
||||
)),
|
||||
);
|
||||
if custom_debug_sim.is_none() {
|
||||
let debug_match_arms = Vec::from_iter(
|
||||
variants
|
||||
.iter()
|
||||
.map(
|
||||
|ParsedVariant {
|
||||
attrs: _,
|
||||
options: _,
|
||||
ident,
|
||||
field,
|
||||
}| {
|
||||
let variant_name = ident.to_string();
|
||||
if let Some(_) = field {
|
||||
quote_spanned! {span=>
|
||||
#sim_value_ident::#ident(field, _) => {
|
||||
f.debug_tuple(#variant_name).field(field).finish()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
#sim_value_ident::#ident(_) => {
|
||||
f.write_str(#variant_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.chain(sim_value_unknown_variant_name.as_ref().map(
|
||||
|sim_value_unknown_variant_name| {
|
||||
let sim_value_unknown_variant_name_str =
|
||||
sim_value_unknown_variant_name.to_string();
|
||||
quote_spanned! {span=>
|
||||
#sim_value_ident::#sim_value_unknown_variant_name(_) => {
|
||||
f.write_str(#sim_value_unknown_variant_name_str)
|
||||
}
|
||||
}
|
||||
},
|
||||
)),
|
||||
);
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::ty::SimValueDebug for #target #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn sim_value_debug(
|
||||
value: &<Self as ::fayalite::ty::Type>::SimValue,
|
||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
||||
) -> ::fayalite::__std::fmt::Result {
|
||||
match value {
|
||||
#(#debug_match_arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
if custom_sim_display.is_some() {
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(
|
||||
&self,
|
||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
||||
) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(
|
||||
self,
|
||||
f,
|
||||
)
|
||||
}
|
||||
}
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
if let Some((cmp_eq,)) = cmp_eq {
|
||||
let mut cmp_eq_where_clause =
|
||||
Generics::from(generics)
|
||||
.where_clause
|
||||
.unwrap_or_else(|| syn::WhereClause {
|
||||
where_token: Token,
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
let mut variants_value_eq = vec![];
|
||||
let mut variants_expr_eq = vec![];
|
||||
let mut fields_valueless_eq = vec![];
|
||||
let mut structural_eq: Option<TokenStream> = None;
|
||||
for (
|
||||
variant_index,
|
||||
ParsedVariant {
|
||||
attrs: _,
|
||||
options: variant_options,
|
||||
ident: variant_ident,
|
||||
field,
|
||||
},
|
||||
) in variants.iter().enumerate()
|
||||
{
|
||||
let VariantOptions {} = variant_options.body;
|
||||
if let Some(ParsedVariantField {
|
||||
paren_token: _,
|
||||
attrs: _,
|
||||
options: field_options,
|
||||
ty: field_ty,
|
||||
comma_token: _,
|
||||
}) = field
|
||||
{
|
||||
let FieldOptions {} = field_options.body;
|
||||
cmp_eq_where_clause
|
||||
.predicates
|
||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||
});
|
||||
match &mut structural_eq {
|
||||
Some(structural_eq) => {
|
||||
structural_eq.extend(quote_spanned! {cmp_eq.span=>
|
||||
&& <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||
});
|
||||
}
|
||||
None => {
|
||||
structural_eq = Some(quote_spanned! {cmp_eq.span=>
|
||||
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||
});
|
||||
}
|
||||
}
|
||||
variants_value_eq.push(quote_spanned! {span=>
|
||||
(
|
||||
#sim_value_ident::#variant_ident(__lhs_field, _),
|
||||
#sim_value_ident::#variant_ident(__rhs_field, _),
|
||||
) => {
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||
__lhs.#variant_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
||||
__rhs.#variant_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(__rhs_field),
|
||||
)
|
||||
}
|
||||
});
|
||||
variants_expr_eq.push(quote_spanned! {span=>
|
||||
{
|
||||
let (#match_variant_ident::#variant_ident(__lhs), __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
::fayalite::__std::iter::Iterator::next(&mut __lhs_match_variant_iter)
|
||||
.expect("known to have enough variants"),
|
||||
)
|
||||
else {
|
||||
::fayalite::__std::unreachable!();
|
||||
};
|
||||
let (#match_variant_ident::#variant_ident(__rhs), __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
::fayalite::__std::iter::Iterator::nth(
|
||||
&mut ::fayalite::module::match_(__rhs),
|
||||
#variant_index,
|
||||
)
|
||||
.expect("known to have variant"),
|
||||
)
|
||||
else {
|
||||
::fayalite::__std::unreachable!();
|
||||
};
|
||||
::fayalite::module::connect(
|
||||
__retval,
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
|
||||
);
|
||||
}
|
||||
});
|
||||
fields_valueless_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_valueless_eq(
|
||||
::fayalite::expr::Valueless::new(__lhs.#variant_ident),
|
||||
::fayalite::expr::Valueless::new(__rhs.#variant_ident),
|
||||
)
|
||||
});
|
||||
} else {
|
||||
variants_value_eq.push(quote_spanned! {span=>
|
||||
(#sim_value_ident::#variant_ident(_), #sim_value_ident::#variant_ident(_)) => true,
|
||||
});
|
||||
variants_expr_eq.push(quote_spanned! {span=>
|
||||
{
|
||||
let (#match_variant_ident::#variant_ident, __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
::fayalite::__std::iter::Iterator::next(&mut __lhs_match_variant_iter)
|
||||
.expect("known to have enough variants"),
|
||||
)
|
||||
else {
|
||||
::fayalite::__std::unreachable!();
|
||||
};
|
||||
let (#match_variant_ident::#variant_ident, __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
::fayalite::__std::iter::Iterator::nth(
|
||||
&mut ::fayalite::module::match_(__rhs),
|
||||
#variant_index,
|
||||
)
|
||||
.expect("known to have variant"),
|
||||
)
|
||||
else {
|
||||
::fayalite::__std::unreachable!();
|
||||
};
|
||||
::fayalite::module::connect(__retval, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
||||
variants_value_eq.push(quote_spanned! {span=>
|
||||
(
|
||||
#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown),
|
||||
#sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown),
|
||||
) => {
|
||||
__lhs_unknown == __rhs_unknown
|
||||
}
|
||||
});
|
||||
}
|
||||
let valueless_eq_body = if fields_valueless_eq.is_empty() {
|
||||
quote_spanned! {span=>
|
||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
|
||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||
#(#fields_valueless_eq)&*
|
||||
}
|
||||
};
|
||||
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
|
||||
let structural_eq = structural_eq.unwrap_or_else(|| {
|
||||
quote_spanned! {span=>
|
||||
true
|
||||
}
|
||||
});
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||
#cmp_eq_where_clause
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
__lhs: Self,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_,
|
||||
<Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs: Self,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_,
|
||||
<Self as ::fayalite::ty::Type>::SimValue>,
|
||||
) -> ::fayalite::__std::primitive::bool {
|
||||
match (&*__lhs_value, &*__rhs_value) {
|
||||
#(#variants_value_eq)*
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(
|
||||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
||||
::fayalite::expr::ops::StructuralEq::try_new(
|
||||
::fayalite::expr::Expr::canonical(__lhs),
|
||||
::fayalite::expr::Expr::canonical(__rhs),
|
||||
)
|
||||
{
|
||||
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
||||
}
|
||||
}
|
||||
let __retval = ::fayalite::module::wire(
|
||||
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
|
||||
::fayalite::int::Bool,
|
||||
);
|
||||
::fayalite::module::connect(__retval, false);
|
||||
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
||||
#(#variants_expr_eq)*
|
||||
__retval
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_eq(
|
||||
__lhs: ::fayalite::expr::Valueless<Self>,
|
||||
__rhs: ::fayalite::expr::Valueless<Self>,
|
||||
) -> ::fayalite::expr::Valueless<::fayalite::int::Bool> {
|
||||
#valueless_eq_body
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
let variants_len = variants.len();
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
|
|
@ -537,9 +1161,11 @@ impl ToTokens for ParsedEnum {
|
|||
{
|
||||
type BaseType = ::fayalite::enum_::Enum;
|
||||
type MaskType = ::fayalite::int::Bool;
|
||||
type SimValue = #sim_value_ident #type_generics;
|
||||
type MatchVariant = #match_variant_ident #type_generics;
|
||||
type MatchActiveScope = ::fayalite::module::Scope;
|
||||
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||
type MatchVariantAndInactiveScope =
|
||||
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
||||
|
||||
fn match_variants(
|
||||
|
|
@ -552,7 +1178,9 @@ impl ToTokens for ParsedEnum {
|
|||
::fayalite::int::Bool
|
||||
}
|
||||
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
|
||||
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token)))
|
||||
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(
|
||||
::fayalite::enum_::EnumType::variants(#self_token),
|
||||
))
|
||||
}
|
||||
#[track_caller]
|
||||
#[allow(non_snake_case)]
|
||||
|
|
@ -561,7 +1189,11 @@ impl ToTokens for ParsedEnum {
|
|||
::fayalite::__std::panic!("expected enum");
|
||||
};
|
||||
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
|
||||
::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants");
|
||||
::fayalite::__std::assert_eq!(
|
||||
#variants_token.len(),
|
||||
#variants_len,
|
||||
"enum has wrong number of variants",
|
||||
);
|
||||
Self {
|
||||
#(#from_canonical_body_fields)*
|
||||
}
|
||||
|
|
@ -569,14 +1201,48 @@ impl ToTokens for ParsedEnum {
|
|||
fn source_location() -> ::fayalite::source_location::SourceLocation {
|
||||
::fayalite::source_location::SourceLocation::caller()
|
||||
}
|
||||
fn sim_value_from_opaque(
|
||||
&self,
|
||||
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
|
||||
) -> <Self as ::fayalite::ty::Type>::SimValue {
|
||||
let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque);
|
||||
match v.discriminant() {
|
||||
#(#sim_value_from_opaque_match_arms)*
|
||||
}
|
||||
}
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
fn sim_value_clone_from_opaque(
|
||||
&self,
|
||||
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
|
||||
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
|
||||
) {
|
||||
let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque);
|
||||
match v.discriminant() {
|
||||
#(#sim_value_clone_from_opaque_match_arms)*
|
||||
}
|
||||
}
|
||||
fn sim_value_to_opaque<'__w>(
|
||||
&self,
|
||||
value: &<Self as ::fayalite::ty::Type>::SimValue,
|
||||
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
|
||||
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
|
||||
let v = ::fayalite::enum_::EnumSimValueToOpaque::new(*self, writer);
|
||||
match value {
|
||||
#(#sim_value_to_opaque_match_arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type SimBuilder = #sim_builder_ident #type_generics;
|
||||
fn match_activate_scope(
|
||||
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
||||
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
|
||||
) -> (
|
||||
<Self as ::fayalite::ty::Type>::MatchVariant,
|
||||
<Self as ::fayalite::ty::Type>::MatchActiveScope,
|
||||
) {
|
||||
let (#variant_access_token, scope) = v.activate();
|
||||
(
|
||||
match #variant_access_token.variant_index() {
|
||||
|
|
@ -592,6 +1258,47 @@ impl ToTokens for ParsedEnum {
|
|||
][..])
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(
|
||||
&self,
|
||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
||||
) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics>
|
||||
for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value_with_type(
|
||||
&self,
|
||||
ty: #target #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
ty,
|
||||
::fayalite::__std::clone::Clone::clone(self),
|
||||
)
|
||||
}
|
||||
fn into_sim_value_with_type(
|
||||
self,
|
||||
ty: #target #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::convert::From<#target #type_generics>
|
||||
for #sim_builder_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn from(#sim_builder_ty_field_ident: #target #type_generics) -> Self {
|
||||
Self { #sim_builder_ty_field_ident }
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
|
||||
|
|
@ -629,6 +1336,15 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
}));
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::__std::default::Default
|
||||
for #target #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
fn default() -> Self {
|
||||
<Self as ::fayalite::ty::StaticType>::TYPE
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::ty::StaticType
|
||||
for #target #static_type_generics
|
||||
|
|
@ -647,6 +1363,44 @@ impl ToTokens for ParsedEnum {
|
|||
const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties =
|
||||
<::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES;
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::expr::ValueType
|
||||
for #sim_value_ident #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
type Type = #target #static_type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
::fayalite::ty::StaticType::TYPE
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::sim::value::ToSimValue
|
||||
for #sim_value_ident #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
::fayalite::ty::StaticType::TYPE,
|
||||
::fayalite::__std::clone::Clone::clone(self),
|
||||
)
|
||||
}
|
||||
fn into_sim_value(
|
||||
self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
::fayalite::ty::StaticType::TYPE,
|
||||
self,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,277 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
Errors, HdlAttr,
|
||||
hdl_type_common::{
|
||||
get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType,
|
||||
TypesParser,
|
||||
ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType,
|
||||
PhantomConstGetBound, TypesParser, WrappedInConst, common_derives, get_target, known_items,
|
||||
},
|
||||
kw, Errors, HdlAttr,
|
||||
kw,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{parse_quote_spanned, Attribute, Generics, Ident, ItemType, Token, Type, Visibility};
|
||||
use quote::{ToTokens, format_ident, quote_spanned};
|
||||
use syn::{
|
||||
Attribute, Expr, Fields, GenericParam, Generics, Ident, ItemStruct, ItemType, Token, Type,
|
||||
TypeGroup, TypeParam, TypeParen, Visibility, parse_quote_spanned, punctuated::Pair,
|
||||
token::Paren,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ParsedTypeAlias {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
pub(crate) vis: Visibility,
|
||||
pub(crate) type_token: Token![type],
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
|
||||
pub(crate) eq_token: Token![=],
|
||||
pub(crate) ty: MaybeParsed<ParsedType, Type>,
|
||||
pub(crate) semi_token: Token![;],
|
||||
pub(crate) struct PhantomConstAccessorTypeParam {
|
||||
attrs: Vec<Attribute>,
|
||||
ident: Ident,
|
||||
colon_token: Token![:],
|
||||
phantom_const_get_bound: PhantomConstGetBound,
|
||||
plus_token: Option<Token![+]>,
|
||||
}
|
||||
|
||||
impl From<PhantomConstAccessorTypeParam> for TypeParam {
|
||||
fn from(value: PhantomConstAccessorTypeParam) -> Self {
|
||||
let PhantomConstAccessorTypeParam {
|
||||
attrs,
|
||||
ident,
|
||||
colon_token,
|
||||
phantom_const_get_bound,
|
||||
plus_token,
|
||||
} = value;
|
||||
TypeParam {
|
||||
attrs,
|
||||
ident,
|
||||
colon_token: Some(colon_token),
|
||||
bounds: FromIterator::from_iter([Pair::new(
|
||||
phantom_const_get_bound.into(),
|
||||
plus_token,
|
||||
)]),
|
||||
eq_token: None,
|
||||
default: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PhantomConstAccessorTypeParam> for GenericParam {
|
||||
fn from(value: PhantomConstAccessorTypeParam) -> Self {
|
||||
TypeParam::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl PhantomConstAccessorTypeParam {
|
||||
fn parse_opt(generic_param: GenericParam) -> Option<Self> {
|
||||
let GenericParam::Type(TypeParam {
|
||||
attrs,
|
||||
ident,
|
||||
colon_token,
|
||||
bounds,
|
||||
eq_token: None,
|
||||
default: None,
|
||||
}) = generic_param
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let colon_token = colon_token.unwrap_or(Token));
|
||||
let mut bounds = bounds.into_pairs();
|
||||
let (bound, plus_token) = bounds.next()?.into_tuple();
|
||||
let phantom_const_get_bound = PhantomConstGetBound::parse_type_param_bound(bound)
|
||||
.ok()?
|
||||
.ok()?;
|
||||
let None = bounds.next() else {
|
||||
return None;
|
||||
};
|
||||
Some(Self {
|
||||
attrs,
|
||||
ident,
|
||||
colon_token,
|
||||
phantom_const_get_bound,
|
||||
plus_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct PhantomConstAccessorGenerics {
|
||||
lt_token: Token![<],
|
||||
type_param: PhantomConstAccessorTypeParam,
|
||||
comma_token: Option<Token![,]>,
|
||||
gt_token: Token![>],
|
||||
}
|
||||
|
||||
impl From<PhantomConstAccessorGenerics> for Generics {
|
||||
fn from(value: PhantomConstAccessorGenerics) -> Self {
|
||||
let PhantomConstAccessorGenerics {
|
||||
lt_token,
|
||||
type_param,
|
||||
comma_token,
|
||||
gt_token,
|
||||
} = value;
|
||||
Generics {
|
||||
lt_token: Some(lt_token),
|
||||
params: FromIterator::from_iter([Pair::new(type_param.into(), comma_token)]),
|
||||
gt_token: Some(gt_token),
|
||||
where_clause: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PhantomConstAccessorGenerics> for Generics {
|
||||
fn from(value: &'a PhantomConstAccessorGenerics) -> Self {
|
||||
value.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl PhantomConstAccessorGenerics {
|
||||
fn parse_opt(generics: Generics) -> Option<Self> {
|
||||
let Generics {
|
||||
lt_token,
|
||||
params,
|
||||
gt_token,
|
||||
where_clause: None,
|
||||
} = generics
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let mut params = params.into_pairs();
|
||||
let (generic_param, comma_token) = params.next()?.into_tuple();
|
||||
let type_param = PhantomConstAccessorTypeParam::parse_opt(generic_param)?;
|
||||
let span = type_param.ident.span();
|
||||
let lt_token = lt_token.unwrap_or(Token);
|
||||
let gt_token = gt_token.unwrap_or(Token);
|
||||
let None = params.next() else {
|
||||
return None;
|
||||
};
|
||||
Some(Self {
|
||||
lt_token,
|
||||
type_param,
|
||||
comma_token,
|
||||
gt_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum ParsedTypeAlias {
|
||||
TypeAlias {
|
||||
attrs: Vec<Attribute>,
|
||||
options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
vis: Visibility,
|
||||
type_token: Token![type],
|
||||
ident: Ident,
|
||||
generics: MaybeParsed<ParsedGenerics, Generics>,
|
||||
eq_token: Token![=],
|
||||
ty: MaybeParsed<ParsedType, Type>,
|
||||
semi_token: Token![;],
|
||||
},
|
||||
PhantomConstAccessor {
|
||||
attrs: Vec<Attribute>,
|
||||
options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
get: (kw::get, Paren, Expr),
|
||||
vis: Visibility,
|
||||
type_token: Token![type],
|
||||
ident: Ident,
|
||||
generics: PhantomConstAccessorGenerics,
|
||||
eq_token: Token![=],
|
||||
ty: Type,
|
||||
ty_is_dyn_size: Option<known_items::DynSize>,
|
||||
semi_token: Token![;],
|
||||
},
|
||||
}
|
||||
|
||||
impl ParsedTypeAlias {
|
||||
fn ty_is_dyn_size(ty: &Type) -> Option<known_items::DynSize> {
|
||||
match ty {
|
||||
Type::Group(TypeGroup {
|
||||
group_token: _,
|
||||
elem,
|
||||
}) => Self::ty_is_dyn_size(elem),
|
||||
Type::Paren(TypeParen {
|
||||
paren_token: _,
|
||||
elem,
|
||||
}) => Self::ty_is_dyn_size(elem),
|
||||
Type::Path(syn::TypePath { qself: None, path }) => {
|
||||
known_items::DynSize::parse_path(path.clone()).ok()
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn parse_phantom_const_accessor(
|
||||
item: ItemType,
|
||||
mut errors: Errors,
|
||||
options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
get: (kw::get, Paren, Expr),
|
||||
) -> syn::Result<Self> {
|
||||
let ItemType {
|
||||
attrs,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
} = item;
|
||||
let ItemOptions {
|
||||
outline_generated: _,
|
||||
ref target,
|
||||
custom_bounds,
|
||||
no_static,
|
||||
no_runtime_generics,
|
||||
cmp_eq,
|
||||
get: _,
|
||||
ref custom_debug,
|
||||
custom_sim_display,
|
||||
} = options.body;
|
||||
if let Some((no_static,)) = no_static {
|
||||
errors.error(no_static, "no_static is not valid on type aliases");
|
||||
}
|
||||
if let Some((target, ..)) = target {
|
||||
errors.error(
|
||||
target,
|
||||
"target is not implemented on PhantomConstGet type aliases",
|
||||
);
|
||||
}
|
||||
if let Some((no_runtime_generics,)) = no_runtime_generics {
|
||||
errors.error(
|
||||
no_runtime_generics,
|
||||
"no_runtime_generics is not implemented on PhantomConstGet type aliases",
|
||||
);
|
||||
}
|
||||
if let Some((cmp_eq,)) = cmp_eq {
|
||||
errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
|
||||
}
|
||||
if let Some((custom_debug, _, _)) = custom_debug {
|
||||
errors.error(custom_debug, "custom_debug is not valid on type aliases");
|
||||
}
|
||||
if let Some((custom_sim_display,)) = custom_sim_display {
|
||||
errors.error(
|
||||
custom_sim_display,
|
||||
"custom_sim_display is not valid on type aliases",
|
||||
);
|
||||
}
|
||||
if let Some((custom_bounds,)) = custom_bounds {
|
||||
errors.error(
|
||||
custom_bounds,
|
||||
"custom_bounds is not implemented on PhantomConstGet type aliases",
|
||||
);
|
||||
}
|
||||
let Some(generics) = PhantomConstAccessorGenerics::parse_opt(generics) else {
|
||||
errors.error(ident, "#[hdl(get(...))] type alias must be of the form:\ntype MyTypeGetter<P: PhantomConstGet<MyType>> = RetType;");
|
||||
errors.finish()?;
|
||||
unreachable!();
|
||||
};
|
||||
errors.finish()?;
|
||||
let ty_is_dyn_size = Self::ty_is_dyn_size(&ty);
|
||||
Ok(Self::PhantomConstAccessor {
|
||||
attrs,
|
||||
options,
|
||||
get,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty: *ty,
|
||||
ty_is_dyn_size,
|
||||
semi_token,
|
||||
})
|
||||
}
|
||||
fn parse(item: ItemType) -> syn::Result<Self> {
|
||||
let ItemType {
|
||||
mut attrs,
|
||||
|
|
@ -49,10 +296,43 @@ impl ParsedTypeAlias {
|
|||
custom_bounds,
|
||||
no_static,
|
||||
no_runtime_generics: _,
|
||||
cmp_eq,
|
||||
ref mut get,
|
||||
ref custom_debug,
|
||||
custom_sim_display,
|
||||
} = options.body;
|
||||
if let Some(get) = get.take() {
|
||||
return Self::parse_phantom_const_accessor(
|
||||
ItemType {
|
||||
attrs,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
},
|
||||
errors,
|
||||
options,
|
||||
get,
|
||||
);
|
||||
}
|
||||
if let Some((no_static,)) = no_static {
|
||||
errors.error(no_static, "no_static is not valid on type aliases");
|
||||
}
|
||||
if let Some((cmp_eq,)) = cmp_eq {
|
||||
errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
|
||||
}
|
||||
if let Some((custom_debug, _, _)) = custom_debug {
|
||||
errors.error(custom_debug, "custom_debug is not valid on type aliases");
|
||||
}
|
||||
if let Some((custom_sim_display,)) = custom_sim_display {
|
||||
errors.error(
|
||||
custom_sim_display,
|
||||
"custom_sim_display is not valid on type aliases",
|
||||
);
|
||||
}
|
||||
let generics = if custom_bounds.is_some() {
|
||||
MaybeParsed::Unrecognized(generics)
|
||||
} else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
|
||||
|
|
@ -62,7 +342,7 @@ impl ParsedTypeAlias {
|
|||
};
|
||||
let ty = TypesParser::maybe_run(generics.as_ref(), *ty, &mut errors);
|
||||
errors.finish()?;
|
||||
Ok(Self {
|
||||
Ok(Self::TypeAlias {
|
||||
attrs,
|
||||
options,
|
||||
vis,
|
||||
|
|
@ -78,53 +358,159 @@ impl ParsedTypeAlias {
|
|||
|
||||
impl ToTokens for ParsedTypeAlias {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
attrs,
|
||||
options,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
} = self;
|
||||
let ItemOptions {
|
||||
outline_generated: _,
|
||||
target,
|
||||
custom_bounds: _,
|
||||
no_static: _,
|
||||
no_runtime_generics,
|
||||
} = &options.body;
|
||||
let target = get_target(target, ident);
|
||||
let mut type_attrs = attrs.clone();
|
||||
type_attrs.push(parse_quote_spanned! {ident.span()=>
|
||||
#[allow(type_alias_bounds)]
|
||||
});
|
||||
ItemType {
|
||||
attrs: type_attrs,
|
||||
vis: vis.clone(),
|
||||
type_token: *type_token,
|
||||
ident: ident.clone(),
|
||||
generics: generics.into(),
|
||||
eq_token: *eq_token,
|
||||
ty: Box::new(ty.clone().into()),
|
||||
semi_token: *semi_token,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) =
|
||||
(generics, ty, no_runtime_generics)
|
||||
{
|
||||
generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
|
||||
ty.make_hdl_type_expr(context)
|
||||
})
|
||||
match self {
|
||||
Self::TypeAlias {
|
||||
attrs,
|
||||
options,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
} => {
|
||||
let ItemOptions {
|
||||
outline_generated: _,
|
||||
target,
|
||||
custom_bounds: _,
|
||||
no_static: _,
|
||||
no_runtime_generics,
|
||||
cmp_eq: _,
|
||||
get: _,
|
||||
custom_debug: _,
|
||||
custom_sim_display: _,
|
||||
} = &options.body;
|
||||
let target = get_target(target, ident);
|
||||
let mut type_attrs = attrs.clone();
|
||||
type_attrs.push(parse_quote_spanned! {ident.span()=>
|
||||
#[allow(type_alias_bounds)]
|
||||
});
|
||||
ItemType {
|
||||
attrs: type_attrs,
|
||||
vis: vis.clone(),
|
||||
type_token: *type_token,
|
||||
ident: ident.clone(),
|
||||
generics: generics.into(),
|
||||
eq_token: *eq_token,
|
||||
ty: Box::new(ty.clone().into()),
|
||||
semi_token: *semi_token,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) =
|
||||
(generics, ty, no_runtime_generics)
|
||||
{
|
||||
generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
|
||||
ty.make_hdl_type_expr(context)
|
||||
})
|
||||
}
|
||||
}
|
||||
Self::PhantomConstAccessor {
|
||||
attrs,
|
||||
options,
|
||||
get: (_get_kw, _get_paren, get_expr),
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
ty_is_dyn_size,
|
||||
semi_token,
|
||||
} => {
|
||||
let ItemOptions {
|
||||
outline_generated: _,
|
||||
target: _,
|
||||
custom_bounds: _,
|
||||
no_static: _,
|
||||
no_runtime_generics: _,
|
||||
cmp_eq: _,
|
||||
get: _,
|
||||
custom_debug: _,
|
||||
custom_sim_display: _,
|
||||
} = &options.body;
|
||||
let span = ident.span();
|
||||
let mut type_attrs = attrs.clone();
|
||||
type_attrs.push(parse_quote_spanned! {span=>
|
||||
#[allow(type_alias_bounds)]
|
||||
});
|
||||
let type_param_ident = &generics.type_param.ident;
|
||||
let syn_generics = Generics::from(generics);
|
||||
ItemType {
|
||||
attrs: type_attrs,
|
||||
vis: vis.clone(),
|
||||
type_token: *type_token,
|
||||
ident: ident.clone(),
|
||||
generics: syn_generics.clone(),
|
||||
eq_token: *eq_token,
|
||||
ty: parse_quote_spanned! {span=>
|
||||
<#ty as ::fayalite::phantom_const::ReturnSelfUnchanged<#type_param_ident>>::Type
|
||||
},
|
||||
semi_token: *semi_token,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let generics_accumulation_ident =
|
||||
format_ident!("__{}__GenericsAccumulation", ident);
|
||||
ItemStruct {
|
||||
attrs: vec![
|
||||
common_derives(span, true),
|
||||
parse_quote_spanned! {span=>
|
||||
#[allow(non_camel_case_types)]
|
||||
},
|
||||
],
|
||||
vis: vis.clone(),
|
||||
struct_token: Token,
|
||||
ident: generics_accumulation_ident.clone(),
|
||||
generics: Generics::default(),
|
||||
fields: Fields::Unnamed(parse_quote_spanned! {span=>
|
||||
(())
|
||||
}),
|
||||
semi_token: Some(Token),
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
quote_spanned! {span=>
|
||||
#[allow(non_upper_case_globals, dead_code)]
|
||||
#vis const #ident: #generics_accumulation_ident = #generics_accumulation_ident(());
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
let mut wrapped_in_const = WrappedInConst::new(tokens, span);
|
||||
let tokens = wrapped_in_const.inner();
|
||||
let (impl_generics, _type_generics, where_clause) = syn_generics.split_for_impl();
|
||||
let phantom_const_get_ty = &generics.type_param.phantom_const_get_bound.ty;
|
||||
let index_output = if let Some(ty_is_dyn_size) = ty_is_dyn_size {
|
||||
known_items::usize(ty_is_dyn_size.span).to_token_stream()
|
||||
} else {
|
||||
ty.to_token_stream()
|
||||
};
|
||||
quote_spanned! {span=>
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::__std::ops::Index<#type_param_ident>
|
||||
for #generics_accumulation_ident
|
||||
#where_clause
|
||||
{
|
||||
type Output = #index_output;
|
||||
|
||||
fn index(&self, __param: #type_param_ident) -> &Self::Output {
|
||||
::fayalite::phantom_const::type_alias_phantom_const_get_helper::<#phantom_const_get_ty, #index_output>(
|
||||
__param,
|
||||
#get_expr,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hdl_type_alias_impl(item: ItemType) -> syn::Result<TokenStream> {
|
||||
let item = ParsedTypeAlias::parse(item)?;
|
||||
let outline_generated = item.options.body.outline_generated;
|
||||
let outline_generated = match &item {
|
||||
ParsedTypeAlias::TypeAlias { options, .. }
|
||||
| ParsedTypeAlias::PhantomConstAccessor { options, .. } => options.body.outline_generated,
|
||||
};
|
||||
let mut contents = item.to_token_stream();
|
||||
if outline_generated.is_some() {
|
||||
contents = crate::outline_generated(contents, "hdl-type-alias-");
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,15 +2,20 @@
|
|||
// See Notices.txt for copyright information
|
||||
#![cfg_attr(test, recursion_limit = "512")]
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::io::{ErrorKind, Write};
|
||||
use quote::{ToTokens, quote};
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
io::{ErrorKind, Write},
|
||||
};
|
||||
use syn::{
|
||||
bracketed, parenthesized,
|
||||
AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token, bracketed,
|
||||
ext::IdentExt,
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream, Parser},
|
||||
parse_quote,
|
||||
punctuated::Pair,
|
||||
punctuated::{Pair, Punctuated},
|
||||
spanned::Spanned,
|
||||
AttrStyle, Attribute, Error, Item, ItemFn, Token,
|
||||
token::{Bracket, Paren},
|
||||
};
|
||||
|
||||
mod fold;
|
||||
|
|
@ -19,6 +24,7 @@ mod hdl_enum;
|
|||
mod hdl_type_alias;
|
||||
mod hdl_type_common;
|
||||
mod module;
|
||||
mod process_cfg;
|
||||
|
||||
pub(crate) trait CustomToken:
|
||||
Copy
|
||||
|
|
@ -36,6 +42,7 @@ pub(crate) trait CustomToken:
|
|||
|
||||
mod kw {
|
||||
pub(crate) use syn::token::Extern as extern_;
|
||||
pub(crate) use syn::token::Type as type_;
|
||||
|
||||
macro_rules! custom_keyword {
|
||||
($kw:ident) => {
|
||||
|
|
@ -59,26 +66,40 @@ mod kw {
|
|||
};
|
||||
}
|
||||
|
||||
custom_keyword!(__evaluated_cfgs);
|
||||
custom_keyword!(add_platform_io);
|
||||
custom_keyword!(all);
|
||||
custom_keyword!(any);
|
||||
custom_keyword!(cfg);
|
||||
custom_keyword!(cfg_attr);
|
||||
custom_keyword!(clock_domain);
|
||||
custom_keyword!(cmp_eq);
|
||||
custom_keyword!(connect_inexact);
|
||||
custom_keyword!(custom_bounds);
|
||||
custom_keyword!(custom_debug);
|
||||
custom_keyword!(custom_sim_display);
|
||||
custom_keyword!(flip);
|
||||
custom_keyword!(get);
|
||||
custom_keyword!(hdl);
|
||||
custom_keyword!(hdl_module);
|
||||
custom_keyword!(input);
|
||||
custom_keyword!(incomplete_wire);
|
||||
custom_keyword!(input);
|
||||
custom_keyword!(instance);
|
||||
custom_keyword!(m);
|
||||
custom_keyword!(mask_sim);
|
||||
custom_keyword!(mask_type);
|
||||
custom_keyword!(memory);
|
||||
custom_keyword!(memory_array);
|
||||
custom_keyword!(memory_with_init);
|
||||
custom_keyword!(no_reset);
|
||||
custom_keyword!(no_runtime_generics);
|
||||
custom_keyword!(no_static);
|
||||
custom_keyword!(not);
|
||||
custom_keyword!(outline_generated);
|
||||
custom_keyword!(output);
|
||||
custom_keyword!(reg_builder);
|
||||
custom_keyword!(reset);
|
||||
custom_keyword!(sim);
|
||||
custom_keyword!(skip);
|
||||
custom_keyword!(target);
|
||||
custom_keyword!(wire);
|
||||
|
|
@ -871,7 +892,13 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
|
|||
}
|
||||
}
|
||||
let _print_on_panic = PrintOnPanic(&contents);
|
||||
let contents = prettyplease::unparse(&parse_quote! { #contents });
|
||||
let mut parse_err = None;
|
||||
let (Ok(contents) | Err(contents)) = syn::parse2(contents.clone())
|
||||
.map(|file| prettyplease::unparse(&file))
|
||||
.map_err(|e| {
|
||||
parse_err = Some(e);
|
||||
contents.to_string()
|
||||
});
|
||||
let hash = <sha2::Sha256 as sha2::Digest>::digest(&contents);
|
||||
let hash = base16ct::HexDisplay(&hash[..5]);
|
||||
file.write_all(contents.as_bytes()).unwrap();
|
||||
|
|
@ -883,9 +910,26 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
|
|||
e.unwrap();
|
||||
}
|
||||
}
|
||||
eprintln!("generated {}", dest_file.display());
|
||||
let log_msg = if let Some(parse_err) = parse_err {
|
||||
format!(
|
||||
"fayalite-proc-macros-impl internal error:\nfailed to parse generated output: {parse_err}\nunformatted output is in: {}\n",
|
||||
dest_file.display()
|
||||
)
|
||||
} else {
|
||||
format!("generated {}\n", dest_file.display())
|
||||
};
|
||||
// write message atomically if possible
|
||||
let mut stderr = std::io::stderr().lock();
|
||||
let write_result = stderr.write_all(log_msg.as_bytes());
|
||||
let flush_result = stderr.flush();
|
||||
drop(stderr); // unlock before we try to panic
|
||||
write_result.unwrap();
|
||||
flush_result.unwrap();
|
||||
std::io::stderr()
|
||||
.lock()
|
||||
.write_all(log_msg.as_bytes())
|
||||
.unwrap();
|
||||
let dest_file = dest_file.to_str().unwrap();
|
||||
|
||||
quote! {
|
||||
include!(#dest_file);
|
||||
}
|
||||
|
|
@ -901,15 +945,346 @@ fn hdl_module_impl(item: ItemFn) -> syn::Result<TokenStream> {
|
|||
Ok(contents)
|
||||
}
|
||||
|
||||
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
let kw = kw::hdl_module::default();
|
||||
hdl_module_impl(syn::parse2(quote! { #[#kw(#attr)] #item })?)
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) enum CfgExpr {
|
||||
Option {
|
||||
ident: Ident,
|
||||
value: Option<(Token![=], LitStr)>,
|
||||
},
|
||||
All {
|
||||
all: kw::all,
|
||||
paren: Paren,
|
||||
exprs: Punctuated<CfgExpr, Token![,]>,
|
||||
},
|
||||
Any {
|
||||
any: kw::any,
|
||||
paren: Paren,
|
||||
exprs: Punctuated<CfgExpr, Token![,]>,
|
||||
},
|
||||
Not {
|
||||
not: kw::not,
|
||||
paren: Paren,
|
||||
expr: Box<CfgExpr>,
|
||||
trailing_comma: Option<Token![,]>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
let kw = kw::hdl::default();
|
||||
let item = quote! { #[#kw(#attr)] #item };
|
||||
let item = syn::parse2::<Item>(item)?;
|
||||
impl Parse for CfgExpr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
match input.cursor().ident() {
|
||||
Some((_, cursor)) if cursor.eof() => {
|
||||
return Ok(CfgExpr::Option {
|
||||
ident: input.call(Ident::parse_any)?,
|
||||
value: None,
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
|
||||
return Ok(CfgExpr::Option {
|
||||
ident: input.call(Ident::parse_any)?,
|
||||
value: Some((input.parse()?, input.parse()?)),
|
||||
});
|
||||
}
|
||||
let contents;
|
||||
if input.peek(kw::all) {
|
||||
Ok(CfgExpr::All {
|
||||
all: input.parse()?,
|
||||
paren: parenthesized!(contents in input),
|
||||
exprs: contents.call(Punctuated::parse_terminated)?,
|
||||
})
|
||||
} else if input.peek(kw::any) {
|
||||
Ok(CfgExpr::Any {
|
||||
any: input.parse()?,
|
||||
paren: parenthesized!(contents in input),
|
||||
exprs: contents.call(Punctuated::parse_terminated)?,
|
||||
})
|
||||
} else if input.peek(kw::not) {
|
||||
Ok(CfgExpr::Not {
|
||||
not: input.parse()?,
|
||||
paren: parenthesized!(contents in input),
|
||||
expr: contents.parse()?,
|
||||
trailing_comma: contents.parse()?,
|
||||
})
|
||||
} else {
|
||||
Err(input.error("expected cfg-pattern"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for CfgExpr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
CfgExpr::Option { ident, value } => {
|
||||
ident.to_tokens(tokens);
|
||||
if let Some((eq, value)) = value {
|
||||
eq.to_tokens(tokens);
|
||||
value.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
CfgExpr::All { all, paren, exprs } => {
|
||||
all.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| exprs.to_tokens(tokens));
|
||||
}
|
||||
CfgExpr::Any { any, paren, exprs } => {
|
||||
any.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| exprs.to_tokens(tokens));
|
||||
}
|
||||
CfgExpr::Not {
|
||||
not,
|
||||
paren,
|
||||
expr,
|
||||
trailing_comma,
|
||||
} => {
|
||||
not.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| {
|
||||
expr.to_tokens(tokens);
|
||||
trailing_comma.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) struct Cfg {
|
||||
cfg: kw::cfg,
|
||||
paren: Paren,
|
||||
expr: CfgExpr,
|
||||
trailing_comma: Option<Token![,]>,
|
||||
}
|
||||
|
||||
impl Cfg {
|
||||
fn parse_meta(meta: &Meta) -> syn::Result<Self> {
|
||||
syn::parse2(meta.to_token_stream())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Cfg {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
cfg,
|
||||
paren,
|
||||
expr,
|
||||
trailing_comma,
|
||||
} = self;
|
||||
cfg.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| {
|
||||
expr.to_tokens(tokens);
|
||||
trailing_comma.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Cfg {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let contents;
|
||||
Ok(Self {
|
||||
cfg: input.parse()?,
|
||||
paren: parenthesized!(contents in input),
|
||||
expr: contents.parse()?,
|
||||
trailing_comma: contents.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) struct CfgAttr {
|
||||
cfg_attr: kw::cfg_attr,
|
||||
paren: Paren,
|
||||
expr: CfgExpr,
|
||||
comma: Token![,],
|
||||
attrs: Punctuated<Meta, Token![,]>,
|
||||
}
|
||||
|
||||
impl CfgAttr {
|
||||
pub(crate) fn to_cfg(&self) -> Cfg {
|
||||
Cfg {
|
||||
cfg: kw::cfg(self.cfg_attr.span),
|
||||
paren: self.paren,
|
||||
expr: self.expr.clone(),
|
||||
trailing_comma: None,
|
||||
}
|
||||
}
|
||||
fn parse_meta(meta: &Meta) -> syn::Result<Self> {
|
||||
syn::parse2(meta.to_token_stream())
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for CfgAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let contents;
|
||||
Ok(Self {
|
||||
cfg_attr: input.parse()?,
|
||||
paren: parenthesized!(contents in input),
|
||||
expr: contents.parse()?,
|
||||
comma: contents.parse()?,
|
||||
attrs: contents.call(Punctuated::parse_terminated)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CfgAndValue {
|
||||
cfg: Cfg,
|
||||
eq_token: Token![=],
|
||||
value: LitBool,
|
||||
}
|
||||
|
||||
impl Parse for CfgAndValue {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self {
|
||||
cfg: input.parse()?,
|
||||
eq_token: input.parse()?,
|
||||
value: input.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Cfgs<T> {
|
||||
pub(crate) bracket: Bracket,
|
||||
pub(crate) cfgs_map: HashMap<Cfg, T>,
|
||||
pub(crate) cfgs_list: Vec<Cfg>,
|
||||
}
|
||||
|
||||
impl<T> Default for Cfgs<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bracket: Default::default(),
|
||||
cfgs_map: Default::default(),
|
||||
cfgs_list: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Cfgs<T> {
|
||||
fn insert_cfg(&mut self, cfg: Cfg, value: T) {
|
||||
match self.cfgs_map.entry(cfg) {
|
||||
Entry::Occupied(_) => {}
|
||||
Entry::Vacant(entry) => {
|
||||
self.cfgs_list.push(entry.key().clone());
|
||||
entry.insert(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Cfgs<bool> {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let contents;
|
||||
let bracket = bracketed!(contents in input);
|
||||
let mut cfgs_map = HashMap::new();
|
||||
let mut cfgs_list = Vec::new();
|
||||
for CfgAndValue {
|
||||
cfg,
|
||||
eq_token,
|
||||
value,
|
||||
} in contents.call(Punctuated::<CfgAndValue, Token![,]>::parse_terminated)?
|
||||
{
|
||||
let _ = eq_token;
|
||||
match cfgs_map.entry(cfg) {
|
||||
Entry::Occupied(_) => {}
|
||||
Entry::Vacant(entry) => {
|
||||
cfgs_list.push(entry.key().clone());
|
||||
entry.insert(value.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
bracket,
|
||||
cfgs_map,
|
||||
cfgs_list,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Cfgs<()> {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let contents;
|
||||
let bracket = bracketed!(contents in input);
|
||||
let mut cfgs_map = HashMap::new();
|
||||
let mut cfgs_list = Vec::new();
|
||||
for cfg in contents.call(Punctuated::<Cfg, Token![,]>::parse_terminated)? {
|
||||
match cfgs_map.entry(cfg) {
|
||||
Entry::Occupied(_) => {}
|
||||
Entry::Vacant(entry) => {
|
||||
cfgs_list.push(entry.key().clone());
|
||||
entry.insert(());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
bracket,
|
||||
cfgs_map,
|
||||
cfgs_list,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Cfgs<()> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
bracket,
|
||||
cfgs_map: _,
|
||||
cfgs_list,
|
||||
} = self;
|
||||
bracket.surround(tokens, |tokens| {
|
||||
for cfg in cfgs_list {
|
||||
cfg.to_tokens(tokens);
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn hdl_main(
|
||||
kw: impl CustomToken,
|
||||
attr: TokenStream,
|
||||
item: TokenStream,
|
||||
) -> syn::Result<TokenStream> {
|
||||
fn parse_evaluated_cfgs_attr<R>(
|
||||
input: ParseStream,
|
||||
parse_inner: impl FnOnce(ParseStream) -> syn::Result<R>,
|
||||
) -> syn::Result<R> {
|
||||
let _: Token![#] = input.parse()?;
|
||||
let bracket_content;
|
||||
bracketed!(bracket_content in input);
|
||||
let _: kw::__evaluated_cfgs = bracket_content.parse()?;
|
||||
let paren_content;
|
||||
parenthesized!(paren_content in bracket_content);
|
||||
parse_inner(&paren_content)
|
||||
}
|
||||
let (evaluated_cfgs, item): (_, TokenStream) = Parser::parse2(
|
||||
|input: ParseStream| {
|
||||
let peek = input.fork();
|
||||
if parse_evaluated_cfgs_attr(&peek, |_| Ok(())).is_ok() {
|
||||
let evaluated_cfgs = parse_evaluated_cfgs_attr(input, Cfgs::<bool>::parse)?;
|
||||
Ok((Some(evaluated_cfgs), input.parse()?))
|
||||
} else {
|
||||
Ok((None, input.parse()?))
|
||||
}
|
||||
},
|
||||
item,
|
||||
)?;
|
||||
let cfgs = if let Some(cfgs) = evaluated_cfgs {
|
||||
cfgs
|
||||
} else {
|
||||
let cfgs = process_cfg::collect_cfgs(syn::parse2(item.clone())?)?;
|
||||
if cfgs.cfgs_list.is_empty() {
|
||||
Cfgs::default()
|
||||
} else {
|
||||
return Ok(quote! {
|
||||
::fayalite::__cfg_expansion_helper! {
|
||||
[]
|
||||
#cfgs
|
||||
{#[::fayalite::#kw(#attr)]} { #item }
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
let item = syn::parse2(quote! { #[#kw(#attr)] #item })?;
|
||||
let Some(item) = process_cfg::process_cfgs(item, cfgs)? else {
|
||||
return Ok(TokenStream::new());
|
||||
};
|
||||
match item {
|
||||
Item::Enum(item) => hdl_enum::hdl_enum(item),
|
||||
Item::Struct(item) => hdl_bundle::hdl_bundle(item),
|
||||
|
|
@ -921,3 +1296,11 @@ pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream
|
|||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
hdl_main(kw::hdl_module::default(), attr, item)
|
||||
}
|
||||
|
||||
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
hdl_main(kw::hdl::default(), attr, item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
hdl_type_common::{ParsedGenerics, SplitForImpl},
|
||||
kw,
|
||||
module::transform_body::{HdlLet, HdlLetKindIO},
|
||||
options, Errors, HdlAttr, PairsIterExt,
|
||||
module::transform_body::{HdlLet, HdlLetKindIO, ModuleIOOrAddPlatformIO},
|
||||
options,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||
use quote::{ToTokens, format_ident, quote, quote_spanned};
|
||||
use std::collections::HashSet;
|
||||
use syn::{
|
||||
parse_quote,
|
||||
visit::{visit_pat, Visit},
|
||||
Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct,
|
||||
LifetimeParam, ReturnType, Signature, TypeParam, Visibility, WhereClause, WherePredicate,
|
||||
parse_quote,
|
||||
visit::{Visit, visit_pat},
|
||||
};
|
||||
|
||||
mod transform_body;
|
||||
|
|
@ -38,7 +39,7 @@ pub(crate) fn check_name_conflicts_with_module_builder(name: &Ident) -> syn::Res
|
|||
if name == "m" {
|
||||
Err(Error::new_spanned(
|
||||
name,
|
||||
"name conflicts with implicit `m: &mut ModuleBuilder<_>`",
|
||||
"name conflicts with implicit `m: &ModuleBuilder`",
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
@ -66,7 +67,7 @@ struct ModuleFnModule {
|
|||
vis: Visibility,
|
||||
sig: Signature,
|
||||
block: Box<Block>,
|
||||
struct_generics: ParsedGenerics,
|
||||
struct_generics: Option<ParsedGenerics>,
|
||||
the_struct: TokenStream,
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +290,7 @@ impl ModuleFn {
|
|||
paren_token,
|
||||
body,
|
||||
} => {
|
||||
debug_assert!(io.is_empty());
|
||||
debug_assert!(matches!(io, ModuleIOOrAddPlatformIO::ModuleIO(v) if v.is_empty()));
|
||||
return Ok(Self(ModuleFnImpl::Fn {
|
||||
attrs,
|
||||
config_options: HdlAttr {
|
||||
|
|
@ -321,6 +322,21 @@ impl ModuleFn {
|
|||
body,
|
||||
},
|
||||
};
|
||||
let io = match io {
|
||||
ModuleIOOrAddPlatformIO::ModuleIO(io) => io,
|
||||
ModuleIOOrAddPlatformIO::AddPlatformIO => {
|
||||
return Ok(Self(ModuleFnImpl::Module(ModuleFnModule {
|
||||
attrs,
|
||||
config_options,
|
||||
module_kind: module_kind.unwrap(),
|
||||
vis,
|
||||
sig,
|
||||
block,
|
||||
struct_generics: None,
|
||||
the_struct: TokenStream::new(),
|
||||
})));
|
||||
}
|
||||
};
|
||||
let (_struct_impl_generics, _struct_type_generics, struct_where_clause) =
|
||||
struct_generics.split_for_impl();
|
||||
let struct_where_clause: Option<WhereClause> = parse_quote! { #struct_where_clause };
|
||||
|
|
@ -363,7 +379,7 @@ impl ModuleFn {
|
|||
vis,
|
||||
sig,
|
||||
block,
|
||||
struct_generics,
|
||||
struct_generics: Some(struct_generics),
|
||||
the_struct,
|
||||
})))
|
||||
}
|
||||
|
|
@ -377,7 +393,7 @@ impl ModuleFn {
|
|||
module_kind,
|
||||
vis,
|
||||
sig,
|
||||
block,
|
||||
mut block,
|
||||
struct_generics,
|
||||
the_struct,
|
||||
} = match self.0 {
|
||||
|
|
@ -432,13 +448,24 @@ impl ModuleFn {
|
|||
ModuleKind::Normal => quote! { ::fayalite::module::ModuleKind::Normal },
|
||||
};
|
||||
let fn_name = &outer_sig.ident;
|
||||
let (_struct_impl_generics, struct_type_generics, _struct_where_clause) =
|
||||
struct_generics.split_for_impl();
|
||||
let struct_ty = quote! {#fn_name #struct_type_generics};
|
||||
let struct_ty = match struct_generics {
|
||||
Some(struct_generics) => {
|
||||
let (_struct_impl_generics, struct_type_generics, _struct_where_clause) =
|
||||
struct_generics.split_for_impl();
|
||||
quote! {#fn_name #struct_type_generics}
|
||||
}
|
||||
None => quote! {::fayalite::bundle::Bundle},
|
||||
};
|
||||
body_sig.ident = parse_quote! {__body};
|
||||
body_sig
|
||||
.inputs
|
||||
.insert(0, parse_quote! { m: &::fayalite::module::ModuleBuilder });
|
||||
block.stmts.insert(
|
||||
0,
|
||||
parse_quote! {
|
||||
let _ = m;
|
||||
},
|
||||
);
|
||||
let body_fn = ItemFn {
|
||||
attrs: vec![],
|
||||
vis: Visibility::Inherited,
|
||||
|
|
|
|||
|
|
@ -1,36 +1,45 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
fold::{impl_fold, DoFold},
|
||||
Errors, HdlAttr,
|
||||
fold::{DoFold, impl_fold},
|
||||
hdl_type_common::{
|
||||
known_items, ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser,
|
||||
ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser, known_items,
|
||||
},
|
||||
is_hdl_attr, kw,
|
||||
module::{check_name_conflicts_with_module_builder, ModuleIO, ModuleIOKind, ModuleKind},
|
||||
options, Errors, HdlAttr,
|
||||
module::{ModuleIO, ModuleIOKind, ModuleKind, check_name_conflicts_with_module_builder},
|
||||
options,
|
||||
};
|
||||
use num_bigint::BigInt;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use quote::{ToTokens, quote, quote_spanned};
|
||||
use std::{borrow::Borrow, convert::Infallible};
|
||||
use syn::{
|
||||
fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold},
|
||||
Attribute, Block, Error, Expr, ExprIf, ExprLet, ExprLit, ExprRepeat, ExprUnary,
|
||||
GenericArgument, Ident, Item, Lit, LitStr, Local, LocalInit, Pat, Token, Type, UnOp,
|
||||
fold::{Fold, fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt},
|
||||
parenthesized,
|
||||
parse::{Nothing, Parse, ParseStream},
|
||||
parse::{Parse, ParseStream},
|
||||
parse_quote, parse_quote_spanned,
|
||||
spanned::Spanned,
|
||||
token::Paren,
|
||||
Attribute, Block, Error, Expr, ExprIf, ExprLet, ExprLit, ExprRepeat, ExprUnary,
|
||||
GenericArgument, Ident, Item, Lit, LitStr, Local, LocalInit, Pat, Token, Type, UnOp,
|
||||
};
|
||||
|
||||
mod expand_aggregate_literals;
|
||||
mod expand_match;
|
||||
|
||||
options! {
|
||||
#[options = ExprOptions]
|
||||
pub(crate) enum ExprOption {
|
||||
Sim(sim),
|
||||
}
|
||||
}
|
||||
|
||||
options! {
|
||||
pub(crate) enum LetFnKind {
|
||||
Input(input),
|
||||
Output(output),
|
||||
AddPlatformIO(add_platform_io),
|
||||
Instance(instance),
|
||||
RegBuilder(reg_builder),
|
||||
Wire(wire),
|
||||
|
|
@ -208,6 +217,49 @@ impl HdlLetKindToTokens for HdlLetKindInstance {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct HdlLetKindAddPlatformIO {
|
||||
pub(crate) m: kw::m,
|
||||
pub(crate) dot_token: Token![.],
|
||||
pub(crate) add_platform_io: kw::add_platform_io,
|
||||
pub(crate) paren: Paren,
|
||||
pub(crate) platform_io_builder: Box<Expr>,
|
||||
}
|
||||
|
||||
impl ParseTypes<Self> for HdlLetKindAddPlatformIO {
|
||||
fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||
Ok(input.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
struct HdlLetKindAddPlatformIO<> {
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
add_platform_io: kw::add_platform_io,
|
||||
paren: Paren,
|
||||
platform_io_builder: Box<Expr>,
|
||||
}
|
||||
}
|
||||
|
||||
impl HdlLetKindToTokens for HdlLetKindAddPlatformIO {
|
||||
fn ty_to_tokens(&self, _tokens: &mut TokenStream) {}
|
||||
|
||||
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
m,
|
||||
dot_token,
|
||||
add_platform_io,
|
||||
paren,
|
||||
platform_io_builder,
|
||||
} = self;
|
||||
m.to_tokens(tokens);
|
||||
dot_token.to_tokens(tokens);
|
||||
add_platform_io.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| platform_io_builder.to_tokens(tokens));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct RegBuilderClockDomain {
|
||||
pub(crate) dot_token: Token![.],
|
||||
|
|
@ -703,6 +755,7 @@ impl HdlLetKindMemory {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum HdlLetKind<IOType = ParsedType> {
|
||||
IO(HdlLetKindIO<ModuleIOKind, IOType>),
|
||||
AddPlatformIO(HdlLetKindAddPlatformIO),
|
||||
Incomplete(HdlLetKindIncomplete),
|
||||
Instance(HdlLetKindInstance),
|
||||
RegBuilder(HdlLetKindRegBuilder),
|
||||
|
|
@ -713,6 +766,7 @@ pub(crate) enum HdlLetKind<IOType = ParsedType> {
|
|||
impl_fold! {
|
||||
enum HdlLetKind<IOType,> {
|
||||
IO(HdlLetKindIO<ModuleIOKind, IOType>),
|
||||
AddPlatformIO(HdlLetKindAddPlatformIO),
|
||||
Incomplete(HdlLetKindIncomplete),
|
||||
Instance(HdlLetKindInstance),
|
||||
RegBuilder(HdlLetKindRegBuilder),
|
||||
|
|
@ -728,6 +782,9 @@ impl<T: ParseTypes<I>, I> ParseTypes<HdlLetKind<I>> for HdlLetKind<T> {
|
|||
) -> Result<Self, ParseFailed> {
|
||||
match input {
|
||||
HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO),
|
||||
HdlLetKind::AddPlatformIO(input) => {
|
||||
ParseTypes::parse_types(input, parser).map(HdlLetKind::AddPlatformIO)
|
||||
}
|
||||
HdlLetKind::Incomplete(input) => {
|
||||
ParseTypes::parse_types(input, parser).map(HdlLetKind::Incomplete)
|
||||
}
|
||||
|
|
@ -853,6 +910,23 @@ impl HdlLetKindParse for HdlLetKind<Type> {
|
|||
ModuleIOKind::Output(output),
|
||||
)
|
||||
.map(Self::IO),
|
||||
LetFnKind::AddPlatformIO((add_platform_io,)) => {
|
||||
if let Some(parsed_ty) = parsed_ty {
|
||||
return Err(Error::new_spanned(
|
||||
parsed_ty.1,
|
||||
"type annotation not allowed for instance",
|
||||
));
|
||||
}
|
||||
let (m, dot_token) = unwrap_m_dot(m_dot, kind)?;
|
||||
let paren_contents;
|
||||
Ok(Self::AddPlatformIO(HdlLetKindAddPlatformIO {
|
||||
m,
|
||||
dot_token,
|
||||
add_platform_io,
|
||||
paren: parenthesized!(paren_contents in input),
|
||||
platform_io_builder: paren_contents.call(parse_single_fn_arg)?,
|
||||
}))
|
||||
}
|
||||
LetFnKind::Instance((instance,)) => {
|
||||
if let Some(parsed_ty) = parsed_ty {
|
||||
return Err(Error::new_spanned(
|
||||
|
|
@ -928,6 +1002,7 @@ impl HdlLetKindToTokens for HdlLetKind {
|
|||
fn ty_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
HdlLetKind::IO(v) => v.ty_to_tokens(tokens),
|
||||
HdlLetKind::AddPlatformIO(v) => v.ty_to_tokens(tokens),
|
||||
HdlLetKind::Incomplete(v) => v.ty_to_tokens(tokens),
|
||||
HdlLetKind::Instance(v) => v.ty_to_tokens(tokens),
|
||||
HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens),
|
||||
|
|
@ -939,6 +1014,7 @@ impl HdlLetKindToTokens for HdlLetKind {
|
|||
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
HdlLetKind::IO(v) => v.expr_to_tokens(tokens),
|
||||
HdlLetKind::AddPlatformIO(v) => v.expr_to_tokens(tokens),
|
||||
HdlLetKind::Incomplete(v) => v.expr_to_tokens(tokens),
|
||||
HdlLetKind::Instance(v) => v.expr_to_tokens(tokens),
|
||||
HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens),
|
||||
|
|
@ -952,7 +1028,7 @@ with_debug_clone_and_fold! {
|
|||
#[allow(dead_code)]
|
||||
pub(crate) struct HdlLet<Kind = HdlLetKind> {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
pub(crate) hdl_attr: HdlAttr<syn::parse::Nothing, kw::hdl>,
|
||||
pub(crate) let_token: Token![let],
|
||||
pub(crate) mut_token: Option<Token![mut]>,
|
||||
pub(crate) name: Ident,
|
||||
|
|
@ -1109,7 +1185,7 @@ fn parse_quote_let_pat<T, R: ToTokens, C: Borrow<Token![:]>>(
|
|||
}
|
||||
}
|
||||
|
||||
fn wrap_ty_with_expr(ty: impl ToTokens) -> Type {
|
||||
pub(crate) fn wrap_ty_with_expr(ty: impl ToTokens) -> Type {
|
||||
parse_quote_spanned! {ty.span()=>
|
||||
::fayalite::expr::Expr<#ty>
|
||||
}
|
||||
|
|
@ -1141,7 +1217,7 @@ impl<T: ToString> ToTokens for ImplicitName<T> {
|
|||
struct Visitor<'a> {
|
||||
module_kind: Option<ModuleKind>,
|
||||
errors: Errors,
|
||||
io: Vec<ModuleIO>,
|
||||
io: ModuleIOOrAddPlatformIO,
|
||||
block_depth: usize,
|
||||
parsed_generics: &'a ParsedGenerics,
|
||||
}
|
||||
|
|
@ -1173,7 +1249,7 @@ impl Visitor<'_> {
|
|||
Some(_) => {}
|
||||
}
|
||||
}
|
||||
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing, kw::hdl>, expr_if: ExprIf) -> Expr {
|
||||
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<ExprOptions, kw::hdl>, expr_if: ExprIf) -> Expr {
|
||||
let ExprIf {
|
||||
attrs,
|
||||
if_token,
|
||||
|
|
@ -1181,10 +1257,10 @@ impl Visitor<'_> {
|
|||
then_branch,
|
||||
else_branch,
|
||||
} = expr_if;
|
||||
self.require_normal_module_or_fn(if_token);
|
||||
let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr {
|
||||
Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if),
|
||||
expr => expr,
|
||||
let (else_token, else_expr) = else_branch.unzip();
|
||||
let else_expr = else_expr.map(|else_expr| match *else_expr {
|
||||
Expr::If(expr_if) => Box::new(self.process_hdl_if(hdl_attr.clone(), expr_if)),
|
||||
_ => else_expr,
|
||||
});
|
||||
if let Expr::Let(ExprLet {
|
||||
attrs: let_attrs,
|
||||
|
|
@ -1206,7 +1282,19 @@ impl Visitor<'_> {
|
|||
},
|
||||
);
|
||||
}
|
||||
if let Some(else_expr) = else_expr {
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
if sim.is_some() {
|
||||
ExprIf {
|
||||
attrs,
|
||||
if_token,
|
||||
cond: parse_quote_spanned! {if_token.span=>
|
||||
*::fayalite::sim::value::SimValue::<::fayalite::int::Bool>::value(&::fayalite::sim::value::ToSimValue::into_sim_value(#cond))
|
||||
},
|
||||
then_branch,
|
||||
else_branch: else_token.zip(else_expr),
|
||||
}
|
||||
.into()
|
||||
} else if let Some(else_expr) = else_expr {
|
||||
parse_quote_spanned! {if_token.span=>
|
||||
#(#attrs)*
|
||||
{
|
||||
|
|
@ -1269,7 +1357,81 @@ impl Visitor<'_> {
|
|||
}),
|
||||
semi_token: hdl_let.semi_token,
|
||||
};
|
||||
self.io.push(hdl_let);
|
||||
match &mut self.io {
|
||||
ModuleIOOrAddPlatformIO::ModuleIO(io) => io.push(hdl_let),
|
||||
ModuleIOOrAddPlatformIO::AddPlatformIO => {
|
||||
self.errors.error(
|
||||
kind,
|
||||
"can't have other inputs/outputs in a module using m.add_platform_io()",
|
||||
);
|
||||
}
|
||||
}
|
||||
let_stmt
|
||||
}
|
||||
fn process_hdl_let_add_platform_io(
|
||||
&mut self,
|
||||
hdl_let: HdlLet<HdlLetKindAddPlatformIO>,
|
||||
) -> Local {
|
||||
let HdlLet {
|
||||
mut attrs,
|
||||
hdl_attr: _,
|
||||
let_token,
|
||||
mut_token,
|
||||
ref name,
|
||||
eq_token,
|
||||
kind:
|
||||
HdlLetKindAddPlatformIO {
|
||||
m,
|
||||
dot_token,
|
||||
add_platform_io,
|
||||
paren,
|
||||
platform_io_builder,
|
||||
},
|
||||
semi_token,
|
||||
} = hdl_let;
|
||||
let mut expr = quote! {#m #dot_token #add_platform_io};
|
||||
paren.surround(&mut expr, |expr| {
|
||||
let name_str = ImplicitName {
|
||||
name,
|
||||
span: name.span(),
|
||||
};
|
||||
quote_spanned! {name.span()=>
|
||||
#name_str, #platform_io_builder
|
||||
}
|
||||
.to_tokens(expr);
|
||||
});
|
||||
self.require_module(add_platform_io);
|
||||
attrs.push(parse_quote_spanned! {let_token.span=>
|
||||
#[allow(unused_variables)]
|
||||
});
|
||||
let let_stmt = Local {
|
||||
attrs,
|
||||
let_token,
|
||||
pat: parse_quote! { #mut_token #name },
|
||||
init: Some(LocalInit {
|
||||
eq_token,
|
||||
expr: parse_quote! { #expr },
|
||||
diverge: None,
|
||||
}),
|
||||
semi_token,
|
||||
};
|
||||
match &mut self.io {
|
||||
ModuleIOOrAddPlatformIO::ModuleIO(io) => {
|
||||
for io in io {
|
||||
self.errors.error(
|
||||
io.kind.kind,
|
||||
"can't have other inputs/outputs in a module using m.add_platform_io()",
|
||||
);
|
||||
}
|
||||
}
|
||||
ModuleIOOrAddPlatformIO::AddPlatformIO => {
|
||||
self.errors.error(
|
||||
add_platform_io,
|
||||
"can't use m.add_platform_io() more than once in a single module",
|
||||
);
|
||||
}
|
||||
}
|
||||
self.io = ModuleIOOrAddPlatformIO::AddPlatformIO;
|
||||
let_stmt
|
||||
}
|
||||
fn process_hdl_let_instance(&mut self, hdl_let: HdlLet<HdlLetKindInstance>) -> Local {
|
||||
|
|
@ -1490,6 +1652,7 @@ impl Visitor<'_> {
|
|||
}
|
||||
the_match! {
|
||||
IO => process_hdl_let_io,
|
||||
AddPlatformIO => process_hdl_let_add_platform_io,
|
||||
Incomplete => process_hdl_let_incomplete,
|
||||
Instance => process_hdl_let_instance,
|
||||
RegBuilder => process_hdl_let_reg_builder,
|
||||
|
|
@ -1586,7 +1749,7 @@ impl Visitor<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn empty_let() -> Local {
|
||||
pub(crate) fn empty_let() -> Local {
|
||||
Local {
|
||||
attrs: vec![],
|
||||
let_token: Default::default(),
|
||||
|
|
@ -1668,20 +1831,42 @@ impl Fold for Visitor<'_> {
|
|||
Repeat => process_hdl_repeat,
|
||||
Struct => process_hdl_struct,
|
||||
Tuple => process_hdl_tuple,
|
||||
MethodCall => process_hdl_method_call,
|
||||
Call => process_hdl_call,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_local(&mut self, let_stmt: Local) -> Local {
|
||||
fn fold_local(&mut self, mut let_stmt: Local) -> Local {
|
||||
match self
|
||||
.errors
|
||||
.ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr(
|
||||
.ok(HdlAttr::<ExprOptions, kw::hdl>::parse_and_leave_attr(
|
||||
&let_stmt.attrs,
|
||||
)) {
|
||||
None => return empty_let(),
|
||||
Some(None) => return fold_local(self, let_stmt),
|
||||
Some(Some(HdlAttr { .. })) => {}
|
||||
};
|
||||
let mut pat = &let_stmt.pat;
|
||||
if let Pat::Type(pat_type) = pat {
|
||||
pat = &pat_type.pat;
|
||||
}
|
||||
let Pat::Ident(syn::PatIdent {
|
||||
attrs: _,
|
||||
by_ref: None,
|
||||
mutability: _,
|
||||
ident: _,
|
||||
subpat: None,
|
||||
}) = pat
|
||||
else {
|
||||
let hdl_attr =
|
||||
HdlAttr::<ExprOptions, kw::hdl>::parse_and_take_attr(&mut let_stmt.attrs)
|
||||
.ok()
|
||||
.flatten()
|
||||
.expect("already checked above");
|
||||
let let_stmt = fold_local(self, let_stmt);
|
||||
return self.process_hdl_let_pat(hdl_attr, let_stmt);
|
||||
};
|
||||
let hdl_let = syn::parse2::<HdlLet<HdlLetKind<Type>>>(let_stmt.into_token_stream());
|
||||
let Some(hdl_let) = self.errors.ok(hdl_let) else {
|
||||
return empty_let();
|
||||
|
|
@ -1711,15 +1896,20 @@ impl Fold for Visitor<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) enum ModuleIOOrAddPlatformIO {
|
||||
ModuleIO(Vec<ModuleIO>),
|
||||
AddPlatformIO,
|
||||
}
|
||||
|
||||
pub(crate) fn transform_body(
|
||||
module_kind: Option<ModuleKind>,
|
||||
mut body: Box<Block>,
|
||||
parsed_generics: &ParsedGenerics,
|
||||
) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> {
|
||||
) -> syn::Result<(Box<Block>, ModuleIOOrAddPlatformIO)> {
|
||||
let mut visitor = Visitor {
|
||||
module_kind,
|
||||
errors: Errors::new(),
|
||||
io: vec![],
|
||||
io: ModuleIOOrAddPlatformIO::ModuleIO(vec![]),
|
||||
block_depth: 0,
|
||||
parsed_generics,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,45 +1,105 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{kw, module::transform_body::Visitor, HdlAttr};
|
||||
|
||||
use crate::{
|
||||
HdlAttr, kw,
|
||||
module::transform_body::{
|
||||
ExprOptions, Visitor,
|
||||
expand_match::{EnumPath, parse_enum_path},
|
||||
},
|
||||
};
|
||||
use quote::{format_ident, quote_spanned};
|
||||
use std::mem;
|
||||
use syn::{
|
||||
parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
|
||||
ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath,
|
||||
Expr, ExprArray, ExprCall, ExprGroup, ExprMethodCall, ExprParen, ExprPath, ExprRepeat,
|
||||
ExprStruct, ExprTuple, FieldValue, Token, TypePath, parse_quote_spanned,
|
||||
punctuated::Punctuated, spanned::Spanned, token::Paren,
|
||||
};
|
||||
|
||||
impl Visitor<'_> {
|
||||
pub(crate) fn process_hdl_array(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut expr_array: ExprArray,
|
||||
) -> Expr {
|
||||
self.require_normal_module_or_fn(hdl_attr);
|
||||
for elem in &mut expr_array.elems {
|
||||
*elem = parse_quote_spanned! {elem.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&(#elem))
|
||||
};
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
let span = hdl_attr.kw.span;
|
||||
if sim.is_some() {
|
||||
for elem in &mut expr_array.elems {
|
||||
*elem = parse_quote_spanned! {elem.span()=>
|
||||
::fayalite::sim::value::ToSimValue::to_sim_value(&(#elem))
|
||||
};
|
||||
}
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::sim::value::ToSimValue::into_sim_value(#expr_array)
|
||||
}
|
||||
} else {
|
||||
for elem in &mut expr_array.elems {
|
||||
*elem = parse_quote_spanned! {elem.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&(#elem))
|
||||
};
|
||||
}
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::expr::ToExpr::to_expr(&#expr_array)
|
||||
}
|
||||
}
|
||||
parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)}
|
||||
}
|
||||
pub(crate) fn process_hdl_repeat(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut expr_repeat: ExprRepeat,
|
||||
) -> Expr {
|
||||
self.require_normal_module_or_fn(hdl_attr);
|
||||
let repeated_value = &expr_repeat.expr;
|
||||
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
|
||||
};
|
||||
parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)}
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
let span = hdl_attr.kw.span;
|
||||
if sim.is_some() {
|
||||
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
|
||||
::fayalite::sim::value::ToSimValue::to_sim_value(&(#repeated_value))
|
||||
};
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::sim::value::ToSimValue::into_sim_value(#expr_repeat)
|
||||
}
|
||||
} else {
|
||||
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
|
||||
};
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::expr::ToExpr::to_expr(&#expr_repeat)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_struct(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
expr_struct: ExprStruct,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut expr_struct: ExprStruct,
|
||||
) -> Expr {
|
||||
self.require_normal_module_or_fn(&hdl_attr);
|
||||
let name_span = expr_struct.path.segments.last().unwrap().ident.span();
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
if sim.is_some() {
|
||||
let ty_path = TypePath {
|
||||
qself: expr_struct.qself.take(),
|
||||
path: expr_struct.path,
|
||||
};
|
||||
expr_struct.path = parse_quote_spanned! {name_span=>
|
||||
__SimValue::<#ty_path>
|
||||
};
|
||||
for field in &mut expr_struct.fields {
|
||||
let expr = &field.expr;
|
||||
field.expr = parse_quote_spanned! {field.member.span()=>
|
||||
::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr))
|
||||
};
|
||||
field
|
||||
.colon_token
|
||||
.get_or_insert(Token));
|
||||
}
|
||||
return parse_quote_spanned! {name_span=>
|
||||
{
|
||||
type __SimValue<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let value: ::fayalite::sim::value::SimValue<#ty_path> = ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_struct);
|
||||
value
|
||||
}
|
||||
};
|
||||
}
|
||||
let builder_ident = format_ident!("__builder", span = name_span);
|
||||
let empty_builder = if expr_struct.qself.is_some()
|
||||
|| expr_struct
|
||||
|
|
@ -91,12 +151,126 @@ impl Visitor<'_> {
|
|||
}
|
||||
pub(crate) fn process_hdl_tuple(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
expr_tuple: ExprTuple,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut expr_tuple: ExprTuple,
|
||||
) -> Expr {
|
||||
self.require_normal_module_or_fn(hdl_attr);
|
||||
parse_quote_spanned! {expr_tuple.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
if sim.is_some() {
|
||||
for element in &mut expr_tuple.elems {
|
||||
*element = parse_quote_spanned! {element.span()=>
|
||||
&(#element)
|
||||
};
|
||||
}
|
||||
parse_quote_spanned! {expr_tuple.span()=>
|
||||
::fayalite::sim::value::ToSimValue::into_sim_value(#expr_tuple)
|
||||
}
|
||||
} else {
|
||||
parse_quote_spanned! {expr_tuple.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_call(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut expr_call: ExprCall,
|
||||
) -> Expr {
|
||||
let span = hdl_attr.kw.span;
|
||||
let mut func = &mut *expr_call.func;
|
||||
let EnumPath {
|
||||
variant_path: _,
|
||||
enum_path,
|
||||
variant_name,
|
||||
} = loop {
|
||||
match func {
|
||||
Expr::Group(ExprGroup { expr, .. }) | Expr::Paren(ExprParen { expr, .. }) => {
|
||||
func = &mut **expr;
|
||||
}
|
||||
Expr::Path(_) => {
|
||||
let Expr::Path(ExprPath { attrs, qself, path }) =
|
||||
mem::replace(func, Expr::PLACEHOLDER)
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
match parse_enum_path(TypePath { qself, path }) {
|
||||
Ok(path) => break path,
|
||||
Err(path) => {
|
||||
self.errors.error(&path, "unsupported enum variant path");
|
||||
let TypePath { qself, path } = path;
|
||||
*func = ExprPath { attrs, qself, path }.into();
|
||||
return expr_call.into();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.errors.error(
|
||||
&expr_call.func,
|
||||
"#[hdl] function call -- function must be a possibly-parenthesized path",
|
||||
);
|
||||
return expr_call.into();
|
||||
}
|
||||
}
|
||||
};
|
||||
self.process_hdl_method_call(
|
||||
hdl_attr,
|
||||
ExprMethodCall {
|
||||
attrs: expr_call.attrs,
|
||||
receiver: parse_quote_spanned! {span=>
|
||||
<#enum_path as ::fayalite::ty::StaticType>::TYPE
|
||||
},
|
||||
dot_token: Token,
|
||||
method: variant_name,
|
||||
turbofish: None,
|
||||
paren_token: expr_call.paren_token,
|
||||
args: expr_call.args,
|
||||
},
|
||||
)
|
||||
}
|
||||
pub(crate) fn process_hdl_method_call(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut expr_method_call: ExprMethodCall,
|
||||
) -> Expr {
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
let span = hdl_attr.kw.span;
|
||||
// remove any number of groups and up to one paren
|
||||
let mut receiver = &mut *expr_method_call.receiver;
|
||||
let mut has_group = false;
|
||||
let receiver = loop {
|
||||
match receiver {
|
||||
Expr::Group(ExprGroup { expr, .. }) => {
|
||||
has_group = true;
|
||||
receiver = expr;
|
||||
}
|
||||
Expr::Paren(ExprParen { expr, .. }) => break &mut **expr,
|
||||
receiver @ Expr::Path(_) => break receiver,
|
||||
_ => {
|
||||
if !has_group {
|
||||
self.errors.error(
|
||||
&expr_method_call.receiver,
|
||||
"#[hdl] on a method call needs parenthesized receiver",
|
||||
);
|
||||
}
|
||||
break &mut *expr_method_call.receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
let func = if sim.is_some() {
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::enum_::enum_type_to_sim_builder
|
||||
}
|
||||
} else {
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::enum_::assert_is_enum_type
|
||||
}
|
||||
};
|
||||
*expr_method_call.receiver = ExprCall {
|
||||
attrs: vec![],
|
||||
func,
|
||||
paren_token: Paren(span),
|
||||
args: Punctuated::from_iter([mem::replace(receiver, Expr::PLACEHOLDER)]),
|
||||
}
|
||||
.into();
|
||||
expr_method_call.into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,132 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
fold::{impl_fold, DoFold},
|
||||
kw,
|
||||
module::transform_body::{with_debug_clone_and_fold, Visitor},
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
fold::{DoFold, impl_fold},
|
||||
kw,
|
||||
module::transform_body::{
|
||||
ExprOptions, Visitor, empty_let, with_debug_clone_and_fold, wrap_ty_with_expr,
|
||||
},
|
||||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt, format_ident, quote_spanned};
|
||||
use std::collections::BTreeMap;
|
||||
use syn::{
|
||||
fold::{fold_arm, fold_expr_match, fold_pat, Fold},
|
||||
parse::Nothing,
|
||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr,
|
||||
PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment,
|
||||
Token, TypePath,
|
||||
fold::{Fold, fold_arm, fold_expr_match, fold_local, fold_pat},
|
||||
parse_quote_spanned,
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned,
|
||||
token::{Brace, Paren},
|
||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Member, Pat, PatIdent, PatOr, PatParen,
|
||||
PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, PathSegment, Token, TypePath,
|
||||
};
|
||||
|
||||
macro_rules! visit_trait {
|
||||
(
|
||||
$($vis:vis fn $fn:ident($state:ident: _, $value:ident: &mut $Value:ty) $block:block)*
|
||||
) => {
|
||||
trait VisitMatchPat<'a> {
|
||||
$(fn $fn(&mut self, $value: &'a mut $Value) {
|
||||
$fn(self, $value);
|
||||
})*
|
||||
}
|
||||
|
||||
$($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a mut $Value) $block)*
|
||||
};
|
||||
}
|
||||
|
||||
visit_trait! {
|
||||
fn visit_match_pat_binding(_state: _, v: &mut MatchPatBinding) {
|
||||
let MatchPatBinding { mutability: _, ident: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_wild(_state: _, v: &mut MatchPatWild) {
|
||||
let MatchPatWild { underscore_token: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_rest(_state: _, v: &mut MatchPatRest) {
|
||||
let MatchPatRest { dot2_token: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_paren(state: _, v: &mut MatchPatParen<MatchPat>) {
|
||||
let MatchPatParen { paren_token: _, pat } = v;
|
||||
state.visit_match_pat(pat);
|
||||
}
|
||||
fn visit_match_pat_paren_simple(state: _, v: &mut MatchPatParen<MatchPatSimple>) {
|
||||
let MatchPatParen { paren_token: _, pat } = v;
|
||||
state.visit_match_pat_simple(pat);
|
||||
}
|
||||
fn visit_match_pat_or(state: _, v: &mut MatchPatOr<MatchPat>) {
|
||||
let MatchPatOr { leading_vert: _, cases } = v;
|
||||
for v in cases {
|
||||
state.visit_match_pat(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_or_simple(state: _, v: &mut MatchPatOr<MatchPatSimple>) {
|
||||
let MatchPatOr { leading_vert: _, cases } = v;
|
||||
for v in cases {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_struct_field(state: _, v: &mut MatchPatStructField) {
|
||||
let MatchPatStructField { field_name: _, colon_token: _, pat } = v;
|
||||
state.visit_match_pat_simple(pat);
|
||||
}
|
||||
fn visit_match_pat_struct(state: _, v: &mut MatchPatStruct) {
|
||||
let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v;
|
||||
for v in fields {
|
||||
state.visit_match_pat_struct_field(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_tuple(state: _, v: &mut MatchPatTuple) {
|
||||
let MatchPatTuple { paren_token: _, fields } = v;
|
||||
for v in fields {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_enum_variant(state: _, v: &mut MatchPatEnumVariant) {
|
||||
let MatchPatEnumVariant {
|
||||
match_span:_,
|
||||
sim:_,
|
||||
variant_path: _,
|
||||
enum_path: _,
|
||||
variant_name: _,
|
||||
field,
|
||||
} = v;
|
||||
if let Some((_, v)) = field {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_simple(state: _, v: &mut MatchPatSimple) {
|
||||
match v {
|
||||
MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v),
|
||||
MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v),
|
||||
MatchPatSimple::Binding(v) => state.visit_match_pat_binding(v),
|
||||
MatchPatSimple::Wild(v) => state.visit_match_pat_wild(v),
|
||||
MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v),
|
||||
}
|
||||
}
|
||||
fn visit_match_pat(state: _, v: &mut MatchPat) {
|
||||
match v {
|
||||
MatchPat::Simple(v) => state.visit_match_pat_simple(v),
|
||||
MatchPat::Or(v) => state.visit_match_pat_or(v),
|
||||
MatchPat::Paren(v) => state.visit_match_pat_paren(v),
|
||||
MatchPat::Struct(v) => state.visit_match_pat_struct(v),
|
||||
MatchPat::Tuple(v) => state.visit_match_pat_tuple(v),
|
||||
MatchPat::EnumVariant(v) => state.visit_match_pat_enum_variant(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatBinding<> {
|
||||
mutability: Option<Token![mut]>,
|
||||
ident: Ident,
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPatBinding {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self { ident } = self;
|
||||
let Self { mutability, ident } = self;
|
||||
mutability.to_tokens(tokens);
|
||||
ident.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +152,15 @@ with_debug_clone_and_fold! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<P> MatchPatOr<P> {
|
||||
/// returns the first `|` between two patterns
|
||||
fn first_inner_vert(&self) -> Option<Token![|]> {
|
||||
let mut pairs = self.cases.pairs();
|
||||
pairs.next_back();
|
||||
pairs.next().and_then(|v| v.into_tuple().1.copied())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: ToTokens> ToTokens for MatchPatOr<P> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
|
|
@ -77,6 +185,19 @@ impl ToTokens for MatchPatWild {
|
|||
}
|
||||
}
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatRest<> {
|
||||
dot2_token: Token![..],
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPatRest {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self { dot2_token } = self;
|
||||
dot2_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatStructField<> {
|
||||
field_name: Ident,
|
||||
|
|
@ -92,12 +213,20 @@ impl ToTokens for MatchPatStructField {
|
|||
colon_token,
|
||||
pat,
|
||||
} = self;
|
||||
field_name.to_tokens(tokens);
|
||||
if let (None, MatchPatSimple::Binding(MatchPatBinding { ident })) = (colon_token, pat) {
|
||||
if let (
|
||||
None,
|
||||
MatchPatSimple::Binding(MatchPatBinding {
|
||||
mutability: _,
|
||||
ident,
|
||||
}),
|
||||
) = (colon_token, pat)
|
||||
{
|
||||
if field_name == ident {
|
||||
pat.to_tokens(tokens);
|
||||
return;
|
||||
}
|
||||
}
|
||||
field_name.to_tokens(tokens);
|
||||
colon_token
|
||||
.unwrap_or_else(|| Token))
|
||||
.to_tokens(tokens);
|
||||
|
|
@ -159,9 +288,29 @@ impl ToTokens for MatchPatStruct {
|
|||
}
|
||||
}
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatTuple<> {
|
||||
paren_token: Paren,
|
||||
fields: Punctuated<MatchPatSimple, Token![,]>,
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPatTuple {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
paren_token,
|
||||
fields,
|
||||
} = self;
|
||||
paren_token.surround(tokens, |tokens| {
|
||||
fields.to_tokens(tokens);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatEnumVariant<> {
|
||||
match_span: Span,
|
||||
sim: Option<(kw::sim,)>,
|
||||
variant_path: Path,
|
||||
enum_path: Path,
|
||||
variant_name: Ident,
|
||||
|
|
@ -173,6 +322,7 @@ impl ToTokens for MatchPatEnumVariant {
|
|||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
match_span,
|
||||
sim,
|
||||
variant_path: _,
|
||||
enum_path,
|
||||
variant_name,
|
||||
|
|
@ -182,7 +332,28 @@ impl ToTokens for MatchPatEnumVariant {
|
|||
__MatchTy::<#enum_path>::#variant_name
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
if let Some((paren_token, field)) = field {
|
||||
if sim.is_some() {
|
||||
if let Some((paren_token, field)) = field {
|
||||
paren_token.surround(tokens, |tokens| {
|
||||
field.to_tokens(tokens);
|
||||
match field {
|
||||
MatchPatSimple::Paren(_)
|
||||
| MatchPatSimple::Or(_)
|
||||
| MatchPatSimple::Binding(_)
|
||||
| MatchPatSimple::Wild(_) => quote_spanned! {*match_span=>
|
||||
, _
|
||||
}
|
||||
.to_tokens(tokens),
|
||||
MatchPatSimple::Rest(_) => {}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
quote_spanned! {*match_span=>
|
||||
(_)
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
} else if let Some((paren_token, field)) = field {
|
||||
paren_token.surround(tokens, |tokens| field.to_tokens(tokens));
|
||||
}
|
||||
}
|
||||
|
|
@ -194,6 +365,7 @@ enum MatchPatSimple {
|
|||
Or(MatchPatOr<MatchPatSimple>),
|
||||
Binding(MatchPatBinding),
|
||||
Wild(MatchPatWild),
|
||||
Rest(MatchPatRest),
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
|
|
@ -202,6 +374,7 @@ impl_fold! {
|
|||
Or(MatchPatOr<MatchPatSimple>),
|
||||
Binding(MatchPatBinding),
|
||||
Wild(MatchPatWild),
|
||||
Rest(MatchPatRest),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,17 +385,18 @@ impl ToTokens for MatchPatSimple {
|
|||
Self::Paren(v) => v.to_tokens(tokens),
|
||||
Self::Binding(v) => v.to_tokens(tokens),
|
||||
Self::Wild(v) => v.to_tokens(tokens),
|
||||
Self::Rest(v) => v.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EnumPath {
|
||||
variant_path: Path,
|
||||
enum_path: Path,
|
||||
variant_name: Ident,
|
||||
pub(crate) struct EnumPath {
|
||||
pub(crate) variant_path: Path,
|
||||
pub(crate) enum_path: Path,
|
||||
pub(crate) variant_name: Ident,
|
||||
}
|
||||
|
||||
fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> {
|
||||
pub(crate) fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> {
|
||||
let TypePath {
|
||||
qself: None,
|
||||
path: variant_path,
|
||||
|
|
@ -278,14 +452,15 @@ trait ParseMatchPat: Sized {
|
|||
fn or(v: MatchPatOr<Self>) -> Self;
|
||||
fn paren(v: MatchPatParen<Self>) -> Self;
|
||||
fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result<Self, ()>;
|
||||
fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result<Self, ()>;
|
||||
fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant)
|
||||
-> Result<Self, ()>;
|
||||
-> Result<Self, ()>;
|
||||
fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result<Self, ()> {
|
||||
match pat {
|
||||
Pat::Ident(PatIdent {
|
||||
attrs: _,
|
||||
by_ref,
|
||||
mutability,
|
||||
mut mutability,
|
||||
ident,
|
||||
subpat,
|
||||
}) => {
|
||||
|
|
@ -294,10 +469,13 @@ trait ParseMatchPat: Sized {
|
|||
.errors
|
||||
.error(by_ref, "ref not allowed in #[hdl] patterns");
|
||||
}
|
||||
if let Some(mutability) = mutability {
|
||||
state
|
||||
.errors
|
||||
.error(mutability, "mut not allowed in #[hdl] patterns");
|
||||
if let Some(mut_token) = mutability {
|
||||
if state.sim.is_none() {
|
||||
state
|
||||
.errors
|
||||
.error(mut_token, "mut not allowed in #[hdl] patterns");
|
||||
mutability = None; // avoid duplicate errors
|
||||
}
|
||||
}
|
||||
if let Some((at_token, _)) = subpat {
|
||||
state
|
||||
|
|
@ -309,17 +487,26 @@ trait ParseMatchPat: Sized {
|
|||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
}) => Self::enum_variant(
|
||||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
),
|
||||
}) => {
|
||||
if let Some(mut_token) = mutability {
|
||||
state
|
||||
.errors
|
||||
.error(mut_token, "mut not allowed on unit variants");
|
||||
}
|
||||
Self::enum_variant(
|
||||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
Err(ident) => Ok(Self::simple(MatchPatSimple::Binding(MatchPatBinding {
|
||||
mutability,
|
||||
ident,
|
||||
}))),
|
||||
}
|
||||
|
|
@ -359,6 +546,7 @@ trait ParseMatchPat: Sized {
|
|||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
|
|
@ -443,6 +631,7 @@ trait ParseMatchPat: Sized {
|
|||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
|
|
@ -462,7 +651,34 @@ trait ParseMatchPat: Sized {
|
|||
}) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild {
|
||||
underscore_token,
|
||||
}))),
|
||||
Pat::Tuple(_) | Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => {
|
||||
Pat::Tuple(PatTuple {
|
||||
attrs: _,
|
||||
paren_token,
|
||||
elems,
|
||||
}) => {
|
||||
let fields = elems
|
||||
.into_pairs()
|
||||
.filter_map_pair_value(|field_pat| {
|
||||
if let Pat::Rest(PatRest {
|
||||
attrs: _,
|
||||
dot2_token,
|
||||
}) = field_pat
|
||||
{
|
||||
Some(MatchPatSimple::Rest(MatchPatRest { dot2_token }))
|
||||
} else {
|
||||
MatchPatSimple::parse(state, field_pat).ok()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Self::tuple(
|
||||
state,
|
||||
MatchPatTuple {
|
||||
paren_token,
|
||||
fields,
|
||||
},
|
||||
)
|
||||
}
|
||||
Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => {
|
||||
state
|
||||
.errors
|
||||
.error(pat, "not yet implemented in #[hdl] patterns");
|
||||
|
|
@ -497,6 +713,14 @@ impl ParseMatchPat for MatchPatSimple {
|
|||
Err(())
|
||||
}
|
||||
|
||||
fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result<Self, ()> {
|
||||
state.errors.push(syn::Error::new(
|
||||
v.paren_token.span.open(),
|
||||
"matching tuples is not yet implemented inside structs/enums in #[hdl] patterns",
|
||||
));
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn enum_variant(
|
||||
state: &mut HdlMatchParseState<'_>,
|
||||
v: MatchPatEnumVariant,
|
||||
|
|
@ -515,6 +739,7 @@ enum MatchPat {
|
|||
Or(MatchPatOr<MatchPat>),
|
||||
Paren(MatchPatParen<MatchPat>),
|
||||
Struct(MatchPatStruct),
|
||||
Tuple(MatchPatTuple),
|
||||
EnumVariant(MatchPatEnumVariant),
|
||||
}
|
||||
|
||||
|
|
@ -524,6 +749,7 @@ impl_fold! {
|
|||
Or(MatchPatOr<MatchPat>),
|
||||
Paren(MatchPatParen<MatchPat>),
|
||||
Struct(MatchPatStruct),
|
||||
Tuple(MatchPatTuple),
|
||||
EnumVariant(MatchPatEnumVariant),
|
||||
}
|
||||
}
|
||||
|
|
@ -545,6 +771,10 @@ impl ParseMatchPat for MatchPat {
|
|||
Ok(Self::Struct(v))
|
||||
}
|
||||
|
||||
fn tuple(_state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result<Self, ()> {
|
||||
Ok(Self::Tuple(v))
|
||||
}
|
||||
|
||||
fn enum_variant(
|
||||
_state: &mut HdlMatchParseState<'_>,
|
||||
v: MatchPatEnumVariant,
|
||||
|
|
@ -560,6 +790,7 @@ impl ToTokens for MatchPat {
|
|||
Self::Or(v) => v.to_tokens(tokens),
|
||||
Self::Paren(v) => v.to_tokens(tokens),
|
||||
Self::Struct(v) => v.to_tokens(tokens),
|
||||
Self::Tuple(v) => v.to_tokens(tokens),
|
||||
Self::EnumVariant(v) => v.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
|
|
@ -622,10 +853,6 @@ struct RewriteAsCheckMatch {
|
|||
}
|
||||
|
||||
impl Fold for RewriteAsCheckMatch {
|
||||
fn fold_field_pat(&mut self, mut i: FieldPat) -> FieldPat {
|
||||
i.colon_token = Some(Token));
|
||||
i
|
||||
}
|
||||
fn fold_pat(&mut self, pat: Pat) -> Pat {
|
||||
match pat {
|
||||
Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) {
|
||||
|
|
@ -740,17 +967,183 @@ impl Fold for RewriteAsCheckMatch {
|
|||
// don't recurse into expressions
|
||||
i
|
||||
}
|
||||
fn fold_local(&mut self, mut let_stmt: Local) -> Local {
|
||||
if let Some(syn::LocalInit {
|
||||
eq_token,
|
||||
expr: _,
|
||||
diverge,
|
||||
}) = let_stmt.init.take()
|
||||
{
|
||||
let_stmt.init = Some(syn::LocalInit {
|
||||
eq_token,
|
||||
expr: parse_quote_spanned! {self.span=>
|
||||
__match_value
|
||||
},
|
||||
diverge: diverge.map(|(else_, _expr)| {
|
||||
(
|
||||
else_,
|
||||
parse_quote_spanned! {self.span=>
|
||||
match __infallible {}
|
||||
},
|
||||
)
|
||||
}),
|
||||
});
|
||||
}
|
||||
fold_local(self, let_stmt)
|
||||
}
|
||||
}
|
||||
|
||||
struct HdlMatchParseState<'a> {
|
||||
sim: Option<(kw::sim,)>,
|
||||
match_span: Span,
|
||||
errors: &'a mut Errors,
|
||||
}
|
||||
|
||||
struct HdlLetPatVisitState<'a> {
|
||||
errors: &'a mut Errors,
|
||||
bindings: BTreeMap<Ident, MatchPatBinding>,
|
||||
}
|
||||
|
||||
impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
||||
fn visit_match_pat_binding(&mut self, v: &'a mut MatchPatBinding) {
|
||||
self.bindings.insert(v.ident.clone(), v.clone());
|
||||
v.mutability = None;
|
||||
}
|
||||
|
||||
fn visit_match_pat_or(&mut self, v: &'a mut MatchPatOr<MatchPat>) {
|
||||
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||
self.errors.error(
|
||||
first_inner_vert,
|
||||
"or-patterns are not supported in let statements",
|
||||
);
|
||||
}
|
||||
visit_match_pat_or(self, v);
|
||||
}
|
||||
|
||||
fn visit_match_pat_or_simple(&mut self, v: &'a mut MatchPatOr<MatchPatSimple>) {
|
||||
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||
self.errors.error(
|
||||
first_inner_vert,
|
||||
"or-patterns are not supported in let statements",
|
||||
);
|
||||
}
|
||||
visit_match_pat_or_simple(self, v);
|
||||
}
|
||||
|
||||
fn visit_match_pat_enum_variant(&mut self, v: &'a mut MatchPatEnumVariant) {
|
||||
self.errors.error(v, "refutable pattern in let statement");
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'_> {
|
||||
pub(crate) fn process_hdl_let_pat(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
mut let_stmt: Local,
|
||||
) -> Local {
|
||||
let span = let_stmt.let_token.span();
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
if let Pat::Type(pat) = &mut let_stmt.pat {
|
||||
*pat.ty = wrap_ty_with_expr((*pat.ty).clone());
|
||||
}
|
||||
let check_let_stmt = RewriteAsCheckMatch { span }.fold_local(let_stmt.clone());
|
||||
let Local {
|
||||
attrs: _,
|
||||
let_token,
|
||||
pat,
|
||||
init,
|
||||
semi_token,
|
||||
} = let_stmt;
|
||||
let Some(syn::LocalInit {
|
||||
eq_token,
|
||||
expr,
|
||||
diverge,
|
||||
}) = init
|
||||
else {
|
||||
self.errors
|
||||
.error(let_token, "#[hdl] let must be assigned a value");
|
||||
return empty_let();
|
||||
};
|
||||
if let Some((else_, _)) = diverge {
|
||||
// TODO: implement let-else
|
||||
self.errors
|
||||
.error(else_, "#[hdl] let ... else { ... } is not implemented");
|
||||
return empty_let();
|
||||
}
|
||||
let Ok(mut pat) = MatchPat::parse(
|
||||
&mut HdlMatchParseState {
|
||||
sim,
|
||||
match_span: span,
|
||||
errors: &mut self.errors,
|
||||
},
|
||||
pat,
|
||||
) else {
|
||||
return empty_let();
|
||||
};
|
||||
let mut state = HdlLetPatVisitState {
|
||||
errors: &mut self.errors,
|
||||
bindings: BTreeMap::new(),
|
||||
};
|
||||
state.visit_match_pat(&mut pat);
|
||||
let HdlLetPatVisitState {
|
||||
errors: _,
|
||||
bindings,
|
||||
} = state;
|
||||
let bindings_idents = bindings.keys();
|
||||
let bindings = bindings.values();
|
||||
let retval = if sim.is_some() {
|
||||
parse_quote_spanned! {span=>
|
||||
let (#(#bindings,)*) = {
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_value = #expr;
|
||||
// use method syntax to deduce what type to convert to
|
||||
let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value)
|
||||
.__fayalite_match_sim_value();
|
||||
#let_token #pat #eq_token __match_value #semi_token
|
||||
(#(#bindings_idents,)*)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
parse_quote_spanned! {span=>
|
||||
let (#(#bindings,)* __scope,) = {
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant;
|
||||
let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr));
|
||||
::fayalite::expr::check_match_expr(
|
||||
__match_expr,
|
||||
|__match_value, __infallible| {
|
||||
#[allow(unused_variables)]
|
||||
#check_let_stmt
|
||||
match __infallible {}
|
||||
},
|
||||
);
|
||||
let mut __match_iter = ::fayalite::module::match_(__match_expr);
|
||||
let ::fayalite::__std::option::Option::Some(__match_variant) =
|
||||
::fayalite::__std::iter::Iterator::next(&mut __match_iter)
|
||||
else {
|
||||
::fayalite::__std::unreachable!("#[hdl] let with uninhabited type");
|
||||
};
|
||||
let ::fayalite::__std::option::Option::None =
|
||||
::fayalite::__std::iter::Iterator::next(&mut __match_iter)
|
||||
else {
|
||||
::fayalite::__std::unreachable!("#[hdl] let with refutable pattern");
|
||||
};
|
||||
let (__match_variant, __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
__match_variant,
|
||||
);
|
||||
#let_token #pat #eq_token __match_variant #semi_token
|
||||
(#(#bindings_idents,)* __scope,)
|
||||
};
|
||||
}
|
||||
};
|
||||
match retval {
|
||||
syn::Stmt::Local(retval) => retval,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_match(
|
||||
&mut self,
|
||||
_hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
|
||||
expr_match: ExprMatch,
|
||||
) -> Expr {
|
||||
let span = expr_match.match_token.span();
|
||||
|
|
@ -762,8 +1155,9 @@ impl Visitor<'_> {
|
|||
brace_token: _,
|
||||
arms,
|
||||
} = expr_match;
|
||||
self.require_normal_module_or_fn(match_token);
|
||||
let ExprOptions { sim } = hdl_attr.body;
|
||||
let mut state = HdlMatchParseState {
|
||||
sim,
|
||||
match_span: span,
|
||||
errors: &mut self.errors,
|
||||
};
|
||||
|
|
@ -771,24 +1165,39 @@ impl Visitor<'_> {
|
|||
arms.into_iter()
|
||||
.filter_map(|arm| MatchArm::parse(&mut state, arm).ok()),
|
||||
);
|
||||
let expr = quote_spanned! {span=>
|
||||
{
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant;
|
||||
let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr));
|
||||
::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| {
|
||||
#[allow(unused_variables)]
|
||||
#check_match
|
||||
});
|
||||
for __match_variant in ::fayalite::module::match_(__match_expr) {
|
||||
let (__match_variant, __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
__match_variant,
|
||||
);
|
||||
#match_token __match_variant {
|
||||
let expr = if sim.is_some() {
|
||||
quote_spanned! {span=>
|
||||
{
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_value = #expr;
|
||||
// use method syntax to deduce what type to convert to
|
||||
let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value)
|
||||
.__fayalite_match_sim_value();
|
||||
#match_token __match_value {
|
||||
#(#arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
{
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant;
|
||||
let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr));
|
||||
::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| {
|
||||
#[allow(unused_variables)]
|
||||
#check_match
|
||||
});
|
||||
for __match_variant in ::fayalite::module::match_(__match_expr) {
|
||||
let (__match_variant, __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
__match_variant,
|
||||
);
|
||||
#match_token __match_variant {
|
||||
#(#arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
syn::parse2(expr).unwrap()
|
||||
}
|
||||
|
|
|
|||
2527
crates/fayalite-proc-macros-impl/src/process_cfg.rs
Normal file
2527
crates/fayalite-proc-macros-impl/src/process_cfg.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use quote::{ToTokens, format_ident, quote};
|
||||
use std::{collections::BTreeMap, fs};
|
||||
use syn::{fold::Fold, parse_quote};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@ rust-version.workspace = true
|
|||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
base64.workspace = true
|
||||
bitvec.workspace = true
|
||||
blake3.workspace = true
|
||||
clap.workspace = true
|
||||
clap_complete.workspace = true
|
||||
ctor.workspace = true
|
||||
eyre.workspace = true
|
||||
fayalite-proc-macros.workspace = true
|
||||
|
|
@ -24,20 +26,26 @@ hashbrown.workspace = true
|
|||
jobslot.workspace = true
|
||||
num-bigint.workspace = true
|
||||
num-traits.workspace = true
|
||||
os_pipe.workspace = true
|
||||
once_cell.workspace = true
|
||||
ordered-float.workspace = true
|
||||
petgraph.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
sha2.workspace = true
|
||||
tempfile.workspace = true
|
||||
vec_map.workspace = true
|
||||
which.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild.workspace = true
|
||||
serde = { workspace = true, features = ["rc"] }
|
||||
|
||||
[build-dependencies]
|
||||
fayalite-visit-gen.workspace = true
|
||||
|
||||
[features]
|
||||
unstable-doc = []
|
||||
unstable-test-hasher = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["unstable-doc"]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ use std::{env, fs, path::Path};
|
|||
|
||||
fn main() {
|
||||
println!("cargo::rustc-check-cfg=cfg(todo)");
|
||||
println!("cargo::rustc-check-cfg=cfg(cfg_false_for_tests)");
|
||||
println!("cargo::rustc-check-cfg=cfg(cfg_true_for_tests)");
|
||||
println!("cargo::rustc-cfg=cfg_true_for_tests");
|
||||
let path = "visit_types.json";
|
||||
println!("cargo::rerun-if-changed={path}");
|
||||
println!("cargo::rerun-if-changed=build.rs");
|
||||
|
|
|
|||
|
|
@ -1,47 +1,64 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use clap::Parser;
|
||||
use fayalite::{cli, prelude::*};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
#[hdl_module]
|
||||
fn blinky(clock_frequency: u64) {
|
||||
#[hdl]
|
||||
let clk: Clock = m.input();
|
||||
#[hdl]
|
||||
let rst: SyncReset = m.input();
|
||||
fn blinky(platform_io_builder: PlatformIOBuilder<'_>) {
|
||||
let clk_input =
|
||||
platform_io_builder.peripherals_with_type::<peripherals::ClockInput>()[0].use_peripheral();
|
||||
let rst = platform_io_builder.peripherals_with_type::<Reset>()[0].use_peripheral();
|
||||
let cd = #[hdl]
|
||||
ClockDomain {
|
||||
clk,
|
||||
rst: rst.to_reset(),
|
||||
clk: clk_input.clk,
|
||||
rst,
|
||||
};
|
||||
let max_value = clock_frequency / 2 - 1;
|
||||
let max_value = (clk_input.ty().frequency() / 2.0).round_ties_even() as u64 - 1;
|
||||
let int_ty = UInt::range_inclusive(0..=max_value);
|
||||
#[hdl]
|
||||
let counter_reg: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty));
|
||||
#[hdl]
|
||||
let output_reg: Bool = reg_builder().clock_domain(cd).reset(false);
|
||||
#[hdl]
|
||||
let rgb_output_reg = reg_builder().clock_domain(cd).reset(
|
||||
#[hdl]
|
||||
peripherals::RgbLed {
|
||||
r: false,
|
||||
g: false,
|
||||
b: false,
|
||||
},
|
||||
);
|
||||
#[hdl]
|
||||
if counter_reg.cmp_eq(max_value) {
|
||||
connect_any(counter_reg, 0u8);
|
||||
connect(output_reg, !output_reg);
|
||||
connect(rgb_output_reg.r, !rgb_output_reg.r);
|
||||
#[hdl]
|
||||
if rgb_output_reg.r {
|
||||
connect(rgb_output_reg.g, !rgb_output_reg.g);
|
||||
#[hdl]
|
||||
if rgb_output_reg.g {
|
||||
connect(rgb_output_reg.b, !rgb_output_reg.b);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
connect_any(counter_reg, counter_reg + 1_hdl_u1);
|
||||
}
|
||||
for led in platform_io_builder.peripherals_with_type::<peripherals::Led>() {
|
||||
if let Ok(led) = led.try_use_peripheral() {
|
||||
connect(led.on, output_reg);
|
||||
}
|
||||
}
|
||||
for rgb_led in platform_io_builder.peripherals_with_type::<peripherals::RgbLed>() {
|
||||
if let Ok(rgb_led) = rgb_led.try_use_peripheral() {
|
||||
connect(rgb_led, rgb_output_reg);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
let led: Bool = m.output();
|
||||
connect(led, output_reg);
|
||||
let io = m.add_platform_io(platform_io_builder);
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Cli {
|
||||
/// clock frequency in hertz
|
||||
#[arg(long, default_value = "1000000", value_parser = clap::value_parser!(u64).range(2..))]
|
||||
clock_frequency: u64,
|
||||
#[command(subcommand)]
|
||||
cli: cli::Cli,
|
||||
}
|
||||
|
||||
fn main() -> cli::Result {
|
||||
let cli = Cli::parse();
|
||||
cli.cli.run(blinky(cli.clock_frequency))
|
||||
fn main() {
|
||||
<BuildCli>::main("blinky", |_, platform, _| {
|
||||
Ok(JobParams::new(platform.wrap_main_module(blinky)))
|
||||
});
|
||||
}
|
||||
|
|
|
|||
188
crates/fayalite/examples/tx_only_uart.rs
Normal file
188
crates/fayalite/examples/tx_only_uart.rs
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use clap::builder::TypedValueParser;
|
||||
use fayalite::{
|
||||
build::{ToArgs, WriteArgs},
|
||||
platform::PeripheralRef,
|
||||
prelude::*,
|
||||
};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
fn pick_clock<'a>(
|
||||
platform_io_builder: &PlatformIOBuilder<'a>,
|
||||
) -> PeripheralRef<'a, peripherals::ClockInput> {
|
||||
let mut clks = platform_io_builder.peripherals_with_type::<peripherals::ClockInput>();
|
||||
clks.sort_by_key(|clk| {
|
||||
// sort clocks by preference, smaller return values means higher preference
|
||||
let mut frequency = clk.ty().frequency();
|
||||
let priority;
|
||||
if frequency < 10e6 {
|
||||
frequency = -frequency; // prefer bigger frequencies
|
||||
priority = 1;
|
||||
} else if frequency > 50e6 {
|
||||
// prefer smaller frequencies
|
||||
priority = 2; // least preferred
|
||||
} else {
|
||||
priority = 0; // most preferred
|
||||
frequency = (frequency - 25e6).abs(); // prefer closer to 25MHz
|
||||
}
|
||||
(priority, NotNan::new(frequency).expect("should be valid"))
|
||||
});
|
||||
clks[0]
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
fn tx_only_uart(
|
||||
platform_io_builder: PlatformIOBuilder<'_>,
|
||||
divisor: f64,
|
||||
message: impl AsRef<[u8]>,
|
||||
) {
|
||||
let message = message.as_ref();
|
||||
let clk_input = pick_clock(&platform_io_builder).use_peripheral();
|
||||
let rst = platform_io_builder.peripherals_with_type::<Reset>()[0].use_peripheral();
|
||||
let cd = #[hdl]
|
||||
ClockDomain {
|
||||
clk: clk_input.clk,
|
||||
rst,
|
||||
};
|
||||
let numerator = 1u128 << 16;
|
||||
let denominator = (divisor * numerator as f64).round() as u128;
|
||||
|
||||
#[hdl]
|
||||
let remainder_reg: UInt<128> = reg_builder().clock_domain(cd).reset(0u128);
|
||||
|
||||
#[hdl]
|
||||
let sum: UInt<128> = wire();
|
||||
connect_any(sum, remainder_reg + numerator);
|
||||
|
||||
#[hdl]
|
||||
let tick_reg = reg_builder().clock_domain(cd).reset(false);
|
||||
connect(tick_reg, false);
|
||||
|
||||
#[hdl]
|
||||
let next_remainder: UInt<128> = wire();
|
||||
connect(remainder_reg, next_remainder);
|
||||
|
||||
#[hdl]
|
||||
if sum.cmp_ge(denominator) {
|
||||
connect_any(next_remainder, sum - denominator);
|
||||
connect(tick_reg, true);
|
||||
} else {
|
||||
connect(next_remainder, sum);
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
let uart_state_reg = reg_builder().clock_domain(cd).reset(0_hdl_u4);
|
||||
#[hdl]
|
||||
let next_uart_state: UInt<4> = wire();
|
||||
|
||||
connect_any(next_uart_state, uart_state_reg + 1u8);
|
||||
|
||||
#[hdl]
|
||||
let message_mem: Array<UInt<8>> = wire(Array[UInt::new_static()][message.len()]);
|
||||
for (message, message_mem) in message.iter().zip(message_mem) {
|
||||
connect(message_mem, *message);
|
||||
}
|
||||
#[hdl]
|
||||
let addr_reg: UInt<32> = reg_builder().clock_domain(cd).reset(0u32);
|
||||
#[hdl]
|
||||
let next_addr: UInt<32> = wire();
|
||||
connect(next_addr, addr_reg);
|
||||
|
||||
#[hdl]
|
||||
let tx = reg_builder().clock_domain(cd).reset(true);
|
||||
|
||||
#[hdl]
|
||||
let tx_bits: Array<Bool, 10> = wire();
|
||||
|
||||
connect(tx_bits[0], false); // start bit
|
||||
connect(tx_bits[9], true); // stop bit
|
||||
|
||||
for i in 0..8 {
|
||||
connect(tx_bits[i + 1], message_mem[addr_reg][i]); // data bits
|
||||
}
|
||||
|
||||
connect(tx, tx_bits[uart_state_reg]);
|
||||
|
||||
#[hdl]
|
||||
if uart_state_reg.cmp_eq(tx_bits.ty().len() - 1) {
|
||||
connect(next_uart_state, 0_hdl_u4);
|
||||
let next_addr_val = addr_reg + 1u8;
|
||||
#[hdl]
|
||||
if next_addr_val.cmp_lt(message.len()) {
|
||||
connect_any(next_addr, next_addr_val);
|
||||
} else {
|
||||
connect(next_addr, 0u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
if tick_reg {
|
||||
connect(uart_state_reg, next_uart_state);
|
||||
connect(addr_reg, next_addr);
|
||||
}
|
||||
|
||||
for uart in platform_io_builder.peripherals_with_type::<peripherals::Uart>() {
|
||||
connect(uart.use_peripheral().tx, tx);
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
let io = m.add_platform_io(platform_io_builder);
|
||||
}
|
||||
|
||||
fn parse_baud_rate(
|
||||
v: impl AsRef<str>,
|
||||
) -> Result<NotNan<f64>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let retval: NotNan<f64> = v
|
||||
.as_ref()
|
||||
.parse()
|
||||
.map_err(|_| "invalid baud rate, must be a finite positive floating-point value")?;
|
||||
if *retval > 0.0 && retval.is_finite() {
|
||||
Ok(retval)
|
||||
} else {
|
||||
Err("baud rate must be finite and positive".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||
pub struct ExtraArgs {
|
||||
#[arg(long, value_parser = clap::builder::StringValueParser::new().try_map(parse_baud_rate), default_value = "115200")]
|
||||
pub baud_rate: NotNan<f64>,
|
||||
#[arg(long, default_value = "Hello World from Fayalite!!!\r\n", value_parser = clap::builder::NonEmptyStringValueParser::new())]
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl ToArgs for ExtraArgs {
|
||||
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
||||
let Self { baud_rate, message } = self;
|
||||
args.write_display_arg(format_args!("--baud-rate={baud_rate}"));
|
||||
args.write_long_option_eq("message", message);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
type Cli = BuildCli<ExtraArgs>;
|
||||
Cli::main(
|
||||
"tx_only_uart",
|
||||
|_, platform, ExtraArgs { baud_rate, message }| {
|
||||
Ok(JobParams::new(platform.try_wrap_main_module(|io| {
|
||||
let clk = pick_clock(&io).ty();
|
||||
let divisor = clk.frequency() / *baud_rate;
|
||||
let baud_rate_error = |msg| {
|
||||
<Cli as clap::CommandFactory>::command()
|
||||
.error(clap::error::ErrorKind::ValueValidation, msg)
|
||||
};
|
||||
const HUGE_DIVISOR: f64 = u64::MAX as f64;
|
||||
match divisor {
|
||||
divisor if !divisor.is_finite() => {
|
||||
return Err(baud_rate_error("bad baud rate"));
|
||||
}
|
||||
HUGE_DIVISOR.. => return Err(baud_rate_error("baud rate is too small")),
|
||||
4.0.. => {}
|
||||
_ => return Err(baud_rate_error("baud rate is too large")),
|
||||
}
|
||||
Ok(tx_only_uart(io, divisor, message))
|
||||
})?))
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
//! ## `#[hdl] let` statements
|
||||
|
||||
pub mod destructuring;
|
||||
pub mod inputs_outputs;
|
||||
pub mod instances;
|
||||
pub mod memories;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
//! ### Destructuring Let
|
||||
//!
|
||||
//! You can use `#[hdl] let` to destructure types, similarly to Rust `let` statements with non-trivial patterns.
|
||||
//!
|
||||
//! `#[hdl] let` statements can only match one level of struct/tuple pattern for now,
|
||||
//! e.g. you can match with the pattern `MyStruct { a, b }`, but not `MyStruct { a, b: Struct2 { v } }`.
|
||||
//!
|
||||
//! ```
|
||||
//! # use fayalite::prelude::*;
|
||||
//! #[hdl]
|
||||
//! struct MyStruct {
|
||||
//! a: UInt<8>,
|
||||
//! b: Bool,
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl_module]
|
||||
//! fn my_module() {
|
||||
//! #[hdl]
|
||||
//! let my_input: MyStruct = m.input();
|
||||
//! #[hdl]
|
||||
//! let my_output: UInt<8> = m.input();
|
||||
//! #[hdl]
|
||||
//! let MyStruct { a, b } = my_input;
|
||||
//! #[hdl]
|
||||
//! if b {
|
||||
//! connect(my_output, a);
|
||||
//! } else {
|
||||
//! connect(my_output, 0_hdl_u8);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! You can also use `#[hdl(sim)] let` to destructure [`SimValue`]s (or anything that implements [`ToSimValue`]).
|
||||
//!
|
||||
//! [`SimValue`]: crate::sim::value::SimValue
|
||||
//! [`ToSimValue`]: crate::sim::value::ToSimValue
|
||||
//!
|
||||
//! ```
|
||||
//! # use fayalite::prelude::*;
|
||||
//! #[hdl]
|
||||
//! struct MyStruct<T> {
|
||||
//! a: UInt<8>,
|
||||
//! b: Bool,
|
||||
//! c: T,
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure<T: Type>(v: SimValue<MyStruct<T>>) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! mut b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: SimValue<UInt<8>> = a;
|
||||
//! let _: SimValue<Bool> = b;
|
||||
//! let _: SimValue<T> = c;
|
||||
//! *b = false; // can modify b since mut was used
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_ref<'a, T: Type>(v: &'a SimValue<MyStruct<T>>) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: &'a SimValue<UInt<8>> = a;
|
||||
//! let _: &'a SimValue<Bool> = b;
|
||||
//! let _: &'a SimValue<T> = c;
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_mut<'a, T: Type>(v: &'a mut SimValue<MyStruct<T>>) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! **b = true; // you can modify v by modifying b which borrows from it
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: &'a mut SimValue<UInt<8>> = a;
|
||||
//! let _: &'a mut SimValue<Bool> = b;
|
||||
//! let _: &'a mut SimValue<T> = c;
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_inner<T: Type>(v: <MyStruct<T> as Type>::SimValue) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! mut b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: SimValue<UInt<8>> = a;
|
||||
//! let _: SimValue<Bool> = b;
|
||||
//! let _: SimValue<T> = c;
|
||||
//! *b = false; // can modify b since mut was used
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_inner_ref<'a, T: Type>(v: &'a <MyStruct<T> as Type>::SimValue) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: &'a SimValue<UInt<8>> = a;
|
||||
//! let _: &'a SimValue<Bool> = b;
|
||||
//! let _: &'a SimValue<T> = c;
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_inner_mut<'a, T: Type>(v: &'a mut <MyStruct<T> as Type>::SimValue) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! **b = true; // you can modify v by modifying b which borrows from it
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: &'a mut SimValue<UInt<8>> = a;
|
||||
//! let _: &'a mut SimValue<Bool> = b;
|
||||
//! let _: &'a mut SimValue<T> = c;
|
||||
//! }
|
||||
//! ```
|
||||
|
|
@ -7,5 +7,112 @@
|
|||
//!
|
||||
//! `#[hdl] match` statements' bodies must evaluate to type `()` for now.
|
||||
//!
|
||||
//! `#[hdl] match` statements can only match one level of struct/enum pattern for now,
|
||||
//! `#[hdl] match` statements can only match one level of struct/tuple/enum pattern for now,
|
||||
//! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`.
|
||||
//!
|
||||
//! You can also use `#[hdl(sim)] match` to match [`SimValue`]s (or anything that implements [`ToSimValue`]).
|
||||
//!
|
||||
//! `#[hdl(sim)] match` statements' bodies may have any type, unlike `#[hdl] match`.
|
||||
//!
|
||||
//! [`SimValue`]: crate::sim::value::SimValue
|
||||
//! [`ToSimValue`]: crate::sim::value::ToSimValue
|
||||
//!
|
||||
//! ```
|
||||
//! # use fayalite::prelude::*;
|
||||
//! #[hdl]
|
||||
//! enum MyEnum<T> {
|
||||
//! A,
|
||||
//! B(Bool),
|
||||
//! C(T),
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_move<T: Type>(v: SimValue<MyEnum<T>>) -> String {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => String::from("got A"),
|
||||
//! MyEnum::<T>::B(mut b) => {
|
||||
//! let _: SimValue<Bool> = b; // b has this type
|
||||
//! let text = format!("got B({b})");
|
||||
//! *b = true; // can modify b since mut was used
|
||||
//! text
|
||||
//! }
|
||||
//! _ => String::from("something else"),
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_ref<'a, T: Type>(v: &'a SimValue<MyEnum<T>>) -> u32 {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => 1,
|
||||
//! MyEnum::<T>::B(b) => {
|
||||
//! let _: &'a SimValue<Bool> = b; // b has this type
|
||||
//! println!("got B({b})");
|
||||
//! 5
|
||||
//! }
|
||||
//! _ => 42,
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_mut<'a, T: Type>(v: &'a mut SimValue<MyEnum<T>>) -> Option<&'a mut SimValue<T>> {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => None,
|
||||
//! MyEnum::<T>::B(b) => {
|
||||
//! println!("got B({b})");
|
||||
//! **b = true; // you can modify v by modifying b which borrows from it
|
||||
//! let _: &'a mut SimValue<Bool> = b; // b has this type
|
||||
//! None
|
||||
//! }
|
||||
//! MyEnum::<T>::C(v) => Some(v), // you can return matched values
|
||||
//! _ => None, // HDL enums can have invalid discriminants, so we need this extra match arm
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||