masmlint

Crates.iomasmlint
lib.rsmasmlint
version0.1.1
created_at2025-06-15 15:38:59.142675+00
updated_at2025-06-15 15:43:25.617858+00
descriptionA linter for Miden Assembly
homepage
repositoryhttps://github.com/PhilippGackstatter/masmlint
max_upload_size
id1713421
size75,424
Philipp Gackstatter (PhilippGackstatter)

documentation

README

MASM Linter

A linter for Miden Assembly.

Installation

Install via cargo:

cargo install masmlint

Usage

The linter supports passing a single file or a directory which is searched for MASM files. An example usage looks like this:

masmlint miden-base/crates/miden-lib/asm/kernels/transaction/

The full --help message is:

A linter for Miden Assembly

Usage: lint [OPTIONS] <PATH>

Arguments:
  <PATH>  Path to a MASM file to lint or a directory of MASM files. If a directory is given, it is searched recursively and lints all MASM files that are found

Options:
  -e, --exclude <EXCLUDE>  Comma-separated list of lint names to exclude. These will be excluded from the default list of lints
  -s, --select <SELECT>    Comma-separated list of lint names to run. This list is exhaustive; no other lints will be run
  -h, --help               Print help
  -V, --version            Print version

Lints

PushImmediate

What it does

Checks if immediate values are pushed before instructions that could take that immediate directly.

Why is this bad?

It is faster to read and understand lt.2 than push.2 lt.

Example

Error:   x operand is pushed before an instruction that can take an immediate value
     ,-[lib/tx.masm:227:9]
 226 |     dup neq.0 assert.err=ERR_TX_INVALID_EXPIRATION_DELTA
 227 |     dup push.EXPIRY_UPPER_LIMIT lt assert.err=ERR_TX_INVALID_EXPIRATION_DELTA
     :         ^^^^^^^^^^^^^|^^^^^^^^^^^^
     :                      `-- instruction can be rewritten to take the immediate directly
 228 |     # => [block_height_delta]
     `----
  help: use the instruction in its immediate form `lt.EXPIRY_UPPER_LIMIT`

BareAssert

What it does

Checks for assertions without error messages.

Why is this bad?

Without error messages, failed assertions will produce a message like "assertion failed at clock cycle 123 with error code: 0". This is an unhelpful start to finding the cause of that error.

Example

Error:   x assert without error message
     ,-[lib/prologue.masm:146:18]
 145 |     # assert that sequential hash matches the precomputed kernel commitment
 146 |     movup.4 drop assert_eqw
     :                  ^^^^^|^^^^
     :                       `-- does not include an error message
 147 |     # OS => [kernel_version]
     `----
  help: use the instruction with a helpful error message, e.g.
        `assert_eqw.err=helpful error message`

Potential Lints

The following is a list of ideas of potential lints but are not currently implemented:

  • Check for occurences of eq not, which should be written as neq.
  • Check for occurences of if.true push.0 assert end, which should be written as assert directly. There are multiple variants of this using different assert instructions.
  • Warn about a large number of instructions per line. If too many instructions are in the same line, the code becomes much harder to follow.
Commit count: 30

cargo fmt