Program Structure

Program consists of several subroutines, each identified by its name. Subroutine definition starts with the line containing keyword sub followed by name. Next lines contain the body of subroutine:

sub main
    call "println" "Hello, World!"

Subroutine declaration sub main should start from the beginning of the line, without indent. All following lines should be indented, until next declaration:

sub main
    call "greeting"

sub greeting
    call "println" "Hello, World!"

In this example subroutine main calls another subroutine greeting, which in its turn calls built-in subroutine println passing it the string to print.

Default executor starts the program with running subroutine main.

Statements

There are only a few types of statements. They are recognized by the first word of the statement.

Subroutine call as we have seen before starts with the keyword call which is followed by the subroutine name (or expression evaluated to subroutine name) and, possibly, more expressions to be evaluated to subroutine arguments. For example the line call "println" "Hello" requires the executing system to call subroutine println passing it string Hello as argument.

Assignment of a value to variable is described by keyword let which is then followed by the name of the variable (or expression evaluated to subroutine name) and expression the value of which should be written to variable:

sub main
    let "x" 5
    let "hi" "Hello, People!"
    call "println" $hi

Here the value 5 is assigned to variable named x and string value Hello, People! is assigned to variable hi. As you may guess later $hi is used to fetch the value of the variable with the name hi - i.e. dollar sign $ is a prefix for getting variable value.

Evaluation statement is started with keyword eval it does nothing except evaluating the expression following this keyword. We shall see later when this could be useful.

Combined statement is created by putting several statements into one line, separating them with semicolon ; like following:

sub main
    call "print" "Hello, " ; call "println" "World!"

Note (it is important) that semicolon should be separated with spaces on both sides!

Conditional statement is not used on its own. It should always be a part of a combined statement, like this:

sub conditional_print
    if $x 5 = ; call "println" "X equals to five!"

As you see, conditional statement is started with keyword if which is followed by an expression. You also see from here that expressions are written in postfix notation (i.e. equality operator is following its two operands) - you will read about it later.

If the expression after if is calculated to be non-zero, the rest part of combined statement is executed. Otherwise it is skipped.

Loop statement is similar to conditional. It is started with keyword while and the following part of the combined statement is executed several time, while the expression after while is evaluated to be non-zero:

sub numbers
    let "x" 10
    while $x ; call "println" $x ; let "x" $x 1 -

Here the second part of combined expression prints the value of x and third part decrements the value of x so that the whole statement is executed ten times until x becomes zero.

Expressions

Expressions are evaluated on the special stack, like in Forth programming language or in the processor of Java Virtual Machine. The evaluation is performed straightforward through all components of expression, by the following rules:

Operators usually take one or more operands from the top of the stack, perform an operation and put the result back to stack. For example:

sub main
    call 'println 5 3 +

Here execution works as following: the keyword call is recognized so the system is ready to perform subroutine call; then the rest is evaluated:

So when expressions are evaluated, two values are left on the stack - the string println and the number 8. The first is interpreted by call to be the name of subroutine, the latter becomes an argument for subroutine.

Most binary operators work similarly:

sub main
    let 'x 9
    call 'println $x $x *
    call 'println $x 3 /
    call 'println $x 5 >
    call 'println $x 8 <=

This program will printl values of 81, 3, 1 and 0 (you see, logical operators have result of 0 for false and 1 for true).

The full list of built-in operators could be found further.

Tricks

Since subroutine call statement uses a string value as a name of subroutine, it could be evaluated in runtime:

sub main
    let 'name "println"
    call $name 15

This could be useful for building some flexible code with self-modifying behavior.

Similarly, the names of variables could be constructed in the runtime:

sub main
    let 'a 1 + 10
    let 'a 2 + 50
    call 'println $a1
    call 'println $a2

In this example the variable name is concatenated of a prefix a and index (1 or 2). This is useful when we need an array in our program. Consider the following example:

sub main
    let 'total 10
    call 'calc_squares
    call 'print_values

sub calc_squares
    let 'i 1
    while $i $total <= ; let 'val $i + $i $i * ; let 'i $i 1 +

sub print_values
    let 'i 1
    while $i $total <= ; call 'println 'val $i [] ; let 'i $i 1 +

Here main subroutine assigns 10 to variable total and calls calc_squares and then print_values subroutines.

The calc_squares have a loop inside, which runs variable i from 1 to 10 and calculates the square of it (by $i $i * expression) which is assigned to variables from val1 to val10 thanks to let 'val $i + ... statement.

The print_values also runs a loop for i from 1 to 10 and fetches variables from val1 to val10, printing their values.

Fetching is performed by special binary operator []. Obviously we could not use usual dollar sign to fetch the variable with the name not evaluated yet. Instead such operator pops out two last values from the stack (i.e. string val and the value of variable i), concatenates these two values (so that string like val1, val3 etc. is formed) and then fetches the value from variable with such name.

Variables and arguments

Variables have different scope, which is determined by the length of their names:

For example:

sub main
    let 'x 5
    let 'xaxa 10
    call 'change
    call 'println $x
    call 'println $xaxa

sub change
    let 'x 7
    let 'xaxa 20

This code will print values 5 and 20 because changing variable x inside subroutine change does not affect x in main, while xaxa is shared between both subroutines and is changed.

Special case of local variables are subroutine arguments. They are represented by a single char variable names following the definition of the subroutine. When subroutine is called, the same amount of values are popped out from stack and are assigned to local variables with those names. For example:

sub main
    call 'print_three 5 9 30

sub print_three a b c
    call 'print $a
    call 'print " "
    call 'print $b
    call 'print " "
    call 'println $c

Here when call statement is executed we have 4 values on the stack - subroutine name and then three numbers. Subroutine with the required name (print_three) is found and is determined to have 3 arguments. So 3 values are popped out from stack before executing this subroutine and are assigned to its local variables a, b and c (so 5 goes to a etc.)

After execution you will see line 5 9 30 printed.

Built-ins

Several subroutines and operators are predefined:

Stack manipulation operators are similar to ones in Forth language: