 
 
 
 
 
  
 
 
 Next: Exception handling
 Up: Control structures
 Previous: Booleans and branching
     Index 
In closure.cecil:
     abstract representation closure;
The closure representation is the parent of all closure
  expressions. Many control structures are defined on this object. But
  it's a regular object, so other user-defined objects can be
  descendants (e.g., see eval.cecil in the compiler directory tree).
 method loop(c@:&():void):none;
 
The loop method invokes its closure argument endlessly. It
 never returns normally. To exit the loop, the closure must do a
 non-local return or invoke some closure that does (e.g., using
 the exit control structure).  All other looping constructs are
 built upon this method.
 method while(cond:&():bool, c:&():void):void;
 
while implements a standard while-do loop. E.g.:
    while({ i < last }, {
            ...
            i := i.succ;
   });
 method while_true(cond:&():bool, c:&():void):void;  - same as while_true
method while_false(cond:&():bool, c:&():void):void;
method while(cond:&():bool):void;
method while_true(cond:&():bool):void;
method while_false(cond:&():bool):void;
method until(c:&():void, cond:&():bool):void;
method until_true(c:&():void, cond:&():bool):void;
method until_false(c:&():void, cond:&():bool):void;
 
Other while-do and do-until loops are implemented using the
  {while,until}[_{true,false}] methods.
  The one-argument while_{true,false} methods simply evaluate
  their argument test until it returns true or false, respectively,
  presumably for its side effects.  The until_ versions evaluate their
  body closure and then the test until the test returns true or
  false, as appropriate.
 method exit(c@:&(exit:&():none):void):void;
method exit_value(c:&(exit:&(`T):none):`T):T;
method exit_continue(c:&(exit:&():none, continue:&():none):void):void;
method exit_value_continue(c:&(exit:&(`T):none, continue:&():none):T):T;
 
The exit[_value][_continue] constructs support evaluating a block
  of code (the body closure), breaking out of it if the break closure
  is evaluated inside body. The _value versions return a
  value.  The _continue versions allows body to be
  restarted from the beginning when the continue closure is evaluated.
For example, to execute some code, but perhaps quit early:
     exit(&(break:&():none){
        ...
        if(..., { eval(break) }); - skip the rest of the body of exit
        ...
        - fall off bottom
    });
This idiom supports breaking out of any sort of looping or non-looping
  piece of code: just wrap the thing in an exit or exit_value control
  structure and invoke the break block where the control structure should be
  exited.
 method loop_exit(c:&(exit:&():none):void):void;
method loop_exit_value(c:&(exit:&(`T):none):void):T;
method loop_exit_continue(c:&(exit:&():none, continue:&():none):void):void;
method loop_exit_value_continue(c:&(exit:&(`T):none, continue:&():none):void):T;
method loop_continue(c:&(continue:&():none):void):void;
 
For loops, some additional methods are defined for convenience.
The loop[_exit[_value]][_continue] methods evaluate the body closure
  again and again until the break closure is evaluated inside
  body. For the _continue version, execution of body can be restarted
  from the beginning by evaluating the continue closure. The _value
  version returns a value.
To write a simple loop with a break statement:
     loop_exit(&(break:&():none){
        ...
        if(..., { eval(break) }); - exit loop conditionally
        ...
        - loop
    });
To loop and compute a value:
     let result:int := loop_exit_value(&(break:&(int):none){
        ...
        if(..., { eval(break, theResult) }); - exit loop, returning theResult
        ...
    });
If both break and continue are desired for an arbitrary iterating
  construct, such as do, two exit methods should be used, as in the
  following example. The outer method encloses the iterator and
  provides breaking out of the loop, while the inner method encloses
  the loop body and provides continuing to the next iteration:
   exit(&(break:&():none){
      10.do(&(i:int){                - for i := 0 to 10-1 do
          exit(&(continue:&():none){
              ...
              if(..., break);        - break out of loop
              ...
              if(..., continue);     - continue the iteration by jumping
                                     - to the end of the loop body
              ...
          });
      });
  });
 template object case_pair[T];
  extend type case_pair[`T] subtypes case_pair[`S >= T];
  field cond(@:case_pair[`T]):&():bool;
  field stmt(@:case_pair[`T]):&():T;
method case(c:&():bool, s:&():`T):case_pair[T];
method else(s:&():`T):case_pair[T];
method switch(t@:ordered_collection[case_pair[`T]]):T;
method unrolled_switch(t@:i_vector[case_pair[`T]]):T;
 
Case statements are supported through the switch, case, and else
  methods.  The elements of switch's argument collection (usually a
  vector literal expression) are evaluated in turn, until one of the
  test blocks evaluates to true or the else case is found. Then the
  corresponding do block is evaluated and its result returned as the
  result of the switch method. (Thus switch is very much like Lisp's
  cond.) The switch method dies with a run-time error if none of the
  cases match and there is no else case. To illustrate:
     let result:string :=
      switch([case({ x < 0 }, { "negative" }),
              case({ x = 0 }, { "zero" }),
              else(           { "positive" })]);
Unfortunately, unlike most Cecil control structures, the switch construct
  is not as efficient as the C version: a vector object is created and
  filled in with objects containing real closures, and a bunch of
  messages get sent. So you might wish to use chained if expressions
  instead of switch expressions in the most time-critical parts of
  your program. (Recently, some optimizations have been implemented
  that often transform switch statements of this form into an
  if-then-else chain, but only if you invoke unrolled_switch instead
  of switch, and object creations still remain unless debug_support is
  disabled.)
There's an inconsistency between the closure representation and closure
types, however.  The closure representation is not parameterized, but
closure types (using the &(...):... syntax) effectively are
parameterized by the closure's argument and result types.  The closure
representation should be parameterized, too. The language defines the
standard contravariant subtyping relationship among closure types, i.e.:
  extend &(T1, ..., TN):T subtypes &(`S1 >= T1, ..., `SN >= TN):(`S <= T)
 
 
 
 
 
  
 
 
 Next: Exception handling
 Up: Control structures
 Previous: Booleans and branching
     Index 
Cecil/Vortex Project