//
// 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.
//
// CodeGenerator.h --
//
// Author           : Richard C. Bilson
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Thu Aug  4 13:37:07 2016
// Update Count     : 38
//

#ifndef CODEGENV_H
#define CODEGENV_H

#include <list>

#include "SynTree/Declaration.h"
#include "SynTree/SynTree.h"
#include "SynTree/Visitor.h"

#include "SymTab/Indexer.h"

namespace CodeGen {
	class CodeGenerator : public Visitor {
	  public:
		static int tabsize;

		CodeGenerator( std::ostream &os );
		CodeGenerator( std::ostream &os, std::string, int indent = 0, bool infun = false );
		CodeGenerator( std::ostream &os, char *, int indent = 0, bool infun = false );

		//*** Declaration
		virtual void visit( StructDecl * );
		virtual void visit( FunctionDecl * );
		virtual void visit( ObjectDecl * );
		virtual void visit( UnionDecl *aggregateDecl );
		virtual void visit( EnumDecl *aggregateDecl );
		virtual void visit( TraitDecl *aggregateDecl );
		virtual void visit( TypedefDecl *typeDecl );
		virtual void visit( TypeDecl *typeDecl );

		//*** Initializer
		virtual void visit( SingleInit * );
		virtual void visit( ListInit * );

		//*** Constant
		virtual void visit( Constant * );

		//*** Expression
		virtual void visit( ApplicationExpr *applicationExpr );
		virtual void visit( UntypedExpr *untypedExpr );
		virtual void visit( RangeExpr * rangeExpr );
		virtual void visit( NameExpr *nameExpr );
		virtual void visit( AddressExpr *addressExpr );
		virtual void visit( CastExpr *castExpr );
		virtual void visit( UntypedMemberExpr *memberExpr );
		virtual void visit( MemberExpr *memberExpr );
		virtual void visit( VariableExpr *variableExpr );
		virtual void visit( ConstantExpr *constantExpr );
		virtual void visit( SizeofExpr *sizeofExpr );
		virtual void visit( AlignofExpr *alignofExpr );
		virtual void visit( UntypedOffsetofExpr *offsetofExpr );
		virtual void visit( OffsetofExpr *offsetofExpr );
		virtual void visit( OffsetPackExpr *offsetPackExpr );
		virtual void visit( LogicalExpr *logicalExpr );
		virtual void visit( ConditionalExpr *conditionalExpr );
		virtual void visit( CommaExpr *commaExpr );
		virtual void visit( TupleExpr *tupleExpr );
		virtual void visit( TypeExpr *typeExpr );
		virtual void visit( AsmExpr * );

		//*** Statements
		virtual void visit( CompoundStmt * );
		virtual void visit( ExprStmt * );
		virtual void visit( AsmStmt * );
		virtual void visit( IfStmt * );
		virtual void visit( SwitchStmt * );
		virtual void visit( CaseStmt * );
		virtual void visit( BranchStmt * );
		virtual void visit( ReturnStmt * );
		virtual void visit( WhileStmt * );
		virtual void visit( ForStmt * );
		virtual void visit( NullStmt * );
		virtual void visit( DeclStmt * );

		void genAttributes( std::list< Attribute * > & attributes );

		template< class Iterator > void genCommaList( Iterator begin, Iterator end );

		struct Indenter {
			Indenter(CodeGenerator &cg) : cg(cg) {}
			CodeGenerator & cg;
			std::ostream& operator()(std::ostream & os) const;
		};

		struct LabelPrinter {
			LabelPrinter(CodeGenerator &cg) : cg(cg), labels( 0 ) {}
			LabelPrinter & operator()( std::list< Label > & l );
			CodeGenerator & cg;
			std::list< Label > * labels;
		};

		void extension( Expression *expr );
		void extension( Declaration *decl );
	  private:

		Indenter indent;
		int cur_indent;
		bool insideFunction;
		std::ostream &output;
		LabelPrinter printLabels;

		void printDesignators( std::list< Expression * > & );
		void handleStorageClass( Declaration *decl );
		void handleAggregate( AggregateDecl *aggDecl );
		void handleTypedef( NamedTypeDecl *namedType );
	}; // CodeGenerator

	template< class Iterator >
	void CodeGenerator::genCommaList( Iterator begin, Iterator end ) {
		if ( begin == end ) return;

		for ( ;; ) {
			(*begin++)->accept( *this );
			if ( begin == end ) return;
			output << ", ";
		} // for
	}

	inline bool doSemicolon( Declaration* decl ) {
		if ( FunctionDecl* func = dynamic_cast< FunctionDecl* >( decl ) ) {
			return ! func->get_statements();
		} // if
		return true;
	}
} // namespace CodeGen

#endif // CODEGENV_H

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