Orb Programming Language

Reference: Base

This section documents definitions found in base.orb. To use these definitions, you need to import this file.

Due to how importing works, you may place import "base.orb"; at the start of your main Orb source file and not need to import it from any other file.

Declarations use the same syntax used in the reference for Orb special forms.

if cond<bool> then<block> [rest...]

Conditionally executes one of the provided blocks of instructions based on the conditions provided.

Conditions and bodies are consecutive pairs of arguments. Optionally, the last argument may be unpaired, in which case it represents the fallback block to execute if no condition is satisfied.

Will not process all condition nodes if a previous condition has been satisfied (short-circuiting).

    if cond0 {
        doThing0;
    } cond1 {
        doThing1;
    } {
        fallback;
    };

switch val targets body<block> [rest...]

Conditionally executes one of the provided blocks of instructions based on which target val is equal to.

Targets and bodies are consecutive pairs of arguments. Optionally, the last argument may be unpaired, in which case it represents the fallback block to execute if no target equals val.

Target nodes are raw values containing values to compare against.

Will not process target nodes if a target equal to val has already been found (short-circuiting).

    switch (x)
        (0 1) {
            doThing0;
        } (2 3 4) {
            doThing1;
        } {
            fallback;
        };

for init cond<bool> step body<block>

First, executes init. Then, repeatedly checks if cond is true and, if it is, executes instructions in body, then executes step; if cond is false, the instruction is finished.

    for (sym (i 0)) (< i n) (++ i) {
        doThing i;
    };

while cond<bool> body<block>

Repeatedly executes instructions in body as long as cond is true.

    while cond {
        doThing;
    };

repeat body<block>

Repeatedly executes instructions in body.

    repeat {
        doThing;

        if cond {
            break;
        };
    };

repeat n<integer> body<block>

Executes instructions in body the number of times given by n.

If n is negative, will result in undefined behaviour.

    repeat 5 {
        doThing;
    };

range i<id> up<integer> body<block>

Declares a symbol with the name i. Repeatedly executes instructions in body while iterating values of i from zero to one less than up.

If up is not positive, will result in undefined behaviour.

    # 0, 1, 2, ..., 9
    range i 10 {
        doThing i;
    };

range i<id> lo<integer> hi<integer> body<block>

Declares a symbol with the name i. Repeatedly executes instructions in body while iterating values of i from lo to hi.

If lo is greater than hi, will result in undefined behaviour.

    # 5, 6, 7, 8, 9, 10
    range i 5 10 {
        doThing i;
    };

range i<id> lo<integer> hi<integer> delta<integer> body<block>

Declares a symbol with the name i. Repeatedly executes instructions in body while iterating values of i from lo to hi, but increasing by delta after each iteration.

If lo is greater than hi, will result in undefined behaviour.

    # 5, 8
    range i 5 10 3 {
        doThing i;
    };

rangeRev i<id> up<integer> body<block>

Declares a symbol with the name i. Repeatedly executes instructions in body while iterating values of i from one less than up down to zero.

If up is not positive, will result in undefined behaviour.

    # 9, 8, 7, ..., 0
    rangeRev i 10 {
        doThing i;
    };

rangeRev i<id> hi<integer> lo<integer> body<block>

Declares a symbol with the name i. Repeatedly executes instructions in body while iterating values of i from hi down to lo.

If lo is greater than hi, will result in undefined behaviour.

    # 10, 9, 8, 7, 6, 5
    rangeRev i 10 5 {
        doThing i;
    };

rangeRev i<id> hi<integer> lo<integer> delta<integer> body<block>

Declares a symbol with the name i. Repeatedly executes instructions in body while iterating values of i from hi down to lo, but decreasing by delta after each iteration.

If lo is greater than hi, will result in undefined behaviour.

    # 10, 7
    rangeRev i 10 5 3 {
        doThing i;
    };

break

Prematurely ends a for, while, repeat, range, or rangeRev loop.

continue

Prematurely ends the current iteration of a for, while, repeat, range, or rangeRev loop.


++ val<integer>

Increases the value of val by one and returns it.

    ++ i;

-- val<integer>

Decreases the value of val by one and returns it.

    -- i;

+= val by

-= val by

*= val by

/= val by

%= val by

>>= val by

<<= val by

&= val by

|= val by

^= val by

Assigns a new value to val based on the calculation with val and by as operands and returns val.

    += x k;

    <<= n 1;

&& val0<bool> val<bool>... -> bool

Calculates the logical conjunction on arguments (AND operator), with short-circuiting.

Iteratively going through the arguments, if any are false, finishes the instruction and returns false. Otherwise, returns true.

    if (&& b0 b1 b2) {
        doThing;
    };

|| val0<bool> val<bool>... -> bool

Calculates the logical disjunction on arguments (OR operator), with short-circuiting.

Iteratively going through the arguments, if any are true, finishes the instruction and returns true. Otherwise, returns false.

    if (|| b0 b1 b2) {
        doThing;
    };

-> val m...

Dereferences val and performs [] on the result with m as the index. Then, repeats this for the previous result and the next argument, until all arguments have been used.

    sym x:(Person *);
    # = x ...;

    std.println (-> x name);

alias name<id> ty<type>

Makes name refer to ty.

    alias myArray (i32 4);

String

Alias for the type of string literals.

arr ty<type> val...

Constructs an array of ty. The length of the array is equal to the number of arguments in val....

Each value in val... is implicitly cast to ty and copied to the array.

    sym (array (arr i32 10 11 12 13 14 15));

tup val...

Constructs a tuple with the given values as elements.

    sym (tuple (tup 100.0 true));

make ty<type> pair...

Constructs a value of data type ty and assigns its elements depending on the provided pairs.

ty must be a data type. Each pair must be a raw of two elements - an element name and value.

For each pair, the element in the data type under that name will be assigned with the given value.

    make Person (name 'Alice') (age 32);

lam body -> function

lam retTy body -> function

lam args retTy body -> function

Defines and returns a function.

If args is given, it will be used to define the arguments of the function. Otherwise, the function will take no arguments.

If retTy is given, it will be used to define the return type of the function. Otherwise, the function will not be a returning function.

body will be used as the body of the function.

    lam { std.println; };

    lam i32 { ret (* 2 (std.scanI32)); };

    lam (x:i32) i32 { ret (* x x); };

pat body -> macro

pat args body -> macro

Defines and returns a macro.

If args is given, it will be used to define the arguments of the macro. Otherwise, the macro will take no arguments.

body will be used as the body of the macro.

    pat { ret \(block {}); };

    pat (a) { ret \(sym ,a:i32); };

enum name<id> vals

enum name<id> ty<type> vals

Defines an explicit type (an enum type) and creates values of that type.

If ty is provided it will be used as the base type. Otherwise, the base type will be i32.

vals is a list of symbols of this type to define. Each entry must be either an id or a pair of id and a value. The created symbol will use that id for its name. If the value is provided, it will be cast to ty and used to initialize that symbol.

If the value is not provided, and this is the first entry, its value will be zero. Default values of entries past the first are one more than the value of the previous entry.

Each symbol will be declared constant.

enum CoinSide {
    Head
    Tails
};

fnc flipCoin () CoinSide {
    if (< (myRandGen) 0.5) {
        ret CoinSide.Head;
    };
    ret CoinSide.Tails;
};

enum HttpStatus u32 {
    (Ok 200)
    Created
    Accepted
    (BadRequest 400)
    Unauthorized
    PaymentRequired
    Forbidden
    NotFound
    (InternalError 500)
};

base.getEnumSize ty<type> -> unsigned

Returns the number of enum entries (initially created symbols of the ty, created by enum).

    base.getEnumSize CoinSide; # 2

genId -> id

Generates and returns an id. Returns a different value on each call.

    eval (sym (s:id (genId)));

cond<bool> onTrue onFalse

Conditionally processes either the onTrue or onFalse node depending on the value of cond.

cond must be an evaluated value.

    cond verbose
        (std.println "index=" ind " value=" ([] array ind))
        (std.println ([] array ind));

cond<bool> onTrue

Only processes the onTrue node if cond is true.

cond must be an evaluated value.

    cond enableDebugAsserts
        (if (< ind 0) { exit 1; });

passthrough node

Returns node (ie. the node is processed).

This has a very fringe use-case which may appear when writing a macro that returns a special form that escapes one of its id arguments.

process node

Does an extra processesing of the result of the node node.

escape node

Escapes node.

This is useful when a macro needs to return a value and tell its invoker to escape it.

unref val

Returns val as a non-ref value.

base.isOfType val ty<type> -> bool

Returns whether val is of type ty or ty cn.

val must be a typed value.

base.isRaw val -> bool

Returns whether val is of type raw or raw cn.

val must be a typed value.

base.isEmptyRaw val -> bool

Returns whether val is an empty raw value (ie. ()).

val must be a typed value.

base.assertIsOfType val ty<type>

Raises an error if val is not of type ty or ty cn.

base.makeRawWith val... -> raw

Creates a raw with arguments as its elements.

This is different from building a raw by escaping a node, since here the arguments will not be escaped.