#include "pretty_printer.hh"
using namespace ast;

#include <iostream>
using namespace std;

void
PrettyPrinter::visit(BinRelLT &)
{
    _os << " < ";
}

void
PrettyPrinter::visit(BinRelLTE &)
{
    _os << " <= ";
}

void
PrettyPrinter::visit(BinRelGT &)
{
    _os << " > ";
}

void
PrettyPrinter::visit(BinRelGTE &)
{
    _os << " >= ";
}

void
PrettyPrinter::visit(BinRelEQ &)
{
    _os << " = ";
}

void
PrettyPrinter::visit(BinRelNEQ &)
{
    _os << " != ";
}

void
PrettyPrinter::visit(RExpr &rexpr)
{
    rexpr.begin()->accept(*this);
    rexpr.begin_br()->accept(*this);
    _os << rexpr.index();
    rexpr.end_br()->accept(*this);
    rexpr.end()->accept(*this);
}

void
PrettyPrinter::visit(WhereExpr &where_expr)
{
    where_expr.fun()->accept(*this);
    _os << " where ";

    const list<RExpr*> *rexpr_list = where_expr.rexpr_list();
    list<RExpr*>::const_iterator i = rexpr_list->begin();
    (*i)->accept(*this);
    for (++i; i != rexpr_list->end(); ++i)
	{
	    _os << " and ";
	    (*i)->accept(*this);
	}
}

void
PrettyPrinter::visit(WhenExpr &when_expr)
{
    when_expr.fun()->accept(*this);
    _os << " when ";
    when_expr.bexpr()->accept(*this);
}

void
PrettyPrinter::visit(Range &range)
{
    _os << range.id() << '{';
    range.where_expr()->accept(*this);
    _os << '}';
}

void
PrettyPrinter::visit(Values &values)
{
    _os << values.id() << '{';
    const list<WhenExpr*> *when_expr_list = values.when_expr_list();
    list<WhenExpr*>::const_iterator i = when_expr_list->begin();
    (*i)->accept(*this);
    for (++i; i != when_expr_list->end(); ++i)
	{
	    _os << ',';
	    (*i)->accept(*this);
	}
    _os << '}';
}

void
PrettyPrinter::visit(SimpleFun &simple_fun)
{
    simple_fun.expr()->accept(*this);
}

void
PrettyPrinter::visit(IDExpr &id_expr)
{
    _os << id_expr.id();
}

void
PrettyPrinter::visit(IntegerExpr &integer_expr)
{
    _os << integer_expr.integer();
}

void
PrettyPrinter::visit(MatrixExpr &matrix_expr)
{
    _os << matrix_expr.id() << '[';
    const list<Expr*> *expr_list = matrix_expr.expr_list();
    list<Expr*>::const_iterator i = expr_list->begin();
    (*i)->accept(*this);
    for (++i; i != expr_list->end(); ++i)
	{
	    _os << ',';
	    (*i)->accept(*this);
	}
    _os << ']';
}

void
PrettyPrinter::visit(FunCallExpr &matrix_expr)
{
    _os << matrix_expr.id() << '(';
    const list<Expr*> *expr_list = matrix_expr.expr_list();
    list<Expr*>::const_iterator i;
    bool first = true;
    for (i = expr_list->begin(); i != expr_list->end(); ++i)
	{
	    if (!first) _os << ','; first = false;
	    (*i)->accept(*this);
	}
    _os << ')';
}


void
PrettyPrinter::visit(BinOpExpr &binop_expr)
{
    _os << '(';
    binop_expr.left()->accept(*this);
    _os << ' ' << binop_expr.binop() << ' ';
    binop_expr.right()->accept(*this);
    _os << ')';
}

void
PrettyPrinter::visit(NEGExpr &nexpr)
{
    _os << '-';
    nexpr.expr()->accept(*this);
}

void
PrettyPrinter::visit(RelBExpr &bexpr)
{
    _os << '(';
    bexpr.left()->accept(*this);
    bexpr.rel()->accept(*this);
    bexpr.right()->accept(*this);
    _os << ')';
}

void
PrettyPrinter::visit(ANDBExpr &bexpr)
{
    _os << '(';
    bexpr.left()->accept(*this);
    _os << " and ";
    bexpr.right()->accept(*this);
    _os << ')';
}

void
PrettyPrinter::visit(ORBExpr &bexpr)
{
    _os << '(';
    bexpr.left()->accept(*this);
    _os << " or ";
    bexpr.right()->accept(*this);
    _os << ')';
}

void
PrettyPrinter::visit(NOTBExpr &bexpr)
{
    _os << '!';
    bexpr.bexpr()->accept(*this);
}

void
PrettyPrinter::visit(TrueExpr &bexpr)
{
    _os << "true";
}


void
PrettyPrinter::visit(Update &update)
{
    _os << update.type() << ' '
	<< update.name()
	<< '[';
    const list<const char *> *indices = update.indices();
    list<const char *>::const_iterator i = indices->begin();
    _os << *i;
    for (++i; i != indices->end(); ++i)
	_os << ',' << *i;
    _os << "] = ";
    update.fun()->accept(*this);
}

void
PrettyPrinter::visit(ValDeclaration &val_decl)
{
    _os << "val " << val_decl.name() << " : " << val_decl.type() << ' ';
}
void
PrettyPrinter::visit(FunDeclaration &fun_decl)
{
    _os << "fun " << fun_decl.name() << '(';
    const char *sep = "";
    list<basic_type_t>::const_iterator i;
    const list<basic_type_t> *par_types = fun_decl.parameter_types();
    for (i = par_types->begin(); i != par_types->end(); ++i)
	{
	    _os << sep << *i;
	    sep = ", ";
	}
    _os << ')' << " : " << fun_decl.return_type() << ' ';
}

void
PrettyPrinter::visit(MatrixDeclaration &matrix_decl)
{
    _os << "matrix " << matrix_decl.name() << '[';
    list<Expr*> *dims = matrix_decl.dim_list();
    list<Expr*>::const_iterator i;
    const char *sep = "";
    for (i = dims->begin(); i != dims->end(); ++i)
	{
	    _os << sep;
	    (*i)->accept(*this);
	    sep = ", ";
	}
    _os << ']' << " : " << matrix_decl.type() << ' ';
}


void
PrettyPrinter::visit(DProg &dprog)
{
    bool in_end_p = false;

    const list<Declaration*> *globals = dprog.globals();
    if (globals->begin() != globals->end())
	{
	    _os << "globals ";
	    list<Declaration*>::const_iterator g_itr;
	    for (g_itr = globals->begin(); g_itr != globals->end(); ++g_itr)
		(*g_itr)->accept(*this);
	    in_end_p = true;
	}

    const list<Declaration*> *parameters = dprog.parameters();
    if (parameters->begin() != parameters->end())
	{
	    _os << "parameters ";
	    list<Declaration*>::const_iterator p_itr;
	    for (p_itr = parameters->begin(); p_itr != parameters->end(); ++p_itr)
		(*p_itr)->accept(*this);
	    in_end_p = true;
	}

    const list<Declaration*> *locals = dprog.locals();
    if (locals->begin() != locals->end())
	{
	    _os << "locals ";
	    list<Declaration*>::const_iterator l_itr;
	    for (l_itr = locals->begin(); l_itr != locals->end(); ++l_itr)
		(*l_itr)->accept(*this);
	    in_end_p = true;
	}

    if (in_end_p)
	_os << "in ";

    const list<Update*> *update_list = dprog.update_list();
    list<Update*>::const_iterator u_itr = update_list->begin();
    (*u_itr)->accept(*this);

    for (u_itr++ ; u_itr != update_list->end(); ++u_itr)
	{
	    _os << ' ';
	    (*u_itr)->accept(*this);
	}

    _os << " where ";

    const list<RExpr*> *rexpr_list = dprog.rexpr_list();
    list<RExpr*>::const_iterator re_itr = rexpr_list->begin();
    (*re_itr)->accept(*this);
    for (++re_itr; re_itr != rexpr_list->end(); ++re_itr)
	{
	    _os << " and ";
	    (*re_itr)->accept(*this);
	}

    if (in_end_p)
	_os << " end";
    _os << endl;
}


syntax highlighted by Code2HTML, v. 0.9.1