Basics

Guides

API Reference

Menu

Basics

Guides

API Reference

Aussom Scripting Guide

This is a usage guide for script mode in Aussom. Script mode lets you write .aus files that contain bare top-level statements -- the kind of small, direct file you reach for when you want to quickly automate a task without writing a full class and main wrapper.

Two pieces work together:

  • aussom-base ships the engine API (Engine.setScriptMode, Engine.evalLine, Engine.getScriptClass, etc.). This is what an embedder uses to add script-mode evaluation to a host application.
  • The aussom CLI surfaces script mode to end users with a -s / --scripting flag, a new .auss file extension, and shebang support so scripts feel like first-class executables on every platform.

This guide is for the script writer -- someone who wants to write Aussom scripts and run them from a terminal, a file manager, or a shebang line. If you are embedding Aussom in a Java host, see the embedding guide (design/usage-docs/aussom-lang-standard-embedding-usage.md) for the engine-API side.

The CLI design that this guide leans on lives at aussom/design/script-mode.md in the aussom repository.


1. The big idea

A traditional Aussom file declares a class with a main function:

include sys;

class App {
    public main(args) {
        c.log("hello world");
        return 0;
    }
}

A script-mode file drops the wrapper:

include sys;
c.log("hello world");

That is the entire program. The CLI runs it and prints hello world.

Script mode is built around three ideas:

  1. Top-level statements are allowed. Assignments, expression calls, if / while / for, try / catch, and return can all appear at the file's top level -- they no longer have to live inside a function body.
  2. Includes and class declarations still work the same way. You can mix include sys;, a class point { ... } declaration, and top-level statements that use the class, all in one file.
  3. The script's locals persist across statements the same way they would inside a single function body. A variable bound on line 5 is visible on line 6.

A "script" in this guide is just an Aussom file that uses these top-level statements. The two pipelines (classical "find main() and call it" vs. script "evaluate top-level statements") are independent on the engine; the CLI picks one based on how you invoke the file.


2. Your first script

Save the following as hello.aus:

include sys;
c.log("hello, world");

Run it with the -s flag:

$ aussom -s hello.aus
hello, world

The -s (or long form --scripting) flag tells the CLI to treat the file as a script. Without it, the file would fail to parse -- the classical pipeline does not allow c.log(...) at the top level.

A slightly more interesting example:

include sys;

x = 5;
y = 7;
c.log("sum = " + (x + y));

if (x < y) {
    c.log("x is smaller");
}

Run:

$ aussom -s sum.aus
sum = 12
x is smaller

Notice three things:

  • include sys; works at the top level.
  • x and y are bound by top-level assignments and reused on the next line.
  • if works at the top level; control flow is no different from what you would write inside a function body.

3. Three ways to launch a script

The CLI accepts three independent signals, any one of which turns on script mode. They compose freely -- a file can use one or all three, and the result is the same.

Signal Where you set it When to use it
-s / --scripting Command line flag One-off use of an existing file with no extension change.
.auss file extension The file name on disk The recommended default for new script files.
#! shebang on line 1 Inside the file Unix-style executable scripts run with chmod +x.

3.1 The -s flag

Most explicit. Always wins, regardless of file name or first line:

$ aussom -s myscript.aus
$ aussom -s myscript.auss
$ aussom -s myscript        # extension-less, also fine

Pass -s when you want to be unambiguous, when the file has no recognizable extension, or when you do not control the file name.

3.2 The .auss extension

Files with the .auss extension are run in script mode automatically:

$ aussom hello.auss
hello, world

.auss stands for "Aussom Script". This is the recommended default for any new script file -- it works the same way on every platform, requires no flag, and lets the CLI and any file manager visually distinguish "scripts" from class-based source files.

The check is case-insensitive, so .auss, .AUSS, and .Auss all count.

3.3 The #! shebang

If the file's first line starts with #!, the CLI strips that line and runs the rest in script mode -- whether or not you passed -s and whether or not the file ends in .auss:

#!/usr/bin/env aussom
include sys;
c.log("hello from a shebang");
$ aussom hello.aus
hello from a shebang

The shebang line is meant for Unix kernels (see Section 6) but the CLI still understands it everywhere, so cross-platform scripts do not have to worry about whether they were launched via the shell, via the CLI, or by double-click.


4. Mixing classes and top-level code

A script file is not limited to bare statements. You can declare classes alongside top-level code, and the top-level code can use those classes:

include sys;
include math;

class point {
    public x = 0;
    public y = 0;

    public point(int X, int Y) {
        this.x = X;
        this.y = Y;
    }

    public dist() {
        return math.sqrt(this.x * this.x + this.y * this.y);
    }
}

p = new point(3, 4);
c.log("distance = " + p.dist());

Run:

$ aussom -s point.auss
distance = 5.0

The class declaration registers normally with the engine; the two top-level statements (p = new point(...) and the c.log(...)) become part of the script's body. The class is available immediately to the statements that follow it.

This pattern is useful when a script needs a small reusable type but is not big enough to warrant breaking it up into multiple files.


5. Passing arguments to a script

Anything you put on the command line after the script file is passed to the script as args, an Aussom list of strings:

$ aussom -s greet.auss Alice Bob Carol

Inside greet.auss:

include sys;
for (i = 0; i < args.size(); i = i + 1) {
    c.log("hello " + args.get(i));
}

Output:

hello Alice
hello Bob
hello Carol

args is the same list you would receive as the parameter to a classical main(args) -- same type, same indexing, same methods. You can iterate, slice via args.range(...), count with args.size(), or check whether anything was passed with args.size() == 0.


6. Making a script directly executable on Linux and macOS

On Unix-style systems, a file with a #! shebang on its first line and the executable bit set runs directly when you invoke it -- no aussom prefix needed.

6.1 The portable form

#!/usr/bin/env aussom
include sys;
c.log("hello from a portable shebang");

After making the file executable:

$ chmod +x hello.aus
$ ./hello.aus
hello from a portable shebang

/usr/bin/env aussom is the portable shebang because env finds aussom in your PATH, regardless of where it was installed.

6.2 The -S form

If you want the shebang line to be self-documenting about script mode, use env -S to pass -s through the kernel:

#!/usr/bin/env -S aussom -s
include sys;
c.log("hello with explicit -s");

env -S (coreutils 8.30+, present on modern Linux and on macOS) splits its single argument so aussom and -s are passed as separate words. Use this form when you want the shebang line to make clear that the file is a script.

The CLI auto-detects the leading #! line either way, so the plain #!/usr/bin/env aussom form (Section 6.1) works without the extra flag. Pick whichever you find more readable.

6.3 Absolute-path shebangs

If you know exactly where aussom is installed, you can hard- code the path:

#!/usr/bin/aussom
include sys;
c.log("direct shebang");
Install Binary path
Official .deb (Debian/Ubuntu) /usr/bin/aussom
Official .pkg (macOS) /usr/local/bin/aussom
Source build (mvn install + manual copy) typically /usr/local/bin/aussom
Homebrew, conda, or ~/.local/bin/ install varies per tool

These work because the CLI auto-detects the #! line on the first read, so even though no -s is passed, script mode kicks in.

Trade-offs:

  • #!/usr/bin/aussom does not work on macOS -- Apple's SIP makes /usr/bin/ read-only, so the pkg installer cannot put a symlink there.
  • #!/usr/local/bin/aussom does not work on default Debian/Ubuntu installs -- the deb's symlink lands in /usr/bin/, not /usr/local/bin/.
  • Neither form survives a Homebrew, conda, or user-local install.

The portable #!/usr/bin/env aussom form is the recommended default for any script you intend to share. Use absolute paths only when you control the install layout (a private tool inside your team, for example).

6.4 Line numbers in error messages

When the CLI strips a shebang line, it preserves the file's line count -- so an error reported as script.aus:4 matches line 4 in your editor, not line 3. You can write #!/usr/bin/env aussom on line 1 and stack traces will still match the file on disk one-for-one.


7. Running scripts on Windows

Windows does not honor #! shebang lines at the kernel level, so the Unix-style ./hello.aus invocation does not work on Windows. Instead, Windows users have two options:

7.1 The .auss extension and file associations

The recommended path. The Aussom MSI installer registers .auss (and .aus) as file types associated with the bundled aussom interpreter. After installing aussom on Windows:

  • Double-clicking a .auss file in File Explorer runs it through aussom automatically.
  • Right-clicking a .aus or .auss file shows the bundled Aussom interpreter as the default "Open with..." choice.
  • PowerShell can run a .auss file by name:
    PS> .\hello.auss
    hello, world
    
    PowerShell consults the file association the installer registered, finds aussom.exe, and launches it with the script file as the argument.

The MSI registers two distinct MIME-style types:

  • text/x-aussom-source for .aus (the classical, class-based source file).
  • text/x-aussom-script for .auss (top-level-statement scripts).

Both ultimately route to the same aussom.exe -- the CLI then decides classical vs. script mode based on the file extension or a #! first line. Distinct types let editors and file managers theme the two differently.

7.2 The explicit -s flag

If you have a .aus file that contains top-level statements (for example, a script you wrote on Linux and renamed to .aus out of habit), you can run it from PowerShell or cmd with -s:

C:\> aussom -s hello.aus
hello, world

The -s flag works the same way on every platform.

7.3 Cross-platform shebang lines on Windows

A #! line at the top of the file is harmless on Windows -- the CLI strips it before parsing, so the same file with the same shebang line runs cleanly on Linux, macOS, and Windows.

A typical cross-platform script might look like this:

#!/usr/bin/env -S aussom -s
include sys;
c.log("works on every platform");
  • On Linux/macOS, the kernel sees the shebang and launches aussom -s against the file.
  • On Windows, the user double-clicks the file (or runs .\script.auss) and the CLI strips the shebang transparently.

For best Windows ergonomics, also name the file .auss so the file association picks it up. Combining all three signals costs nothing and gives the script the broadest possible reach out of the box.


8. Errors and exit codes

The CLI maps script outcomes to exit codes:

Outcome Exit code
Script runs successfully 0
Uncaught Aussom exception at runtime 1
Parse error in the script 2
Missing or unreadable script file 2
Invalid CLI usage (e.g., -s with -t) 2

Aussom does not currently ship a sys.exit(N) helper, so a script cannot directly choose its exit code. The only way to return non-zero is to let an uncaught exception propagate, which the CLI maps to 1.

8.1 Parse errors

A parse error reports the file and line:

$ aussom -s broken.aus
[error] broken.aus [3]: PARSE_ERROR: Unknown symbol found at line 3 column 5.
$ echo $?
2

8.2 Runtime errors

A runtime error -- division by zero, calling a missing method, accessing an undefined variable -- prints an Aussom stack trace and exits with code 1:

$ aussom -s zero.aus
[error] zero.aus [4]: division by zero
$ echo $?
1

The line number on the error matches the line in your editor, including when a shebang line was stripped (Section 6.4).

8.3 Catching errors inside the script

try / catch works at the top level just like inside a function body:

include sys;

try {
    bad = 1 / 0;
    c.log("not reached");
} catch (e) {
    c.log("caught: division by zero");
}

c.log("script continues");

Output:

caught: division by zero
script continues

A caught exception is gone -- the script keeps running and exits 0 when it finishes.


9. What scripts can and cannot do

9.1 What works

  • All control-flow statements: if / else, while, for, switch, try / catch, return, break.
  • Expression statements, assignments, function-call statements.
  • include directives at the top level.
  • class and enum declarations at the top level.
  • Reading and using static classes (c.log, sys.getSysInfo, math.sqrt, etc.) the same way you would inside main.
  • Aussom doc comments (/** ... */) and annotations (@Test, etc.) on classes and methods.
  • The full standard library.

9.2 What does not work

  • Top-level function definitions. A public f(x) { ... } at the top level is a parse error. Reusable functions belong inside a class. A script can declare any number of classes, and code at the top level can instantiate and use them freely.
  • this has no meaningful binding at the top level. The script does not run inside a normal class instance, so this.x cannot reach members of any user-declared class. Use locals or static-class references instead.
  • Combining -s with -t, -ta, -d, or -od is a usage error. The test runner and doc generator both require classical class-based files; passing a .auss file to -t is also rejected with a clear message.

9.3 When to use classical mode instead

Use a classical class-with-main file (no -s, no .auss, no shebang) when:

  • You want the file's behavior to match the existing batch contract (run() returns the int from main, or 1 on exception).
  • You are writing a unit-test file for aunit. The aunit framework is class-based; tests live in classes annotated with @Test, and the -t / -ta flags require a class-based file.
  • You are generating documentation with -d. The -d flag walks class definitions; a script-mode file has no user-declared class for it to traverse.

10. A complete worked example

Putting the pieces together. A script that reads command-line arguments, defines a small helper class, runs a loop, and handles errors:

#!/usr/bin/env -S aussom -s
include sys;
include math;

/**
 * Wraps a numeric input plus a label, with a defensive parse.
 */
class measurement {
    public label = "";
    public value = 0.0;

    public measurement(string Label, string Raw) {
        this.label = Label;
        try {
            this.value = math.parseDouble(Raw);
        } catch (e) {
            throw "could not parse '" + Raw + "' as a number";
        }
    }

    public describe() {
        return this.label + " = " + this.value;
    }
}

if (args.size() == 0) {
    c.log("usage: measure.auss <name1> <value1> [<name2> <value2> ...]");
} else if (args.size() % 2 != 0) {
    c.log("expected pairs of <name> <value>; got an odd count.");
} else {
    for (i = 0; i < args.size(); i = i + 2) {
        try {
            m = new measurement(args.get(i), args.get(i + 1));
            c.log(m.describe());
        } catch (e) {
            c.log("skipping pair " + (i / 2 + 1) + ": " + e.message);
        }
    }
}

Save as measure.auss, then:

$ chmod +x measure.auss
$ ./measure.auss height 1.78 weight 72.5 age twelve
height = 1.78
weight = 72.5
skipping pair 3: could not parse 'twelve' as a number

This file uses every feature the guide has covered:

  • A #! shebang for direct execution on Linux/macOS.
  • A .auss extension so file managers and the Windows MSI installer route it to aussom automatically.
  • An Aussom doc comment on a class.
  • A class declaration the top-level code uses.
  • Top-level if / else and for loops.
  • A top-level try / catch that catches a thrown string.
  • args for command-line input.
  • Standard library calls (include sys;, include math;, c.log, math.parseDouble).