Package: src/packages/control.fdoc

Control Basics

key file
__init__.flx share/lib/std/control/__init__.flx
control.flx share/lib/std/control/control.flx

Control Synopsis

//[__init__.flx]
// stream is part of datatype, included in std/datatype/__init__
include "std/control/svc";
include "std/control/control";
include "std/control/unique";
include "std/control/iterator";
include "std/control/schannels";
include "std/control/fibres";
include "std/control/spipes";
include "std/control/chips";

//include "std/control/mux";

Misc Control Flow

//[control.flx]
open class Control
{
  open C_hack;

  // FIXPOINT OPERATOR
  fun fix[D,C] (f:(D->C)->D->C) (x:D) : C => f (fix f) x;

  /* Example use: factorial function
  fun flat_fact (g:int->int) (x:int):int =>
    if x == 0 then 1
    else x * g (x - 1)
  ;
  var fact = fix flat_fact;
  println$ fact 5;
  */

  proc _swap[t] (a:&t,b:&t) =
  {
    var tmp = *a;
    a <- *b;
    b <- tmp;
  }
  proc swap[t] (a:&t,b:&t) => _swap(a,b);

  //$ infinite loop
  proc forever (bdy:unit->void)
  {
    rpeat:>
      bdy();
      goto rpeat;
    dummy:> // fool reachability checker
  }

  publish "do nothing [the name pass comes from Python]"
  proc pass(){}

  //$ C style for loop
  proc for_each
    (init:unit->void)
    (cond:unit->bool)
    (incr:unit->void)
    (bdy:unit->void)
  {
    init();
    rpeat:>
      if not (cond()) goto finish;
      bdy();
      incr();
      goto rpeat;
    finish:>
  }

  proc branch-and-link (target:&LABEL, save:&LABEL)
  {
     save <- next;
     goto *target;
     next:>
  }

  //$ throw[ret, exn] throw exception of type exn
  //$ in a context expecting type ret.
  gen throw[ret,exn] : exn -> ret = "(throw $1,*(?1*)0)";
  proc raise[exn] : exn = "(throw $1);";
  proc proc_fail:string = 'throw ::std::runtime_error($1);'
    requires Cxx_headers::stdexcept;

  // Note: must be a fun not a gen to avoid lifting.
  fun fun_fail[ret]:string -> ret = '(throw ::std::runtime_error($1),*(?1*)0)'
    requires Cxx_headers::stdexcept;

  //$ This is the type of a Felix procedural
  //$ continuations in C++ lifted into Felix.
  //$ Do not confuse this with the Felix type of the procedure.
  _gc_pointer type cont = "::flx::rtl::con_t*";

  fun entry_label : cont -> LABEL = "::flx::rtl::jump_address_t($1)";
  fun current_position : cont -> LABEL = "::flx::rtl::jump_address_t($1,$1->pc)";
  fun entry_label[T] (p:T->0):LABEL => entry_label (C_hack::cast[cont] p);

  //$ This is a hack to get the procedural continuation
  //$ currently executing, it is just the procedures
  //$ C++ this pointer.
  fun current_continuation: unit -> cont = "this";

  //$ The type of a Felix fthread or fibre, which is
  //$ a container which holds a procedural continuation.
  _gc_pointer type fthread = "::flx::rtl::fthread_t*";


  //$  Throw a continuation. This is unsafe. It should
  //$  work from a top level procedure, or any function
  //$  called by such a procedure, but may fail
  //$  if thrown from a procedure called by a function.
  //$  The library run and driver will catch the
  //$  continuation and execute it instead of the
  //$  current continuation. If the library run is used
  //$  and the continuation being executed is down the
  //$  C stack, the C stack will not have been correctly
  //$  popped. Crudely, nested drivers should rethrow
  //$  the exception until the C stack is in the correct
  //$  state to execute the continuation, but there is no
  //$  way to determine that at the moment.
  //$
  //$  Compiler generated runs ignore the exception,
  //$  the library run catches it. Exceptions typically
  //$  use a non-local goto, and they cannot pass across
  //$  a function boundary.

  proc throw_continuation(x: unit->void) { _throw (C_hack::cast[cont] x); }
  private proc _throw: cont = "throw $1;";

  //$ Type of the implementation of a  synchronous channel.
  //$ should be private but needed in this class for the data type,
  //$ and also needed in schannels to do the svc call.

  _gc_pointer type _schannel = "::flx::rtl::schannel_t*";

}