#include <thread.hfa>
#include <fstream.hfa>

int fn1, fn2, state = 1;
int fib_gvar() {
	int fn;
	choose ( state ) {
	  case 1: fn = 0;  fn1 = fn;  state = 2;
	  case 2: fn = 1;  fn2 = fn1;  fn1 = fn;  state = 3;
	  case 3: fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;
	}
	return fn;
}

#define FibCtor { 1, 0 }
typedef struct { int fn1, fn; } Fib;
int fib_state( Fib & f ) with(f) {
	int ret = fn; fn = fn1; fn1 = fn + ret;
	return ret;
}

coroutine Fib1 { int fn; };						// used for communication
void main( Fib1 & fib ) with( fib ) {			// called on first resume
	fn = 0;  int fn1 = fn; suspend();
	fn = 1;  int fn2 = fn1;  fn1 = fn; suspend();
	for () {
		fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn; suspend();
	}
}
int ?()( Fib1 & fib ) with( fib ) { return resume( fib ).fn; }

coroutine Fib2 { int fn; };						// used for communication
void main( Fib2 & fib ) with( fib ) {			// called on first resume
	int fn1;									// precompute first two states
	[fn1, fn] = [1, 0];
	for () {
		suspend();								// restart last resume
		[fn1, fn] = [fn, fn + fn1];
	}
}
int ?()( Fib2 & fib ) {							// function-call interface
	return resume( fib ).fn;					// restart last suspend
}
int ?()( Fib2 & fib, int N ) {					// skip N values
	for ( N - 1 ) fib();						// use function-call interface
	return fib();
}
double ?()( Fib2 & fib ) {						// different return type
	return (int)(fib()) / 3.14159;				// cast prevents recursive call
}

int main() {
	for ( 10 )
		sout | fib_gvar();
	sout | nl;

	Fib f1 = FibCtor, f2 = FibCtor;
	for ( 10 )
		sout | fib_state( f1 ) | fib_state( f2 );
	sout | nl;

	Fib1 f1, f2;
	for ( 10 )
		sout | f1() | f2();
	sout | nl;

	Fib2 f12, f22;
	for ( 10 )
		sout | (int)f12() | (double)f12() | f22( 2 );
}

// Local Variables: //
// tab-width: 4 //
// fill-column: 120 //
// compile-command: "cfa Fib.cfa" //
// End: //
