Skip to main content

Basic syntax

How a JARU program is written: the order of its parts, how statements are separated, how blocks are closed, how values are written and in which order operators are calculated. The pitfalls people fall into most often are at the end.

Each part of the language then has its own page: Variables and constants, Operators, Control structures, Functions...

A program​

A JARU program is one .aru file, or several. There is no main function: the VM runs the main file from top to bottom, and the program ends when it reaches the end.

This is the usual order:

use Math                     // 1. The modules the program uses

const SIDE = 4 // 2. The constants

func area(side) // 3. The functions
return side * side
end

// 4. What the program does
var a = area(SIDE)
println("Area: ", a) // Area: 16
println("The largest: ", Math.max(a, 20)) // The largest: 20
  • use opens the VM modules you are going to use; several fit on one line: use Display, Sprite, Input. Without it, the program compiles, but it stops at the first line that uses the module, with the error “Module 'Math' not found or not imported.”. The modules are in The API.
  • import "File.aru" brings in the code of another file of the project. That code runs before the first line of the main file, even if the import is further down. Programs in several files explains it.
  • A function exists from the line where it is declared. If you call it from higher up, the program stops with the error “Undefined variable”. More in Functions.
  • The program can also end earlier, with exit: see Errors and exceptions.

Statements and semicolons​

The normal thing is to write one statement per line. The semicolon at the end is optional:

var lives = 3
var score = 0;

To put several on the same line, separate them with ;. The compiler also separates them without it, but they are harder to read:

var x = 10; var y = 20; println(x + y)    // 30

A line break does not end a statement: the compiler considers it finished when what comes next can no longer be part of it. That is why a long statement can carry on in the line below:

var total = 10 +
20 +
30
println(total) // 60
A line that starts with ++ or --

Because a line break does not end a statement, a ++ or a -- at the start of a line sticks to the line above if that line ends in a variable:

var games = 0
var score = 10
var best = score
++games // read as: var best = score++
println(best, " ", score, " ", games) // 10 11 0

Write games++ or games += 1, or end the line above with ;.

Comments​

// One-line comment: it runs to the end of the line
var lives = 3 // also after a statement

/* Comment over
several lines */
println("10 // 2") // inside a string, // is text: prints 10 // 2
  • Comments can contain accented letters.
  • A /* … */ cannot go inside another one: the first */ closes the comment, and whatever is left behind it is an error.
  • A /* without its */ gives the error “Detected unterminated comment, expecting '*/'”.
/* A comment /* inside another one */ is not allowed */
println("hello")

Blocks: end, parentheses and then​

Every block is closed with end. Indentation does not matter to the compiler: it is only there to make the code easier to read.

BlockOpens withPage
Conditionif (…) then, and inside it elsif (…) then and elseControl structures
Selectionswitch (…), and inside it case …: and default:Control structures
Loopsfor (…; …; …), foreach (var x in …), while (…) and until (…)Control structures
Functionsfunc name(…) and fn(…):Functions
Classesclass Name, and inside it def method(…)Classes and objects
Structs and enumerationsstruct Name and enum NameStructs and Enumerations
Errorstry, and inside it catch (var e)Errors and exceptions

The rules that are forgotten most often:

  • The whole condition goes inside parentheses in if, elsif, while, until and switch.
  • if and elsif always take then. while and until take neither then nor do.
  • It is elsif, not elif nor else if. An else if opens a new if inside the else, which needs its own end. If it is missing, the compiler says so: “missing 'end' at the end of the 'else' block (check the 'else if' on line 4: in JARU it is 'elsif')”.
  • A short block fits on one line: if (lives == 0) then println("Game over") end.
var lives = 2
var seconds = 30

if (lives > 0 and seconds > 0) then
println("Keep playing")
elsif (lives > 0) then
println("Time is up")
else
println("Game over")
end

These three do not compile:

var lives = 2
if lives > 0 then // the parentheses are missing
println("Keep playing")
end
var lives = 2
var seconds = 30
if (lives > 0) and (seconds > 0) then // the condition ends at the first )
println("Keep playing")
end
var level = 2
if (level == 1) then
println("Easy")
elif (level == 2) then // it is elsif
println("Normal")
end

Literals​

This is how each value is written directly in the code:

ValueExamplesHow it is written
Integer42, -7, 0x1F, 0xffIn decimal, or in hexadecimal with 0x in front
Decimal3.14, .5, 1e3, 2.5e-2With a point or with an exponent
String"hello", 'hello'Between double or single quotes
Booleantrue, false, on, offon is true, and off is false
No valuenil
List, map and array[1, 2], {"x": 1}, {1, 2}See Lists, maps and arrays
println(0x1F)          // 31
println(0xff) // 255
println(1e3) // 1000
println(on == true) // true

In hexadecimal, the letters work in upper and lower case. A number with an exponent is always a decimal, even though println writes 1000. The range of integers, what happens with a number that doesn't fit in 32 bits and hexadecimals above 0x7FFFFFFF are in Data types.

Strings​

A string ends with the same quote it starts with, so the other kind can go inside: 'She said "hi"', "It's". The backslash \ starts an escape: \n (line break), \r, \t and \\ (a backslash).

  • \" is not an escape. The string does not end there, but the backslash stays inside: "she said \"hi\"" prints she said \"hi\". To put double quotes in a string, write the string between single quotes.
  • Careful with Windows paths: "C:\new" contains a line break. Write "C:\\new".
  • A string does not end at the end of the line. If you forget to close it, it carries on in the lines below, and the error, “String without terminating quotation mark”, appears further down than where the quote is missing.
  • Accented letters are fine inside strings, but not in names.

What each escape puts in the string and how to write a string over several lines is in Writing strings.

Operator precedence​

When an expression has several operators, the ones in the upper rows are calculated first. Those in the same row are calculated from left to right, except ? : and the assignments, which go from right to left.

OperatorsWhat they are
1a.b, a[i], f(x)Property or method, index and call
2-x, +x, not x, !x, ~x, ++x, --x, x++, x--Single-value operators
3*, /, %, div, modMultiplication and division
4+, -Addition and subtraction
5<<, >>Bit shifts
6&, |, ^Bitwise
7<, <=, >, >=Comparison
8==, !=Equality
9and, orLogical
10? :Conditional
11=, +=, -=, *=, /=, %=Assignment

Three things are different from other languages:

println(not 1 == 2)                  // false: it is (not 1) == 2
println(not (1 == 2)) // true
println(6 & 3 == 2) // true: it is (6 & 3) == 2
println(4 | 1 & 2) // 0: it is (4 | 1) & 2
println(true or false and false) // false: it is (true or false) and false
println(true or (false and false)) // true
  • not and ! are calculated before comparisons. To negate a comparison, put it in parentheses.
  • The bitwise operators go before comparisons, the other way round from C, and &, | and ^ have the same precedence.
  • and and or also have the same precedence:
and and or have the same precedence

In most languages, and is calculated before or. Not in JARU: they are calculated from left to right, so a or b and c is (a or b) and c. When you mix and and or, use parentheses.

Pitfalls​

All the known issues of JARU, together, are in Known issues.

String + number​

+ joins two strings, but not a string and a number. "Lives: " + lives compiles, but the program stops when it reaches that line, with the error “Unsupported operand types for operator '+'.”. Convert the number first with toString(), as in "Lives: " + lives.toString(), or pass the parts to println separately: println("Lives: ", lives). Joining strings explains it.

.. is not a JARU operator: the compiler gives the error “Operator '..' doesn't exist in JARU. Use '+' to join strings.”.

var lives = 3
println("Lives: " .. lives)

Methods on a literal or on parentheses​

A method goes after a variable, an element or a property: name.size(), list[0].toString(), player.lives.toString(). After a literal or after parentheses it does not compile, with the error “Expected identifier in method name.”:

println("hello".size())
var a = 2
var b = 3
println((a + b).toString())

Store the value in a variable first:

var greeting = "hello"
println(greeting.size()) // 5

var a = 2
var b = 3
var sum = a + b
println(sum.toString()) // 5

With a number it is worse: in 5.toString(), the compiler reads 5. as the decimal 5.0, and toString() as another statement. A line like var s = 5.toString() compiles, and the program stops with “Undefined variable 'toString'.”.

Indexing what a call returns​

f(x)[0] compiles, but it does not index what f returns: the program stops with the error “This object type is not indexable.”. With a method it is worse: map.keys()[0] makes the compiler close without explaining the error, and list.copy()[0] stops the program with an error that makes no sense (“List has no property ''.”). Store the result in a variable first:

func ends(list)
return [list[0], list[list.size() - 1]]
end

var numbers = [4, 8, 15]
// println(ends(numbers)[0]) <- stops when it runs
var e = ends(numbers)
println(e[0], " ", e[1]) // 4 15