Skip to main content

astli

SystemVerilog language tooling in pure Rust: a preprocessor, a lossless syntax tree, and a formatter built on them.

The documentation covers the astli command; the libraries are documented on docs.rs.

Why

A Rust tool that wants to understand SystemVerilog has had to bind a C++ frontend. That works, but the FFI hands back opaque objects: walking a syntax tree means writing a binding for every node and method you touch, and the C++ build is slow and hard to cache. bender is where that friction showed up.

astli is the frontend as a Rust library. The tree is ordinary Rust data that keeps every byte of the source, comments and whitespace included, so a tool can walk it, query it, and print it back exactly.

The formatter is the first thing built on it, and a linter the second. A language server, or deeper analysis, could follow.

Scope

astli lexes, preprocesses and parses; it does not elaborate or type-check. slang is the state of the art for SystemVerilog, a complete compiler, and the right tool whenever you need one. astli does not try to replace it.

Status

Pre-1.0, and the API still changes. What exists:

  • Preprocessor. All directives, macro expansion, includes, and filelists with +incdir+ and +define+.
  • Parser. Design units, declarations, classes, instances, generate blocks, statements and expressions, constraints, assertions, covergroups and clocking blocks. Rarer constructs such as specify, checker, gate primitives and UDPs are kept verbatim for now, so nothing is ever lost; docs/grammar-coverage.md has the detail.
  • Formatter. The lowRISC style. It checks that every result preprocesses to the same thing as its input, and refuses a file rather than change what it means.
  • Linter. Rules for likely bugs and for the lowRISC style, with verible's names where verible has the rule, waived by attribute or by path.
  • Filelists. Trimmed to what a top needs, and put in dependency order.

All of it is tested against open-source designs, fetched by scripts/fetch-corpus.sh.

Install

The astli command comes prebuilt for Linux, macOS and Windows. With the installer script:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/fischeti/astli/releases/latest/download/astli-cli-installer.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/fischeti/astli/releases/latest/download/astli-cli-installer.ps1 | iex"

With uv, or to run it once without installing:

uv tool install astli
uvx astli fmt top.sv

With pip, or pipx to install it in an environment of its own or run it once:

pip install astli
pipx install astli
pipx run astli fmt top.sv

With cargo, as a prebuilt binary through cargo-binstall, or from source:

cargo binstall astli-cli
cargo install astli-cli

Formatting

astli fmt top.sv            # print the formatted file
astli fmt -w rtl/*.sv       # rewrite in place
astli fmt --check -f src.f  # fail if any file in a filelist is unformatted
astli fmt --diff top.sv     # show what would change
astli fmt -                 # stdin to stdout

Each file is formatted on its own: includes are not followed and no +define+ reaches the formatter, so the output depends only on the file.

astli-pre-commit runs it as a pre-commit hook.

An astli.toml sets the width, the indentation and how far a column may pad to line up; these are the defaults:

[fmt]
width = 100
indent = 2
max-pad = 12

To keep an item, statement or member as you wrote it, put the attribute (* astli_fmt_skip *) on it. It is left as written and only moved to its indentation:

(* astli_fmt_skip *)
assign out = sel ? a
               : b;

Linting

astli lint -f src.f                 # report what the rules find
astli lint -W correctness rtl/*.sv  # report a group as warnings
astli lint --list                   # every rule, its group and its level

Rules come in groups: correctness fails the run, suspicious and lowrisc warn, restriction is off. To turn a rule off for one construct, put an attribute on it:

(* astli_allow = "always-ff-non-blocking" *)
always_ff @(posedge clk_i) q = d;

An astli.toml sets levels for a project, and per path for what no attribute reaches:

[lint.paths]
"hw/vendor/**" = { allow = ["lowrisc"] }

Filelists

astli files -f design.f --top soc_top          # only what soc_top needs
astli files -f design.f --top soc_top --order  # packages before their users
astli files -f design.f --emit tops            # modules nothing instantiates
astli files -f design.f --top soc_top --why rtl/fifo.sv

Each file is expanded as it would be compiled, with the filelist's +incdir+s and +define+s, so a module a macro instantiates counts. A name used and declared in no file is a warning.

astli pickle takes the same selection and writes the files as one source, each as written with its headers inlined. With --expand, each is written as a compiler reads it instead, and --prefix and --suffix can rename every module, interface, program, package and class the files declare, wherever it is named, so that two designs can share a compilation:

astli pickle -f design.f --top soc_top --order > soc.sv
astli pickle -f design.f --top soc_top --order --expand --prefix v2_ > soc.sv

--exclude-rename NAME keeps a name as it is.

As a library

[dependencies]
astli = "0.2"
use astli::parse::SyntaxTree;
use astli::syntax::ast::{AstNode, ModuleDecl};

let tree = SyntaxTree::read("top.sv")?;

for module in tree.root().descendants().filter_map(ModuleDecl::cast) {
    if let Some(name) = module.name() {
        println!("module {}", name.text());
    }
}

print!("{}", astli::fmt::format(&tree, &Default::default())?);

astli re-exports each astli-* crate as a module; they can also be used on their own. docs/api.md explains the shape of the API.

Development

astli-cli is the workspace's default member, so cargo run needs no -p. Besides fmt, the driver has one subcommand per stage, each printing what that stage made of a file:

cargo run -- lex        top.sv
cargo run -- preprocess top.sv -I include --emit text
cargo run -- parse      top.sv --quiet

The same default member means every other cargo command needs --workspace: cargo nextest run --workspace, not cargo nextest run. -P quick skips the tests that read the corpus. Hooks run through prek: prek install.

docs/plan.md has the architecture and the decisions behind it.

Path
crates/astli-text Spans, the file store, reading a file
crates/astli-diag Rendering a diagnostic, with its macro and include chain
crates/astli-syntax SyntaxKind, the lexer, the rowan tree types
crates/astli-preproc Directives, macros, includes
crates/astli-parse The grammar, and the tree it builds
crates/astli-fmt The formatter
crates/astli-index The top-level names files declare and use
crates/astli-lint Lint rules over one file's tree
crates/astli The umbrella: every library crate, as a module
crates/astli-cli The driver, a binary named astli
docs/ Design and planning
site/ The documentation site, built by scripts/site.sh

Acknowledgements

  • slang, the reference for how SystemVerilog behaves. The preprocessor is tested against it, file by file.
  • rust-analyzer, whose architecture this follows: an event-based parser, a lossless tree, and typed views generated from a tree grammar.
  • rowan, logos and ungrammar, which it is built on.
  • lowRISC's style guide, which the formatter implements.
  • The open-source designs in the test corpus, for being real code.

Licence

MIT or Apache-2.0, at your option. Unless you state otherwise, any contribution you submit is licensed the same way, without further terms.

Metadata

Release files for astli 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for astli 0.3.0
File Size Uploaded
astli-0.3.0.tar.gz 286.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for astli 0.3.0
File
astli-0.3.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
astli-0.3.0-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
astli-0.3.0-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
astli-0.3.0-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
astli-0.3.0-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
astli-0.3.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
astli-0.3.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 15.7 MB

Release files / astli-0.3.0.tar.gz

Download URL astli-0.3.0.tar.gz
Size 286.0 kB
Tags Source
SHA-256 checksum
How to use checksums
b07fff8af8ebdbf67a3e8d06d786fae2919d6613426d045edf56760f38ce6c3c
BLAKE2b-256 checksum
How to use checksums
dbcbe8d933ec08a1e90d542afbaa7aa04d1a5180c0bdb58ffc3689ab40d1e6cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-win_amd64.whl

Download URL astli-0.3.0-py3-none-win_amd64.whl
Size 2.0 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
398730d62f73962bcecc0191c99c561eb94bf55afbcdbddeb30c01581a6923a3
BLAKE2b-256 checksum
How to use checksums
2df387309e96a6e3602cc0d574f3d6f04a97e742d3f1173e2b957dce82ca4971
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-musllinux_1_2_x86_64.whl

Download URL astli-0.3.0-py3-none-musllinux_1_2_x86_64.whl
Size 2.4 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
1304c6ce5cd5652a15a3f518b85c65756e32fbd0a4bf7ff07305b9f44a7e78e8
BLAKE2b-256 checksum
How to use checksums
f9c4eaeda75c77f20815b848a7575b01834c965e3c9575170a864ee23252098c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-musllinux_1_2_aarch64.whl

Download URL astli-0.3.0-py3-none-musllinux_1_2_aarch64.whl
Size 2.3 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
023b7d893e2333e8e2da4c5bf96b1136395f8f96009640b64ff9db9f40327865
BLAKE2b-256 checksum
How to use checksums
9f15295d919c5aca0498c759982d3ea882ae26d0e7f6d3561c22d2f39fff574f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-manylinux_2_28_x86_64.whl

Download URL astli-0.3.0-py3-none-manylinux_2_28_x86_64.whl
Size 2.3 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
cd349f1ad9589eeeb1e889015b32a347a737ae8b7929db660102727ed25651ad
BLAKE2b-256 checksum
How to use checksums
213159d0b5f2c8dd30c1ea5b525801337969e4f6d923ddb2d517ef7b9b76e1e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-manylinux_2_28_aarch64.whl

Download URL astli-0.3.0-py3-none-manylinux_2_28_aarch64.whl
Size 2.2 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
acca4dc6468145fa59c63ea4efc44f5d971d97ef747e9b6fca5e54c1d8210eeb
BLAKE2b-256 checksum
How to use checksums
e1cdd58aa5cd35df3ae30eb07ac1ac12e42b2119d667764a987ce82bcc34831b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-macosx_11_0_arm64.whl

Download URL astli-0.3.0-py3-none-macosx_11_0_arm64.whl
Size 2.1 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
f135c1a8d5a894142ff551f1d2d9affea332455a60ea6b529d605a6f108766f1
BLAKE2b-256 checksum
How to use checksums
472c7f1c74658066d87f7ae7e59901d64f568a4d668c0ba6370a4e241d754a05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / astli-0.3.0-py3-none-macosx_10_12_x86_64.whl

Download URL astli-0.3.0-py3-none-macosx_10_12_x86_64.whl
Size 2.2 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
f4ed0256414ffe77bcb5c486493e92cf9e7affdc45d0cdb724d35712fe5f4471
BLAKE2b-256 checksum
How to use checksums
c8374bdcb6c7e119b892b897b0f0656486e4931083253c9924ff0373ce51d2fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.3.0 This release

8 release files

0.2.0

8 release files

0.1.1

8 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page