Statements
This section briefly discusses FunC statements, constituting the code of ordinary function bodies.
Expression statements
The most common type of a statement is the expression statement. It's an expression followed by ;
. Expression's description would be quite complicated, so only a sketch is presented here. As a rule all sub-expressions are computed left to right with one exception of asm stack rearrangement which may define order manually.
Variable declaration
It is not possible to declare a local variable without defining its initial value.
Here are some examples of variables declarations:
int x = 2;
var x = 2;
(int, int) p = (1, 2);
(int, var) p = (1, 2);
(int, int, int) (x, y, z) = (1, 2, 3);
(int x, int y, int z) = (1, 2, 3);
var (x, y, z) = (1, 2, 3);
(int x = 1, int y = 2, int z = 3);
[int, int, int] [x, y, z] = [1, 2, 3];
[int x, int y, int z] = [1, 2, 3];
var [x, y, z] = [1, 2, 3];
Variable can be "redeclared" in the same scope. For example, this is a correct code:
int x = 2;
int y = x + 1;
int x = 3;
In fact, the second occurrence of int x
is not a declaration, but just a compile-time insurance that x
has type int
. So the third line is essentially equivalent to a simple assignment x = 3;
.
In nested scopes, a variable can be truly redeclared just like in the C language. For example, consider the code:
int x = 0;
int i = 0;
while (i < 10) {
(int, int) x = (i, i + 1);
;; here x is a variable of type (int, int)
i += 1;
}
;; here x is a (different) variable of type int
But as mentioned in the global variables section, a global variable cannot be redeclared.
Note that a variable declaration is an expression statement, so actually constructions like int x = 2
are full-fledged expressions. For example, this is a correct code:
int y = (int x = 3) + 1;
It is a declaration of two variables x
and y
equal to 3
and 4
correspondingly.
Underscore
Underscore _
is used when a value is not needed. For example, suppose a function foo
has type int -> (int, int, int)
. We can get the first returned value and ignore the second and third like this:
(int fst, _, _) = foo(42);
Function application
A call of a function looks like as such in a conventional language. The arguments of the function call are listed after the function name, separated by commas.
;; suppose foo has type (int, int, int) -> int
int x = foo(1, 2, 3);
But notice that foo
is actually a function of one argument of type (int, int, int)
. To see the difference, suppose bar
is a function of type int -> (int, int, int)
. Unlike in conventional languages, you can compose the functions like that:
int x = foo(bar(42));
instead of the similar but longer form:
(int a, int b, int c) = bar(42);
int x = foo(a, b, c);
Also Haskell-style calls are possible, but not always (to be fixed later):
;; suppose foo has type int -> int -> int -> int
;; i.e. it's carried
(int a, int b, int c) = (1, 2, 3);
int x = foo a b c; ;; ok
;; int y = foo 1 2 3; wouldn't compile
int y = foo (1) (2) (3); ;; ok