O Language

O Language syntax

Declarations, expressions, blocks and collection syntax accepted by the current interpreter parser.

O Language pagesLanguage basics
On this page

This guide describes the interpreter grammar at revision eb2301c. It does not imply that the bytecode VM or ELF compiler accepts every parsed form; compare execution paths.

Names and values

Use def for a binding. The parser does not use bare assignment as a declaration.

def project = "OnixOS"
def editionCount = 6
def enabled = true
def ratio = float 3.14

The ordinary literal forms are integers, strings and booleans. A float uses the float keyword followed by an integer, a dot and another integer. The source scanner does not implement quoted-string escaping, so examples should not rely on escaped quote sequences. Strings do not have interpolation; + joins two strings.

Operators

Form Supported behavior
+, -, *, / Arithmetic on matching integer types or matching float types. String + concatenates.
==, != Equality and inequality.
<, >, <=, >= Comparisons for matching numeric types.
!, unary - Boolean negation and numeric negation.
function(…) Function call.
value[index] Array index or hash lookup.

Logical && and ||, modulo, compound assignments such as +=, and dot-property access are not registered as normal infix expressions in this parser. Indentation and trailing-colon blocks are not part of the grammar. A # token ends lexing for the rest of the input; it is not a usable line or inline comment.

Although != is registered, the current string evaluator handles string == separately and returns false for other string infix operators. Do not use string != as a reliable comparison in this revision.

Functions and conditions

Function literals use fn, and blocks use braces:

def add = fn(left, right) {
    return left + right
}

output("sum: " + itostr(add(5, 3)))

Conditions require parentheses and a brace-delimited body:

def edition = "KDE"

if (edition == "KDE") {
    output("This profile uses the Calamares installer.")
} else {
    output("Check the selected profile documentation.")
}

Arrays and hashes

Arrays use square brackets. Hash entries use a colon between the key and value. The interpreter supports string, integer and boolean hash keys.

def profiles = ["Core", "KDE", "GNOME"]
def release = {"name": "OnixOS", "base": "Arch Linux"}

output(profiles[0])
output(release["base"])

An array index outside its range and a missing hash key evaluate to NULL. Hash keys of unsupported runtime types produce an error.

Iteration

For array iteration, the first name after in receives the index and the second receives the value. Hash iteration binds the actual key and value:

def profiles = ["Core", "KDE", "GNOME"]

for (profiles in index, profile) {
    output(itostr(index) + ": " + profile)
}

The bindings are written into the current environment; the loop does not create a block-local scope. The parser also accepts while and loop forms. Prefer the examples in this guide and the versioned source for less common loop behavior.

Loading another file

load parses a file from the process working directory and evaluates its statements in the current environment:

load "lib/settings.ola"

The path is resolved from the working directory, not automatically from the directory containing the importing source file. A missing or unreadable file currently produces no parser diagnostic. This form is used by the runtime’s library and web-project layouts.

Parser forms that need source review

The parser recognizes additional forms including scope, set, env, proc, sock, route, signal, begin/except/recover/final, async/wait and eval. Their behavior is uneven between the interpreter and compiler paths. Use the runtime API reference for documented built-ins and check the parser and evaluator before depending on one.