#include <cassert>

#include "ast.hh"
#include "visitor.hh"

#include "pretty_printer.hh" 	// for operator<<()

using namespace std;
using namespace ast;


std::ostream &
operator<<(std::ostream &os, const basic_type_t bt)
{
    switch (bt)
	{
	case TYPE_CHAR:
	    os << "char";
	    break;

	case TYPE_INT:
	    os << "int";
	    break;

	case TYPE_FLOAT:
	    os << "float";
	    break;

	default:
	    assert(false);
	}

    return os;
}

std::ostream &
operator<<(std::ostream &os, const binop_t bo)
{
    switch (bo)
	{
	case BINOP_PLUS:
	    os << '+';
	    break;

	case BINOP_MINUS:
	    os << '-';
	    break;

	case BINOP_MULT:
	    os << '*';
	    break;

	case BINOP_DIV:
	    os << '/';
	    break;

	default:
	    assert(false);
	}
    return os;
}


std::ostream &operator<<(std::ostream &os, const Ast &ast)
{
    PrettyPrinter pprinter(os);
    // hacky
    Ast &ast_ = const_cast<Ast&>(ast);
    ast_.accept(pprinter);
    return os;
}

int ast::Ast::current_id = 0;

void
BinRelLT::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelLT::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelLTE::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelLTE::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelGT::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelGT::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelGTE::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelGTE::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelEQ::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelEQ::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelNEQ::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinRelNEQ::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

RExpr::RExpr(int line_no,
	     Expr *begin, BinRel *begin_br,
	     char *index, BinRel *end_br, Expr *end)
    : Ast(line_no), _begin(begin), _begin_br(begin_br),
      _index(index), _end_br(end_br), _end(end)
{
    assert(begin != 0);
    assert(begin_br != 0);
    assert(index != 0);
    assert(end_br != 0);
    assert(end != 0);
}

void
RExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
RExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _begin->accept_top_down(visitor);
    _end->accept_top_down(visitor);
}


WhenExpr::WhenExpr(int line_no, Fun *fun, BExpr *bexpr)
    : Ast(line_no), _fun(fun), _bexpr(bexpr)
{
    assert(fun != 0);
    assert(bexpr != 0);
}

void
WhenExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
WhenExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _fun->accept_top_down(visitor);
    _bexpr->accept_top_down(visitor);
}

WhereExpr::WhereExpr(int line_no, Fun *fun, std::list<RExpr*> *rexpr_list)
    : Ast(line_no), _fun(fun), _rexpr_list(rexpr_list)
{
    assert(fun != 0);
    assert(rexpr_list != 0);
}

void
WhereExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
WhereExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _fun->accept_top_down(visitor);
    list<RExpr*>::iterator i;
    for (i = _rexpr_list->begin(); i != _rexpr_list->end(); ++i)
	(*i)->accept_top_down(visitor);
}


Range::Range(int line_no, char *id, WhereExpr *where_expr)
    : Fun(line_no, id), _where_expr(where_expr)
{
    assert(where_expr != 0);
}

void
Range::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
Range::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _where_expr->accept_top_down(visitor);
}

Values::Values(int line_no, char *id, std::list<WhenExpr*> *when_expr_list)
    : Fun(line_no, id), _when_expr_list(when_expr_list)
{
    assert(when_expr_list != 0);
}

void
Values::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
Values::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    list<WhenExpr*>::iterator i;
    for (i = _when_expr_list->begin(); i != _when_expr_list->end(); ++i)
	(*i)->accept_top_down(visitor);
}

SimpleFun::SimpleFun(int line_no, Expr *expr)
    : Fun(line_no, ""), _expr(expr)
{
    assert(expr != 0);
}

void
SimpleFun::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
SimpleFun::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _expr->accept_top_down(visitor);
}


Expr::Expr(int line_no)
    : Ast(line_no)
{
    ;
}

IDExpr::IDExpr(int line_no, char *id)
    : Expr(line_no), _id(id)
{
    ;
}

void
IDExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
IDExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}


IntegerExpr::IntegerExpr(int line_no, int integer)
    : Expr(line_no), _integer(integer)
{
    ;
}

void
IntegerExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
IntegerExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

MatrixExpr::MatrixExpr(int line_no, char *id, std::list<Expr*> *expr_list)
    : Expr(line_no), _id(id), _expr_list(expr_list)
{
    ;
}

void
MatrixExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
MatrixExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    list<Expr*>::iterator i;
    for (i = _expr_list->begin(); i != _expr_list->end(); ++i)
	(*i)->accept_top_down(visitor);
}

FunCallExpr::FunCallExpr(int line_no, char *id, std::list<Expr*> *expr_list)
    : Expr(line_no), _id(id), _expr_list(expr_list)
{
    ;
}

void
FunCallExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
FunCallExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    list<Expr*>::iterator i;
    for (i = _expr_list->begin(); i != _expr_list->end(); ++i)
	(*i)->accept_top_down(visitor);
}


BinOpExpr::BinOpExpr(int line_no, Expr *left, binop_t binop, Expr *right)
    : Expr(line_no), _left(left), _binop(binop), _right(right)
{
    assert(left != 0);
    assert(right != 0);
}

void
BinOpExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
BinOpExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _left->accept_top_down(visitor);
    _right->accept_top_down(visitor);
}


NEGExpr::NEGExpr(int line_no, Expr *expr)
    : Expr(line_no), _expr(expr)
{
    assert(expr != 0);
}


void
NEGExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
NEGExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _expr->accept_top_down(visitor);
}


RelBExpr::RelBExpr(int line_no, Expr *left, BinRel *rel, Expr *right)
    : BExpr(line_no), _left(left), _rel(rel), _right(right)
{
    assert(left != 0);
    assert(rel != 0);
    assert(right != 0);
}

void
RelBExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
RelBExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _left->accept_top_down(visitor);
    _right->accept_top_down(visitor);
}

ANDBExpr::ANDBExpr(int line_no, BExpr *left, BExpr *right)
    : BExpr(line_no), _left(left), _right(right)
{
    assert(left != 0);
    assert(right != 0);
}

void
ANDBExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
ANDBExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _left->accept_top_down(visitor);
    _right->accept_top_down(visitor);
}


ORBExpr::ORBExpr(int line_no, BExpr *left, BExpr *right)
    : BExpr(line_no), _left(left), _right(right)
{
    assert(left != 0);
    assert(right != 0);
}

void
ORBExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
ORBExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _left->accept_top_down(visitor);
    _right->accept_top_down(visitor);
}


NOTBExpr::NOTBExpr(int line_no, BExpr *bexpr)
    : BExpr(line_no), _bexpr(bexpr)
{
    assert(bexpr != 0);
}

void
NOTBExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
NOTBExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _bexpr->accept_top_down(visitor);
}

void
TrueExpr::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
TrueExpr::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

Update::Update(int line_no,
	       basic_type_t type,
	       char *name,
	       std::list<const char *> *indices,
	       Fun *fun)
    : Ast(line_no), _type(type), _name(name), _indices(indices), _fun(fun)
{
    assert(name != 0);
    assert(indices != 0);
    assert(fun != 0);
}

void
Update::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
Update::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
    _fun->accept_top_down(visitor);
}

Declaration::Declaration(int line_no, const char *name)
    : Ast(line_no), _name(name)
{
    assert(name != 0);
}


ValDeclaration::ValDeclaration(int line_no, const char *name, basic_type_t type)
    : Declaration(line_no, name), _type(type)
{
    ;
}

void
ValDeclaration::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
ValDeclaration::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

FunDeclaration::FunDeclaration(int line_no, const char *name,
			       list<basic_type_t> *parameter_types,
			       basic_type_t return_type)
    : Declaration(line_no, name),
      _parameter_types(parameter_types),
      _return_type(return_type)
{
    ;
}

void
FunDeclaration::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
FunDeclaration::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}

MatrixDeclaration::MatrixDeclaration(int line_no, const char *name,
				     list<Expr*> *dim_list,
				     basic_type_t type)
    : Declaration(line_no, name), _dim_list(dim_list), _type(type)
{
    ;
}

void
MatrixDeclaration::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
MatrixDeclaration::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);
}


DProg::DProg(int line_no,
	     std::list<Declaration*> *globals,
	     std::list<Declaration*> *parameters,
	     std::list<Declaration*> *locals,
	     std::list<Update*> *update_list,
	     std::list<RExpr*> *rexpr_list)
    : Ast(line_no),
      _globals(globals), _parameters(parameters), _locals(locals),
      _update_list(update_list), _rexpr_list(rexpr_list)
{
    assert(globals != 0);
    assert(parameters != 0);
    assert(locals != 0);
    assert(update_list != 0);
    assert(rexpr_list != 0);
}

void
DProg::accept(Visitor &visitor)
{
    visitor.visit(*this);
}

void
DProg::accept_top_down(Visitor &visitor)
{
    visitor.visit(*this);

    list<Declaration*>::iterator d_itr;
    for (d_itr = _globals->begin(); d_itr != _globals->end(); ++d_itr)
	(*d_itr)->accept_top_down(visitor);

    for (d_itr = _parameters->begin(); d_itr != _parameters->end(); ++d_itr)
	(*d_itr)->accept_top_down(visitor);

    for (d_itr = _locals->begin(); d_itr != _locals->end(); ++d_itr)
	(*d_itr)->accept_top_down(visitor);

    list<Update*>::iterator u_itr;
    for (u_itr = _update_list->begin(); u_itr != _update_list->end(); ++u_itr)
	(*u_itr)->accept_top_down(visitor);

    list<RExpr*>::iterator r_itr;
    for (r_itr = _rexpr_list->begin(); r_itr != _rexpr_list->end(); ++r_itr)
	(*r_itr)->accept_top_down(visitor);

}

void
Exception::print_error(std::ostream &os)
{
    os << "Error in line " << _ast.line_no() << ": ";
    print_error_msg(os);
    os << '\n'
       << _ast
       << std::endl;
}


syntax highlighted by Code2HTML, v. 0.9.1