Statements denote actions. There are simple and
compound statements. Simple statements do not consist of any
parts that are statements themselves. They are the assignment,
procedure call, return, break, continue, throw, and the wait
statements. Analogous to the language C the last symbol of a Dino
simple statement is semicolon ;
. Compound statements
consists of parts that are statements themselves. They are used to
express sequencing, exception handling, conditional, and repetitive
execution.
There is an empty statement in Dino. It denotes no action. The empty statement is included in Dino for convenience.
ExecutiveStmt = ";"
Example: Usage of an empty statement in a for-statement:
for (i = 0; a[i] == 0; i++)
;
A block-statement is simply a block and can used to group statements into one statement and/or describe local declarations. For details on how the block is executed see the section Declaration and Scope Rules.
ExecutiveStmt = BlockStmt
BlockStmt = Block
Example: Usage of a block-statement in a for-statement:
sum = 0;
for (i = 0; i < #a; i++)
{
var value = a[i];
if (value > 0)
sum += value;
}
Dino has an expression statement. Although it seems that the expression value is not used, the expression evaluation can results in side-effects, e.g. through calling a function/class. An expression-statement as textually the last statement in the function block means a return of the expression value as the function call result. In REPL (see Appendix B. Implementation), execution of an expression-statement results in printing the expression value.
ExecutiveStmt = Expr ";"
Examples:
putln ("percent=" @ percent @ "%");
newfiber ();
5 + 10;
Assignment-statements are used to change variable values or element
values of a structured value which are referred through a designator
(see sub-section Designator in section Expressions.
The designator can not denote a final variable (see the section
Variable Declaration). You can not change the element value
of an immutable value (see the section Types and Values). In
this case the exception immutable
is generated. Assignment
to a table element has a side effect, the element key becomes
immutable.
A simple assignment statement looks like Designator = Expr;
.
That means that the expression value is assigned to a variable or
element of a structured type value denoted by the designator. For the
convenience of C programmers there are also the Dino assignments
Designator op= Expr;
, Designator++;
,
++Designator;
, Designator--;
, and
--Designator;
. They are analogous correspondingly to
Designator = Designator op Expr;
, Designator = Designator
+ 1;
, and Designator = Designator - 1;
. The only
difference is in the fact that the designator is evaluated only once,
not twice as in the analogous form. It is important to know if you
have side effects in the statement.
ExecutiveStmt = Designator Assign Expr ";"
| Designator ("++" | "--") ";"
| ("++" | "--") Designator ";"
Assign = "="
| "*="
| "/="
| "%="
| "+="
| "-="
| "@="
| "<<="
| ">>="
| ">>>="
| "&="
| "^="
| "|="
Examples:
v = [10, 20];
i = 1;
i++;
--i;
i *= 20;
If the designator is a slice and the expression value is a slice too,
they both should have the same form, otherwise the
exception sliceform
is generated. In this case each element
referenced by the designator slice gets value of the corresponding
element referenced by the expression slice. If the designator is a
slice but the expression value is not, each element referenced by the
designator slice gets the expression value. Examples of the slice
assignment:
v = [1, 2, 3, 4];
v[:] += 1;
v[::-1] = v[:]; // reverse v
The Dino if-statement is analogous to the C language one. First, the
expression after if
is evaluated and an arithmetic conversion
is done to it. The value should be an integer, a long integer, or a
floating-point number, otherwise the exception optype
is
generated. If the value is nonzero the first statement is executed,
otherwise the statement after else
is executed (if any). The
problem with dangling else is resolved analogous to the
language C -- else
part is associated with the
closest if
.
ExecutiveStmt = if "(" Expr ")" Stmt [ else Stmt ]
Examples:
if (i < 0) i = 0;
if (i < j) return -1; else if (i > 0) return 1; else return 0;
The Dino for-statement is analogous to the C language one. The statement is executed in the following way.
optype
is generated.break
in the body. The rest body
execution can be skipped by an execution of the
statement continue
. In this case, the for-statement
execution continues with the step 4.
ExecutiveStmt = for "(" Stmt ForGuardExpr ";" Stmt ")" Stmt
ForGuardExpr = [Expr]
Examples:
for (i = 0; i < 10; i++;) sum += v [i];
for (i = 0; i < 10; i++) sum += v [i];
for ({sum = 0; i = 0;} i < 10; i++) sum += v [i];
This statement is used to execution of the foreach-statement body (the
statement) for all keys of table which is a value of the expression.
The expression value should be a table. If this is not true, the
exception keyop
is generated. The current key value on each
iteration is assigned to the designator. The order in which the key
values are assigned on each iteration is undefined. One iteration can
be finished with the aid of the statement continue
and a
foreach-statement can be finished by execution of statement
break
.
ExecutiveStmt = for "(" Designator in Expr ")" Stmt
Examples:
putln ("The table is");
for (k in t) {
put ("key=");
print (k);
put (", element=");
println (t{k});
}
There are two kinds of the match-statement. One is used for pattern
matching and another one is used for regular expression matching.
They have practically the same syntax. They differ in usage of
different start keywords pmatch
and rmatch
correspondingly for the pattern and regular expression matching.
The pattern or regular expression match statement is used to try matching the match-expression value (it is evaluated only once) and the patterns or regular expressions in given order and execute the statements corresponding to the first matched case.
Each case forms an own scope. The pattern variables in the pattern
match statement are declared in the corresponding case scope. Each
case scope of the regular expression match statement contains an
implicitly declared variable m
. If a regular expression in
the case successfully matches the match-expression, value of the
corresponding variable m
is a vector of indexes describing
matched substrings (see the result of function match
for
details).
In the case of regular expression matching the string conversion is
implicitly applied to the match-expression and the case expression
values. The exception optype
occurs if the conversion
results are not strings. A case with wildcard _
also can
occur in a rmatch-statement. Matching with such case is always
successful but the value of the variable m
is undefined in
this case.
Execution of a continue-statement in the case-statements results in continuing the process of matching the match-expression value with the subsequent patterns or regular expressions. Execution of a break-statement in the case-statements results in finishing the match-statement execution. There is an implicit break at the end of each case statement list.
If an optional case condition is given, then it is evaluated after the
succesfull matching with the corresponding pattern and an arithmetic
conversion is done to it. The value should be an integer, a long
integer, or a floating-point number, otherwise the
exception optype
is generated. If the value is nonzero the
all match is considered successfull, otherwise the subsequent case
patterns are tried.
ExecutiveStmt = (pmatch | rmatch) "(" Expr ")" "{" CaseList "}"
CaseList = { case Pattern [CaseCond] ":" StmtList }
CaseCond = if Expr
Examples:
class c (a1, a2) {}
pmatch (c (2, 3)) {
case c (i, j): putln (i, j);
case _: putln ("default");
}
pmatch (c (2, 3)) {
case c (i, j) if i == j: putln ("eq=", i, j);
case c (i, j) if i != j: putln ("neq=", i, j);
case _: putln ("default");
}
rmatch (str) {
case "[a-zA-Z]+": putln ("word starting at ", m[0]);
case "[0-9]+": putln ("number starting at ", m[0]);
case _: putln ("anything else, m is undefined");
}
The statements break
and continue
are used
correspondingly to finish execution of the closest-containing for-,
foreach-, or match-statement covering the statement and to finish one
iteration of the body of the for- or foreach-statement and to continue
trying subsequent cases for the match-statement. These statement can
be used only inside a for-, foreach-, or match-statement.
ExecutiveStmt = break ";"
| continue ";"
Examples:
for (i = 0; i < 10; i++) {
if (ind [i] < 0)
continue;
val = v [ind[i]];
}
for (i in t)
if (t{i} == elval)
break;
match (tree) {
case leaf (n):
putln ("leaf");
if (n == 10) continue;
case node (n1, n2):
if (n1 != n2) break;
putln ("special node");
case _: putln ("might be a leaf with 10");
}
A return-statement is used to finish execution of a function, a fiber, or class block. The statement corresponds to the closest-containing function, fiber, or class covering the statement, so the return-statement can be placed only in a function, a fiber, or a class. The expression in a return-statement can be given only for functions. In this case, the expression value will be the value of the function call (instead of undefined value).
ExecutiveStmt = return [ Expr ] ";"
Examples:
return;
return [10, 2:0]
This statement generates an exception which is given by value of the
expression. The expression should evaluate to an object of
predeclared class except
or of its sub-class. If this is not
true, the exception optype
is generated. How exceptions are
processed is described in the following section.
ExecutiveStmt = throw Expr ";"
Examples:
class myexcept (msg) {use error former msg;}
throw myexcept ("this is an user defined exception");
Exceptions can be generated by the Dino interpreter when some
conditions are not satisfied, by predeclared Dino functions, by other
OS processes, by user interruptions, or by the user with the aid of a
throw-statement. Actually, the exceptions are represented by an
object of the predeclared class except
or by an object of its
sub-class. All predeclared exceptions are described in the
section Predeclared Identifiers. To detect and process
exceptions, a try-block can be used.
When an exception is generated, the closest-containing try-block which
is covering the statement generating the exception or currently being
executed (when this is is generated by an OS process or by an user
interruption) is searched for. Then, expressions in the catch list
elements are processed. The expression value in the catch list
element being currently processed should be the predeclared class
except
or its sub-class. If the expression being processed
is a class and the exception is an object of the class or an object of
a sub-class of the class, the block corresponding to the given catch
list element is executed. If there is no such catch expression, the
closest-containing try-block covering the current try-block is
searched for and processing the exception is repeated. If there are
no more try-blocks, the program finishes with a diagnostic message
which is dependent on the generated exception.
Blocks corresponding to catch list elements have a predeclared
variable e
. When the block execution starts, the variable
contains the object representing the exception.
ExecutiveStmt = TryBlockStmt
TryBlockStmt = try Block { Catch }
Catch = catch "(" ExceptClassList ")" Block
ExceptClassList = Expr { "," Expr }
Examples:
try {
var ln;
for (;;)
ln = getln ();
} catch (eof) {
}
try {
var v = [];
v {1} = 0;
} catch (except) {
put ("catching and propagating exception"); println (class (e));
throw e;
}
This statement is used for the synchronization of different threads in
a Dino program. The expression can not contain a function, class, or
a fiber call. The thread in which the statement has been executed
waits until the expression value becomes nonzero. The expression
value (after an implicit arithmetic conversion) should be an integer,
a long integer, or a floating point number. Otherwise the
exception optype
is generated. When the expression value
becomes nonzero, the statement after the expression (it is called a
sync-statement) is executed without interruption by other threads. It
is used as a critical region for the thread synchronization. In a
critical region an execution of wait-statement is prohibited (it
results in generation of the exception syncwait
). Also fiber
calls inside a critical region result in generation of the
exception syncthreadcall
.
ExecutiveStmt = wait "(" Expr ")" Stmt
An example:
wait (!empty);
All C code between pairs of brackets %{
and %}
in
one Dino file is concatenated in the same order as they occur
in the file. The result code with some pre-appended C code providing
an interface to the Dino interpreter internal data representation is
compiled when the execution the first time achieves the
location of the first
%{
in the file. The result shared object is loaded and
external variables and functions are searched lately in the same order
as the shared objects are loaded.
ExecutiveStmt = C_CODE
If an error during the compilation or loading the shared object file
occurs, the exception compile
is generated.
An example:
%{
#include <math.h>
val_t isnan_p (int npars, val_t *vals) {
val_t val;
ER_node_t res = (ER_node_t) & val;
ER_SET_MODE (res, ER_NM_int);
ER_set_i (res, 0);
if (npars == 1
&& ER_NODE_MODE ((ER_node_t) vals) == ER_NM_float
&& isnan (ER_f ((ER_node_t) vals)))
ER_set_i (res, 1);
return val;
}
%}
extern isnan_p ();
putln (isnan_p (10.0));