Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision c86b08de42d13ee7646e48f36c60ff65633dc0ea)
+++ src/Parser/StatementNode.cc	(revision 62d62db217dc9f917346863faa9d03148d98844f)
@@ -11,7 +11,9 @@
 // Created On       : Sat May 16 14:59:41 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Apr  4 11:40:00 2023
-// Update Count     : 427
+// Last Modified On : Tue Apr 11 10:16:00 2023
+// Update Count     : 428
 //
+
+#include "StatementNode.h"
 
 #include <cassert>                 // for assert, strict_dynamic_cast, assertf
@@ -23,5 +25,6 @@
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
-#include "ParseNode.h"             // for StatementNode, ExpressionNode, bui...
+#include "DeclarationNode.h"       // for DeclarationNode
+#include "ExpressionNode.h"        // for ExpressionNode
 #include "parserutility.h"         // for notZeroExpr
 
@@ -29,4 +32,19 @@
 
 using namespace std;
+
+// Some helpers for cases that really want a single node but check for lists.
+static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
+	std::vector<ast::ptr<ast::Stmt>> list;
+	buildMoveList( node, list );
+	assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
+	return list.front().release();
+}
+
+static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
+	std::vector<ast::ptr<ast::Stmt>> list;
+	buildMoveList( node, list );
+	assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
+	return list.empty() ? nullptr : list.front().release();
+}
 
 StatementNode::StatementNode( DeclarationNode * decl ) {
@@ -53,15 +71,27 @@
 } // StatementNode::StatementNode
 
-StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
-	StatementNode * prev = this;
+StatementNode * StatementNode::add_label(
+		const CodeLocation & location,
+		const std::string * name,
+		DeclarationNode * attr ) {
+	stmt->labels.emplace_back( location,
+		*name,
+		attr ? std::move( attr->attributes )
+			: std::vector<ast::ptr<ast::Attribute>>{} );
+	delete attr;
+	delete name;
+	return this;
+}
+
+ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
+	ClauseNode * prev = this;
 	// find end of list and maintain previous pointer
-	for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
-		StatementNode * node = strict_dynamic_cast< StatementNode * >(curr);
-		assert( nullptr == node->stmt.get() );
+	for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
+		ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
 		assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
 		prev = curr;
 	} // for
+	ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
 	// convert from StatementNode list to Statement list
-	StatementNode * node = dynamic_cast< StatementNode * >(prev);
 	std::vector<ast::ptr<ast::Stmt>> stmts;
 	buildMoveList( stmt, stmts );
@@ -73,5 +103,5 @@
 	stmts.clear();
 	return this;
-} // StatementNode::append_last_case
+} // ClauseNode::append_last_case
 
 ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
@@ -97,7 +127,5 @@
 		for ( ast::ptr<ast::Stmt> & stmt : inits ) {
 			// build the && of all of the declared variables compared against 0
-			//auto declStmt = strict_dynamic_cast<ast::DeclStmt *>( stmt );
 			auto declStmt = stmt.strict_as<ast::DeclStmt>();
-			//ast::DeclWithType * dwt = strict_dynamic_cast<ast::DeclWithType *>( declStmt->decl );
 			auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
 			ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
@@ -113,16 +141,6 @@
 	ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
 
-	std::vector<ast::ptr<ast::Stmt>> aststmt;
-	buildMoveList( then, aststmt );
-	assert( aststmt.size() == 1 );
-	ast::Stmt const * astthen = aststmt.front().release();
-
-	ast::Stmt const * astelse = nullptr;
-	if ( else_ ) {
-		std::vector<ast::ptr<ast::Stmt>> aststmt;
-		buildMoveList( else_, aststmt );
-		assert( aststmt.size() == 1 );
-		astelse = aststmt.front().release();
-	} // if
+	ast::Stmt const * astthen = buildMoveSingle( then );
+	ast::Stmt const * astelse = buildMoveOptional( else_ );
 
 	return new ast::IfStmt( location, astcond, astthen, astelse,
@@ -131,42 +149,7 @@
 } // build_if
 
-// Temporary work around. Split StmtClause off from StatementNode.
-template<typename clause_t>
-static void buildMoveClauseList( StatementNode * firstNode,
-		std::vector<ast::ptr<clause_t>> & output ) {
-	SemanticErrorException errors;
-	std::back_insert_iterator<std::vector<ast::ptr<clause_t>>>
-		out( output );
-	StatementNode * cur = firstNode;
-
-	while ( cur ) {
-		try {
-			auto clause = cur->clause.release();
-			if ( auto result = dynamic_cast<clause_t *>( clause ) ) {
-				*out++ = result;
-			} else {
-				assertf(false, __PRETTY_FUNCTION__ );
-				SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
-			} // if
-		} catch( SemanticErrorException & e ) {
-			errors.append( e );
-		} // try
-		ParseNode * temp = cur->get_next();
-		// Should not return nullptr, then it is non-homogeneous:
-		cur = dynamic_cast<StatementNode *>( temp );
-		if ( !cur && temp ) {
-			SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
-		} // if
-	} // while
-	if ( ! errors.isEmpty() ) {
-		throw errors;
-	} // if
-	// Usually in the wrapper.
-	delete firstNode;
-}
-
-ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
+ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
 	std::vector<ast::ptr<ast::CaseClause>> aststmt;
-	buildMoveClauseList( stmt, aststmt );
+	buildMoveList( stmt, aststmt );
 	// If it is not a switch it is a choose statement.
 	if ( ! isSwitch ) {
@@ -190,8 +173,8 @@
 } // build_switch
 
-ast::CaseClause * build_case( ExpressionNode * ctl ) {
+ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
 	// stmt starts empty and then added to
 	auto expr = maybeMoveBuild( ctl );
-	return new ast::CaseClause( expr->location, expr, {} );
+	return new ast::CaseClause( location, expr, {} );
 } // build_case
 
@@ -205,37 +188,21 @@
 	ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
 
-	std::vector<ast::ptr<ast::Stmt>> aststmt;						// loop body, compound created if empty
-	buildMoveList( stmt, aststmt );
-	assert( aststmt.size() == 1 );
-
-	std::vector<ast::ptr<ast::Stmt>> astelse;						// else clause, maybe empty
-	buildMoveList( else_, astelse );
-	assert( astelse.size() <= 1 );
-
 	return new ast::WhileDoStmt( location,
 		astcond,
-		aststmt.front(),
-		astelse.empty() ? nullptr : astelse.front().release(),
+		buildMoveSingle( stmt ),
+		buildMoveOptional( else_ ),
 		std::move( astinit ),
-		false
+		ast::While
 	);
 } // build_while
 
 ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
-	std::vector<ast::ptr<ast::Stmt>> aststmt;						// loop body, compound created if empty
-	buildMoveList( stmt, aststmt );
-	assert( aststmt.size() == 1 );						// compound created if empty
-
-	std::vector<ast::ptr<ast::Stmt>> astelse;						// else clause, maybe empty
-	buildMoveList( else_, astelse );
-	assert( astelse.size() <= 1 );
-
 	// do-while cannot have declarations in the contitional, so init is always empty
 	return new ast::WhileDoStmt( location,
 		notZeroExpr( maybeMoveBuild( ctl ) ),
-		aststmt.front(),
-		astelse.empty() ? nullptr : astelse.front().release(),
+		buildMoveSingle( stmt ),
+		buildMoveOptional( else_ ),
 		{},
-		true
+		ast::DoWhile
 	);
 } // build_do_while
@@ -251,12 +218,4 @@
 	astincr = maybeMoveBuild( forctl->change );
 	delete forctl;
-
-	std::vector<ast::ptr<ast::Stmt>> aststmt;						// loop body, compound created if empty
-	buildMoveList( stmt, aststmt );
-	assert( aststmt.size() == 1 );
-
-	std::vector<ast::ptr<ast::Stmt>> astelse;						// else clause, maybe empty
-	buildMoveList( else_, astelse );
-	assert( astelse.size() <= 1 );
 
 	return new ast::ForStmt( location,
@@ -264,6 +223,6 @@
 		astcond,
 		astincr,
-		aststmt.front(),
-		astelse.empty() ? nullptr : astelse.front().release()
+		buildMoveSingle( stmt ),
+		buildMoveOptional( else_ )
 	);
 } // build_for
@@ -326,7 +285,7 @@
 } // build_resume_at
 
-ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
+ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
 	std::vector<ast::ptr<ast::CatchClause>> aststmt;
-	buildMoveClauseList( catch_, aststmt );
+	buildMoveList( catch_, aststmt );
 	ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
 	ast::FinallyClause * finallyBlock = nullptr;
@@ -342,35 +301,27 @@
 
 ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
-	std::vector<ast::ptr<ast::Stmt>> aststmt;
-	buildMoveList( body, aststmt );
-	assert( aststmt.size() == 1 );
 	return new ast::CatchClause( location,
 		kind,
 		maybeMoveBuild( decl ),
 		maybeMoveBuild( cond ),
-		aststmt.front().release()
+		buildMoveSingle( body )
 	);
 } // build_catch
 
 ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
-	std::vector<ast::ptr<ast::Stmt>> aststmt;
-	buildMoveList( stmt, aststmt );
-	assert( aststmt.size() == 1 );
 	return new ast::FinallyClause( location,
-		aststmt.front().strict_as<ast::CompoundStmt>()
+		strict_dynamic_cast<const ast::CompoundStmt *>(
+			buildMoveSingle( stmt )
+		)
 	);
 } // build_finally
 
-ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Type type ) {
-	std::vector<ast::ptr<ast::Stmt>> stmts;
-	buildMoveList( then, stmts );
-	ast::CompoundStmt const * then2 = nullptr;
-	if(!stmts.empty()) {
-		assert( stmts.size() == 1 );
-		then2 = stmts.front().strict_as<ast::CompoundStmt>();
-	}
-	auto node = new ast::SuspendStmt( location, then2, ast::SuspendStmt::None );
-	node->type = type;
-	return node;
+ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
+	return new ast::SuspendStmt( location,
+		strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
+			buildMoveOptional( then )
+		),
+		kind
+	);
 } // build_suspend
 
@@ -525,5 +476,5 @@
 
 // Question
-ast::Stmt * build_asm( const CodeLocation & location, bool voltile, ast::Expr * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
+ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
 	std::vector<ast::ptr<ast::Expr>> out, in;
 	std::vector<ast::ptr<ast::ConstantExpr>> clob;
@@ -533,6 +484,6 @@
 	buildMoveList( clobber, clob );
 	return new ast::AsmStmt( location,
-		voltile,
-		instruction,
+		is_volatile,
+		maybeMoveBuild( instruction ),
 		std::move( out ),
 		std::move( in ),
