Statements



Statements are separated into two groups: operations and control flow. Operations are assignments and procedure calls. Control flow includes if, each and while statements. Statements can be grouped into statemenet block using do and end. Statement block is treated like a single statement.

do
    a := a + 1;
    b := b + 1;
end;

Each statement inside statement block must be ended with ;. Statement block without statements inside is empty statement block and does nothing. Also some statements can have their own inner variables. These variables are accessible only inside their statements, but are declared in function scope so their names should not conflict with local variables.

Expressions

Expressions in Jarog represents relations between constants, variables and values, declared using math operations.

Operations

To express relations between variables and constants Jarog has unary and binary operations. Unary operations have the highest priority.

Symbol Operand types Description
- int, float Minus
! bool Logical Not
@ list, set List length or set power

Binary operations have different priority. Jarog supports next operations given in order by their priority. Higher operations have higher priority.

Symbol Operand types Description
^ int, float Power
* int, float, set Multiplication
/ int, float, set Division
% int, float Modulo
+ int, float, set Addition
- int, float Subtraction
: int Range
= any type Equals
<> any type Not equals
> int, float, set Is greater
< int, float, set Is less
>= int, float Is greater or equal
<= int, float Is less or equal
& bool Logical And
| bool Logical Or

Procedure call

Procedures are functions, that return no results, procedures unlike functions can be called instantly.

const proc := $() do
     # do smth here
end;

...
proc();

Functions and any other expressions can not be called instantly cause they all have results, which must be assigned to some variable (or logged). On the other hand procedures can not be used in expressions or logged.

log proc();           # will cause an error

Assignment

Assignment calculates expression result and assigns it to a variable. Unlike the most of languages Jarog uses symbol := to assign values.

<var1> := <expr1>;

Also there is a way to assign multiple values at once.

var a, b, c: int;
...
{a, b} := {0, 1};
{a, b} := {b, a};          # swap values
[a, b] := [0, 1];          # lists are fine too
[{a, b}, c] := [{1, 2}, 3] # even combined values

Structures and lists are automatically destructed into tuple of variables and tuple of values can be composed into a struct and assigned to it as a single value. For better understanding see Structs and Lists

If statement

If statement has next syntax structure:

if (<expression>) 
    <statement1>
else
    <statement2>;

Expression must be bool, first branch is executed if expression results true otherwise second branch is executed.

Second branch is optional.

if (<expression>) do
    <statement1>;
    <statement2>;
    ...
end;

While statement

While statement is the generic way to declare loops in Jarog. Expression must return boolean. Loop body is repeated while expression is true.

while (<expression>)
    <statement1>;

Break and Continue

Like the most other languages, Jarog has break and continue statements, used to interrupt loop execution. break stops loop execution and continue stops current iteration of the loop and moves to next one.

while (true) do
    n := n + 1;
    if (n > 10)
        break;
end;

Each statement

Each statement is a special loop construction designed to walk through list or set. Example of declaration is next:

each (<list> -> <var>: <type>)
    <statement>;

It accepts two arguments - <list> and <var>. <var> is inner variable, it is declared and accessible only inside each statements. <type> must be compatible with <list> item type. Loop is executed as many times as many items <list> contains. Each time next item of list is assigned to <var>. <var> is writable inside loop but this doesn’t affects <list> items. Also list items can be changed during loop execution but it wouldn’t take any effect on loop execution as it uses a copy of <list> during all iterations. Loop execution can be interrupted with break and continue statements. After loop ends item preserves it’s value assigned to it during the last iteration. Example:

each([1, 2, 3] -> n: int)
    log n;                    

There is alternative form of each when no variable is declared.

each (<list> -> <expression>)
    <statement>;

<expression> must be assignable to use it inside each. In this case after the last iteration last value of expression is preserved outside of each. For example this code will print 1 is one, 2 is two, 3 is three,:

var n: int;
var s: string;
...
each([{1, "one"}, {2, "two"}, {3, "three"}] -> {n, s})
    io::put(str::fmt("%d is %s, ", [n, s]));

With statement

With statement syntax is displayed below:

with (<expression> -> <var>: <type>)
    <statement>;

This statement declartes a variable visible in next statement only similar to each statement. See more in statement variables

Exception handling

Exceptions can be handled with next syntax construction:

try
    <statement>
catch(<var>: <type>)
    <catch statement>;

Variable <var> shouldn’t be declared in function scope as it is inner variable. There is no special type Exception to be thrown in Jarog. Value of any type can be thrown. Standard exceptions throw string.

Here is some examples for better understanding.

var f: float;
try
    f := f / 0      # division by zero throws string
catch(e: string)    # which can be caught here
    io::print(e);

There is also an ability to use try with multiple catches and throw own exceptions.

try
    throw 5         # int exception is thrown
catch(e1: string)
    io::print(e1)   # this catch will be ignored
catch(e2: int) do
    if (e2 = 5)
      io::put("Error 5")
    else
      io::put("Unknown error");
end;

When the exception is thrown interpreter searches first catch clause, which has compatible type and executes it. If no suitable catch clauses found, exception is thrown again. Also if there is two or more clauses with compatible types, only first one is executed. Never move catch with int type below catch with float, otherwise float will eat all int exceptions.

try
   throw 5                  # int exception is thrown
catch(e1: float)            # int can be assigned to float
   io::put("float error")   # so this will be called
catch(e2: int)                  
   io::put("int error");    # is never called

Catch section can has no variables at all. In this case it will catch all exceptions, but it will have no information about it.

try
   throw "I'm exception!"
catch
   io::put("Some terrible exception happened but we don't know which :(");

Exception handling does not support finally section. Instead of this Jarog has binded functions.

Try Finally

Instead of catch try statement can have finally section. This statement is executed always, even if exception is thrown inside or return statement is called. It does not eats exception so it can be used inside try-catch statement.

Log

Log prints expression value to stdout. It can be used for debug purposes. It accepts expressions with any result types. Expression is executed and it’s result is printed to console.

log "Hello, world!"; 

Run

Run accepts procedure. It calls the procedure and runs in a new thread. When the procedure is executed thread is terminated.

const proc := $() do
     # do smth here
end;

run proc();     

Threads can interact with other threads and share data among them using global variables, closures or pipes, but accessing a global variable or closure without synchronization can cause undefined behavior and data corruption.

Sync

Sync statements wraps an instruction into critical section and ensures that only one thread at a time can execute it. Sync can have a name - string variable. If there are few blocks with the same name, only one of them can be executed at a time. Name is optional.

sync("<name>") do
    <statement>;
    ...
end;

Sync blocks help to prevent data corruption on multiple thread access to a single variable.