// SPDX-License-Identifier: CC-BY-SA-4.0
// SPDX-FileCopyrightText: 2024-2026 Jonathan D.A. Jewell (hyperpolymath)
= RattleScript
:toc:
:toc-placement: preamble

Python-syntax AffineScript.
Write code that looks like Python.
Get affine resource guarantees, algebraic effects, and typed WASM out.

---

== What it is

RattleScript is AffineScript with its Python face pre-selected.
If you write Python, you already know most of the syntax.
The compiler checks that your resources (files, sockets, tokens) are used
*exactly as many times as you say* — and proves it at compile time.

[source,python]
----
def greet(name: String) -> String:
    "Hello, " + name + "!"

def main() -> ():
    let msg = greet("world")
    IO.println(msg)
----

That's a valid `.rattle` file.  Run it:

[source,bash]
----
rattle eval hello.rattle
----

== Why Python syntax?

Because Python programmers deserve a sound type system.
RattleScript is Python's more dangerous cousin — same comfortable whitespace-
delimited blocks, but with teeth: no null pointer exceptions, no
use-after-free, no data races, and no runtime surprises that the type
checker already knows about.

The mascot is a rattlesnake.  Python's more dangerous cousin.

== Surface mappings

[cols="1,1"]
|===
|Python surface |AffineScript equivalent

|`def f(x: T) -> R:`   |`fn f(x: T) -> R { ... }`
|`True` / `False`       |`true` / `false`
|`None`                 |`()`
|`and` / `or` / `not`  |`&&` / `\|\|` / `!`
|`class Name:`          |`type Name`
|`pass`                 |`()`
|`import a.b`           |`use a::b;`
|`from a import b`      |`use a::b;`
|`if cond:` / `else:`   |`if cond { ... } else { ... }`
|`for x in e:`          |`for x in e { ... }`
|`match e:`             |`match e { ... }`
|`# comment`            |`// comment`
|===

See `rattle preview-python-transform <file>` to inspect the full transform
for any file.

== Installation

=== From source (monorepo dev)

[source,bash]
----
# From nextgen-languages/affinescript root — build affinescript first:
dune build

# Then build the rattle wrapper:
cd distributions/rattlescript
just build
# Binary at: target/debug/rattle
----

=== Installed release

[source,bash]
----
just install
# Installs rattle to ~/.cargo/bin
----

=== Standalone GitHub repo

The standalone https://github.com/hyperpolymath/rattlescript[hyperpolymath/rattlescript]
repo contains a pre-configured distribution with affinescript as a git
submodule.  Use that for a self-contained checkout.

== Usage

[source,bash]
----
# Type-check a file
rattle check hello.rattle

# Evaluate
rattle eval hello.rattle

# Compile to WASM
rattle compile hello.rattle

# See the canonical AffineScript generated by the preprocessor
rattle preview-python-transform hello.rattle

# All affinescript subcommands work — --face python is pre-injected
rattle lint hello.rattle
rattle fmt hello.rattle
----

== Relationship to AffineScript

RattleScript *is* AffineScript — same compiler, same type system, same WASM
output.  The only difference is `--face python` is the default.

The Python face lives in
link:../../lib/python_face.ml[`lib/python_face.ml`] and the error vocabulary
in link:../../lib/face.ml[`lib/face.ml`].  No compiler internals change when
the face changes.

== Sync strategy

This directory (`distributions/rattlescript/`) lives inside the affinescript
monorepo.  The standalone https://github.com/hyperpolymath/rattlescript[rattlescript]
GitHub repo uses affinescript as a git submodule and contains only:

* This `distributions/rattlescript/` content (copied at release time)
* Branding assets
* CI workflows

`just update-affinescript` advances the submodule pointer after each
affinescript release.  All language changes, face changes, and bug fixes
come through that single submodule bump — no duplication.
