Skip to content
PaskalCPP
Language

Statements

The statement rules, local declarations, if, while, repeat, for, match, leave and skip, return, guard, and expression statements.

Directive statements (@breakpoint, @message) are on Directives; C++ preprocessor lines and cppstart blocks in a body are on C++ mixing.

The statement rules

Every statement ends in ;. Two expressions in a row with no ; between them are a syntax error (PR0001), never two statements, and a lone ; is no statement.

  • An expression statement is an expression with an effect: an assignment (:= and the compound forms such as LN *= 2), a call, or a C++ expression (LV.push_back(1);). An expression with no effect (LN + 1;) is SM0613 (statement has no effect).
  • begin ... end; is a statement: a nested block in any statement list.
C++ side

C++ statements are not written in a body: switch, try and throw have the PaskalCPP forms match, guard and raise, and a C++ statement keyword in a body (switch (LN) { ... }) is PR0049. A C++ statement PaskalCPP has no form for goes in cppstart source ... cppend;: see The three forms.

Local declarations

A var, const or type block is a statement in every statement list: a routine or module body, a loop body, a nested begin ... end; block and a match arm. Its names are visible from it to the end of its list (var LA: int32 = 3;, type TSmall = int8;).

  • In a match arm each keyword takes one item (1: var LY: int32 = 5;): before a later item, a label list followed by : would start the next arm.
  • Two locals of one name in one list are SM0004; a local var with no type is PR0001.

if, while, repeat

if C then ... [else ...] end;: each branch is a statement list, and a chain of tests nests an if in the else.

while C do ... end; tests C before each pass, so a false C never runs the body. repeat ... until C; runs the body first and ends when C is true, so the body runs at least once.

The condition of if, while and until is a bool: an int32 condition is SM0263 (a condition is bool).

From C

There is no truthiness: write if LN <> 0 then, not if LN then.

for

for V := A to B do ... end; counts up, downto counts down. Both ends are included, and an empty range (for LI := 5 to 1) runs nothing.

statements_wchar.pcpp
module exe statements_wchar;

type
  TColor = choices(cRed, cGreen, cBlue);

routine Kind(AW: wchar): string;
var
  LR: string;
begin
  match AW of
    L'a'..L'z': LR := "letter";
    L'0'..L'9': LR := "digit";
  else
    LR := "other";
  end;
  return LR;
end;

var
  LW: wchar;
  LI: int32;
  LJ: int32;
  LK: TColor;

begin
  print("wide");
  for LW := L'a' to L'c' do
    print(" {}", LW);
  end;
  println("");
  println("wide x {}", Kind(L'x'));
  println("wide 5 {}", Kind(L'5'));
  print("grid");
  for LI := 1 to 2 do
    for LJ := 1 to 2 do
      print(" {}", LI * 10 + LJ);
    end;
  end;
  println("");
  LK := TColor.cBlue;
  match LK of
    TColor.cRed: println("red");
    TColor.cGreen, TColor.cBlue:
      if LK = TColor.cBlue then
        println("blue");
      end;
  end;
end.
output on x86_64-windows-gnu and x86_64-linux-gnu
wide a b c
wide x letter
wide 5 digit
grid 11 12 21 22
blue
[Heap] Allocs: 0, Frees: 0, Leaked: 0
  • V names a variable declared before the loop (a var, or a parameter that is not const); for never declares one. A constant as V is SM0600, and so are a type, a routine, a field, a choice value and a const parameter.
  • V is an integer, char, wchar or a choices type (for LW := L'a' to L'c', for LK := TColor.cRed to TColor.cBlue); any other type is SM0601. A choice iterator takes bounds of its own choices type. A C/C++ variable mixed into the file is an iterator too (int GCpp = 0; as plain C++, then for GCpp := 7 to 9); its type is clang's.
  • The body reads V but never writes it: an assignment to V in the body is SM0602, and so is a nested for over the same V.
  • A for nests in a for over another iterator.

match

match S of label[, label]: ...; [else ...] end;: an arm holds a list of labels and a statement list. A label is a constant or a range a..b (4..6, 'a'..'z'), and else takes every other value.

  • S is an integer, char, wchar or a choice; a string subject is SM0603.
  • A label is a constant: a variable as a label is SM0202. A label outside the subject's type is SM0604 (match label 300 is outside 'int8': it never matches), a range whose low bound exceeds its high bound SM0267, and a label two arms hold SM0605, with the first label covering it as a note.
  • A match on a choice with no else names every value or warns: SM0606 (match on 'TColor' does not cover: cBlue) lists the values no arm names. A match that names every value needs no else.

leave and skip

leave; ends the innermost loop or match; skip; goes to the next pass of the innermost loop. Both work in while, for and repeat, and a leave in a match inside a loop ends the match only.

leave outside a loop or match is SM0607, skip outside a loop SM0608.

return

return V; returns a value of the function's return type, and every path of a function's body ends in a return: a body that can reach its end is SM0612 (missing return: 'F' can reach its end without returning a value).

return; leaves a procedure early, from inside loops and matches too. return; in a function is SM0610, and return V; in a procedure is SM0611.

guard

guard ... [except ...] [finally ...] end; takes at least one of except and finally; a guard with neither is PR0052.

  • except runs when the body raises, and exccode() / excmsg() read the exception there; outside an except body they are SM0615.
  • finally runs either way, last.
  • A guard nests in a guard, and an inner raise reaches the outer except after the inner finally.
  • leave, skip and return jump out of a guard body or an except body, and finally runs on the way out.
statements_guard_flow.pcpp
module exe statements_guard_flow;

routine Find(): int32;
begin
  guard
    return 7;
  finally
    println("return finally");
  end;
end;

routine Handle(): int32;
begin
  guard
    raisecode(9, "nine");
  except
    print("except {}", exccode());
    return -1;
  finally
    println(" finally");
  end;
  return 0;
end;

var
  LI: int32;

begin
  for LI := 1 to 5 do
    guard
      if LI = 2 then
        print("skip {}", LI);
        skip;
      end;
      if LI = 3 then
        print("leave {}", LI);
        leave;
      end;
      print("pass {}", LI);
    finally
      println(" finally");
    end;
  end;
  println("loop done");
  println("found {}", Find());
  println("handled {}", Handle());
end.
output on x86_64-windows-gnu and x86_64-linux-gnu
pass 1 finally
skip 2 finally
leave 3 finally
loop done
return finally
found 7
except 9 finally
handled -1
[Heap] Allocs: 0, Frees: 0, Leaked: 0
  • No jump leaves a finally body: leave, skip and return there are SM0609.
  • A C++ jump (break; in mixed C++) inside a guard body is SM0614: it would leave only the guard's hidden function.

What a guard catches, beyond raise, is on The runtime.