– Typee Documentation –
3 – Typee Language Description
3.5 – Compound Statements
Let’s first explain what are the different categories of statements in Typee.
<typee statement> ::= <compound statement> | <empty statement> | <simple statement> | <statements block>
We first describe here the specification of compound statements, i.e. statements that are composed of many keywords.
Here is the formal EBNF specification of compound statements in Typee:
<compound statement> ::= <assign decl def func-call statement> | <embed statement> | <exclude statement> | <for statement> | <forever statement> | <if statement> | <repeat statement> | <switch statement> | <try statement> | <while statement> | <with statement>
We explain each of them in next sub-sections, classic statements first, specific to Typee ones then and finally the assignment, declaration, definition and function call statements which are specified the most voluminous rules of Typee grammar.
3.5.1 for statement
The for
statement creates an iteration over a list of typed items and processes its first block of statements for each of the items contained in the list. A second block of statements may be defined after a specific keyword, otherwise
.
Python programmers: caution! Keyword otherwise
in Typee does NOT behave as keyword else
after for
in Python – see explanations below.
Formal EBNF specification is provided below in a simplified form to be easier to understand
<for statement> ::= 'for' '(' <typed targets list> 'in' <indexed iterables list> ')' <statements block> ['otherwise' <statements block>] <typed targets list> ::= <typed target> (',' <typed target>)* <typed target> ::= <type> <dotted name> (<subscription or slicing>)* <indexed iterables list> ::= 'indexed' '(' <iterables list> ')' | <iterables list> <iterables list> ::= <iterable expression> ( ',' <iterable expression> )* <iterable expression>::= <container or iterable object>
The expression following keyword in
has to be iterable. This means that it should be a container or an instance of an interable class – more about iterable classes later in this documentation.
A specific keyword, indexed
, is used to get an integer index associated with the iterated returned value from the container or from the iterable object. Python programmers will understand this as keyword enumerated
in their favorite programming language. See example for illustration below:
for( uint8 index, uint8 val in indexed [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] ) print( index, val ); // prints: // 0 1 // 1 2 // 2 3 // 3 5 // 4 8 // 5 13 // 6 21 // 7 34 // 8 55 // 9 89 // did you recognize a part of the Fibonacci suite?
If no item is finally processed, the block of statements after keyword otherwise
is processed.
If at least one item has been processed by the ‘for’ block of statements, the ‘otherwise’ block of statements is not processed.
Python programmers, CAUTION: this is not the behavior of controversial keyword else
in Python when associated with for
.
Three flow keywords can be used within the block of statements of for
: break
, continue
and return
.
break
immediately stops the processing within the statements block of for
and exits from it. If an otherwise
statements block is present, it is not processed too.
continue
skips the processing of the statements below it into the for
statements block and processing gets back to the start of this block, for a next iteration within the for
loop.
return
may be used when the loop is present in the statements block of a function or of a method. The loop processing stops then immediately and control is given back to the caller of the function or method.
3.5.2 forever statement
The forever
keyword implements infinite loops. While this may sound strange, it avoids programming things like while(true)
and there are ways to exit such loops (i.e. break
and return
).
The formal EBNF specification is:
<forever statement> ::= 'forever' '(' ')' <statements block>
Notice: there is no otherwise
alternative associated with forever
loops.
Typee translators verify the presence of exiting keywords in infinite loops and raise a warning if none of them is detected within the block of statements.
Exiting keywords are break
, and return
when the the loop is within a function or a method body. They act exactly as for for
loops.
continue
may also be used in forever
loops and acts exactly as with for
loops.
3.5.3 if statement
Conditional branching in Typee is very classical. Its formal EBNF specification is:
<if statement> ::= 'if' <parenthesised expr> <statements block> <elseif statement> [<else statement>] <elseif statement> ::= ( <elseif> <parenthesised expr> <statements block> )* <else statement> ::= ('else' | 'otherwise') <statements block> <elseif> ::= 'elseif' | 'elsif' | 'elif' <parenthesised expr> ::= '(' <expression> ')'
The parenthesised expressions are conditional expressions. They return either true
or false
.
If the conditional expression after the if
evaluates to true
, the statements block of the if
is processed.
If this conditional expression evaluates to false
, the if
statements block is ignored and the first elseif
conditional expression is evaluated.
This process is repeated along the next elseif
clauses if present.
If none of the preceeding conditional expression evaluate to true
, the block of statements asociated with else
is processed, if present. A valid alternative to clause else
is clause otherwise
. This is unusual in usual programming languages, but it makes sense and consistency in Typee with the meaning of clauses otherwise
in other statements while
, for
, try
and switch
.
During this whole process, the first clause that evaluates to true
stops the processing. Its block of statements is processed and processing goes then straight to the first statement after the whole if
statement.
3.5.4 repeat statement
This type of loop first processes its statements block then evaluates a conditional expression and stops looping as soon as the conditional expression evaluates to true
.
This is its formal EBNF specification:
<repeat statement> ::= 'repeat' <statements block> 'until' <parenthesised expr> ';'
The parenthesised expression is a conditional expression. It evaluates to either true
or false
.
As for any type of loops, three flow keywords can be used within the block of statements of repeat
: break
, continue
and return
.
break
immediately stops the processing within the statements block of repeat
and exits from it.
continue
skips the processing of the statements below it into the repeat
statements block and processing gets back to the start of this block, for a next iteration within the repeat
loop.
return
may be used when the loop is present in the statements block of a function or of a method. The loop processing stops then immediately and control is given back to the caller of the function or method.
3.5.5 switch statement
The switch
statement in Typee does not act exactly as a traditional switch. Let’s explain this that way: a switch
statement in Typee evaluates an expression, checks it against values associated with case
s and runs the statements block associated with all the corresponding case
s this value appears in.
The formal EBNF specification for switch
is:
<switch statement> ::= 'switch' <parenthesised expr> '{' <switch block> '}' ['otherwise' <statements block>] <switch block> ::= (<case> [<switch block>])* <case> ::= 'case' <expr list> <statements block> <expr list> := <expression> ( ',' <expression> )*
Since a same value may appear in many case
clauses, many blocks of statements may be processed within the switch
statement. We do understand that this may lead to code that could be a little bit more difficult to read, but it surely will shorten the code also, factorizing it when possible.
When processing a switch
statement, the associated parenthesised expression is first evaluated. It gets a value which may be of any type. Each case
clause is checked then, searching for the evaluated value within the list of expressed values associated with it. The expressed values have not to be literals, as it may have to be with other programming languages. Every time the evaluated value of the swicth
expression matches with at least one of the expressed values of the case
clause, the block of statements corresponding to this clause is processed.
Notice: Typee switch
statement is not specified to finally optimize the processor generated binary code, while this is the case in C or C++ for instance. Nevertheless, Typee translators aim at optimizing the source code they generate for it to take as much as possible benefits from the final targeted programming language they are translating Typee code to.
3.5.6 try statement
Typee manages exceptions. Exceptions are faulty execution of code, such as division by 0 or out-of-bounds indexing, for instance. Typee uses a Python-like naming. C++ and Java programmers should nevertheless get no difficulty to understand and to use this concept.
The formal EBNF specification in Typee is this:
<try statement> ::= 'try' <statements block> <try except> <statements block> (<try except> <statements block>)* [<try otherwise> <statements block>] [<try finally> <statements block>] <try except> ::= 'except' '(' [ (<try except expr> | 'all' ) ] ')' <try except expr> ::= <expression> ['as' <identifier>] (',' <expression> ['as' <identifier>])* <try otherwise> ::= 'otherwise' <try finally> ::= 'finally'
The keyword try
tags a block of statements in which any raised exception will be caught. As soon as an exception is raised by some statement in this block, the execution of the statements in this block stops and the chain of except
clauses is checked against the type of the raised exception.
Each except
clause specify one or many types of exceptions for which their associated block of statements will be processed. The keyword as
names the raised exception which can then be addressed in the statements block after it.
If the type of the raised exception matches the type expressed in an except
clause, the statements block associated with this except
clause is immediately processed.
If none of the exceptions types expressed in the chain of except
clauses matches the raised exception, then the otherwise
clause is used and its associated block of statements is processed, if this clause is present.
If a finally
clause is present, the raised exception having been caught by a previous except
clause or not, the statements block associated with clause finally
is processed. This means that when a finally
clause is present, it is always processed.
The Exceptions concept will be fully explained later in this documentation. For the sole purpose of describing the related syntax, the EBNF specification should be enough to provide.
3.5.7 while statement
The while
first evaluates a conditional expression. If it evaluates to true
, the block of statements associated whith the while
keyword is processed and processing gets back to the evaluation again of the conditional expression.
Here is a formal EBNF specification of it:
<while statement> ::= 'while' <parenthesised expr> <statements block> ['otherwise' <statements block>]
The parenthesised expression above is a conditional expression which evaluates either to true
or to false
.
While the conditional expression evaluates to true
, the block of statements is processed. As soon as it evaluates then to false, processing is kept on at the first statement after the block of statements.
If the conditional expression evaluates to false
the very first time it is evaluated, the block of statements associated with the keyword otherwise
is processed, as long as this clause appears after the while
-related block of statements.
Python programmers, CAUTION: this is not the Python behavior of controversial keyword else
put after a while
.
3.5.8 with statement
The with
concept of Typee is directly inherited from Python syntax. This Python goodie is so useful that we have decided to specify it in Typee also.
This concept will be fully explained later in this documentation. Let’s just see its syntax for now. Its formal EBNF specification is:
<with statement> ::= 'with' <with items list> <statements block> <with items list> ::= <with item> (',' <with item>)* <with item> ::= <expression> ['as' <target>]
After keyword with
, at least one entity is declared as an expression. Each of these declared entities may be associated with an alias, or wrapper: an identifier that will be locally known in the block of statements which is processed just after the with
clause.
3.5.9 embed statement
This is a key concept in Typee associated with keyword exclude
. When translating Typee code into some targeted programming language, and since Typee code aims at being generic enough, it might be that some specificities of the targeted programming language are not available with Typee. The embed
statement lets programmers embed native code in Typee code.
A semi-formal EBNF specification of its syntax is:
<embed statement> ::= 'embed' <languages> ( <dotted name> ';' | <embedded native code> ) ['exit'] <language> ::= 'android' | 'java' | 'cpp' | 'cs' | 'csharp' | 'py' | 'python' <languages> ::= <language> ( ',' <language> )* <embedded native code> ::= '{{' (<any code chars but '}}'>)* '}}'
This is not a truly formal LL(1) EBNF specification, but trust us, it can very easily be transformed in a legal one. The advantage of its formulation this way is that it is far easier to understand.
Of course, native code will be put as is in the finally generated source code files. Then, it gets also access to every declared entity locally known at the embed
clause level. Python programmers will have to take care of indentation within embeded code. They should be multiple of 4 spaces each (currently not configurable).
Keyword exit
can be added at the end of the statements block of an embed
clause. The use of this is that, when translating a Typee portion of code that contains embedded native code, once this native code has been put as-is in the created translation file nothing after this exit
will be inserted in the created file until the end of the currently translated portion of Typee code.
See example of use in Typee built-in library Thread
, for instance. You will find this extensively used in module base_thread.ty
for instance.
You will have noticed that android
is an allowed language. Well, Android is not a programming language but it is still defined as being one just to distinguish Java and Java for Android. You will find examples of its use in Typee built-in libraries – see module time.ty
in library Time
, for instance.
Let’s provide a few examples.
const uint32 NB = 16; array<int32>[NB] my_data; embed cpp {{ for ( auto it = my_data.begin(); it != my_data.end(); ++it ) *it = 0; }} embed java, android {{ for( int i=0; i < NB; i++ ) my_data[i] = 0; }} embed python {{ my_data = [0]*NB }} my_data[1] = 1; print( my_data ); // prints 0 1 0 ... 0
const int32 NB = 16; array<int32>[NB] my_data; embed cpp zero_set.cpp; // (all of these native code embed java zero_set.java; // source files being present embed python zero_set.py; // in the 'current' directory) my_data [1] = 1; print( my_data ); // prints 0 1 0 ... 0
3.5.10 exclude statement
This concept is the counterpart of embed
. It excludes some Typee code from being translated into code of specified translated language. It can be used in two ways: either directly in Typee code or right after the signature of a function in its definition.
3.5.10.1 exclude in Typee code
A formal EBNF specification of its syntax is:
<exclude statement> ::= 'exclude' <languages> '{{' <statements list> '}}' <language> ::= 'android' | 'cpp' | 'java' | 'cs' | 'csharp' | 'py' | 'python' <languages> ::= <language> (',' <language>)* <statements list> ::= <statement> (<statement>)*
The main use of this is when some native code is embedded for a targeted programming language while the equivalent code is to be programmed in Typee, to be translated into other targeted programming language for which no native code can be directly equivalent.
Example:
none zero( list[] l, const uint32 n ) { // sets list l with n items with value zero // for sole Python embed python {{ l = [0]*n }} // for any targeted programming language but Python exclude python {{ l = []; while( n != 0 ){ l.append( 0 ); --n; // could have been put in while( n-- != 0 ) } }} }
In the above example, either function zero()
is translated in Python, in which case the sole embedded Python code will be put in the generated module code, or function zero()
is translated in any other programming language than Python, in which case the Typee code contained in the Python exclude
-d block will be translated.
Notice: in the case of translating this code into Python, it may be that Typee optimizer will automatically “inline” the code ot function zero()
directly in place in modules where this function is called – performance and memory space optimizations here.
3.5.10.2 exclude in function definition
We know only one use case for this usage of exclude
. May be you wilil find other ones… We have introduced this use in function definition to exclude its translation into a targeted language when coding an interface layer in a Typee library above some already existing libraries in different targeted languages.
The formal EBNF description of the Typpe syntax is this one
<function definition> ::= <function decl> ['exclude' <languages>] <statements block> <function decl> ::= [<access protection qualifier>] ['final'] <type> <identifier> [<template def>] <function args declaration> <language> ::= 'android' | 'cpp' | 'java' | 'cs' | 'csharp' | 'py' | 'python' <languages> ::= <language> ( ',' <language> )*
It aims at exclude from code translation any method or function that would already exist with exact same signature in a targeted language. Difficult to explain, easy to understand with an example.
This is part of the code of Typee built-in library Thread. Java library Thread already defines method is_daemon()
while Python names it another way.
const bool is_daemon() exclude java /** Returns true if this thread is daemonic, and false otherwise. */ { embed py {{ return self.daemon }} }
Here, the Typee signature is available for any Typee code, but at translation time into Java, the already existing method in Java will be named in the translated code and no other translation from Typee to Java will take place. For any other targeted language, the related translators will attempt to translate the block of Typee statements of the method.
Next section formerly explains the Typee simple statements.