Menu Close

Articles

Level: Structured Programming

Structured programming is a programming paradigm created to improve the clarity, quality and development time for computer programs. The main features of this paradigm is the intensive use of control flow statements and avoid ussage of goto statement that can lead to spaghetti code potential difficult to maintain.

Structured programming emerged in the late 1950s with the appearance of the ALGOL 58 and ALGOL 60 programming. We teach this paradigm due to it’s clarity and popularity. To learn this paradigm we create a special language designed for learning.

Level-1 Dialect

Level-1 is a minimalist structured programming language. It is statically typed 3’rd generation language. We have designed this language for education. The objective is to allow students to learn this language quickly and create a compiler using another language. This is the most easy to learn Level dialect. Also known as Level-1.

Hypothetical usability

  • Console applications
  • Simple algorithms
  • Compiler research

We plan to create several compilers. First compiler will be implemented from scratch using Rust. Maybe in the future new compilers can be implemented using other languages: C++, D, Assembly.

Structure

Level application consist of one main program and subroutines. Every program is stored in a file that is the main module. In a module we organize members in regions: Types are declared first then constants then variables and last the executable sections.

Level application has a main program section that hase the same name as the main module name. In the main module we can import other modules and libraries. The main module can define global variables that are visible in all module  executable sections.

Features

We have selected some of most notable features we think Level 1 should have. Even if the language is stripped down to essential it is going to be a challenge to implement. This is because of the Exceptions and Memory Management model. Due to it’s procedural approach is still a high-level and modular language.

#Feature NameDescription
1ProjectWe can define a project structure;
2ModulesA module is a file  components that can be reused for multiple programs;
3ProceduresA sub-program. Subroutine with side-effects;
4FunctionsA sub-program that receive parameters and create one single result;
5User typesUser can define a type composition based on pre-defined types;
6Static typesConstants, variables and parameters must be declared with type information;
7Composite typesCollection of multiple elements of same type or different types;
8Optional argumentsWe can create optional parameters in program, procedures and functions;
9Arguments by nameEvery argument of functions or procedures can be pass by name or by position;
10Exception managementWe can prevent program errors by catching exceptions and analyze them;

Punctuation

We have try to avoid using one symbol to for multiple purposes. This is to reduce complexity of the compiler and also for improved learning experience. Most operators are based on single symbol. Some are based on 2 symbols.

In the next syntax description “…” represent content and “,,,” represents a sequence of elements. In descriptions vertical bar “|” represents alternative use when an operator have multiple purposes.

SymbolDomainDescription
$GeneralGlobal constants | System variables | Static variables
+MathNumeric addition
MathSubtraction | Change sign (unary operator
*MathNumeric multiplication
/MathReal number division
\MathBackslash is used for rational numbers
%MathModulo operator
^MathPower operator. Example: x^n is the x to the power of n.
=PolymorphicAssignment operator | Clone operator
~BitwiseWe use “~” prefix for bit level operators: { ~not, ~or, ~and, ~xor }
>LogicalGreater then (strong comparison)
<LogicalLess then (strong comparison)
:GeneralDefine type | Association | Paired up
;GeneralThe end of statement | End of program or modle
.GeneralDecimal separator | Member of : {program, module, library, record}
,GeneralEnumeration for elements in a sequence
&StringsString concatenation | String to collection concatenation
<-StringsString injector operator. Used with format placeholder “#”
#StringsFormat placeholder, used like #s, #n or  #(x, ap:m.d). | Compiler directive.
|VectorVector comprehension: v = { x | x in <collection> and <expression> }
‘…’StringsASCII string literal: ‘this is an ASCII string’
“…”StringsString literal: “this isn’t my fault”
\StringsBackslash is used as escape character in strings \0 = NUL
(…)GeneralMath expressions | tuple | parameters | subroutine call | expressions
(,,,)TuplesMath n-Tuple collection of elements like (1,2,3,’a’,’b’,’c’)
[n,m]CompositeIdentify a matrix member using an 2 indexes m[i,j]
[n]CompositeIdentify a matrix member using an 1 index v[i]
[,,,]VectorVector literal [1,2,3] | Matrix [[1,2],[3,4]]
{,,,}OptionEnumeration of elements {Zeros = 0, Unos = 1, Dos = 2}
@PointerPointer declaration. Use like: variable name: @type;
?PointerGet address of variable to assign-it to a pointer use like: pointer = ?variable
!CommentSingle line comment or end of line comment;

Digraph Operators

We call operators based on two symbols digraphs. In the description of digraph operators we use “…” to represent content. We use “,,,” for enumerated elements. In descriptions sometimes we use vertical bar “|” for operators that can have multiple purposes depending on the context.

SymbolDomainDescription
(..)RangeRange operator (n..m) define a subtype of
[..]SliceVector slicing operator [n..m], where n>=0 and m  < length
=>FunctionDeclare function result type
:=AssignAssign value to variable | Modify variable
<>LogicalIs not equal | disjunctive
==LogicalIs equal to comparison | Deep comparison
>=LogicalGreater then or equal to | Numeric relation
<=LogicalLess then or equal to | Numeric relation
+=ModifierIn-place modifiers ( -=, +=, /=, *=, %=, ^= )
<<Bit/mathShift bits to the left
>>Bit/mathShift bits to the right
CommentsSingle line comment (not an operator)
{*…*}CommentsMultiple line comment | Expression comment

Program statements

A program is created from small structures that are expressions specific to a programming language that are called statements. A statement is one or more lines of text that starts at beginning of the line and ends using “;”. Statement can start with spaces and contains keywords, identifiers and literals connected with operators.

  • Keywords: are English words that are reserved by Level and have a predefined purpose;
  • Identifiers: are names for elements created by the users to define a program ;
  • Literals: are sequences of numbers and symbols representing data;
  • Symbolic operators: are based on one or two special characters;
  • Keyword operators: are specific to logical expressions;

Simple statements

Simple statements are using one single line or several lines terminated with one “;” symbol.

Some simple statements:

  • white space: can contain spaces, tabs and empty line terminated with LF or CR/LF;
  • line comment: contains 0 or several spaces followed by operator “!” and a short text;
  • statement comment: is a text fragment following a statement with “!” to the end of the line;
  • pass: has the form “pass;” has significance of “success”. It is recommended as a region placeholder.

Examples

  pass; ! this is an empty statement that does nothing

Composite statements

Composite statements are blocks of code also named code sections. These sections contain other statements that can be simple or composite statements. This is a nested structure or parent/child hierarchical structure. A composite section is ending with “end” keyword.

Procedure Main

In the next example we create a program having a single _main_ procedure . Procedure main is mandatory section in any program. A procedure contains simple statements. We use a _do_ statement to demonstrate one anonymous section.

procedure main is
  r:Integer; !local result variable 
begin
  ! Nested anonymous section
  let !start do statement
    i=10, x=15: Integer; !two local variable
  do
    r=i+x;
  done;
  print(r);
end procedure;

Level comments

We create several comment notations to allow developers to create great documentation for a level program. In fact the main goal of level is to offer great code readability. This require good comments for every code section.

FORTRAN comments

  1. Single line comment start with “!” at beginning of new line.
  2. End of statement comment after “; !” at the end of line.
  3. End of line comment for multi-line statement between “!” and the end of line.

Ada comments

Simple comments can be done using 3 alternative forms:

  1. Single line comment starts with “–” at beginning of line.
  2. Full line separator starts with “–” and continue with “-” to the end of line.
  3. End of statement comment after “; –” at the end of line.

Block comments (Sage)

A block comment is a text enclosed using following operator: {*…*}. Block comments can support a text fragment spanning one or several lines including other block comments. This form of comments is also good to make comments inside expressions. This comment style is Sage Code style and not found in other languages.

{* comments *};
...
{* multi line comment
   can span multiple rows.
*}

Comment Usability

With block comments one can comment segment of code or parts of a complex expression to experiment with code simplification for debug purposes. Block comments can be nested with other comments. This notation is specific to Level and not used in any other language.

Separator

A separator is a on line comment that starts with two dash comment and continue with dashes to the end of the line.  End of the line symbol “;” is not necessary for a comment line. We can use separator to highlight a larger set of comment lines to create a block like documentation before the method specification.

---------------------------------------------------------
! This is a separator comment very common in Level
! We can use this kind of comments to document the code
---------------------------------------------------------
...

Code indentation

In the written form of many languages, an indentation is an empty space at the beginning of a line to signal the start of a new paragraph. Many computer languages have adopted this technique to designate “paragraphs” or other logical blocks in the program.

Paragraph indentation levels:

This paragraph is indented by 0 spaces. indented level 0
  This paragraph is indented by 2 spaces. indented level 1
    This paragraph is indented by 4 spaces. indented level 2
      This paragraph is indented by 6 spaces. indented level 3
        This paragraph is indented by 8 spaces. indented level 4

Indentation rules

  • Level code use mono-space font that means every letter has the same width: “DejaVu Sans Serif”
  • Level uses 2xN spaces for code indentation from left to right where N=level of indentation
  • Level single line comment (–) start at begging of a line and is not indented
  • Level multi line comments can start at the indentation level N=0 or current indentation level with sibling code
  • Level rules for code indentation are mandatory and verified by the compiler.

Program indentation

  • The program keyword, region keywords, begin and end are aligned on left side with 0 indentation;
  • Between the begin and end all members are indented using 2xN spaces where N is the level of indentation;
  • Content of every code region must be indented from left 2xN spaces depending on the number of nested blocks;
  • Region definition keywords are using same indentation level as the section keyword;

Example:

---------------------------------------------
! We use bang system for single line comment
---------------------------------------------
-- declare module members
procedure test() is 
begin 
  pass; !This statement is indented by 2 spaces 
  if TRUE then 
    pass; !This statement is indented by 4 spaces 
  else 
    fail; !This statement is indented by 4 spaces 
  end if; 
recover 
  pass; !This statement is indented by 2 spaces 
end procedure;

procedure main is
  -- declare local variables
  v_var:Integer;
  r_var:Real;
  -- local sum() function
  function sum(a, b:Integer) => Integer is
  begin
    return 0;
  end function;

-- start executable region
begin
  test; !call procedure test
  r_var := sum(1,2) !call function sum()
-- catch exceptions in recover region
recover
  when exception.code==0 then
    fail;   !this makes program to fail
  when exception.code>100 then
    resume; !this makes program to resume
-- close resources and create reporting logs
finalize
  pass; !this statement is indented by 2 spaces
end procedure;

 

Keywords

We use full English words not abbreviations. Here are reserved keywords for Level1:

 

KEYWORDDESCRIPTION
NAMED SECTIONSSection of code that have a name
programDefine a program section
functionDefine a subroutine that create a result
procedureDefine a subroutine that do not have a result
moduleDefine a group of reusable methods
REGIONSBlocks of code used for specific purpose
importImport library in module or program
fromSpecify library file (from library use all)
typeStart a declaration region for types
constantStart a declaration region for constants
variableStart a declaration region for variables
declareStart a declaration region for functions (forward specifications)
implementStart an implementation region for functions and methods
beginBegin executable region of a named section
exportExport public members (used in libraries only)
recoverDefine recover region (named sections only)
finalizeDefine finalization region (named sections only)
endEnd a section (block of code)
BUILT-IN TYPESTypes start with uppercase letters
StringASCII string
Integerinteger number
Realreal number
ByteUnsigned integer on 8 bits
ShortUnsigned integer on 16 bits
LongSigned integer on 32 bits
Tupleone or multiple values like (“one”,”two”,…)
Recordcomposite data type like (one:”one”, two:”two”,…)
Optionenumeration of elements: {one, two,…}
Vectorone dimension array like [1,2,3]
Matrixtwo dimension array  like [[1,2,3][4,5,6][7,8,9]]
LogicBoolean value (TRUE or FALSE)
CONSTANTSPublic constants available in core language
TRUELogical value 1 (constant)
FALSELogical value 0 (constant)
PIMath (constant)
LOGIC OPERATORSDESCRIPTION
andLogical operator
orLogical operator
notLogical operator
isLogical operator (is of specific type)
inLogical operator (belong to a collection)
xorbitwiz xor
 UNNAMED SECTIONSSmaller block of code with no name associated
letStart declaration region for un-named section
ifDecision statement (conditional)
thenStart first block for decision statement
elseSecond block for decision statement
doSimple block of code usually used with a record
switchMulti-decisions statement
caseMulti-decisions statement
checkMulti-select statement
matchUsed in check select statement
defaultUsed in switch and check for default case
loopRepeat a block of code
whenCheck a condition (similar to if)
EXCEPTIONS Handling exceptions
raiseCreate an exception with message and code
failCreate an error with no message and no code
resumeResume program with next line after error line
panicCreate a crytical error (unrecoverable error)
passDoes absolutely nothing (null statement)
assertVerify an assumption (similar to when)
JUMPSStatements that jump to other statements
returnUsed in program or function to stop
exitStop execution of a loop
nextJump to beginning of the loop and cycle next iteration
breakStop execution of next cases in switch all statement
ACCESSORSHelp to set or get scope attributes
 this.*Is referring to current procedure
 parent.*Is referring to parent of current section
BUILT-INS Standard functions and procedures
output()Create output
print()Create output
input() Accept input
parse()Convert string to number
format()Concert real to string
floor()Convert real to integer
ceiling()Convert real to integer
round()Convert real to integer
 MATHAlgebra functions
 abs()Math
 sin() Math
 cos() Math
 tan() Math
 atan() Math
 sqrt() Math

Note: This list may not be 100% complete.

Functions

A function is a section of code that use several parameters and can have a result. Functions can be defined as members in module or local in other sections. We declare functions before we can use them. One function can call itself and become recursive function.

Function syntax:

function <func_name>(<param> type[,<parame> type]...) => <result_type> is
  <declaration_region>;
begin
  <execution_region>;
  ...
  [result=<expression>]; 
[recover]
  <recover_region>;
[finalize]
  <finalization_region>;
end function;

Function scope

A function belong to a scope that is called parent scope. Functions have a local scope that can contain declarations of variables and other nested functions. In a function we can use variables from parent and or local scope. This is called current scope.

Function call

The call for a function is using name of the function and round parentheses (). The brackets are mandatory to call a function. If the brackets are missing the compiler will raise a compilation error. Inside brackets we can enumerate arguments. Arguments are values assigned to parameters before function is executed.

Parameters

Parameters are declared in round parentheses () after the function name. Each parameter has name and type and can have one default value. When a function is called each parameter receive a value that is called argument. There is a difference between the parameter and the argument. The parameter is a local variable of the function scope. Arguments are the values of these parameters used in a function call. Arguments can be a literals, constants or a variables from current scope.

Arguments

Arguments can be pass by value or by reference. By default arguments are pass by value. For vectors and matrixes we can declare parameters using pointer notation ” @type” then we can pass an arguments by reference.

Function result

Functions can have one single result. Developers can use “result” variable that is declared having the same type as the function. The result type is defined using symbol “=>” that is a digraph symbol. Result variable can be used in expressions.

Result of the function is created using “:=”. After this statement we can have other statements that are all executed before the control is returned to the caller. When function is terminated local variables are removed from memory. In Level functions are not re-entrant.

Note: The result of a function must be always used into an expression. If result need to be ignored then a dummy variable can be used to capture the result . If this is not convenient then we must define a procedure not a function.

Early termination:

  • A function normally terminates at the first return keyword;
  • A function can be early terminate using return keyword;
  • Exception can interrupt a function execution prematurely;
  • If function have a finalize region then this region is executed after return;

Example of function call

procedure main is
  c:Integer;
  -- function declaration
  function sum(a, b: Integer) => Integer is
  begin
    result := a+b;
  end function;   
begin
  c=sum(10,20); --function call
  print(c);      --this will print 30
end procedure;

=> 30

Optional Parameters

Function parameters can be defined using assignment operator (:) to have “default values”. These parameters are also optional parameters and can be omitted from the function call.

Parameter values can be pass by position or by name. Passing parameter by name can specify parameters in different order then initially defined in procedure. Also optional parameters may be skipped.

Why we have parameters pass by name? Sometimes the list of parameters is long and all parameters may be optional. Sometimes the function is modified then the parameter order can change. Old calls can be still valid even if the procedure signature was changed.

Example of function declaration with optional parameters

function sum(a=0, b=0 :Integer) => Integer is 
begin 
  result := a+b; 
end function; 

procedure main is
  c:0 Integer;
begin
  c=sum(1,1)    --call function using parameters by position
  c=sum();      --call function using default values a=0, b=0
  print(c);     --will print 0
  c=sum(b=123); --pass only second parameter by name
  print(c);     --will print 123
end procedure;

=> 0
=> 123

Procedures

Procedures are similar to functions except do not have return keyword and do not create a result. A procedure can have side-effects or can use input-output parameters using @type notation. Procedure call is similar to a function call except procedures can’t be used in expressions.

variable
  c=0:Integer; 

procedure sum(a, b :Integer) is 
begin 
  c=a+b; !side-effect 
end procedure; 

procedure main is
begin
  sum(1,122) --call procedure
  print(c);  --will print 123
end program;

Output:

 0
 123

Control Flow

The terminology “Control Flow” imply a river flow. Software developers can use metaphors to explain things.  In this case the flow represents a set of statements that can be controlled like a river. Split in two or more branches. One branch can be blocked and so on.

Control flow statements are anonymous sections of code. In other languages these are also called block statements. Level has an original design for anonymous section. We have enhanced sections to be potent and comprehensive. We have two types of control statements:

  • selection
  • repetition

Do section

This is the most simple unnamed section. It resolve one single aspect of a problem. It is a sequence of code executed one single time. Do section can be used to create a local-scope. The local members can shadow outer-scope members. With this section type a large problem can be split into small aspects.

[let]
  <variable_name>:<type>;
  ...
[with <qualifier>]
do 
  <statements>
  ...
end do;

With: We can use “with” that is optional, to establish a context using <qualifier> that can be a record. Then we do not have to use record name as qualifier for each statement. This is just a syntactic sugar to avoid repeating the qualifier over and over again.

Local scope

Every block statement can use  _”let”_ to create a local scope. Here user can define constants, variables or functions. Elements defined in this region will not be available after the end of block. Local scope is useful to avoid code fragmentation. It is considered bad practice to create procedures or functions that are used one single time.

Decision statement

The decision is an unnamed section defining one or more groups of statements. These statements are executed or not depending on the logical evaluation of the condition expression. The condition is any valid logical expression that can return a true or false value. There are 3 forms of decision statements in Level:

  1. if statement
  2. when statement
  3. assert statement

Single path decision

[let]
 <declaration>
if condition then
  <statement>;
  ...
end if;

Double path decision

[let] 
  <declaration>  
if <condition> then
  <statement>;
  ...
else
  <statement>;
  ...
end if;

Nested decisions

-- nested blocks
if <condition1> then
  <statement>;
  ...
  if <condition2> then
    <statement>;
    ...
  end if;
end if;

Notes:

  • The “if” is a single statement having multiple regions;
  • After “then” or “else” there is no “:” or “;” line terminator;
  • The “end if” is terminated with “;” separator!

When statement

There is one short form of decision using keyword when:

when <condition> then <statement>;

Assert statement

There is a second short form of decision using keyword assert:

assert <condition> else <statement>;

Switch statement

The switch statement is a unnamed section. It is used to create a complex selection using multiple conditions. Unlike other computer languages the switch statement is using logical conditions and not a control variable.

Syntax:

[let]
  <declaration_region>;
switch [top|all]
  case <condition> then
    <first_case>;
    [break|continue];
  case <condition> then
    <second_case>;
    ...
  default
    <default_case>;
    ...
end switch;

Notes:

  • each case conditions are evaluated in order top down until one of conditions is true;
  • When [top] is used and one condition is true the next conditions is not evaluated unless [continue] is used;
  • When [all]  is used next condition is evaluated if no [break] is also used;
  • if no condition is true the “default” case is executed.

The declaration region “let” is optional and can be used to create a local scope where user can define control variables. Variables defined in this region will not be available after end of switch statement. In this region user can also define local functions.

Check statement

The match statement is a unnamed section. It is a decision machine used to select one path from multiple logical choices based on a single variable value. The match is very similar to switch. The difference is we use a variable that can match several values.

General Syntax:

[let]
  <declaration_region>;
check <variable> [top|all]
  match <value1> then 
     <first_statement>;
     [break|continue]
  match <value2> then 
     <second_statement>;
  ...
  default
     <default_statement>;
  ...
end check;

Using tuples

When match it is possible to use more then one value using a list of possible values. (1,2,3,4,5) for example. Also we can match a range (1..5).

Example:

program test(v:Integer) is
  message:String;
begin
  check v all
    match (1,3,5) then 
      message="first match";
    match (2,4) then 
      message="second match";
    match (1,2,3,4,5) then 
      message="third match";
    default
      message="no match";
  end check;
end program;

Note: We cant use any other operator in the match expression. For example: not in (1,2,3) in this case we use a switch statement.

Check rules

  • Each match is evaluated in order from top down until one is found;
  • When [all] is used all matches are evaluated even if one is found;
  • When no match is found default region is executed.

The “continue” can be used with “top” to check next match. The “break” can be used with “all” to stop checking.

Loop statement

The Loop statement is an unnamed section of code that can be executed once or many times.

 

[for]
  <control_var>=<value>:<type>;
  ...
loop [:label] 
  <statement>;
  ...
  if condition> then 
     next ;
  end if;
  <statement>;
  ...
  if <condition> then 
     exit ; 
  end if; 
  <statement>;
  ...
end loop;

Control Variables

The loop has an optional declaration region using  for keyword. This create a local scope where user can define one or more control variables. Inside the loop these variables can be incremented using += modifier or assignment statement.

Example: Manipulate control variable using decision:

if <condition> then
   control_var+=1; 
else
   control_var=0;
end if;

Loop Shortcut

  • The loop can have one or more shortcuts using “next” keyword.
  • This will continue the execution with the beginning of the loop.
when <condition> then next;

Loop Termination

  • The loop can terminate using one or many exit points.
  • The normal loop termination is using “exit” keyword.
  • This will jump the execution flow after the end of the loop.
when <condition> then exit;

Nested loops

A nested loop is a loop within a loop, an inner loop within the body of an outer loop. How this works is that the first pass of the outer loop triggers the inner loop, which executes to completion. Then the second pass of the outer loop triggers the inner loop again. This repeats until the outer loop finishes using exit.

The implicit exit/next are referring to current  loop. For more then two levels developer must use decision statements after each loop to skip or exit. Alternative we can use a loop label. Labeling loops is optional and we can use significant words labels like: main, first, second… or any other identifier you like:  a1, a2, one, two, mark

Example: Exit from all nested loops

loop:all
  loop 
    if <condition> then 
      exit all;
    end if;
  end loop;
end loop;
...

Example: Exit from more then one nested loops:

loop:mark
  loop 
    loop
       when <condition> then exit mark; !will exit to <continue>
    end loop;
  end loop;
end loop;
<continue>;

Example: Skiping more then one neste loops:

loop:one   --> mark 1
  loop:two --> mark 2
    loop:three
       when <condition1> then next two; ! will continue with mark 2
       when <condition2> then next one; ! will continue with mark 1
    end loop;
  end loop;
end loop;

Note:

  • At least one exit point must exist, otherwise we have an infinite loop;
  • A loop can terminate using an early termination by rising an exception;
  • A procedure can be terminated from a loop using return keyword;
  • A loop can use optional labels to resolve nested loop exit and next cycle;

 

Level Exceptions

Exceptions are irregularities in program normal behavior. Exception is interrupting the current logical flow and jump to the recover region in current section or parent section. In level all exceptions are considered errors.

The exception is a variable of type record that is created when exception is raised and is available in the recover block. Exception variable contains several members that are fill-in by the Level program when exception is created:

type Exception:Record of (
  code: Integer, 
  message: String, 
  section_type: String, 
  section_name: String, 
  file_name: String, 
  line_number: Integer
)

Run-time errors

Exceptions can be system exceptions or user defined exceptions. System exceptions are predefined and created during the program execution when there is a “run-time error” and program can’t continue.

User defined error

Developers can verify logical conditions to verify that a program can run correctly. These verifications are called assertions. There are two alternative statements to create user defined exceptions.

-- raise exception from a decision block
if <condition> then
   raise(<code>,"message");
end if;

Quick exception

Using keyword “fail” user can quick create an exception that has no message or continue program using “pass”. Fail is used most frequent in combination with the “when” statement or can be used in decision blocks or recovery regions. Fail has error code=2.

-- raising a quick exception
when <condition> then fail;

-- equivalent for quick exception
if <condition> then
  fail;
else
  pass;
end if;

Unrecoverable exception

We use keyword panic to signal a bug that must stop program execution immediate. This can be due to an unexpected logic situation or a system failure that is unacceptable. This is equivalent to “run-time unhand-led exception” you can find in other languages. panic has error code=1.

Example:

...
when <condition> then panic;
assert <condition> else panic;

-- equivalent for panic 
if <condition> then
  pass;
else
  panic;
end if;

Exception handling

recover: region define an “exception handling region”.

In this region developer can write normal statements like “if”, “switch” to analyze the error record. Developer can decide to stop the program or to print a message or to print the error and resume the program using resume keyword.

This region is executed when an exception is raised by the system or by the developer using raise exception statement. If the program is resumed and the next statement will also create an error then the exception handler is executed again.

Example:

procedure main is
  a:Real; 
begin
  a=1/0;  
recover
  switch
    case error.code == 1000 then
      print(error.message);
      ...
    case error.code == 1001 then
      print(error.message);
      ...
  else
    print(error.message);
  end switch;
end procedure;

=> System Exception: Numeric divison by zero.

An exception can be reiterated in the recover area but this is unusual. To reiterate the exception one must use raise error This will raise the last exception to the parent program or procedure for handling.

When statement

This is a decision statement. It can be used for preconditions or quick interruption points of loops. It is based on a single condition expression and a single statement that can be executed when the condition is true.

Syntax:

  when <condition> then <statement>;

Example:

  when a==0 then fail;

Alternative usage

It is possible to create a bloc of code instead of but this is unusual code. We prefer to use “if/else”block when multiple statements can be executed for a true condition. Following is code that is a little bit harder to understand but is possible to create.

Example 1:

...
  when a<>0 then let
    b=0: Real; 
  do
    b= 1/a;    
    c= b + 123;    
  end do;

Example 2:

  when a > 0 then for 
    b:Integer;
  loop    
    print(b/a);    
    next b;
    when b>10 exit;
  end loop;

Assert Statement

We use assert to verify preconditions. We check if a condition is true and if is not true then we create an assert exception. This will let the programmer know that a required condition is not true and program has to stop execution.

Syntax:

 assert <condition> else raise(<error_code>,error_message);

Note: Assert statement is complement statement for “when” quick exception. We can simulate assert statement using when quick exception using not keyword.

 when not (<condition>) then raise(<error_code>,error_message);

Alternative usage

It is possible to create a bloc of code instead of but this is unusual code. We prefer to use “if,else”block when multiple statements can be executed when a condition is not true. Following code is confusing but is possible to create.

Example 1:

  assert a=0 else let
    b:Real;
  do
    b= 1/a;    
    c= b + 123;    
  end do;

Example 2:

  assert a=0 else for
    b:Integer;
  loop    
    print(b/a);    
    next b;
    when b>10 exit;
  end loop; 

For Iteration

This is a unnamed section of code that is executed repetitive for each element from an iterative collection. The keyword “in” is specific for this loop. Iteration is very similar to classic loop except we use “for” instead of “let” to define a local scope.

for <element> in <collection> loop
   <statements>;
     ...
   if <condition> then 
      skip [all];
   end if; 
   <statements>
    ...
   if <condition> then 
      exit [all];
   end if;
   <statements>
   ...
end loop;

Note: The “for” keyword create a local scope.  In this scope a single variable is defined.

Iterator element

The “element” is local to iteration and is used a control variable. The type of the “element” is cloned from the collection member type.

Premature termination

The iteration stops normally when all elements from collection have been visited. It is possible to change the normal logical flow of iteration using shortcuts or fast forward.

  • skip – will continue from beginning of loop
  • exit – will continue after the loop end

When we have nested loops by default skip and exit will skip only one loop. If we skip more then one loop then we can specify a number or use keyword all.

  • skip [all];
  • exit [all];

Loop shortcut example

The shortcut skip the execution to the beginning of the next iteration.

when <condition> then skip;

-- or alternative
if <condition> then 
  skip;
end if;

Loop forward example

Fast forward jump the logical flow to the first statement after the iteration.

when <condition> then exit;

-- or alternative
if <condition> then 
  exit;
end if;

Program Examples:

--example of collection iteration
procedure main is
  set = ['a','b','c','d','e']: Vector(5) of String;
begin
  for element in set loop
    -- continue shortcut
    when element < "c") then skip;
    output(element);

    -- fast forward 
    if (element = "d") then 
       exit all;
    end if;
    output(',');
  end loop;
end procedure;
c,d

Note: This loop can be used to iterate over characters in a string.

Range Iteration

Range iteration is a unnamed section of a program that is executed repetitive several times. The number of iterations is established using a predefined range of integer values. The range is generated using range notation (n..m).

for <index> in (n..m) loop
  <statements>;
  ...
end loop;

Iteration index

The “index” is a variable local to the iteration section. This variable should not be declared in the parent section of the iteration. The variable is not available after the end of the iteration.

Note: The “for” keyword create a local scope. In this scope a single variable is defined: . We do not terminate range[] wiht “;”. This is optional since the “for” declaration contains a single statement.

See also: best practices

Iteration range

A range is a subset from integer type using syntax: (<from_limit> .. <to_limit>). These range can be only in ascending order from_limit and to_limit value and include the limits. For reverse range or for a ratio, user must derive the desired value from control variable.

Examples:

(0..10)  = {0,1,2,3,4,5,6,7,8,9,10}
(-10..0) = {-10,-9,-8,-7,-4,-3,-2,-1,0}

Termination

Normal termination is established when index has used all the values defined by range. It is possible to change normal flow using shortcuts or exit points.

shortcut:

The “skip” shortcut continue execution with next iteration.

Making a shortcut:

when <condition> then skip;

exit point:

The fast forward “exit” iteration and continue with first statement after the end of iteration.

Making an exit point:

when <condition> then exit; 

Examples:

Example of forward iteration

procedure main is
begin
  for i in (0..10) loop
    output(i);
    if i==10 then 
      exit;
    end if;
    output(',');
  end loop;
end procedure;
0,1,2,3,4,5,6,7,8,9,10

Example of a reverse iteration

-- counting from 20 down to 0 with ration 2
import console;
from console use all;
procedure main is
  j:Integer;
begin
  for i in (0..10) loop
      j= 20 - 2*i;
      output(j);
      if j<0 then 
         output(',');
      end if;
  end loop;
end procedure;
20,18,16,14,12,10,8,6,4,2,0

Read next: Level: Basic Types