#ifndef _INITTWEAK_MODEL_H_
#define _INITTWEAK_MODEL_H_

#include "Association.h"
#include "SemanticError.h"
#include "SynTree/Visitor.h"

#include "SynTree/Initializer.h"
#include "SynTree/Declaration.h"
#include "SynTree/Expression.h"
#include "SynTree/Type.h"

namespace InitTweak {
    class InitModelBuilder : public AssociationBuilder, public Visitor {
      public:
	InitModelBuilder( Declaration * );
	~InitModelBuilder();

	virtual Association *grab_assoc() { taken = true; return building; }
	virtual Association *get_assoc() { return building; }
	void set_assoc( Association *newAssoc ) { building = newAssoc; }

	void init();
	static int interpretDimension( Expression *exp ) {
	    ConstantFolder folder( exp );
	    try {
		return folder.get_constant();
	    } catch (...) {
		throw SemanticError("Invalid array dimension");
	    }
	}

	// types
	virtual void visit( ArrayType * );
	virtual void visit( StructInstType * );
	virtual void visit( UnionInstType * );
	virtual void visit( EnumInstType * );
	virtual void visit( ContextInstType * ) { throw 0; }
	virtual void visit( TypeInstType * )    { throw 0; }
	// virtual void visit( TupleType *tupleType );
	// declarations
	virtual void visit( StructDecl *);
	virtual void visit( UnionDecl *);
	virtual void visit( EnumDecl *);
      private:
	class ConstantFolder : public Visitor {
	  public:
	    ConstantFolder( Expression *_expr = 0 ): expr(_expr) {}
	    int get_constant() throw() { expr->accept( *this ); return value; }
	    void set_constant( Expression *newExp ) { expr = newExp; }
	    // Visitor interface
	    void visit( Expression * ) { throw 0; }
	    void visit( NameExpr * ) { throw 0; }
	    void visit( CastExpr * ) { throw 0; }
	    void visit( UntypedMemberExpr * ) { throw 0; }
	    void visit( VariableExpr * ) { throw 0; }
	    void visit( ConstantExpr * );
	    void visit( SizeofExpr * ) { throw 0; }
	    void visit( AttrExpr * ) { throw 0; }
	    void visit( LogicalExpr * ) { throw 0; }
	    void visit( ConditionalExpr * ) { throw 0; }
	    void visit( CommaExpr * ) { throw 0; }
	  private:
	    Expression *expr;
	    int value;
	};

	bool taken;
	Declaration *decl;  // ?
	Association *building;
    };

    class InitModelFiller : public AssociationFiller, public Visitor {
      public:
	InitModelFiller( Association *, Initializer *, bool _topLevel = false );
	~InitModelFiller() { /* pointers in here are not owned by object (never created by object either) */ }
	virtual Association *get_assoc() { return model; }
	virtual void set_assoc( Association *newAssoc ) { model = newAssoc; }

	void init();
	// Visitor interface
	virtual void visit( SingleInit *singleInit );
	virtual void visit( ListInit *listInit );
      private:
	Association *model;
	Initializer *orgInit;
	bool topLevel;
	long int next;
    };

    class InitUnspooler : public AssociationVisitor {
      public:
	InitUnspooler() : init(0), taken( false ) {}
	virtual ~InitUnspooler() { if (!taken && (init != 0)) { delete init; init = 0; } }
	Initializer *get_initializer() { return init; }
	Initializer *grab_initializer() { taken = true; return init; }

	virtual void visit( SingleName * );
	virtual void visit( PointAssociation * );
	virtual void visit( RangeAssociation * ) { std::cerr << "InitUnspooler - In a range assoc" << std::endl; return; }
      private:
	Initializer *init;
	bool taken;
    };

} // namespace InitTweak

#endif // _INITTWEAK_MODEL_H_

/*
  Local Variables:
  mode: c++
  End:
*/
