//
// 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.
//
// Declaration.h --
//
// Author           : Richard C. Bilson
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Rob Schluntz
// Last Modified On : Fri May 06 16:26:12 2016
// Update Count     : 33
//

#ifndef DECLARATION_H
#define DECLARATION_H

#include "SynTree.h"
#include "Visitor.h"
#include "Mutator.h"
#include "Parser/LinkageSpec.h"
#include "Parser/ParseNode.h"
#include <string>

class Declaration {
  public:
	Declaration( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage );
	Declaration( const Declaration &other );
	virtual ~Declaration();

	const std::string &get_name() const { return name; }
	void set_name( std::string newValue ) { name = newValue; }
	DeclarationNode::StorageClass get_storageClass() const { return storageClass; }
	void set_storageClass( DeclarationNode::StorageClass newValue ) { storageClass = newValue; }
	LinkageSpec::Type get_linkage() const { return linkage; }
	void set_linkage( LinkageSpec::Type newValue ) { linkage = newValue; }
	bool get_isInline() const { return isInline; }
	void set_isInline( bool newValue ) { isInline = newValue; }
	bool get_isNoreturn() const { return isNoreturn; }
	void set_isNoreturn( bool newValue ) { isNoreturn = newValue; }
	UniqueId get_uniqueId() const { return uniqueId; }

	void fixUniqueId( void );
	virtual Declaration *clone() const = 0;
	virtual void accept( Visitor &v ) = 0;
	virtual Declaration *acceptMutator( Mutator &m ) = 0;
	virtual void print( std::ostream &os, int indent = 0 ) const = 0;
	virtual void printShort( std::ostream &os, int indent = 0 ) const = 0;

	static void dumpIds( std::ostream &os );
	static Declaration *declFromId( UniqueId id );
  private:
	std::string name;
	DeclarationNode::StorageClass storageClass;
	LinkageSpec::Type linkage;
	bool isInline, isNoreturn;
	UniqueId uniqueId;
};

class DeclarationWithType : public Declaration {
  public:
	DeclarationWithType( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage );
	DeclarationWithType( const DeclarationWithType &other );
	virtual ~DeclarationWithType();

	std::string get_mangleName() const { return mangleName; }
	void set_mangleName( std::string newValue ) { mangleName = newValue; }

	std::string get_scopedMangleName() const { return mangleName + "_" + std::to_string(scopeLevel); }

	int get_scopeLevel() const { return scopeLevel; }
	void set_scopeLevel( int newValue ) { scopeLevel = newValue; }

	virtual DeclarationWithType *clone() const = 0;
	virtual DeclarationWithType *acceptMutator( Mutator &m ) = 0;

	virtual Type *get_type() const = 0;
	virtual void set_type(Type *) = 0;
  private:
	// this represents the type with all types and typedefs expanded it is generated by SymTab::Validate::Pass2
	std::string mangleName;
	// need to remember the scope level at which the variable was declared, so that
	// shadowed identifiers can be accessed
	int scopeLevel = 0;
};

class ObjectDecl : public DeclarationWithType {
	typedef DeclarationWithType Parent;
  public:
	ObjectDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, Expression *bitfieldWidth, Type *type, Initializer *init, bool isInline = false, bool isNoreturn = false );
	ObjectDecl( const ObjectDecl &other );
	virtual ~ObjectDecl();

	virtual Type *get_type() const { return type; }
	virtual void set_type(Type *newType) { type = newType; }

	Initializer *get_init() const { return init; }
	void set_init( Initializer *newValue ) { init = newValue; }
	Expression *get_bitfieldWidth() const { return bitfieldWidth; }
	void set_bitfieldWidth( Expression *newValue ) { bitfieldWidth = newValue; }

	virtual ObjectDecl *clone() const { return new ObjectDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual DeclarationWithType *acceptMutator( Mutator &m ) { return m.mutate( this ); }
	virtual void print( std::ostream &os, int indent = 0 ) const;
	virtual void printShort( std::ostream &os, int indent = 0 ) const;
  private:
	Type *type;
	Initializer *init;
	Expression *bitfieldWidth;
};

class FunctionDecl : public DeclarationWithType {
	typedef DeclarationWithType Parent;
  public:
	FunctionDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, FunctionType *type, CompoundStmt *statements, bool isInline, bool isNoreturn, const std::list< Attribute * > attributes = std::list< Attribute * >() );
	FunctionDecl( const FunctionDecl &other );
	virtual ~FunctionDecl();

	Type *get_type() const;
	virtual void set_type(Type *);

	FunctionType *get_functionType() const { return type; }
	void set_functionType( FunctionType *newValue ) { type = newValue; }
	CompoundStmt *get_statements() const { return statements; }
	void set_statements( CompoundStmt *newValue ) { statements = newValue; }
	std::list< std::string >& get_oldIdents() { return oldIdents; }
	std::list< Declaration* >& get_oldDecls() { return oldDecls; }
	std::list< Attribute * >& get_attributes() { return attributes; }

	virtual FunctionDecl *clone() const { return new FunctionDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual DeclarationWithType *acceptMutator( Mutator &m ) { return m.mutate( this ); }
	virtual void print( std::ostream &os, int indent = 0 ) const;
	virtual void printShort( std::ostream &os, int indent = 0 ) const;
  private:
	FunctionType *type;
	CompoundStmt *statements;
	std::list< std::string > oldIdents;
	std::list< Declaration* > oldDecls;
	std::list< Attribute * > attributes;
};

class NamedTypeDecl : public Declaration {
	typedef Declaration Parent;
  public:
	NamedTypeDecl( const std::string &name, DeclarationNode::StorageClass sc, Type *type );
	NamedTypeDecl( const TypeDecl &other );
	virtual ~NamedTypeDecl();

	Type *get_base() const { return base; }
	void set_base( Type *newValue ) { base = newValue; }
	std::list< TypeDecl* >& get_parameters() { return parameters; }
	std::list< DeclarationWithType* >& get_assertions() { return assertions; }

	virtual NamedTypeDecl *clone() const = 0;
	virtual void print( std::ostream &os, int indent = 0 ) const;
	virtual void printShort( std::ostream &os, int indent = 0 ) const;
  protected:
	virtual std::string typeString() const = 0;
  private:
	Type *base;
	std::list< TypeDecl* > parameters;
	std::list< DeclarationWithType* > assertions;
};

class TypeDecl : public NamedTypeDecl {
	typedef NamedTypeDecl Parent;
  public:
	enum Kind { Any, Dtype, Ftype };

	TypeDecl( const std::string &name, DeclarationNode::StorageClass sc, Type *type, Kind kind );
	TypeDecl( const TypeDecl &other );

	Kind get_kind() const { return kind; }

	virtual TypeDecl *clone() const { return new TypeDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual TypeDecl *acceptMutator( Mutator &m ) { return m.mutate( this ); }
  private:
	virtual std::string typeString() const;
	Kind kind;
};

class TypedefDecl : public NamedTypeDecl {
	typedef NamedTypeDecl Parent;
  public:
	TypedefDecl( const std::string &name, DeclarationNode::StorageClass sc, Type *type ) : Parent( name, sc, type ) {}
	TypedefDecl( const TypedefDecl &other ) : Parent( other ) {}

	virtual TypedefDecl *clone() const { return new TypedefDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual Declaration *acceptMutator( Mutator &m ) { return m.mutate( this ); }
  private:
	virtual std::string typeString() const;
};

class AggregateDecl : public Declaration {
	typedef Declaration Parent;
  public:
	AggregateDecl( const std::string &name );
	AggregateDecl( const AggregateDecl &other );
	virtual ~AggregateDecl();

	std::list<Declaration*>& get_members() { return members; }
	std::list<TypeDecl*>& get_parameters() { return parameters; }

	virtual void print( std::ostream &os, int indent = 0 ) const;
	virtual void printShort( std::ostream &os, int indent = 0 ) const;
  protected:
	virtual std::string typeString() const = 0;

  private:
	std::list<Declaration*> members;
	std::list<TypeDecl*> parameters;
};

class StructDecl : public AggregateDecl {
	typedef AggregateDecl Parent;
  public:
	StructDecl( const std::string &name ) : Parent( name ) {}
	StructDecl( const StructDecl &other ) : Parent( other ) {}

	virtual StructDecl *clone() const { return new StructDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual Declaration *acceptMutator( Mutator &m ) { return m.mutate( this ); }

  private:
	virtual std::string typeString() const;
};

class UnionDecl : public AggregateDecl {
	typedef AggregateDecl Parent;
  public:
	UnionDecl( const std::string &name ) : Parent( name ) {}
	UnionDecl( const UnionDecl &other ) : Parent( other ) {}

	virtual UnionDecl *clone() const { return new UnionDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual Declaration *acceptMutator( Mutator &m ) { return m.mutate( this ); }
  private:
	virtual std::string typeString() const;
};

class EnumDecl : public AggregateDecl {
	typedef AggregateDecl Parent;
  public:
	EnumDecl( const std::string &name ) : Parent( name ) {}
	EnumDecl( const EnumDecl &other ) : Parent( other ) {}

	virtual EnumDecl *clone() const { return new EnumDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual Declaration *acceptMutator( Mutator &m ) { return m.mutate( this ); }
  private:
	virtual std::string typeString() const;
};

class TraitDecl : public AggregateDecl {
	typedef AggregateDecl Parent;
  public:
	TraitDecl( const std::string &name ) : Parent( name ) {}
	TraitDecl( const TraitDecl &other ) : Parent( other ) {}

	virtual TraitDecl *clone() const { return new TraitDecl( *this ); }
	virtual void accept( Visitor &v ) { v.visit( this ); }
	virtual Declaration *acceptMutator( Mutator &m ) { return m.mutate( this ); }
  private:
	virtual std::string typeString() const;
};

std::ostream & operator<<( std::ostream & out, Declaration * decl );

#endif // DECLARATION_H

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