//
// 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.
//
// ParseNode.h -- 
//
// Author           : Rodolfo G. Esteves
// Created On       : Sat May 16 13:28:16 2015
// Last Modified By : Rob Schluntz
// Last Modified On : Wed Aug 12 13:27:11 2015
// Update Count     : 172
//

#ifndef PARSENODE_H
#define PARSENODE_H

#include <string>
#include <list>
#include <iterator>

#include "utility.h"
#include "Parser/LinkageSpec.h"
#include "SynTree/Type.h"
//#include "SynTree/Declaration.h"
#include "UniqueName.h"

class ExpressionNode;
class CompositeExprNode;
class CommaExprNode;
class StatementNode;
class CompoundStmtNode;
class DeclarationNode;
class InitializerNode;

// Builder
class ParseNode {
  public:
	ParseNode();
	ParseNode( const std::string * );
	ParseNode( const std::string & );  // for copy constructing subclasses
	virtual ~ParseNode();

	ParseNode *get_link() const;
	ParseNode *get_last();
	ParseNode *set_link( ParseNode * );
	void set_next( ParseNode *newlink ) { next = newlink; }

	virtual ParseNode *clone() const { return 0; };

	const std::string &get_name() const { return name; }
	void set_name( const std::string &newValue ) { name = newValue; }

	virtual void print( std::ostream &, int indent = 0 ) const;
	virtual void printList( std::ostream &, int indent = 0 ) const;

	ParseNode &operator,( ParseNode &);
  protected:
	std::string name;
	ParseNode *next;
	static int indent_by;
};

ParseNode *mkList( ParseNode & );

class ExpressionNode : public ParseNode {
  public:
	ExpressionNode();
	ExpressionNode( const std::string * );
	ExpressionNode( const ExpressionNode &other );
	virtual ~ExpressionNode() { delete argName; } // cannot delete argName because it might be referenced elsewhere

	virtual ExpressionNode *clone() const = 0;

	virtual CommaExprNode *add_to_list( ExpressionNode * );

	ExpressionNode *get_argName() const { return argName; }
	ExpressionNode *set_argName( const std::string *aName );
	ExpressionNode *set_argName( ExpressionNode *aDesignator );

	virtual void print( std::ostream &, int indent = 0) const = 0;
	virtual void printOneLine( std::ostream &, int indent = 0) const = 0;

	virtual Expression *build() const = 0;
  protected:
	void printDesignation ( std::ostream &, int indent = 0) const;
  private:
	ExpressionNode *argName;
};

// NullExprNode is used in tuples as a place-holder where a tuple component is omitted e.g., [ 2, , 3 ]
class NullExprNode : public ExpressionNode {
  public:
	NullExprNode();

	virtual NullExprNode *clone() const;

	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;

	virtual Expression *build() const;
};

class ConstantNode : public ExpressionNode {
  public:
	enum Type { Integer, Float, Character, String };

	ConstantNode( Type, std::string * );
	~ConstantNode() { delete &value; }

	virtual ConstantNode *clone() const { return new ConstantNode( *this ); }
	Type get_type( void ) const { return type; }
	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;

	const std::string &get_value() const { return value; }
	ConstantNode *appendstr( const std::string *newValue );

	Expression *build() const;
  private:
	Type type;
	BasicType::Kind btype;
	std::string &value;
};

class VarRefNode : public ExpressionNode {
  public:
	VarRefNode();
	VarRefNode( const std::string *, bool isLabel = false );
	VarRefNode( const VarRefNode &other );

	virtual Expression *build() const ;

	virtual VarRefNode *clone() const { return new VarRefNode( *this ); }

	virtual void print( std::ostream &, int indent = 0 ) const;
	virtual void printOneLine( std::ostream &, int indent = 0 ) const;
  private:
	bool isLabel;
};

class DesignatorNode : public ExpressionNode {
  public:
	DesignatorNode( ExpressionNode *expr, bool isArrayIndex = false );
	DesignatorNode( const DesignatorNode &other );

	virtual Expression *build() const ;
	virtual DesignatorNode *clone() const { return new DesignatorNode( *this ); }

	virtual void print( std::ostream &, int indent = 0 ) const;
	virtual void printOneLine( std::ostream &, int indent = 0 ) const;
  private:
	bool isArrayIndex;
};

class TypeValueNode : public ExpressionNode {
  public:
	TypeValueNode( DeclarationNode * );
	TypeValueNode( const TypeValueNode &other );

	DeclarationNode *get_decl() const { return decl; }

	virtual Expression *build() const ;

	virtual TypeValueNode *clone() const { return new TypeValueNode( *this ); }

	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;
  private:
	DeclarationNode *decl;
};

class OperatorNode : public ExpressionNode {
  public:
	enum Type { TupleC, Comma, TupleFieldSel,
				Cond, NCond, 
				SizeOf, AlignOf, Attr, CompLit, Plus, Minus, Mul, Div, Mod, Or, And, 
				BitOr, BitAnd, Xor, Cast, LShift, RShift, LThan, GThan, LEThan, GEThan, Eq, Neq, 
				Assign, MulAssn, DivAssn, ModAssn, PlusAssn, MinusAssn, LSAssn, RSAssn, AndAssn, 
				ERAssn, OrAssn, Index, FieldSel, PFieldSel, Range,
				UnPlus, UnMinus, AddressOf, PointTo, Neg, BitNeg, Incr, IncrPost, Decr, DecrPost, LabelAddress
	};

	OperatorNode( Type t );
	OperatorNode( const OperatorNode &other );
	virtual ~OperatorNode();

	virtual OperatorNode *clone() const { return new OperatorNode( *this ); }

	Type get_type() const;
	const char *get_typename() const;

	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;

	virtual Expression *build() const { return 0; }
  private:
	Type type;
	static const char *OpName[];
};

class CompositeExprNode : public ExpressionNode {
  public:
	CompositeExprNode();
	CompositeExprNode( const std::string * );
	CompositeExprNode( ExpressionNode *f, ExpressionNode *args = 0 );
	CompositeExprNode( ExpressionNode *f, ExpressionNode *arg1, ExpressionNode *arg2 );
	CompositeExprNode( const CompositeExprNode &other );
	virtual ~CompositeExprNode();

	virtual CompositeExprNode *clone() const { return new CompositeExprNode( *this ); }
	virtual Expression *build() const;

	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;

	void set_function( ExpressionNode * );
	void set_args( ExpressionNode * );

	void add_arg( ExpressionNode * );

	ExpressionNode *get_function() const;
	ExpressionNode *get_args() const;
  private:
	ExpressionNode *function;
	ExpressionNode *arguments;
};

class AsmExprNode : public ExpressionNode {
  public:
	AsmExprNode();
	AsmExprNode( ExpressionNode *inout, ConstantNode *constraint, ExpressionNode *operand ) : inout( inout ), constraint( constraint ), operand( operand ) {}
	virtual ~AsmExprNode() { delete inout; delete constraint; delete operand; }

	virtual AsmExprNode *clone() const { return new AsmExprNode( *this ); }
	virtual Expression *build() const;

	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;

	ExpressionNode *get_inout() const { return inout; };
	void set_inout( ExpressionNode *newValue ) { inout = newValue; }

	ConstantNode *get_constraint() const { return constraint; };
	void set_constraint( ConstantNode *newValue ) { constraint = newValue; }

	ExpressionNode *get_operand() const { return operand; };
	void set_operand( ExpressionNode *newValue ) { operand = newValue; }
  private:
	ExpressionNode *inout;
	ConstantNode *constraint;
	ExpressionNode *operand;
};

class LabelNode : public ExpressionNode {
  public:
	virtual Expression *build() const { return NULL; }
	virtual LabelNode *clone() const { return new LabelNode( *this ); }

	virtual void print( std::ostream &, int indent = 0) const;
	virtual void printOneLine( std::ostream &, int indent = 0) const;

	const std::list< std::string > &get_labels() const { return labels; };
	void append_label( std::string *label ) { labels.push_back( *label ); delete label; }
  private:
	std::list< std::string > labels;
};

class CommaExprNode : public CompositeExprNode {
  public:
	CommaExprNode();
	CommaExprNode( ExpressionNode * );
	CommaExprNode( ExpressionNode *, ExpressionNode * );
	CommaExprNode( const CommaExprNode &other );

	virtual CommaExprNode *add_to_list( ExpressionNode * );
	virtual CommaExprNode *clone() const { return new CommaExprNode( *this ); }
};

class ForCtlExprNode : public ExpressionNode {
  public:
	ForCtlExprNode( ParseNode *, ExpressionNode *, ExpressionNode * ) throw ( SemanticError );
	ForCtlExprNode( const ForCtlExprNode &other );
	~ForCtlExprNode();

	StatementNode *get_init() const { return init; }
	ExpressionNode *get_condition() const { return condition; }
	ExpressionNode *get_change() const { return change; }

	virtual ForCtlExprNode *clone() const { return new ForCtlExprNode( *this ); }
	virtual Expression *build() const;

	virtual void print( std::ostream &, int indent = 0 ) const;
	virtual void printOneLine( std::ostream &, int indent = 0 ) const;
  private:
	StatementNode *init;
	ExpressionNode *condition;
	ExpressionNode *change;
};

class ValofExprNode : public ExpressionNode {
  public:
	ValofExprNode();
	ValofExprNode( StatementNode *s = 0 );
	ValofExprNode( const ValofExprNode &other );
	~ValofExprNode();
  
	virtual ValofExprNode *clone() const { return new ValofExprNode( *this ); }

	StatementNode *get_body() const { return body; }
	void print( std::ostream &, int indent = 0 ) const;
	void printOneLine( std::ostream &, int indent = 0 ) const;
	Expression *build() const;

  private:
	StatementNode *body;
};

class TypeData;

class DeclarationNode : public ParseNode {
  public:
	enum Qualifier { Const, Restrict, Volatile, Lvalue, Atomic };
	enum StorageClass { Extern, Static, Auto, Register, Inline, Fortran, Noreturn, Threadlocal, NoStorageClass, };
	enum BasicType { Char, Int, Float, Double, Void, Bool, Complex, Imaginary };
	enum Modifier  { Signed, Unsigned, Short, Long };
	enum Aggregate { Struct, Union, Context };
	enum TypeClass { Type, Dtype, Ftype };

	static const char *storageName[];  
	static const char *qualifierName[];
	static const char *basicTypeName[];
	static const char *modifierName[];
	static const char *aggregateName[];
	static const char *typeClassName[];

	static DeclarationNode *newFunction( std::string *name, DeclarationNode *ret, DeclarationNode *param, StatementNode *body, bool newStyle = false );
	static DeclarationNode *newQualifier( Qualifier );
	static DeclarationNode *newStorageClass( StorageClass );
	static DeclarationNode *newBasicType( BasicType );
	static DeclarationNode *newModifier( Modifier );
	static DeclarationNode *newForall( DeclarationNode *);
	static DeclarationNode *newFromTypedef( std::string *);
	static DeclarationNode *newAggregate( Aggregate kind, const std::string *name, ExpressionNode *actuals, DeclarationNode *fields );
	static DeclarationNode *newEnum( std::string *name, DeclarationNode *constants );
	static DeclarationNode *newEnumConstant( std::string *name, ExpressionNode *constant );
	static DeclarationNode *newName( std::string *);
	static DeclarationNode *newFromTypeGen( std::string *, ExpressionNode *params );
	static DeclarationNode *newTypeParam( TypeClass, std::string *);
	static DeclarationNode *newContext( std::string *name, DeclarationNode *params, DeclarationNode *asserts );
	static DeclarationNode *newContextUse( std::string *name, ExpressionNode *params );
	static DeclarationNode *newTypeDecl( std::string *name, DeclarationNode *typeParams );
	static DeclarationNode *newPointer( DeclarationNode *qualifiers );
	static DeclarationNode *newArray( ExpressionNode *size, DeclarationNode *qualifiers, bool isStatic );
	static DeclarationNode *newVarArray( DeclarationNode *qualifiers );
	static DeclarationNode *newBitfield( ExpressionNode *size );
	static DeclarationNode *newTuple( DeclarationNode *members );
	static DeclarationNode *newTypeof( ExpressionNode *expr );
	static DeclarationNode *newAttr( std::string *, ExpressionNode *expr );
	static DeclarationNode *newAttr( std::string *, DeclarationNode *type );

	DeclarationNode *addQualifiers( DeclarationNode *);
	DeclarationNode *copyStorageClasses( DeclarationNode *);
	DeclarationNode *addType( DeclarationNode *);
	DeclarationNode *addTypedef();
	DeclarationNode *addAssertions( DeclarationNode *);
	DeclarationNode *addName( std::string *);
	DeclarationNode *addBitfield( ExpressionNode *size );
	DeclarationNode *addVarArgs();
	DeclarationNode *addFunctionBody( StatementNode *body );
	DeclarationNode *addOldDeclList( DeclarationNode *list );
	DeclarationNode *addPointer( DeclarationNode *qualifiers );
	DeclarationNode *addArray( DeclarationNode *array );
	DeclarationNode *addNewPointer( DeclarationNode *pointer );
	DeclarationNode *addNewArray( DeclarationNode *array );
	DeclarationNode *addParamList( DeclarationNode *list );
	DeclarationNode *addIdList( DeclarationNode *list );       // old-style functions
	DeclarationNode *addInitializer( InitializerNode *init );

	DeclarationNode *cloneType( std::string *newName );
	DeclarationNode *cloneType( DeclarationNode *existing );
	DeclarationNode *cloneType( int ) { return cloneType( ( std::string *)0 ); }
	DeclarationNode *cloneBaseType( std::string *newName );
	DeclarationNode *cloneBaseType( DeclarationNode *newdecl );

	DeclarationNode *appendList( DeclarationNode * );

	DeclarationNode *clone() const;
	void print( std::ostream &, int indent = 0 ) const;
	void printList( std::ostream &, int indent = 0 ) const;

	Declaration *build() const;
	::Type *buildType() const;

	bool get_hasEllipsis() const;
	const std::string &get_name() const { return name; }
	LinkageSpec::Type get_linkage() const { return linkage; }
	DeclarationNode *extractAggregate() const;

	DeclarationNode();
	~DeclarationNode();
  private:
	StorageClass buildStorageClass() const;
	bool buildFuncSpecifier( StorageClass key ) const;

	TypeData *type;
	std::string name;
	std::list< StorageClass > storageClasses;
	std::list< std::string > attributes;
	ExpressionNode *bitfieldWidth;
	InitializerNode *initializer;
	bool hasEllipsis;
	LinkageSpec::Type linkage;

	static UniqueName anonymous;
}; // DeclarationNode

class StatementNode : public ParseNode {
  public:
	enum Type { Exp,   If,        Switch,  Case,    Default,  Choose,   Fallthru, 
				While, Do,        For,
				Goto,  Continue,  Break,   Return,  Throw,
				Try,   Catch,     Finally, Asm,
				Decl
	};

	StatementNode();
	StatementNode( const std::string *name );
	StatementNode( Type t, ExpressionNode *control = 0, StatementNode *block = 0 );
	StatementNode( Type t, std::string *target );
	StatementNode( DeclarationNode *decl );

	~StatementNode();

	static StatementNode *newCatchStmt( DeclarationNode *d = 0, StatementNode *s = 0, bool catchRestP = false );

	StatementNode *set_block( StatementNode *b ) {	block = b; return this; }
	StatementNode *get_block() const { return block; }

	void set_control( ExpressionNode *c ) { control = c; }
	ExpressionNode *get_control() const { return control; }

	StatementNode::Type get_type() const { return type; }

	StatementNode *add_label( const std::string * );
	const std::list<std::string> &get_labels() const { return labels; }

	void addDeclaration( DeclarationNode *newDecl ) { decl = newDecl; }
	void setCatchRest( bool newVal ) { isCatchRest = newVal; }

	std::string get_target() const;

	StatementNode *add_controlexp( ExpressionNode * );
	StatementNode *append_block( StatementNode * );
	StatementNode *append_last_case( StatementNode * );

	void print( std::ostream &, int indent = 0) const;
	virtual StatementNode *clone() const;
	virtual Statement *build() const;
  private:
	static const char *StType[];
	Type type;
	ExpressionNode *control;
	StatementNode *block;
	std::list<std::string> labels;
	std::string *target;				// target label for jump statements
	DeclarationNode *decl;
	bool isCatchRest;
}; // StatementNode

class CompoundStmtNode : public StatementNode {
  public:
	CompoundStmtNode();
	CompoundStmtNode( const std::string * );
	CompoundStmtNode( StatementNode * );
	~CompoundStmtNode();

	void add_statement( StatementNode * );

	void print( std::ostream &, int indent = 0 ) const;
	virtual Statement *build() const;
  private:
	StatementNode *first, *last;
};

class AsmStmtNode : public StatementNode {
  public:
	AsmStmtNode( Type, bool voltile, ConstantNode *instruction, ExpressionNode *output = 0, ExpressionNode *input = 0, ConstantNode *clobber = 0, LabelNode *gotolabels = 0 );
	~AsmStmtNode();

	void print( std::ostream &, int indent = 0 ) const;
	Statement *build() const;
  private:
	bool voltile;
	ConstantNode *instruction;
	ExpressionNode *output, *input;
	ConstantNode *clobber;
	std::list<std::string> gotolabels;
};

class NullStmtNode : public CompoundStmtNode {
  public:
	Statement *build() const;
	void print( std::ostream &, int indent = 0 ) const;
};

class InitializerNode : public ParseNode {
  public:
	InitializerNode( ExpressionNode *, bool aggrp = false,  ExpressionNode *des = 0 );
	InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode *des = 0 );
	~InitializerNode();

	ExpressionNode *get_expression() const { return expr; }

	InitializerNode *set_designators( ExpressionNode *des ) { designator = des; return this; }
	ExpressionNode *get_designators() const { return designator; }

	InitializerNode *next_init() const { return kids; }

	void print( std::ostream &, int indent = 0 ) const;
	void printOneLine( std::ostream & ) const;

	virtual Initializer *build() const;
  private:
	ExpressionNode *expr;
	bool aggregate;
	ExpressionNode *designator; // may be list
	InitializerNode *kids;
};

template< typename SynTreeType, typename NodeType >
void buildList( const NodeType *firstNode, std::list< SynTreeType *> &outputList ) {
	SemanticError errors;
	std::back_insert_iterator< std::list< SynTreeType *> > out( outputList );
	const NodeType *cur = firstNode;

	while ( cur ) {
		try {
			SynTreeType *result = dynamic_cast< SynTreeType *>( cur->build() );
			if ( result ) {
				*out++ = result;
			} else {
			} // if
		} catch( SemanticError &e ) {
			errors.append( e );
		} // try
		cur = dynamic_cast< NodeType *>( cur->get_link() );
	} // while
	if ( ! errors.isEmpty() ) {
		throw errors;
	} // if
}

// in DeclarationNode.cc
void buildList( const DeclarationNode *firstNode, std::list< Declaration * > &outputList );
void buildList( const DeclarationNode *firstNode, std::list< DeclarationWithType *> &outputList );
void buildTypeList( const DeclarationNode *firstNode, std::list< Type * > &outputList );

// in ExpressionNode.cc
ExpressionNode *flattenCommas( ExpressionNode *list );
ExpressionNode *tupleContents( ExpressionNode *tuple );

#endif // PARSENODE_H

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