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.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.
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:
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.include sys;, a class point { ... }
declaration, and top-level statements that use the class, all
in one file.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.
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.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. |
-s flagMost 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.
.auss extensionFiles 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.
#! shebangIf 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.
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.
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.
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.
#!/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.
-S formIf 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.
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/.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).
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.
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:
.auss extension and file associationsThe recommended path. The Aussom MSI installer registers
.auss (and .aus) as file types associated with the bundled
aussom interpreter. After installing aussom on Windows:
.auss file in File Explorer runs it
through aussom automatically..aus or .auss file shows the bundled
Aussom interpreter as the default "Open with..." choice..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.
-s flagIf 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.
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");
aussom -s against the file..\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.
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.
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
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).
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.
if / else, while, for,
switch, try / catch, return, break.include directives at the top level.class and enum declarations at the top level.c.log, sys.getSysInfo,
math.sqrt, etc.) the same way you would inside main./** ... */) and annotations (@Test,
etc.) on classes and methods.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.-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.Use a classical class-with-main file (no -s, no .auss, no
shebang) when:
run() returns the int from main, or 1 on
exception).aunit. The aunit
framework is class-based; tests live in classes annotated with
@Test, and the -t / -ta flags require a class-based
file.-d. The -d flag
walks class definitions; a script-mode file has no
user-declared class for it to traverse.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:
#! shebang for direct execution on Linux/macOS..auss extension so file managers and the Windows MSI
installer route it to aussom automatically.if / else and for loops.try / catch that catches a thrown string.args for command-line input.include sys;, include math;,
c.log, math.parseDouble).