Index: src/Concurrency/Waitfor.cc
===================================================================
--- src/Concurrency/Waitfor.cc	(revision 9939dc312f9fd40e9451c8c3c70ac5e68e233d16)
+++ src/Concurrency/Waitfor.cc	(revision c8f5f7df666774630b5067e75d046946bfe8cddf)
@@ -56,5 +56,5 @@
                       |  |
                       |  |
-			    |  |
+                      |  |
                       |  |
                       |  |
Index: src/Concurrency/Waitfor.h
===================================================================
--- src/Concurrency/Waitfor.h	(revision 9939dc312f9fd40e9451c8c3c70ac5e68e233d16)
+++ src/Concurrency/Waitfor.h	(revision c8f5f7df666774630b5067e75d046946bfe8cddf)
@@ -19,7 +19,12 @@
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace Concurrency {
 	void generateWaitFor( std::list< Declaration * > & translationUnit );
+
+void generateWaitFor( ast::TranslationUnit & translationUnit );
 };
 
Index: src/Concurrency/WaitforNew.cpp
===================================================================
--- src/Concurrency/WaitforNew.cpp	(revision c8f5f7df666774630b5067e75d046946bfe8cddf)
+++ src/Concurrency/WaitforNew.cpp	(revision c8f5f7df666774630b5067e75d046946bfe8cddf)
@@ -0,0 +1,580 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// WaitforNew.cpp -- Expand waitfor clauses into code.
+//
+// Author           : Andrew Beach
+// Created On       : Fri May 27 10:31:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jun 13 13:30:00 2022
+// Update Count     : 0
+//
+
+#include "Waitfor.h"
+
+#include <string>
+
+#include "AST/Pass.hpp"
+#include "Common/UniqueName.h"
+#include "InitTweak/InitTweak.h"
+#include "ResolvExpr/Resolver.h"
+
+#include "AST/Print.hpp"
+
+using namespace std::string_literals;
+using ResolvExpr::ResolveContext;
+
+/* So this is what this file dones:
+
+void f(int i, float f, A & mutex b, struct foo *  );
+void f(int );
+
+...{
+	when ( a < 1 ) waitfor( f : a ) { fee(); }
+	or timeout( getWaitTime() ) { fy(); }
+	or waitfor( g : a ) { foe(); }
+	or waitfor( ^?{} : a ) { break; }
+	or waitfor( ^?{} ) { break; }
+	or when ( a < 1 ) else { fum(); }
+}...
+
+		 ||
+		 ||
+		\||/
+		 \/
+
+...{
+	{
+		__acceptable_t __acceptables_#[4 <num-clauses>];
+		bool __do_run_# = false;
+
+		monitor$ * __monitors_#[1 <num-monitors>] = { a };
+		if ( a < 1) {
+			void (*__function_#)() = <casts> f;
+			__acceptables_#[0].is_dtor = false;
+			__acceptables_#[0].func = __function_#;
+			__acceptables_#[0].data = __monitors_#;
+			__acceptables_#[0].size = 1;
+			__do_run_# = true;
+		}
+
+		// Remaining waitfor clauses go here.
+
+		long long unsigned int __timeout_# = -1;
+		if ( true ) {
+			__timeout_# = getWaitTime();
+			__do_run_# = true;
+		}
+
+		if ( a < 1 ) {
+			__timeout_# = 0
+			__do_run_# = true;
+		}
+
+		short int __index_# = -1;
+		__waitfor_mask_t __mask_# = {&__index_#, {__acceptables_#, ?}};
+		__waitfor_internal((__waitfor_mask_t&)__mask_#, __timeout_#);
+
+		switch (__index_#) {
+		case 0:
+			{ { fee(); } break; }
+		case 1:
+			{ { foe(); } break; }
+		case 2:
+			{ <modified-break> break; }
+		case 3:
+			{ <modified-break> break; }
+		case -2:
+			{ { fy(); } break; }
+		case -1:
+			{ { foe(); } break; }
+		}
+	}
+}...
+*/
+
+namespace Concurrency {
+
+namespace {
+
+class GenerateWaitForCore :
+		public ast::WithSymbolTable, public ast::WithConstTranslationUnit {
+	const ast::FunctionDecl * decl_waitfor    = nullptr;
+	const ast::StructDecl   * decl_mask       = nullptr;
+	const ast::StructDecl   * decl_acceptable = nullptr;
+	const ast::StructDecl   * decl_monitor    = nullptr;
+
+	UniqueName namer_acc = "__acceptables_"s;
+	UniqueName namer_idx = "__index_"s;
+	UniqueName namer_flg = "__do_run_"s;
+	UniqueName namer_msk = "__mask_"s;
+	UniqueName namer_mon = "__monitors_"s;
+	UniqueName namer_tim = "__timeout_"s;
+	UniqueName namer_fun = "__function_"s;
+
+	ast::ObjectDecl * declareAcceptables( ast::CompoundStmt * out,
+		const CodeLocation & location, unsigned long numClauses );
+	ast::ObjectDecl * declareFlag(
+		ast::CompoundStmt * out, const CodeLocation & location );
+	ast::ExprStmt * makeSetter(
+		const CodeLocation & location, ast::ObjectDecl * flag );
+	ast::ObjectDecl * declMonitors(
+		ast::CompoundStmt * out, const ast::WaitForClause * clause );
+	void init_clause( ast::CompoundStmt * out, ast::ObjectDecl * acceptables,
+		int index, const ast::WaitForClause * clause, ast::Stmt * setter );
+	ast::Expr * init_timeout(
+		ast::CompoundStmt * out, const CodeLocation & topLocation,
+		const ast::Expr * timeout_time, const ast::Expr * timeout_cond,
+		const ast::Stmt * else_stmt, const ast::Expr * else_cond,
+		const ast::Stmt * setter );
+	ast::Expr * call(
+		ast::CompoundStmt * out, const CodeLocation & location,
+		size_t numClauses, ast::ObjectDecl * acceptables,
+		ast::Expr * timeout );
+public:
+	void previsit( const ast::FunctionDecl * decl );
+	void previsit( const ast::StructDecl * decl );
+	ast::Stmt * postvisit( const ast::WaitForStmt * stmt );
+};
+
+ast::Expr * makeOpIndex( const CodeLocation & location,
+		const ast::DeclWithType * array, unsigned long index ) {
+	return new ast::UntypedExpr( location,
+		new ast::NameExpr( location, "?[?]" ),
+		{
+			new ast::VariableExpr( location, array ),
+			ast::ConstantExpr::from_ulong( location, index ),
+		}
+	);
+}
+
+ast::Expr * makeOpAssign( const CodeLocation & location,
+		const ast::Expr * lhs, const ast::Expr * rhs ) {
+	return new ast::UntypedExpr( location,
+		new ast::NameExpr( location, "?=?" ),
+		{ lhs, rhs }
+	);
+}
+
+ast::Expr * makeOpMember( const CodeLocation & location,
+		const std::string & mem, const ast::Expr * sue ) {
+	return new ast::UntypedMemberExpr( location,
+		new ast::NameExpr( location, mem ),
+		sue
+	);
+}
+
+ast::Stmt * makeAccStmt(
+		const CodeLocation & location, ast::DeclWithType * object,
+		unsigned long index, const std::string & member,
+		const ast::Expr * value, const ResolveContext & context
+) {
+	ast::Expr * expr = makeOpAssign( location,
+		makeOpMember( location,
+			member,
+			makeOpIndex( location,
+				object,
+				index
+			)
+		),
+		value
+	);
+
+	auto result = ResolvExpr::findVoidExpression( expr, context );
+	return new ast::ExprStmt( location, result.get() );
+}
+
+const ast::Stmt * maybeCond( const CodeLocation & location,
+		const ast::Expr * cond, std::list<ast::ptr<ast::Stmt>> && stmts ) {
+	ast::Stmt * block = new ast::CompoundStmt( location, std::move( stmts ) );
+	return (cond) ? new ast::IfStmt( location, cond, block ) : block;
+}
+
+const ast::VariableExpr * extractVariable( const ast::Expr * func ) {
+	if ( auto var = dynamic_cast<const ast::VariableExpr *>( func ) ) {
+		return var;
+	}
+	auto cast = strict_dynamic_cast<const ast::CastExpr *>( func );
+	return cast->arg.strict_as<ast::VariableExpr>();
+}
+
+const ast::Expr * detectIsDtor(
+		const CodeLocation & location, const ast::Expr * func ) {
+	const ast::VariableExpr * typed_func = extractVariable( func );
+	bool is_dtor = InitTweak::isDestructor(
+		typed_func->var.strict_as<ast::FunctionDecl>() );
+	return ast::ConstantExpr::from_bool( location, is_dtor );
+}
+
+ast::ObjectDecl * GenerateWaitForCore::declareAcceptables(
+		ast::CompoundStmt * out,
+		const CodeLocation & location, unsigned long numClauses ) {
+	ast::ObjectDecl * acceptables = new ast::ObjectDecl( location,
+		namer_acc.newName(),
+		new ast::ArrayType(
+			new ast::StructInstType( decl_acceptable ),
+			ast::ConstantExpr::from_ulong( location, numClauses ),
+			ast::FixedLen,
+			ast::DynamicDim
+		)
+	);
+	out->push_back( new ast::DeclStmt( location, acceptables ) );
+
+	ast::Expr * set = new ast::UntypedExpr( location,
+		new ast::NameExpr( location, "__builtin_memset" ),
+		{
+			new ast::VariableExpr( location, acceptables ),
+			ast::ConstantExpr::from_int( location, 0 ),
+			new ast::SizeofExpr( location,
+				new ast::VariableExpr( location, acceptables ) ),
+		}
+	);
+	ResolveContext context{ symtab, transUnit().global };
+	auto result = ResolvExpr::findVoidExpression( set, context );
+	out->push_back( new ast::ExprStmt( location, result.get() ) );
+
+	return acceptables;
+}
+
+ast::ObjectDecl * GenerateWaitForCore::declareFlag(
+		ast::CompoundStmt * out, const CodeLocation & location ) {
+	ast::ObjectDecl * flag = new ast::ObjectDecl( location,
+		namer_flg.newName(),
+		new ast::BasicType( ast::BasicType::Bool ),
+		new ast::SingleInit( location,
+			ast::ConstantExpr::from_ulong( location, 0 )
+		)
+	);
+	out->push_back( new ast::DeclStmt( location, flag ) );
+	return flag;
+}
+
+ast::ExprStmt * GenerateWaitForCore::makeSetter(
+		const CodeLocation & location, ast::ObjectDecl * flag ) {
+	ast::Expr * expr = new ast::UntypedExpr( location,
+		new ast::NameExpr( location, "?=?" ),
+		{
+			new ast::VariableExpr( location, flag ),
+			ast::ConstantExpr::from_ulong( location, 1 ),
+		}
+	);
+	ResolveContext context{ symtab, transUnit().global };
+	auto result = ResolvExpr::findVoidExpression( expr, context );
+	return new ast::ExprStmt( location, result.get() );
+}
+
+ast::ObjectDecl * GenerateWaitForCore::declMonitors(
+		ast::CompoundStmt * out,
+		const ast::WaitForClause * clause ) {
+	const CodeLocation & location = clause->location;
+	ast::ObjectDecl * monitor = new ast::ObjectDecl( location,
+		namer_mon.newName(),
+		new ast::ArrayType(
+			new ast::PointerType(
+				new ast::StructInstType( decl_monitor )
+			),
+			ast::ConstantExpr::from_ulong( location, clause->target_args.size() ),
+			ast::FixedLen,
+			ast::DynamicDim
+		),
+		new ast::ListInit( location,
+			map_range<std::vector<ast::ptr<ast::Init>>>(
+				clause->target_args,
+				[]( const ast::Expr * expr ){
+					return new ast::SingleInit( expr->location, expr ); }
+			)
+		)
+	);
+	out->push_back( new ast::DeclStmt( location, monitor ) );
+	return monitor;
+}
+
+void GenerateWaitForCore::init_clause(
+		ast::CompoundStmt * out,
+		ast::ObjectDecl * acceptables,
+		int index,
+		const ast::WaitForClause * clause,
+		ast::Stmt * setter ) {
+	const CodeLocation & location = clause->location;
+	const ast::ObjectDecl * monitors = declMonitors( out, clause );
+	ast::Type * fptr_t = new ast::PointerType(
+			new ast::FunctionType( ast::VariableArgs ) );
+
+	const ast::VariableExpr * variableExpr =
+		clause->target_func.as<ast::VariableExpr>();
+	ast::Expr * castExpr = new ast::CastExpr(
+		location,
+		new ast::CastExpr(
+			location,
+			clause->target_func,
+			ast::deepCopy( variableExpr->result.get() ),
+			ast::GeneratedCast ),
+		fptr_t,
+		ast::GeneratedCast );
+
+	ast::ObjectDecl * funcDecl = new ast::ObjectDecl( location,
+		namer_fun.newName(),
+		ast::deepCopy( fptr_t ),
+		new ast::SingleInit( location, castExpr )
+		);
+	ast::Expr * funcExpr = new ast::VariableExpr( location, funcDecl );
+	out->push_back( new ast::DeclStmt( location, funcDecl ) );
+
+	ResolveContext context{ symtab, transUnit().global };
+	out->push_back( maybeCond( location, clause->cond.get(), {
+		makeAccStmt( location, acceptables, index, "is_dtor",
+			detectIsDtor( location, clause->target_func ), context ),
+		makeAccStmt( location, acceptables, index, "func",
+			funcExpr, context ),
+		makeAccStmt( location, acceptables, index, "data",
+			new ast::VariableExpr( location, monitors ), context ),
+		makeAccStmt( location, acceptables, index, "size",
+			ast::ConstantExpr::from_ulong( location,
+				clause->target_args.size() ), context ),
+		ast::deepCopy( setter ),
+	} ) );
+}
+
+ast::Expr * GenerateWaitForCore::init_timeout(
+		ast::CompoundStmt * out,
+		const CodeLocation & topLocation,
+		const ast::Expr * timeout_time,
+		const ast::Expr * timeout_cond,
+		const ast::Stmt * else_stmt,
+		const ast::Expr * else_cond,
+		const ast::Stmt * setter ) {
+	ast::ObjectDecl * timeout = new ast::ObjectDecl( topLocation,
+		namer_tim.newName(),
+		new ast::BasicType( ast::BasicType::LongLongUnsignedInt ),
+		new ast::SingleInit( topLocation,
+			ast::ConstantExpr::from_int( topLocation, -1 )
+		)
+	);
+	out->push_back( new ast::DeclStmt( topLocation, timeout ) );
+
+	if ( timeout_time ) {
+		const CodeLocation & location = timeout_time->location;
+		out->push_back( maybeCond( location, timeout_cond, {
+			new ast::ExprStmt( location,
+				makeOpAssign(
+					location,
+					new ast::VariableExpr( location, timeout ),
+					timeout_time
+				)
+			),
+			ast::deepCopy( setter ),
+		} ) );
+	}
+
+	// We only care about the else_stmt's presence and location.
+	if ( else_stmt ) {
+		const CodeLocation & location = else_stmt->location;
+		out->push_back( maybeCond( location, else_cond, {
+			new ast::ExprStmt( location,
+				makeOpAssign(
+					location,
+					new ast::VariableExpr( location, timeout ),
+					ast::ConstantExpr::from_ulong( location, 0 )
+				)
+			),
+			ast::deepCopy( setter ),
+		} ) );
+	}
+
+	return new ast::VariableExpr( topLocation, timeout );
+}
+
+ast::Expr * GenerateWaitForCore::call(
+	ast::CompoundStmt * out,
+	const CodeLocation & location,
+	size_t numClauses,
+	ast::ObjectDecl * acceptables,
+	ast::Expr * timeout
+) {
+	ast::ObjectDecl * index = new ast::ObjectDecl( location,
+		namer_idx.newName(),
+		new ast::BasicType( ast::BasicType::ShortSignedInt ),
+		new ast::SingleInit( location,
+			ast::ConstantExpr::from_int( location, -1 )
+		)
+	);
+	out->push_back( new ast::DeclStmt( location, index ) );
+
+	ast::ObjectDecl * mask = new ast::ObjectDecl( location,
+		namer_msk.newName(),
+		new ast::StructInstType( decl_mask ),
+		new ast::ListInit( location, {
+			new ast::SingleInit( location,
+				new ast::AddressExpr( location,
+					new ast::VariableExpr( location, index )
+				)
+			),
+			new ast::ListInit( location, {
+				new ast::SingleInit( location,
+					new ast::VariableExpr( location, acceptables )
+				),
+				new ast::SingleInit( location,
+					ast::ConstantExpr::from_ulong( location, numClauses )
+				),
+			}),
+		})
+	);
+	out->push_back( new ast::DeclStmt( location, mask ) );
+
+	ast::ApplicationExpr * waitforMask = new ast::ApplicationExpr( location,
+		ast::VariableExpr::functionPointer( location, decl_waitfor ),
+		{
+			new ast::CastExpr(
+				new ast::VariableExpr( location, mask ),
+				new ast::ReferenceType(
+					new ast::StructInstType( decl_mask )
+				)
+			),
+			timeout
+		}
+	);
+	out->push_back( new ast::ExprStmt( location, waitforMask ) );
+
+	return new ast::VariableExpr( location, index );
+}
+
+ast::Stmt * choose( const ast::WaitForStmt * waitfor, ast::Expr * result ) {
+	const CodeLocation & location = waitfor->location;
+
+	ast::SwitchStmt * theSwitch = new ast::SwitchStmt( location,
+		result,
+		std::vector<ast::ptr<ast::CaseClause>>()
+	);
+
+	// For some reason, enumerate doesn't work here because of references.
+	for ( size_t i = 0 ; i < waitfor->clauses.size() ; ++i ) {
+		theSwitch->cases.push_back(
+			new ast::CaseClause( location,
+				ast::ConstantExpr::from_ulong( location, i ),
+				{
+					new ast::CompoundStmt( location, {
+						waitfor->clauses[i]->stmt,
+						new ast::BranchStmt( location,
+							ast::BranchStmt::Break,
+							ast::Label( location )
+						)
+					})
+				}
+			)
+		);
+	}
+
+	if ( waitfor->timeout_stmt ) {
+		theSwitch->cases.push_back(
+			new ast::CaseClause( location,
+				ast::ConstantExpr::from_int( location, -2 ),
+				{
+					new ast::CompoundStmt( location, {
+						waitfor->timeout_stmt,
+						new ast::BranchStmt( location,
+							ast::BranchStmt::Break,
+							ast::Label( location )
+						)
+					})
+				}
+			)
+		);
+	}
+
+	if ( waitfor->else_stmt ) {
+		theSwitch->cases.push_back(
+			new ast::CaseClause( location,
+				ast::ConstantExpr::from_int( location, -1 ),
+				{
+					new ast::CompoundStmt( location, {
+						waitfor->else_stmt,
+						new ast::BranchStmt( location,
+							ast::BranchStmt::Break,
+							ast::Label( location )
+						)
+					})
+				}
+			)
+		);
+	}
+
+	return theSwitch;
+}
+
+void GenerateWaitForCore::previsit( const ast::FunctionDecl * decl ) {
+	if ( "__waitfor_internal" == decl->name ) {
+		decl_waitfor = decl;
+	}
+}
+
+void GenerateWaitForCore::previsit( const ast::StructDecl * decl ) {
+	if ( !decl->body ) {
+		return;
+	} else if ( "__acceptable_t" == decl->name ) {
+		assert( !decl_acceptable );
+		decl_acceptable = decl;
+	} else if ( "__waitfor_mask_t" == decl->name ) {
+		assert( !decl_mask );
+		decl_mask = decl;
+	} else if ( "monitor$" == decl->name ) {
+		assert( !decl_monitor );
+		decl_monitor = decl;
+	}
+}
+
+ast::Stmt * GenerateWaitForCore::postvisit( const ast::WaitForStmt * stmt ) {
+	if ( !decl_monitor || !decl_acceptable || !decl_mask ) {
+		SemanticError( stmt, "waitfor keyword requires monitors to be in scope, add #include <monitor.hfa>" );
+	}
+
+	const CodeLocation & location = stmt->location;
+	ast::CompoundStmt * comp = new ast::CompoundStmt( location );
+
+	ast::ObjectDecl * acceptables = declareAcceptables( comp, location, stmt->clauses.size() );
+	ast::ObjectDecl * flag        = declareFlag( comp, location );
+	ast::Stmt       * setter      = makeSetter( location, flag );
+
+	// For some reason, enumerate doesn't work here because of references.
+	for ( size_t i = 0 ; i < stmt->clauses.size() ; ++i ) {
+		init_clause( comp, acceptables, i, stmt->clauses[i], setter );
+	}
+
+	ast::Expr * timeout = init_timeout(
+		comp,
+		location,
+		stmt->timeout_time,
+		stmt->timeout_cond,
+		stmt->else_stmt,
+		stmt->else_cond,
+		setter
+	);
+
+	ast::CompoundStmt * compound = new ast::CompoundStmt( location );
+	comp->push_back( new ast::IfStmt( location,
+		new ast::VariableExpr( location, flag ),
+		compound,
+		nullptr
+	));
+
+	ast::Expr * result = call(
+		compound, location, stmt->clauses.size(), acceptables, timeout );
+	compound->push_back( choose( stmt, result ) );
+	return comp;
+}
+
+} // namespace
+
+void generateWaitFor( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<GenerateWaitForCore>::run( translationUnit );
+}
+
+} // namespace Concurrency
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Concurrency/module.mk
===================================================================
--- src/Concurrency/module.mk	(revision 9939dc312f9fd40e9451c8c3c70ac5e68e233d16)
+++ src/Concurrency/module.mk	(revision c8f5f7df666774630b5067e75d046946bfe8cddf)
@@ -19,4 +19,5 @@
 	Concurrency/Keywords.cc \
 	Concurrency/Keywords.h \
+	Concurrency/WaitforNew.cpp \
 	Concurrency/Waitfor.cc \
 	Concurrency/Waitfor.h
