Index: benchmark/ctxswitch/cfa_cor.cfa
===================================================================
--- benchmark/ctxswitch/cfa_cor.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ benchmark/ctxswitch/cfa_cor.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -7,5 +7,5 @@
 void main( __attribute__((unused)) C & ) {
 	while () {
-		suspend();
+		suspend;
 	}
 }
Index: libcfa/prelude/builtins.c
===================================================================
--- libcfa/prelude/builtins.c	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ libcfa/prelude/builtins.c	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -48,4 +48,28 @@
 void exit( int status, const char fmt[], ... ) __attribute__ (( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
 void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
+
+forall(dtype T)
+static inline T & identity(T & i) {
+	return i;
+}
+
+// generator support
+struct $generator {
+	inline int;
+};
+
+static inline void  ?{}($generator & this) { ((int&)this) = 0; }
+static inline void ^?{}($generator &) {}
+
+trait is_generator(dtype T) {
+      void main(T & this);
+      $generator * get_generator(T & this);
+};
+
+forall(dtype T | is_generator(T))
+static inline T & resume(T & gen) {
+	main(gen);
+	return gen;
+}
 
 // implicit increment, decrement if += defined, and implicit not if != defined
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -208,5 +208,5 @@
 
 		if(cor->state == Primed) {
-			suspend();
+			__cfactx_suspend();
 		}
 
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ libcfa/src/concurrency/coroutine.hfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -46,9 +46,4 @@
 //-----------------------------------------------------------------------------
 // Public coroutine API
-static inline void suspend(void);
-
-forall(dtype T | is_coroutine(T))
-static inline T & resume(T & cor);
-
 forall(dtype T | is_coroutine(T))
 void prime(T & cor);
@@ -96,22 +91,24 @@
 
 // Suspend implementation inlined for performance
-static inline void suspend(void) {
-	// optimization : read TLS once and reuse it
-	// Safety note: this is preemption safe since if
-	// preemption occurs after this line, the pointer
-	// will also migrate which means this value will
-	// stay in syn with the TLS
-	$coroutine * src = TL_GET( this_thread )->curr_cor;
+extern "C" {
+	static inline void __cfactx_suspend(void) {
+		// optimization : read TLS once and reuse it
+		// Safety note: this is preemption safe since if
+		// preemption occurs after this line, the pointer
+		// will also migrate which means this value will
+		// stay in syn with the TLS
+		$coroutine * src = TL_GET( this_thread )->curr_cor;
 
-	assertf( src->last != 0,
-		"Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
-		"Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
-		src->name, src );
-	assertf( src->last->state != Halted,
-		"Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
-		"Possible cause is terminated coroutine's main routine has already returned.",
-		src->name, src, src->last->name, src->last );
+		assertf( src->last != 0,
+			"Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
+			"Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
+			src->name, src );
+		assertf( src->last->state != Halted,
+			"Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
+			"Possible cause is terminated coroutine's main routine has already returned.",
+			src->name, src, src->last->name, src->last );
 
-	$ctx_switch( src, src->last );
+		$ctx_switch( src, src->last );
+	}
 }
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/AST/Decl.hpp	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -259,6 +259,7 @@
 
 	bool is_coroutine() { return kind == Coroutine; }
-	bool is_monitor() { return kind == Monitor; }
-	bool is_thread() { return kind == Thread; }
+	bool is_generator() { return kind == Generator; }
+	bool is_monitor  () { return kind == Monitor  ; }
+	bool is_thread   () { return kind == Thread   ; }
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/Concurrency/Keywords.cc	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -16,21 +16,22 @@
 #include "Concurrency/Keywords.h"
 
-#include <cassert>                 // for assert
-#include <string>                  // for string, operator==
-
-#include "Common/PassVisitor.h"    // for PassVisitor
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/utility.h"        // for deleteAll, map_range
-#include "CodeGen/OperatorTable.h" // for isConstructor
-#include "InitTweak/InitTweak.h"   // for getPointerBase
-#include "SynTree/LinkageSpec.h"   // for Cforall
-#include "SynTree/Constant.h"      // for Constant
-#include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
-#include "SynTree/Expression.h"    // for VariableExpr, ConstantExpr, Untype...
-#include "SynTree/Initializer.h"   // for SingleInit, ListInit, Initializer ...
-#include "SynTree/Label.h"         // for Label
-#include "SynTree/Statement.h"     // for CompoundStmt, DeclStmt, ExprStmt
-#include "SynTree/Type.h"          // for StructInstType, Type, PointerType
-#include "SynTree/Visitor.h"       // for Visitor, acceptAll
+#include <cassert>                        // for assert
+#include <string>                         // for string, operator==
+
+#include "Common/PassVisitor.h"           // for PassVisitor
+#include "Common/SemanticError.h"         // for SemanticError
+#include "Common/utility.h"               // for deleteAll, map_range
+#include "CodeGen/OperatorTable.h"        // for isConstructor
+#include "ControlStruct/LabelGenerator.h" // for LebelGenerator
+#include "InitTweak/InitTweak.h"          // for getPointerBase
+#include "SynTree/LinkageSpec.h"          // for Cforall
+#include "SynTree/Constant.h"             // for Constant
+#include "SynTree/Declaration.h"          // for StructDecl, FunctionDecl, ObjectDecl
+#include "SynTree/Expression.h"           // for VariableExpr, ConstantExpr, Untype...
+#include "SynTree/Initializer.h"          // for SingleInit, ListInit, Initializer ...
+#include "SynTree/Label.h"                // for Label
+#include "SynTree/Statement.h"            // for CompoundStmt, DeclStmt, ExprStmt
+#include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
+#include "SynTree/Visitor.h"              // for Visitor, acceptAll
 
 class Attribute;
@@ -147,4 +148,6 @@
 	};
 
+
+
 	//-----------------------------------------------------------------------------
 	//Handles monitor type declarations :
@@ -180,4 +183,75 @@
 
 	//-----------------------------------------------------------------------------
+	//Handles generator type declarations :
+	// generator MyGenerator {                   struct MyGenerator {
+	// 	int data;                                  int data;
+	// 	a_struct_t more_data;                      a_struct_t more_data;
+	//                                =>             int __gen_next;
+	// };                                        };
+	//
+	class GeneratorKeyword final : public ConcurrentSueKeyword {
+	  public:
+
+	  	GeneratorKeyword() : ConcurrentSueKeyword(
+			"$generator",
+			"__generator_state",
+			"get_generator",
+			"Unable to find builtin type $generator\n",
+			true,
+			AggregateDecl::Generator
+		)
+		{}
+
+		virtual ~GeneratorKeyword() {}
+
+		virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
+
+		static void implement( std::list< Declaration * > & translationUnit ) {
+			PassVisitor< GeneratorKeyword > impl;
+			mutateAll( translationUnit, impl );
+		}
+	};
+
+
+	//-----------------------------------------------------------------------------
+	class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
+	public:
+		SuspendKeyword() = default;
+		virtual ~SuspendKeyword() = default;
+
+		void  premutate( FunctionDecl * );
+		DeclarationWithType * postmutate( FunctionDecl * );
+
+		Statement * postmutate( SuspendStmt * );
+
+		static void implement( std::list< Declaration * > & translationUnit ) {
+			PassVisitor< SuspendKeyword > impl;
+			mutateAll( translationUnit, impl );
+		}
+
+	private:
+		DeclarationWithType * is_main( FunctionDecl * );
+		bool is_real_suspend( FunctionDecl * );
+
+		Statement * make_generator_suspend( SuspendStmt * );
+		Statement * make_coroutine_suspend( SuspendStmt * );
+
+		struct LabelPair {
+			Label obj;
+			int   idx;
+		};
+
+		LabelPair make_label() {
+			labels.push_back( gen.newLabel("generator") );
+			return { labels.back(), int(labels.size()) };
+		}
+
+		DeclarationWithType * in_generator = nullptr;
+		FunctionDecl * decl_suspend = nullptr;
+		std::vector<Label> labels;
+		ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
+	};
+
+	//-----------------------------------------------------------------------------
 	//Handles mutex routines definitions :
 	// void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
@@ -251,4 +325,6 @@
 		CoroutineKeyword	::implement( translationUnit );
 		MonitorKeyword	::implement( translationUnit );
+		GeneratorKeyword  ::implement( translationUnit );
+		SuspendKeyword    ::implement( translationUnit );
 	}
 
@@ -446,7 +522,236 @@
 
 		declsToAddAfter.push_back( get_decl );
-
-		// get_decl->fixUniqueId();
-	}
+	}
+
+	//=============================================================================================
+	// Suspend keyword implementation
+	//=============================================================================================
+	DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) {
+		if(func->name != "main") return nullptr;
+		if(func->type->parameters.size() != 1) return nullptr;
+
+		auto param = func->type->parameters.front();
+
+		auto type  = dynamic_cast<ReferenceType * >(param->get_type());
+		if(!type) return nullptr;
+
+		auto obj   = dynamic_cast<StructInstType *>(type->base);
+		if(!obj) return nullptr;
+
+		if(!obj->baseStruct->is_generator()) return nullptr;
+
+		return param;
+	}
+
+	bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
+		if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
+		if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
+		if(func->type->parameters.size() != 0) return false; // Too many parameters
+		if(func->type->returnVals.size() != 0) return false; // Too many return values
+
+		return true;
+	}
+
+	void SuspendKeyword::premutate( FunctionDecl * func ) {
+		GuardValue(in_generator);
+		in_generator = nullptr;
+
+		// Is this the real suspend?
+		if(is_real_suspend(func)) {
+			decl_suspend = decl_suspend ? decl_suspend : func;
+			return;
+		}
+
+		// Is this the main of a generator?
+		auto param = is_main( func );
+		if(!param) return;
+
+		if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
+
+		in_generator = param;
+		GuardValue(labels);
+		labels.clear();
+	}
+
+	DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
+		if( !func->statements ) return func; // Not the actual definition, don't do anything
+		if( !in_generator     ) return func; // Not in a generator, don't do anything
+		if( labels.empty()    ) return func; // Generator has no states, nothing to do, could throw a warning
+
+		// This is a generator main, we need to add the following code to the top
+		// static void * __generator_labels[] = {&&s0, &&s1, ...};
+		// goto * __generator_labels[gen.__generator_state];
+		const auto & loc = func->location;
+
+		const auto first_label = gen.newLabel("generator");
+
+		// for each label add to declaration
+		std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
+		for(const auto & label : labels) {
+			inits.push_back(
+				new SingleInit(
+					new LabelAddressExpr( label )
+				)
+			);
+		}
+		auto init = new ListInit(std::move(inits), noDesignators, true);
+		labels.clear();
+
+		// create decl
+		auto decl = new ObjectDecl(
+			"__generator_labels",
+			Type::StorageClasses( Type::Static ),
+			LinkageSpec::AutoGen,
+			nullptr,
+			new ArrayType(
+				Type::Qualifiers(),
+				new PointerType(
+					Type::Qualifiers(),
+					new VoidType( Type::Qualifiers() )
+				),
+				nullptr,
+				false, false
+			),
+			init
+		);
+
+		// create the goto
+		assert(in_generator);
+
+		auto go_decl = new ObjectDecl(
+			"__generator_label",
+			noStorageClasses,
+			LinkageSpec::AutoGen,
+			nullptr,
+			new PointerType(
+				Type::Qualifiers(),
+				new VoidType( Type::Qualifiers() )
+			),
+			new SingleInit(
+				new UntypedExpr(
+					new NameExpr("?[?]"),
+					{
+						new NameExpr("__generator_labels"),
+						new UntypedMemberExpr(
+							new NameExpr("__generator_state"),
+							new VariableExpr( in_generator )
+						)
+					}
+				)
+			)
+		);
+		go_decl->location = loc;
+
+		auto go = new BranchStmt(
+			new VariableExpr( go_decl ),
+			BranchStmt::Goto
+		);
+		go->location = loc;
+		go->computedTarget->location = loc;
+
+		auto noop = new NullStmt({ first_label });
+		noop->location = loc;
+
+		// wrap everything in a nice compound
+		auto body = new CompoundStmt({
+			new DeclStmt( decl ),
+			new DeclStmt( go_decl ),
+			go,
+			noop,
+			func->statements
+		});
+		body->location   = loc;
+		func->statements = body;
+
+		return func;
+	}
+
+	Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
+		SuspendStmt::Type type = stmt->type;
+		if(type == SuspendStmt::None) {
+			// This suspend has a implicit target, find it
+			type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
+		}
+
+		// Check that the target makes sense
+		if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
+
+		// Act appropriately
+		switch(type) {
+			case SuspendStmt::Generator: return make_generator_suspend(stmt);
+			case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
+			default: abort();
+		}
+	}
+
+	Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
+		assert(in_generator);
+		// Target code is :
+		//   gen.__generator_state = X;
+		//   { THEN }
+		//   return;
+		//   __gen_X:;
+
+		// Save the location and delete the old statement, we only need the location from this point on
+		auto loc = stmt->location;
+
+		// Build the label and get its index
+		auto label = make_label();
+
+		// Create the context saving statement
+		auto save = new ExprStmt( new UntypedExpr(
+			new NameExpr( "?=?" ),
+			{
+				new UntypedMemberExpr(
+					new NameExpr("__generator_state"),
+					new VariableExpr( in_generator )
+				),
+				new ConstantExpr(
+					Constant::from_int( label.idx )
+				)
+			}
+		));
+		assert(save->expr);
+		save->location = loc;
+		stmtsToAddBefore.push_back( save );
+
+		// if we have a then add it here
+		auto then = stmt->then;
+		stmt->then = nullptr;
+		delete stmt;
+		if(then) stmtsToAddBefore.push_back( then );
+
+		// Create the return statement
+		auto ret = new ReturnStmt( nullptr );
+		ret->location = loc;
+		stmtsToAddBefore.push_back( ret );
+
+		// Create the null statement with the created label
+		auto noop = new NullStmt({ label.obj });
+		noop->location = loc;
+
+		// Return the null statement to take the place of the previous statement
+		return noop;
+	}
+
+	Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
+		if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
+
+		// Save the location and delete the old statement, we only need the location from this point on
+		auto loc = stmt->location;
+		delete stmt;
+
+		// Create the call expression
+		if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
+		auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
+		expr->location = stmt->location;
+
+		// Change this statement into a regular expr
+		assert(expr);
+		auto nstmt = new ExprStmt( expr );
+		nstmt->location = stmt->location;
+		return nstmt;
+	}
+
 
 	//=============================================================================================
Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/GenPoly/Lvalue.cc	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -140,9 +140,15 @@
 		PassVisitor<FixIntrinsicResult> intrinsicResults;
 		mutateAll( translationUnit, intrinsicResults );
+		translationUnit.back()->print( std::cout );
 		mutateAll( translationUnit, addrRef );
+		translationUnit.back()->print( std::cout );
 		mutateAll( translationUnit, refCvt );
+		translationUnit.back()->print( std::cout );
 		mutateAll( translationUnit, fixer );
+		translationUnit.back()->print( std::cout );
 		mutateAll( translationUnit, collapser );
+		translationUnit.back()->print( std::cout );
 		mutateAll( translationUnit, genLval );
+		translationUnit.back()->print( std::cout );
 		mutateAll( translationUnit, elim );  // last because other passes need reference types to work
 
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/Parser/ParseNode.h	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -428,4 +428,5 @@
 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
 Statement * build_directive( std::string * directive );
+SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/Parser/StatementNode.cc	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -249,4 +249,19 @@
 } // build_finally
 
+SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {
+	auto node = new SuspendStmt();
+
+	node->type = type;
+
+	std::list< Statement * > stmts;
+	buildMoveList< Statement, StatementNode >( then, stmts );
+	if(!stmts.empty()) {
+		assert( stmts.size() == 1 );
+		node->then = dynamic_cast< CompoundStmt * >( stmts.front() );
+	}
+
+	return node;
+}
+
 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
 	auto node = new WaitForStmt();
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/Parser/TypeData.cc	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -769,4 +769,5 @@
 	  case AggregateDecl::Struct:
 	  case AggregateDecl::Coroutine:
+	  case AggregateDecl::Generator:
 	  case AggregateDecl::Monitor:
 	  case AggregateDecl::Thread:
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/Parser/parser.yy	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -1261,15 +1261,15 @@
 		{ SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
 	| SUSPEND ';'
-	  	{ SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_suspend( nullptr ) ); }
 	| SUSPEND compound_statement ';'
-	  	{ SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_suspend( $2 ) ); }
 	| SUSPEND COROUTINE ';'
-	  	{ SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
 	| SUSPEND COROUTINE compound_statement
-	  	{ SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
 	| SUSPEND GENERATOR ';'
-	  	{ SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
 	| SUSPEND GENERATOR compound_statement
-	  	{ SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
 	| THROW assignment_expression_opt ';'				// handles rethrow
 		{ $$ = new StatementNode( build_throw( $2 ) ); }
@@ -2086,5 +2086,5 @@
 aggregate_control:										// CFA
 	GENERATOR
-		{ SemanticError( yylloc, "generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
+		{ yyy = true; $$ = AggregateDecl::Generator; }
 	| MONITOR GENERATOR
 		{ SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/SynTree/Declaration.h	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -302,6 +302,7 @@
 
 	bool is_coroutine() { return kind == Coroutine; }
-	bool is_monitor() { return kind == Monitor; }
-	bool is_thread() { return kind == Thread; }
+	bool is_generator() { return kind == Generator; }
+	bool is_monitor  () { return kind == Monitor  ; }
+	bool is_thread   () { return kind == Thread   ; }
 
 	virtual StructDecl * clone() const override { return new StructDecl( *this ); }
Index: src/SynTree/Statement.h
===================================================================
--- src/SynTree/Statement.h	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ src/SynTree/Statement.h	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -425,5 +425,5 @@
   public:
 	CompoundStmt * then = nullptr;
-	enum { None, Coroutine, Generator } type = None;
+	enum Type { None, Coroutine, Generator } type = None;
 
 	SuspendStmt() = default;
Index: tests/concurrent/coroutineThen.cfa
===================================================================
--- tests/concurrent/coroutineThen.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/concurrent/coroutineThen.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -49,14 +49,13 @@
 
 void main(Coroutine& this) {
-	suspend();
+	suspend;
 	for(int i = 0; TEST(i < N); i++) {
 
 		print("C - Suspending");
-		void publish() {
+		suspend{
 			print("C - Publishing");
 			assert(!the_cor);
 			store( this );
 		}
-		suspend_then(publish);
 		assert(!the_cor);
 		print("Coroutine 2");
@@ -65,5 +64,5 @@
 	}
 	done = true;
-	suspend();
+	suspend;
 }
 
Index: tests/concurrent/coroutineYield.cfa
===================================================================
--- tests/concurrent/coroutineYield.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/concurrent/coroutineYield.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -33,5 +33,5 @@
 			sout | "Coroutine 2";
 		#endif
-		suspend();
+		suspend;
 	}
 }
Index: tests/coroutine/.in/fmtLines.txt
===================================================================
--- tests/coroutine/.in/fmtLines.txt	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/.in/fmtLines.txt	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -35,5 +35,5 @@
 			for ( fmt.b = 0; fmt.b < 4; fmt.b += 1 ) {	// blocks of 4 characters
 				for ( ;; ) {							// for newline characters
-					suspend();
+					suspend;
 					if ( fmt.ch != '\n' ) break;		// ignore newline
 				} // for
Index: tests/coroutine/cntparens.cfa
===================================================================
--- tests/coroutine/cntparens.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/cntparens.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -1,10 +1,10 @@
-// 
+//
 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
 //
 // The contents of this file are covered under the licence agreement in the
 // file "LICENCE" distributed with Cforall.
-// 
+//
 // cntparens.cfa -- match left/right parenthesis
-// 
+//
 // Author           : Peter A. Buhr
 // Created On       : Sat Apr 20 11:04:45 2019
@@ -12,5 +12,5 @@
 // Last Modified On : Sat Apr 20 11:06:21 2019
 // Update Count     : 1
-// 
+//
 
 #include <fstream.hfa>
@@ -26,12 +26,12 @@
 void main( CntParens & cpns ) with( cpns ) {
 	for ( ; ch == '('; cnt += 1 ) {						// left parenthesis
-		suspend();
+		suspend;
 	}
 	for ( ; ch == ')' && cnt > 1; cnt -= 1 ) {			// right parenthesis
-		suspend();
+		suspend;
 	}
 	status = ch == ')' ? Match : Error;
 } // main
-	
+
 void ?{}( CntParens & cpns ) with( cpns ) { status = Cont; cnt = 0; }
 
Index: tests/coroutine/devicedriver.cfa
===================================================================
--- tests/coroutine/devicedriver.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/devicedriver.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -1,10 +1,10 @@
-// 
+//
 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
 //
 // The contents of this file are covered under the licence agreement in the
 // file "LICENCE" distributed with Cforall.
-// 
-// devicedriver.cfa -- 
-// 
+//
+// devicedriver.cfa --
+//
 // Author           : Peter A. Buhr
 // Created On       : Sat Mar 16 15:30:34 2019
@@ -12,5 +12,5 @@
 // Last Modified On : Sat Apr 20 09:07:19 2019
 // Update Count     : 90
-// 
+//
 
 #include <fstream.hfa>
@@ -29,7 +29,7 @@
 
 void checkCRC( Driver & d, unsigned int sum ) with( d ) {
-	suspend();
+	suspend;
 	unsigned short int crc = byte << 8;					// sign extension over written
-	suspend();
+	suspend;
 	// prevent sign extension for signed char
 	status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
@@ -41,17 +41,17 @@
 		status = CONT;
 		unsigned int lnth = 0, sum = 0;
-		while ( byte != STX ) suspend();
+		while ( byte != STX ) suspend;
 	  emsg: for () {
-			suspend();
+			suspend;
 			choose ( byte ) {							// process byte
 			  case STX:
-				status = ESTX; suspend(); continue msg;
+				status = ESTX; suspend; continue msg;
 			  case ETX:
 				break emsg;
 			  case ESC:
-				suspend();
+				suspend;
 			} // choose
 			if ( lnth >= MaxMsg ) {						// buffer full ?
-				status = ELNTH; suspend(); continue msg;
+				status = ELNTH; suspend; continue msg;
 			} // if
 			msg[lnth++] = byte;
@@ -60,5 +60,5 @@
 		msg[lnth] = '\0';								// terminate string
 		checkCRC( d, sum );								// refactor CRC check
-		suspend();
+		suspend;
 	} // for
 } // main
Index: tests/coroutine/fibonacci.cfa
===================================================================
--- tests/coroutine/fibonacci.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/fibonacci.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -22,10 +22,10 @@
 	int fn1, fn2;										// retained between resumes
 	fn = 0;  fn1 = fn;									// 1st case
-	suspend();											// restart last resume
+	suspend;											// restart last resume
 	fn = 1;  fn2 = fn1;  fn1 = fn;						// 2nd case
-	suspend();											// restart last resume
+	suspend;											// restart last resume
 	for () {
 		fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;			// general case
-		suspend();										// restart last resume
+		suspend;										// restart last resume
 	} // for
 }
Index: tests/coroutine/fibonacci_1.cfa
===================================================================
--- tests/coroutine/fibonacci_1.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/fibonacci_1.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -12,5 +12,5 @@
 // Last Modified On : Thu Mar 21 08:10:45 2019
 // Update Count     : 25
-// 
+//
 
 #include <fstream.hfa>
@@ -23,5 +23,5 @@
 	[fn1, fn] = [0, 1];									// precompute first two states
 	for () {
-		suspend();										// restart last resume
+		suspend;										// restart last resume
 		[fn1, fn] = [fn, fn1 + fn];						// general case
 	} // for
Index: tests/coroutine/fmtLines.cfa
===================================================================
--- tests/coroutine/fmtLines.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/fmtLines.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -27,5 +27,5 @@
 			for ( b = 0; b < 4; b += 1 ) {				// blocks of 4 characters
 				for () {								// for newline characters
-					suspend();
+					suspend;
 				  if ( ch != '\n' ) break;				// ignore newline
 				} // for
Index: tests/coroutine/raii.cfa
===================================================================
--- tests/coroutine/raii.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/raii.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -39,5 +39,5 @@
 	Raii raii = { "Coroutine" };
 	sout | "Before Suspend";
-	suspend();
+	suspend;
 	sout | "After Suspend";
 }
Index: tests/coroutine/runningTotal.cfa
===================================================================
--- tests/coroutine/runningTotal.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/runningTotal.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -25,5 +25,5 @@
 void update( RunTotal & rntl, int input ) with( rntl ) { // helper
 	total += input;										// remember between activations
-	suspend();											// inactivate on stack
+	suspend;											// inactivate on stack
 }
 
Index: tests/coroutine/suspend_then.cfa
===================================================================
--- tests/coroutine/suspend_then.cfa	(revision 37cdd97f319c512b8374d214748e986930e2e8f8)
+++ tests/coroutine/suspend_then.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -18,5 +18,5 @@
 
 void then() {
-	sout | "Then!";
+
 }
 
@@ -26,10 +26,10 @@
 	int fn1, fn2;								// retained between resumes
 	fn = 0;  fn1 = fn;							// 1st case
-	suspend_then(then);							// restart last resume
+	suspend { sout | "Then!"; }						// restart last resume
 	fn = 1;  fn2 = fn1;  fn1 = fn;					// 2nd case
-	suspend_then(then);							// restart last resume
+	suspend { sout | "Then!"; }						// restart last resume
 	for () {
 		fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;			// general case
-		suspend_then(then);						// restart last resume
+		suspend { sout | "Then!"; }					// restart last resume
 	} // for
 }
Index: tests/generator/.expect/fibonacci.txt
===================================================================
--- tests/generator/.expect/fibonacci.txt	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
+++ tests/generator/.expect/fibonacci.txt	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -0,0 +1,10 @@
+0 0
+1 1
+1 1
+2 2
+3 3
+5 5
+8 8
+13 13
+21 21
+34 34
Index: tests/generator/fibonacci.cfa
===================================================================
--- tests/generator/fibonacci.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
+++ tests/generator/fibonacci.cfa	(revision 427854baeaba2d97cb23623b6d3c3ad7f7b0dbdd)
@@ -0,0 +1,41 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// fibonacci.cfa
+//
+// Author           : Thierry Delisle
+// Created On       : Mon Mar  1 16:54:23 2020
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+generator Fib {
+	int fn1, fn;
+};
+
+void main(Fib & b) with (b) {
+	[fn1, fn] = [1, 0];
+	for () {
+		suspend;
+		[fn1, fn] = [fn, fn + fn1];
+	}
+}
+
+int main() {
+	Fib f1, f2;
+	for ( 10 ) {
+		resume( f1 );
+		resume( f2 );
+		printf("%d %d\n", f1.fn, f2.fn);
+	}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa fibonacci.cfa" //
+// End: //
