A fast and flexible analyzer for GML (GameMaker Language).
duck is is a highly flexible analyzer that enables far stricter rules for GML than GameMaker itself enforces. It is able to detect code that will directly lead to errors as well as enforce styling rules -- all of which are completely customizable.
duck is also extremely fast. It currently can fully process a 250,000 line project in less than half a second.
duck comes with a variety of lints that offer nuanced feedback about your code, ranging from offering stylistic feedback to encouraging better code patterns.
duck currently supports 38 lints. You can use duck explain <LINT_NAME>
to learn more about each lint as you encounter them.
duck can use a configuration file per-project to change how it behaves. The most basic adjustment you can make is overriding the default "level" of any lint.
[lint-levels]
and_preference = "allow"
try_catch = "warn"
missing_case_member = "deny"
This demonstrates the three different levels: "allow" will tell duck to fully ignore the lint, "warn" will mark them as warnings, and "deny" will treat them like full errors.
Some lints come with customizable behavior. english_flavor_violation
, for example, let's you decide between the British or American spelling of GML functions. var_prefix_violation
let's you decide if you prefer local variables to be prefixed with an underscore (_foo
) or with nothing at all (foo
).
You can read more about these customization features and how to set them up here.
duck supports parsing for arbitrary tags in the codebase written with the following syntax:
// #[tag]
// #[tag_with_parameter(parameter)]
Developers can use duck as a library to fetch all expressions / statements that are tagged in the source code, opening the doors to many new tools that don't need to worry about parsing GML themselves.
These allow for developers to create their own tools for gml while using duck to handle their parsing.
Additionally, duck supports allow
, warn
and deny
tags to customize linting rules on a case by case basis. For example, while I may want globalvar
to be banned from my codebase, I might have one or two exceptions You can tag the specific occurrence of the usage to acknowledge (and ignore) the lint.
// #[allow(deprecated)]
globalvar my_globalvar;
Tags are a great way to enable lints on things you don't want to fully ban, but want to keep a close eye on.
duck has made significant progress in adding type checker that works completely off of inference, but development has halted on this feature due to the scoping patterns that are allowed in GameMaker. The feature will only be enabled if it can achieve meaningful analysis on any GML code, not requiring users to abandon certain patterns and practices. You can see what the analyzer is currently capable of by reading its tests in src/solve/tests/type_tests.rs
.
The latest release can be found here. Rust users can also install with cargo: cargo install duck
.
To run duck, simply use the run
command!
duck run
There are a few different options you can use, as well as other commands. Enter duck help
for more information.
Please open an issue if you encounter any problems with duck, or if you have any feature requests you would like to make!
- Benchmark was run on an MacBook Pro 2021 running an M1 Max with 32 GB of memory.