A brief tour of Aument

Primitive values

Like many scripting languages, Aument supports the usual core data types: integers (3), floats (3.14), strings ("Hello World"), booleans (true and false) and a none value (nil).

For strings, standard escape sequences work (only \n is implemented however).

Operators

Aument supports the binary operations: add +, subtraction -, multiply *, division / and modulo %:

1 + 1; // Results in 2

Comparisons (<, >, <=, >=, ==, != operators) work as you'd expect:

1 < 2; // (true)

You can also use boolean operators: logical AND (&&) and logical OR (||):

true && false; // false

Aument also supports unary operators: bitwise NOT (~), logical NOT (!), and negation (-):

~1; // => -2

The negation operator can only be used inside brackets:

(-1); // -1

Arrays and tuples

You can define arrays by using the literal syntax:

a = [1,2,3];

Tuples are statically sized arrays, you cannot remove items from it:

a = #[1,2,3];

You can index and set an item in an array or a tuple. Like C and Python, Aument's collections begin at index 0.

a[0]; // 1
a[0] = 100;
a[0]; // 100

Variables

You can assign values into variables like so:

pi = 3.14;
greeting = "Hello World!";

All variables are local to the function they belong in. You cannot use variables outside of that function:

y = 1;
x = 0;
def local() {
    y = 0;
    print y;
}
local(); // 1
print y; // 0

This includes the top-level scope as well. In the example above, the function local cannot access the variable x.

Dynamic types, static names

Identifiers, function names and class names in Aument are static: they are resolved at parsing time. As such, the concept of global variables do not exist in Aument.

In order to share states through function calls, you'll have to pass variables directly or wrap them in a class.

Control Flow

You can use if statements like how it works in C. Notice that there are no brackets surrounding the condition.

if 1 + 1 == 2 {
    print "The computer is working normally.";
} else {
    print "The computer is broken!";
}

The if statement checks if the condition is "truthy", converting the condition into a boolean and checks if it's true. Statements like this are valid:

if "string" {
    print "string is true";
}

See the bool function documentation for more details on boolean conversion.

Aument also has while loops:

while true {
    print "Forever";
}

Input/output

To print something to the screen, use the print statement:

print "Hello World!\n";

You can also print multiple objects:

print "The answer to life, universe and everything is ", 42, "\n";

Functions

To define a function, use the def statement. Inside functions, you can use return to return a value.

def y(x) {
    return x + 2;
}
print y(1); // 3

Aument's standard library provides some useful built-in functions. See its reference manual for more details.

Functions have names that are fixed at parse time, and the number of arguments they take is always constant. If you're trying to call or define a function, and Aument can't find it:

def mistype() {}
misttype();

It will error out directly after parsing:

parser error(3) in /tmp/mistype.au: unknown function misttype
2 | misttype();

Of course, you can use a function that is declared later in the source file:

a();
def a(){}

Classes

You can define a compound data type, a class using the class keyword:

class Human {
    var name;
}

Here, we define a class named Human, that holds a private variable name.

You can define a empty class like so:

class EmptyClass;

Creating a new instance

You can create an empty instance of a class using the new keyword:

alice = new Human;

You can pre-initialize an instance's private variables:

alice = new Human {
    name: "Alice"
};

Just like functions, if you try to use a undeclared class, it will error out after parsing.

Methods and private variables

To modify or access a private variable in a class instance, you'll need to declare a method, a function that can only be called if the first argument's type matches that of the class:

def (self: Human) init(name) {
    @name = name;
}

Here, we declare the function init, that takes 2 arguments, self (a Human class instance), and name (any dynamically typed variable). You can call init like any other function:

init(alice, "Alice");

You cannot access private variables of imported classes.

Dynamic dispatch

Methods can also be dynamically dispatched:

def (self: Human) say() {
    print "I'm ", @name, "\n";
}
class Cat {}
def (self: Cat) say() {
    print "meow!\n";
}
cat = new Cat;
say(alice);
say(cat);

Based on the type of the first argument, an Aument program will choose which function to call at runtime. When we call say(alice);, since the program sees that we've passed a Human type, it chooses to forward the call to the first say function, which prints out:

I'm Alice

Likewise, when we call say(cat);, it dispatches the call to the second say function, giving us:

meow!

Dot calls

You can use the dot operator . to call a function, such that the left-hand side of the operation is the first argument of the function:

alice.say();

Is equivalent to:

say(alice);

Dot binding

You can also use the dot operator to bind an argument to a function. Bound functions must be called using the .( operator:

def add(x,y){ return x + y; }
add_5 = (5).add;
print add_5.(10);

Outputs:

15

By omitting the left-hand side in a dot binding expression, you can create an unbounded function value:

def double(x) { return x * 2; }
op = .double;
print op.(10);

Modules

Imports

You can import files using the import statement.

// importee.au
print "Hello World\n";
// importer.au
import "./importee.au"; // prints out Hello World

Exported functions and classes are accessible under a module. You have to explicitly import a file as a module in order to use it:

import "importee.au" as module;
print module::random(); // => 4

Exports

All files are executed separately and you cannot directly use an imported file's variables/functions (unless exported). To export a function, use the export statement:

// importee.au
export def random() {
    return 4;
}

You can also export a class:

export class Human {
    val name;
}

Importing native DLLs

You can also import native, dynamically linked libraries (DLLs). On Unix systems, these files end with .so. On Windows, these files end with .dll. See tests/dl-module for an example of importing a C library from Aument.

If the .lib extension is used, Aument will load the library with the extension corresponding to the platform's library extension.

If a DLL supports subpath imports, the importer can specify which subpath they want to import:

import "./libmodule.dll:subpath";

The example above imports the module in the library ./libmodule.dll specified by the subpath subpath.