A Cargo-style subcommand for building, managing, and publishing ATS3 projects.
- Node.js — the ATS3 compilers (
xats2js,xats2py) are JavaScript programs - XATSHOME environment variable pointing to a valid XATSHOME directory
- XATSXANADU environment variable pointing to ATS-Xanadu source
You can set these up manually by cloning XATSHOME and ATS-Xanadu, or use the ATS flake which sets everything up automatically:
nix develop github:ats-lang/ATS # optional, if you use Nixcargo-ats3 also has its own flake.nix for building from source with Nix:
nix build # in the cargo-ats3 checkoutcargo install cargo-ats3For development of cargo-ats3, install from a local checkout:
cargo install --path .# Create a new binary project
cargo ats3 new hello-world
# Build (JS backend by default)
cd hello-world
cargo ats3 build
# Run
cargo ats3 runThe ats3-matrix project depends on ats3-vec via a git dependency:
$ cargo ats3 build
Fetching ats3-vec (/home/user/workspace/ats3-vec)
Compiling ats3-matrix (JS backend)
$ cargo ats3 run
m1 = list(list(1,2,3),list(4,5,6))
2 * m1 = list(list(2,4,6),list(8,10,12))
m1 + 2*m1 = list(list(3,6,9),list(12,15,18))
m1 * [1,0,1] = list(4,10)On subsequent builds, if sources haven't changed, the build is skipped:
$ cargo ats3 build
Fresh (JS backend)
$ cargo ats3 run
Fresh (JS backend)
m1 = list(list(1,2,3),list(4,5,6))
...Use --force to rebuild regardless:
$ cargo ats3 build --force| Command | Description |
|---|---|
new <name> |
Create a new ATS3 project (--template lib or bin) |
init |
Initialize a project in the current directory |
build |
Compile ATS3 source (--backend js|python, --force, --wheel) |
clean |
Remove build artifacts (--deps to also remove .deps/) |
run |
Build and run a binary (-- args passed through) |
check |
Type-check without producing output |
test |
Build and run tests/test.dats |
add <pkg> |
Add a dependency (--path, --git, --version, --dev) |
remove <pkg> |
Remove a dependency |
fetch |
Update cached git dependencies |
lock |
Generate or update Ats3.lock |
tree |
Display the dependency tree (including transitive deps) |
package |
Create a source tarball for distribution |
version |
Show current version or bump via git tag (--bump patch|minor|major) |
publish |
Build and publish to npm/PyPI (--backend, --all-backends) |
my-project/
├── Ats3.toml # Project manifest
├── Ats3.lock # Lockfile (generated, commit to VCS)
├── src/
│ ├── bin/main.dats # Binary entry point
│ └── lib.dats # Library entry point
├── tests/
│ └── test.dats # Test entry point
├── .deps/ # Symlinks to resolved dependencies
└── target/ats3/
├── js/index.js # JS build output
├── python/ # Python build output
│ ├── <pkg>/ # Package directory
│ └── dist/*.whl # Wheel (with --wheel)
└── package/ # Source tarball (with `package`)
[package]
name = "my-project"
version = "0.0.1"
[dependencies]
# Semver requirement resolved against v* git tags (uses pubgrub solver)
ats3-vec = { git = "https://github.com/ats-lang/ats3-vec", version = "^0.1.0" }
# Pinned to an exact git tag
my-utils = { git = "https://github.com/user/my-utils", tag = "v0.2.0" }
# Local path dependency
my-lib = { path = "../my-lib" }
[backends.js]
enabled = true
[backends.python]
enabled = true
wheel = true # auto-build wheel on `cargo ats3 build`Dependencies are resolved transitively into .deps/ as symlinks. Include them
in your ATS3 source via:
#include ".deps/my-lib/src/lib.dats"
Each dependency must be a valid ATS3 project (i.e., contain an Ats3.toml).
Transitive dependencies (dependencies of your dependencies) are resolved
automatically and included in .deps/.
cargo ats3 add my-lib --path ../my-libcargo ats3 add my-utils --git https://github.com/user/my-utils
cargo ats3 add my-utils --git https://github.com/user/my-utils --tag v0.2.0Git dependencies support --tag, --branch, and --rev options.
Git repos are cached in ~/.cache/cargo-ats3/git/. The fetch policy on
build is:
- Pinned (
tagorrev): cached after first clone, no refetch needed - Unpinned (
branchor default): refetched on every build - Local git URL (filesystem path): always refetched
To manually update all cached git deps, run:
cargo ats3 fetchWhen a git dependency includes a version field, cargo-ats3 uses the
pubgrub SAT solver to resolve
compatible versions from v*-prefixed git tags:
ats3-vec = { git = "https://github.com/ats-lang/ats3-vec", version = "^0.1.0" }This runs git ls-remote --tags to discover available versions and picks the
best match. The resolved version is recorded in Ats3.lock for reproducibility.
Ats3.lock records the exact resolved state of all dependencies (commit SHAs
for git deps, paths for local deps). Commit it to version control for
reproducible builds. To regenerate:
cargo ats3 lockThe ATS3 compiler resolves #include directives in three ways depending on the path prefix:
- Absolute (
/path/to/file.dats) — direct file lookup - Current-dir relative (
./path/to/file.dats) — resolved relative to the directory of the file containing the#include - Bare path (
path/to/file.dats) — searched in$XATSHOME
Standard library includes like #include "prelude/HATS/prelude_dats.hats" use
case 3, resolving to $XATSHOME/prelude/HATS/prelude_dats.hats.
Dependency includes (e.g., #include ".deps/my-lib/src/lib.dats") also use case
3 — the .deps prefix does not start with ./, so the compiler searches
$XATSHOME for it.
To make this work, cargo-ats3 creates a temporary overlay directory at target/ats3/.xatshome-overlay/ that contains:
- Symlinks to all real
$XATSHOMEcontents (prelude/,xassets/, etc.) - A
.deps/directory with symlinks to resolved path dependencies
The compiler is then invoked with XATSHOME pointing to this overlay. From the
compiler's perspective, .deps/my-lib/src/lib.dats is just another file inside
XATSHOME.
The overlay is only created when the project has path dependencies; projects without dependencies use the real XATSHOME directly.
Note:
cargo-ats3invokesnodedirectly with the compiler JS files from$XATSHOMErather than relying on wrapper scripts. This ensurescargo-ats3controls theXATSHOMEenvironment variable (which wrapper scripts may override) and works the same regardless of how the ATS3 toolchain was installed.
| Backend | Compiler | Runtime | Output |
|---|---|---|---|
| JS | xats2js |
Node.js | target/ats3/js/index.js |
| Python | xats2py |
Python 3 | target/ats3/python/<pkg>/__init__.py |
| C | xats2c (planned) |
gcc/cc | target/ats3/c/ |
Build a PEP 427 wheel for PyPI distribution:
cargo ats3 build --backend python --wheelThis creates target/ats3/python/dist/<pkg>-<version>-py3-none-any.whl
containing the compiled Python output, py.typed marker, and standard
dist-info metadata (METADATA, WHEEL, RECORD).
You can also set wheel = true in [backends.python] to build wheels
automatically on every Python build.
cargo ats3 packageCreates target/ats3/package/<name>-<version>.tar.gz containing Ats3.toml,
src/, tests/ (if present), and Ats3.lock (if present). A .sha256
checksum file is written alongside the tarball.
# Publish to npm (builds JS, then runs `npm publish`)
cargo ats3 publish --backend js
# Publish to PyPI (builds Python + wheel, then runs `twine upload`)
cargo ats3 publish --backend python
# Publish to all enabled backends
cargo ats3 publish --all-backendsPrerequisites for publishing:
- npm:
npmon PATH, authenticated (npm login) - PyPI:
twineinstalled (pip install twine), authenticated
Pre-publish validation warns if description, license, or a matching
git tag (v<version>) are missing.
# Unit tests + CLI tests (no toolchain required)
cargo test
# Full suite including integration tests (requires ATS3 toolchain)
CARGO_ATS3_INTEGRATION=1 XATSHOME=/path/to/XATSHOME cargo test