//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// TopLvalue.cc -- Check and force that lvalue is only at the top of types.
//
// Author           : Andrew Beach
// Created On       : Wed Jul 31 15:49:00 2019
// Last Modified By : Andrew Beach
// Last Modified On : Wed Aug  7 15:36:00 2019
// Update Count     : 0
//

#include <iostream>

#include "Common/PassVisitor.h"

namespace {
	class TopLvalue : public WithGuards {
		bool inType = false;
	public:
		void previsit( const BaseSyntaxNode * ) {
			if ( inType ) {
				GuardValue( inType );
				inType = false;
			}
		}

		void previsit( const Type * type ) {
			if ( inType ) {
				assert( !type->get_lvalue() );
			} else {
				GuardValue( inType );
				inType = true;
			}
		}

	};

	class ClearLvalue : public WithGuards {
		bool inType = false;
	public:
		void previsit( BaseSyntaxNode * ) {
			if ( inType ) {
				GuardValue( inType );
				inType = false;
			}
		}

		void previsit( Type * type ) {
			if ( !inType ) {
				GuardValue( inType );
				inType = true;
			} else if ( type->get_lvalue() ) {
				type->set_lvalue( false );
			}
		}
	};

	class TopLvaluePrint : public WithGuards, public WithShortCircuiting {
		bool failed = false;
		bool inType = false;
		bool typeTop = false;
	public:
		bool failedAny = false;
		void previsit() {
			if ( failed ) {
				visit_children = false;
			} else if ( typeTop ) {
				GuardValue( typeTop );
				typeTop = false;
			}
		}

		void previsit( const BaseSyntaxNode * ) {
			previsit();
			if ( inType ) {
				GuardValue( inType );
				inType = false;
			}
		}

		void previsit( const Type * type ) {
			previsit();
			if ( inType ) {
				if ( type->get_lvalue() ) {
					failed = true;
					failedAny = true;
					visit_children = false;
					std::cout << type->location << std::endl;
				}
				//assert( !type->get_lvalue() );
			} else {
				GuardValue( inType );
				inType = true;
				typeTop = true;
			}
		}

		void postvisit( const Type * type ) {
			if ( typeTop ) {
				if ( failed ) {
					std::cout << type->location << std::endl;
					type->print( std::cout );
					//assert( !failed );
					failed = false;
				}
				typeTop = false;
			}
		}
	};
}

void assertTopLvalue( const std::list< Declaration * > & translationUnit ) {
	PassVisitor< TopLvaluePrint > visitor;
	acceptAll( translationUnit, visitor );
	assert( !visitor.pass.failedAny );
}

void clearInnerLvalue( std::list< Declaration * > & translationUnit ) {
	PassVisitor< ClearLvalue > visitor;
	acceptAll( translationUnit, visitor );
}


// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
