Aussom Language Overview

Quick Start

If you are reading this guide it's likely you already got the application installed. To open this guide at any time, run aussom with the -od argument to open the doc in the browser.

$ aussom -od

Programs are written in text files, and saved with a .aus extension. Read on in the next section on how to create the helloworld application and run it.

Your First Aussom Program (helloworld.aus)

Quick overview. Aussom is an interpreted programming language. This means code is read by the interpreter, and then ran right away. The process of creating a Aussom program is simply writing code into a .aus file, and then calling Aussom to run it.

To run a Aussom program, simply open up a terminal window, navigate to the folder where your Aussom file (.aus) is located and then run it with the Aussom command. Here's a simple example.

shell> aussom helloworld.aus

Let's create our first Aussom program. We will start with the simple hello world application just to get familiar. Open up your favorite text editor and create a new file called helloworld.aus. Next, copy and paste the following code and save the file.

class HelloWorld {
	public main(args) {
		msg = "Hello World";
		c.log(msg);
	}
}

Now open up a terminal window and navigate to the folder where your helloworld.aus file is located. Once there, run the aussom helloworld.aus command shown above. If everything went well, you should see "Hello World" printed to your terminal window.

Congratulations! You have written and ran you first Aussom program. Next we will cover OOP in Aussom.

OOP and Aussom

Aussom is based upon Java and like Java Aussom is an Object Orient Programming Language (OOP). This means that all variables (members) and functions are defined within an object. Aussom natively supports basic OOP features such as inheritance and polymorphism. This means that it is easy and natural to create organized and extensible code.

Since Aussom is an OOP language, we cannot just start out writing expressions and functions, we must first create a class. A class represents what will be an instance of your object. To run a class, we must define a function as the entry point to our application. This means that we need to have a way of telling Aussom which function to start executing first. This function is the main function. Each class may only have one main function and when you execute a .aus file from the command line Aussom will look for this main function to execute.

We'll use our helloworld.aus application as an example and go line by line through the code.

The include statement below tells Aussom to include the sys.aus module, which is a Aussom standard library module.

include sys;

This is the class definition. It creates a new class of type 'HelloWorld'. Within the class definition we can create member variables and functions. Any member or function within the class can be referenced using the 'this' key word. More on members and 'this' key word later.

class HelloWorld {
	// ...
}

The main function is the entry point for the application. Main is the first function that Aussom will run when executing a .aus file. Notice that the main function has a single argument called args. The args variable is a list of strings that are any command line arguments to pass to the application. The first line within the main function stores the "Hello World" string into the local msg variable. The second line is a function call 'log' to the c (console) object with the msg string defined above. The c.log(msg) call is what prints the message to the command line.

One thing to note is that when we store "Hello World" into msg variable, msg is considered a local variable and only exists within the main function. Other functions cannot access msg variable, and it can be cleaned up (deleted) as soon as the main function has completed.

public main(args) {
	msg = "Hello World";
	c.log(msg);
}

For demonstration purposes, we will add to our helloworld.aus example. We will add a member variable, a function, and a constructor.

A constructor is a function that is called when an instance of a class is created. This is also called instantiation, or instantiating the object. In this example we instantiate a new helloWorld object within the main function using the new key word. This tells Aussom to create a new instance of HelloWorld and assign it to the world local variable.

Within the constructor function, we make a call to the setName function with a string argument of "Avery". The setName function then takes the passed string of "Avery" and assigns it to the member variable 'name' which is defined toward the top of the HelloWorld class.

include sys;

class HelloWorld {
	// Member variables.
	public name = "";

	// Constructor
	public HelloWorld() {
		this.setName("Avery");
	}

	public main(args) {
		// Create new helloWorld instance
		// which calls the constructor.
		world = new HelloWorld();

		c.log("Hello " + world.name);
	}

	public setName(Name) {
		this.name = Name;
	}
}

Variables

As mentioned in the previous section, there are two types of variables in Aussom, local and member variables. Local variables exist (in scope) within a given function. Once leaving the function, local variables are not accessible and may be cleaned up by the Java garbage collector. Member variables persist as long as the object persists, and can be accessed from member functions or from outside the object if they are public.

Here are examples of defining local variables, they are in bold below.

The two arguments are local variables. When the function is called, the values passed to the function will be stored in the local variable list by the names provided in the function definition.

The other 5 are examples of assigning new local variables. After a variable is assigned, it can be used within that function.

myFunct(ArgumentOne, ArgumentTwo) {
	state = "California";
	pcode = 95678;
	elevation = 100.234;
	warmClimate = true;
	myObj = new SomeObject();
}

Here is an example of member variables. The major difference between local and member variables are that member variables have access modifiers, and they persist for the lifetime of the object.

Member variables accessibility are defined as either public or private. If you do not specify an access modifier, the member is assumed to be private. Public means that any other function can modify the variable and private means that only member functions can modify the variable.

In the example below, we define one public and one private member variable. Notice that we define a public member function that allows any other function to get the value of onlyMyMemberFuncts variable. In order to access a member variable or function, you need to use the 'this' key word. 'this' tells Aussom that you mean a member variable or function, and is literally a reference to the current object.

class MyClass {
	public everyoneCanSeeMe = "Hi";
	private onlyMyMemberFuncts = true;

	public getPrivateMember() {
		return this.onlyMyMemberFuncts;
	}
}

Data Types

Aussom has 9 basic data types. The data types are null, bool, int, double, string, list, map, callback, and object. In this section we will provide a basic description of each.

null:

Null is a placeholder for nothing. In other languages such as C null literally means 0. In Aussom, null simply means nothing. In an expression null equates to false. You may assign null or check for null.

myVar = null;
if(myVar == null) { /* Do something */ }

bool:

Bool is a boolean (true/false) value. A variable can be set as a boolean value by using either the 'true' or 'false' key worlds. Here are a few examples.

mybool = true;
if(true) { /* This will run. */ }
if(mybool) { /* This will run. */ }
if(false) { /* This won't run. */ }

int:

Int is a integer value. Underneath, Aussom represents an integer value as a Java long, which is a 64 bit integer.

num1 = 1;
num2 = -23456;
num3 = 2345566823434;
num4 = 0;

double:

Double is a double precision floating point value. A double in Aussom is the same as a double in Java.

dbl1 = 1.0;
dbl2 = -57392.238432532;
dbl3 = 1238435.23234325;
dbl4 = 0.0;

string:

A string is equivalent to Java's String object. It can hold any number of characters. String can be defined with single or double quotes. You can use double quotes within a single quoted string, or single quotes with a double-quoted string. If you want to use the quote symbol that the string is quoted with, you must escape them. Here are a few examples.

sone = "Hello World!";
stwo = "It's a fine day.";
sthree = 'Here is a "double quote" within a string.';
sfour = "Example of an excaped \"quoted\" string!";

list:

A list is what it sounds like. A list contains any number of other variables. Lists do not need to contain variables of the same type. Various operations can be performed on a list, and they can be appended to dynamically. Lists are generally indexed by an integer value.

myList = [];		// Create a new list dynamically
myList @= "Hi There";	// Append a string to the list.
myList @= 10;		// Append an integer to the list.
#myList			// The # symbol gets the length or number of items in a list.
myList[0]		// The 0 based index of the list holds "Hi There" as a value.

map:

A map is a group of variables that are set and referenced by a key. Sometimes these are referred to as associative arrays. The map data type implemented in Aussom uses strings as keys for the map, and the value can be any data type.

myMap = {};				// Define a new map
myMap['name'] = "Austin";		// Set a value of "Austin" as name.
myMap['name'] = "Tyler Durden";		// Set's the 'name' key to value of "Tyler Durden".
sys.println(myMap['name']);		// Will print "Tyler Durden".

callback:

A callback is a reference to a function. When you create a callback, you can give the callback to another function to call at a later time, or you can call yourself using reflection module. The '::' operator is used with a following string to define a callback. More on callbacks in the callback section.

Given that we have a function:

public makeSoap() { ... }

We can do:

myCallback = ::makeSoap;

And we can pass it to a function like:

someObject.registerCallback(myCallback);
or
someObject.registerCallback(::makeSoap);

object:

The object data type is the most versatile data type. An object is any instance of a class. So you can basically make it anything you like. In our hello world, our HelloWorld class is an object once instantiated. We just need to use the new key world to instantiate the class, and it will then be an object. Here's an example of creating our HelloWorld object.

myObj = new HelloWorld(); 	// Creates a new instance of the HelloWorld 
class and
				// calls the constructor if present. If arguments are
				// provided they are given to the constructor.

myObj.doSomething("Arg");	// Call a public function of the instantiated object.
c.log(myObj.name);	// Dereferences a public member variable 'name' and 
prints
				// to the console.

Functions

Functions in Aussom reside within the class definition. That means in order to call a function, you need to reference the object and the function call. Let's start with function definitions.

Access Modifiers:

Below is an example of a basic public function definition. Notice the access modifier at the beginning is public meaning it can be called from outside of it's class. In this particular example we name the function functOne and the function expects 3 arguments when called. (arg1, arg2, and arg3)

public functOne(arg1, arg2, arg3) {
	// ...
}

Next is an example of a private function. Basically the only difference in the function definition from the previous example is the access modifier is private instead of public. This means that this function can only be called by other functions within the class. It cannot be called from outside of the class.

private functTwo(arg1, arg2, arg3) {
	// ...
}

To further illustrate the difference, consider the two function definitions below. One is public and the other is private. If we want to call functTwo, we need to call it from one of the other functions within the myObj class. We could potentially do this in functOne if we like. See the example below for details.

// Class definition with one public and one private function.
class MyObj {
	public functOne(arg1, arg2, arg3) {
		// ...
	}

	private functTwo(arg1, arg2, arg3) {
		// ...
	}
}

// From another function. (Possibly main)
mobj = new MyObj();		// Instantiate a new myObj instance.
mobj.functOne(1, 2, 3);		// Call our public function with 3 arguments.
mobj.functTwo(1, 2, 3);		// Runtime error! This function is private and not
				// accessible.

Note: If an access modifier is not present, the function is assumed to be private. Also, you cannot name two functions with the same name. If this occurs, the second function definition will overwrite the first.

Arguments:

Aussom offers quite a bit of versatility when it comes to function definition arguments. Let's explore the various function argument scenarios.

Here is a simple case. The function definition has 3 arguments. (arg1, arg2, and arg3) If we wanted to call functOne, we must supply all three arguments. The arguments can be any data type. See example below for details.

public functOne(arg1, arg2, arg3) {
	// ...
}

myObj.functOne(1, 2, 3);		// Valid, all 3 arguments supplied.
myObj.functOne("hi", true, 1.2345);	// Valid, all 3 arguments supplied.
myObj.functOne("wrong");		// Invalid! Function is expecting 3 arguments.

You can also use default arguments, which can be optionally specified when called. Any default arguments in the function definition must be added after any required arguments. When calling a function with default arguments, the default ones do not need to be specified when calling. See examples below.

// Definitions
public functOne(arg1, arg2 = true, arg3 = null) {
	// ...
}

public functTwo(arg1 = "", arg2 = 10) {
	// ...
}

public functThree(arg1 = "", arg2) {		// Syntax error! Default arguments must
	// ...					// go after required arguments.
}

// Calling our functions.
myObj.functOne("test", false, 12345);		// Valid, all arguments provided.
myObj.functOne("test");				// Valid, default arguments in the definition
						// will be used when function is called.
myObj.functOne();				// Invalid, the first argument is required!
myObj.functTwo();				// Valid, function definition has no
						// required arguments, defaults are used.
myObj.functTwo("Tyler Durden", 0);		// Valid, will use supplied arguments.
myObj.functTwo("abcde");			// Valid, arg2 will be set to the default 10.

The etcetera operator (...) can be used to allow any number of arguments to be passed to a function. It must go after any other arguments.

// Definitions
public functOne(...) {
	// ...
}

public functTwo(arg1, arg2 = false, ...) {
	// ...
}

public functThree(..., arg1, arg2) {		// Syntax error! Etcetera operator must go
	// ...					// at the end of argument list.
}

// Calling our functions.
myObj.functOne();				// Valid, any number of arguments are valid.
myObj.functOne("first", "rule", "about");	// Valid, any number of arguments are valid.
myObj.functTwo();				// Invalid! The first argument is required.
myObj.functTwo(true);				// Valid, only the one argument is required.
myObj.functTwo(true, false, "first", "rule");	// Valid, we are providing the first required
						// argument, the second, and any number of
						// extra arguments.

To use the etcetera operator within a function definition, we use the etc variable. This variable is created when the function is called. It is a list that holds all the values provided. It can be used like any other list. We have not gotten to loops yet, but we could use etc with a loop just like any other list.

public functTwo(arg1, arg2 = false, ...) {
	len = #etc;				// Get the number of items in the etc list.
	itemOne = etc[0];			// Get the first element in the etc list.
}

Note: There are functions that have an extern modifier. We will go over these in the extern class section.

Function definitions may optionally specify a required data type. This is especially useful when writing extern functions. This means that you may only provide the required data type to a function with its data type specified. Here are a few examples.

public functOne(int num, string str = "") { }
public functTwo(bool isTrue = false, double dbl) { }
public functThree(list Lst, map Mp) { }
public functFour(object Obj) { }

But wait, isn't Aussom a loosely typed language, why do we specify data types? In some circumstances, the library writer does not want to check every variable passed to a function to ensure its type. This is especially useful to authors of external modules written in Java. By specifying the data type in the function definition, the parser will mandate that the data type is passed. So basically this shifts the ownership to the person using the function to ensure they are passing the correct data type.

Conditional Statements

In Aussom, conditional statements come in two flavors, if/else if/else blocks, or switch/case/default blocks. Conditional statements can also be used in loops, however we are going to focus on these two in this section.

In Aussom, an if statement is required to have an else if or else statement. Below is an example of the syntax for each.

if(false) {
	// Not executed because it's false.
} else if(false) {
	// Not executed because it's false.
} else {
	// Executed, default case.
}

Switch/case/default statements are available as well, but only operate on string values.

switch(var1) {
	case "one": {
		// do something
	}
	case "two": {
		// do something
	}
	default {
		// didn't match 'one' or 'two', do default action.
	}
}

Conditional Operators:

> Greater than.

< Less than.

>= Greater than equal to.

<= Less than equal to.

! Not.

== Equal to.

!= Not equal to.

&& And.

|| Or.

Below are some examples of evaluation of basic conditional statements.

if(10 > 5)			// 10 is greater than 5, so this statement is true.
if(10 < 5)			// 10 is not less than 5, so this statement is false.
if(10 == 10)			// 10 is equal to 10, so this statement is true.
if(10 == 5)			// 10 is not equal to 5, so this statement is false.
if(10 != 5)			// 10 is not equal to 5, so this statement is true.
if(10 != 10)			// 10 is equal to 10, so this statement is false.
if(10 >= 10)			// 10 is equal to 10, so this statement is true.
if(11 >= 10)			// 11 is greater than 10, so this statement is true.
if(10 <= 10)			// 10 is equal to 10, so this statement is true.
if(9 <= 10)			// 9 is less than 10, so this statement is true.
if(true)			// Boolean value of true is true.
if(false)			// Boolean value of false is false.
if(!true)			// Not true is false.
if(1)				// Any integer or double not equal to 0 is true.
if(0)				// Any integer or double that is 0 or 0.0 is false.
if("my string")			// Any non empty string is true.
if("")				// Any empty string is false.
if(null)			// Null is evaluated as false.
if(true && true)		// Both are true, so the and expression is true.
if(true && false)		// One is not true, so the and expression is false.
if(true || false)		// One is true, so the or expression is true.
if(false || false)		// Both are false, so the or expression is false.

Loops

Loops are used to run the same code over and over again or to iterate over a group of items. Aussom features two types of loops, the for loop and the while loop.

While Loop:

The while loop is a simple loop that continues as long as the provided conditional statement is true. The while loop checks the conditional statement first, then executes the code within its block, and then it does it again indefinitely. Here are just a few examples.

while(true) {
	// Infinite loop, will never stop because true is always true.
}

while(1) {
	// Also infinite loop.
}

while(0) {
	// Will never execute
}

i = 0;
while(i < 10) {
	// This code will run 10 times as i goes from 0 to 9.
	i++;	// Increment i by one.
}

For Loop:

The for loop is much more common and can be used a few different ways. The first 3 examples below demonstrate the classic for loop where you define a variable, check a condition, and then do some operation (normally increment or decrement a variable). The bottom two versions use the for loop as an iterator for a list and a map. When iterating a list, each item is placed into the first variable. In the case of a map, the map key is placed into the first variable.

// Classic for loop with definition, condition and operator.
for(i = 0; i < 10; i++) {
	// Will run 10 times as i goes from 0 to 9.
}

for(i = 50; i < 55; i++) {
	// Will run 5 times as i goes from 50 to 54.
}

i = 0;
for(;i < 10;) {
	// This is basically a while loop. This is valid syntax though.
	i++;
}

// For loop as item iterator.
Assuming 'lst' is a list with 10 numbers, 1-9 in it.
for(num : lst) {
	// num equals the item in the list.
}

Assuming 'mp' is a map with 5 items in it.
for(itemKey : mp) {
	// itemKey is the key portion of the key value pair in the map. You can then get
	// the value for that key by doing this.
	// value = mp[itemKey];
}

Exception Handling

Aussom has built-in exception handling. To manage exceptions, Aussom uses try/catch blocks. You can also throw your own exception as well. Below is the basic syntax of a try/catch block. See the comments in the catch section that give the available functions that you can use with the exception.

try {
	// ... some code here to try
}
catch(e) {
	// ... do something with the exception
	// e.getText() gets the exception message text.
	// e.getDetails() gets the exception detail text. This is 
	// often the same text as getText().
	// e.getTrace() gets the trace as a string.
	// e.getStackTrace() gets the message and the trace as a string.
}

You can also throw your own exception. All you have to do is use the throw key word and provide an expression that evaluates to a string after it.

public myFunct() {
	// ... some code here
	throw "Something went wrong!";
}

Here's a simple test to try.

class excepTest {
	public main(args) {
		try {
			tmp = 10/0;
		} catch(e) {
			c.log(e.getStackTrace());
		}
	}
}

Operators

Math Operators:

// Addition
myVar = 5 + 10;		// myVar is 15.

// Subtraction
myVar = 10 - 5;		// myVar is 5.

// Multiplication
myVar = 10 * 5;		// myVar is 50.

// Division
myVar = 10 / 5;		// myVar is 2.

// Plus equals. (myVar currently 10.)
myVar += 5;		// myVar is 15.

// Minus equals. (myVar currently 10.)
myVar -= 5;		// myVar is 5.

// Multiply equals. (myVar currently 10.)
myVar *= 5;		// myVar is 50.

// Divide equals. (myVar currently 10.)
myVar /= 5;		// myVar is 2.

// Plus plus. (myVar currently 10.)
myVar++;		// myVar is 11.

// Minus minus. (myVar currently 10.)
myVar--;		// myVar is 9.

String Concatenation:

// String concatenation uses + operator.
myVar = "Make " + "soap.";		// myVar should be 'Make soap'.

// String + anything else converts the other item to a string.
myVar = "My age is " + 32;		// myVar should be 'My age is 32'.

// Grouping expressions within parenthesis will cause the expression within the
// parenthesis to be evaluated first.
myVar = "My age is " + (20 + 12) + ".";	// myVar should be 'My age is 32.'.

Collection Operators:

// @= is used to append to a list.
myList @= "new value";

// # is the count operator and can be used on maps and lists.
numElements = #myList;

And within the class definition, maps and lists can be assigned starting values using the following syntax.

class myClass {
	public languages = ['c', 'c++', 'java', 'aussom'];
	public myMap = {
		one : 1,
		two : 2,
		three : 3,
		four : ['a', 'b', 'c'],
		'five 5' : { 'make' : 'soap' }
	};

	// ...

	public someFunct() {
		tmp = 'three';
		newmp = { one: 1, two: 2, tmp: this.getAge(), four: [1, 2, 3, 
		'tyler'] };
		newmp['five'] = resultOfSomeMethod();
	}
	
	public getAge() { return 42; }
}

Note: Within the class definition section only, member maps and lists can only be defined with primitive types as shown above. When defining members you cannot say call a method and the result be a value in a map. This is only a limit when declaring a member variable in the class definition. If you assign the value in a function as shown above with getAge, you can use functions or any other expression within the list or map definition.

Callback Operator:

// Double colon operator with a following function name is they proper syntax
// for creating a callback item. They can be stored in variables and passed
// to functions just like other data types.
myCallback = ::someFunction;

Inheritance

Aussom supports inheritance for both Aussom and external classes. Inheritance lets you define a parent class and then create child classes that inherit members and functions from the parent class. Let's start with a simple example.

In the example below, we have a super class Animal and a sub class of Dog. Notice in the class definition of Dog that there is a colon and a reference to Animal after it. This tells Aussom that Dog is a subclass of Animal. This will make all members and functions of Animal available to Dog.

// Super class.
class Animal {
	// Animal actions
	public run() { sys.println("running ..."); }
	public eat() { sys.println("eating ..."); }
	public sleep() { sys.println("sleeping ..."); }
}

// Subclass of animal.
class Dog : Animal {
	public bark() { sys.println("woof! ..."); }
	public wag() { sys.println("wagging tail ..."); }
}

// So we can then do this.
myDog = new Dog();
myDog.run();		// Defined in Animal class.
myDog.eat();		// Defined in Animal class.
myDog.bark();		// Defined in Dog class.

The above example is great, but in Aussom we can inherit from multiple classes. The example below show Dog inheriting from class Animal and Carnivore.

// Super class Carnivore.
class Carnivore {
	public hunt() { sys.println("you don't see me ..."); }
}

// Subclass of Animal and Carnivore.
class Dog : Animal, Carnivore {
	public bark() { sys.println("woof! ..."); }
	public wag() { sys.println("wagging tail ..."); }
}

// So we can do this then.
myDog = new Dog();
myDog.run();		// Defined in Animal class.
myDog.hunt();		// Defined in Carnivore class.
myDog.bark();		// Defined in Dog class.

Note: When inheriting from an external class, you may only inherit from that class at this time. More on that in the external classes and functions section.

Static Classes

Static classes implement the singleton design pattern where there is only a single instance of a specific class. The class is instantiated when it is included and is referenced by it's name after that. A few examples of static classes are the sys and c (console) modules.

// Static class definition.
static class myClass {
	public myStaticFunct() {
		// ... do something
	}
}

// To use
myClass.myStaticFunct();		// We do not use the new operator to instantiate.

Extern Classes and Functions

An extern class definition is used to wrap native Java code. Much of the Aussom standard library is written in Java and is used by defining extern classes. We won't get into writing external modules in this document, but this is the purpose of the extern key word.

If a class is identified as extern, it may then have functions that are also identified as extern. These function definitions do not define the behavior of the function, just the name and the arguments that are provided.

The example below is from the sys library. It references the com.aussom.stdlib.ASys java class, and the extern functions show below define the Java functions that they represent. These functions can be called just like any other function. One thing to keep in mind is that they may specify the data type of the arguments to be passed.

static extern class sys : com.aussom.stdlib.ASys {
	public extern getSysInfo();
	public extern getAssemblyPath();
	public extern getCurrentPath();

	// ...
}

Aside from being external functions, these functions do not behave any differently from any other function. Extern classes can be extended, however you cannot inherit from multiple extern classes at this time.

Modules

Modules in Aussom are simply other .aus files that you want to include. To include other modules, use the include key word. When including modules, use the module name without the file extension. Also, Aussom module files must not contain periods or spaces. It's best to stick with letters, numbers and underscores for module names.

When Aussom looks for modules, it looks in a few locations within the Aussom install path. One of these folders is from within the Aussom JAR file itself.

Aussom will also search the current path where the executing script is located. Modules can be located in sub folders as well. If in sub folders, use the period to specify the path. Here are a few examples.

include sys; 		// The sys.aus file is located in the Aussom JAR.
include myModule;	// Aussom will search for myModule.aus file within the current path.
include folder.myMod;	// Aussom will search for myMod.aus file within the folder directory
			// within the current path.

Modules are normally included in the beginning of the file. They can also be included within a function as well if delayed loading is desired. Here are a couple examples.

include sys;				// Module is included at initial parse time.

class MyClass {
	public main(args) {
		c.log("I will now load another module ...");
		this.myFunct();
	}

	public myFunct() {
		include myModule;	// Module is included after execution has started.
	}
}

Intro to the Standard Library

The Aussom standard library comprises a small number of modules included with the base interpreter. A few modules are included behind the scenes every time you run Aussom such as the lang module which contains a variety of classes including c (console).

Here's a list of the Aussom modules available in the base interpreter.

  • lang - All of the basic language related functions. (automatically included)
  • sys - System related functions.
  • reflect - Support for reflection within Aussom.
  • aunit - A basic unit testing framework.
  • math - Standard math functions.