
/**
 * @file print.c
 *
 * Functions needed by print traversal.
 *
 */

/**
 * @defgroup print Print Functions.
 *
 * Functions needed by print traversal.
 *
 * @{
 */

#include "print.h"
#include "dbug.h"
#include "globals.h"
#include "memory.h"
#include "traverse.h"
#include "tree_basic.h"
#include "print_enum.h"
#include "mymacros.h"

/*
 * INFO structure
 */
struct INFO
{
    bool firsterror;
};

#define INFO_FIRSTERROR(n) ((n)->firsterror)

static info* MakeInfo()
{
    info* result;

    result = MEMmalloc(sizeof(info));

    INFO_FIRSTERROR(result) = FALSE;

    return result;
}

static info* FreeInfo(info* info)
{
    info = MEMfree(info);

    return info;
}



/** <!--******************************************************************-->
 *
 * @fn PRTprogram
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node program node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTprogram(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTprogram");

    PROGRAM_DECLS(arg_node) = TRAVopt(PROGRAM_DECLS(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTdecls
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node decls node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTdecls(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTdecls");

    DECLS_DECL(arg_node) = TRAVopt(DECLS_DECL(arg_node), arg_info);

    DECLS_NEXT(arg_node) = TRAVopt(DECLS_NEXT(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTexprs
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node exprs node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTexprs(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTexprs");

    EXPRS_EXPR(arg_node) = TRAVopt(EXPRS_EXPR(arg_node), arg_info);

    if (EXPRS_NEXT(arg_node)) printf(", ");

    EXPRS_NEXT(arg_node) = TRAVopt(EXPRS_NEXT(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTstmts
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node BinOp node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTstmts(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTstmts");

    STMTS_STMT(arg_node) = TRAVopt(STMTS_STMT(arg_node), arg_info);

    printf("\n");

    STMTS_NEXT(arg_node) = TRAVopt(STMTS_NEXT(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTassign
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node BinOp node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTassign(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTassign");

    if (ASSIGN_LET(arg_node) != NULL)
    {
        ASSIGN_LET(arg_node) = TRAVopt(ASSIGN_LET(arg_node), arg_info);
        printf(" = ");
    }

    ASSIGN_EXPR(arg_node) = TRAVopt(ASSIGN_EXPR(arg_node), arg_info);

    printf(";");

    DBUG_RETURN(arg_node);
}

node* PRTcast(node* arg_node, info* arg_info)
{
    const char* type = type_to_str(CAST_TYPE(arg_node));
    printf("(%s)", type);
    CAST_EXPR(arg_node) = TRAVopt(CAST_EXPR(arg_node), arg_info);
    return arg_node;
}

node* PRTcall(node* arg_node, info* arg_info)
{
    printf("%s (", CALL_NAME(arg_node));
    CALL_PARAMS(arg_node) = TRAVopt(CALL_PARAMS(arg_node), arg_info);
    printf(")");
    return arg_node;
}

/** <!--******************************************************************-->
 *
 * @fn PRTmonop
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node MonOp node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTmonop(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTmonop");

    printf("%s", monop_to_str(MONOP_OP(arg_node)));

    MONOP_EXPR(arg_node) = TRAVopt(MONOP_EXPR(arg_node), arg_info);
    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTbinop
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node BinOp node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTbinop(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTbinop");

    printf("( ");

    BINOP_LEFT(arg_node) = TRAVopt(BINOP_LEFT(arg_node), arg_info);

    const char* tmp = binop_to_str(BINOP_OP(arg_node));

    printf(" %s ", tmp);

    BINOP_RIGHT(arg_node) = TRAVopt(BINOP_RIGHT(arg_node), arg_info);

    printf(")");

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTfloat
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Float node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTfloat(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTfloat");

    printf("%f", FLOAT_VALUE(arg_node));

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTfundefs
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Fundef node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTfundefs(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTfundef");

    FUNDEFS_FUNDEF(arg_node) = TRAVopt(FUNDEFS_FUNDEF(arg_node), arg_info);

    FUNDEFS_NEXT(arg_node) = TRAVopt(FUNDEFS_NEXT(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTfundef
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Fundef node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTfundef(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTfundef");

    const char* type = type_to_str(FUNDEF_TYPE(arg_node));

    printf("%s %s(", type, FUNDEF_NAME(arg_node));

    FUNDEF_PARAMS(arg_node) = TRAVopt(FUNDEF_PARAMS(arg_node), arg_info);
    printf(")\n");

    FUNDEF_BODY(arg_node) = TRAVopt(FUNDEF_BODY(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTfunbody
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Funbody node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTfunbody(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTfunbody");

    printf("{\n");

    FUNBODY_VARDECLS(arg_node) = TRAVopt(FUNBODY_VARDECLS(arg_node), arg_info);
    FUNBODY_FUNDEFS(arg_node)  = TRAVopt(FUNBODY_FUNDEFS(arg_node), arg_info);
    FUNBODY_STMTS(arg_node)    = TRAVopt(FUNBODY_STMTS(arg_node), arg_info);

    printf("}\n\n");

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTglobaldef
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Globaldef node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTglobaldef(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTglobaldef");

    const char* type = type_to_str(GLOBALDEF_TYPE(arg_node));

    printf("%s %s", type, GLOBALDEF_NAME(arg_node));

    if (GLOBALDEF_INIT(arg_node))
    {
        printf(" = ");
        GLOBALDEF_INIT(arg_node) = TRAVopt(GLOBALDEF_INIT(arg_node), arg_info);
    }
    printf(";\n");

    DBUG_RETURN(arg_node);
}

node* PRTvardecl(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTvardecl");

    const char* type = type_to_str(VARDECL_TYPE(arg_node));

    printf("%s %s", type, VARDECL_NAME(arg_node));

    if (VARDECL_INIT(arg_node))
    {
        printf(" = ");
        VARDECL_INIT(arg_node) = TRAVopt(VARDECL_INIT(arg_node), arg_info);
    }

    printf(";\n");

    VARDECL_NEXT(arg_node) = TRAVopt(VARDECL_NEXT(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTparam
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Param node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTparam(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTparam");

    const char* type = type_to_str(PARAM_TYPE(arg_node));

    printf("%s %s", type, PARAM_NAME(arg_node));
    if (PARAM_NEXT(arg_node))
    {
        printf(", ");
    }

    PARAM_NEXT(arg_node) = TRAVopt(PARAM_NEXT(arg_node), arg_info);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTint
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Num node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTint(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTint");

    printf("%i", INT_VALUE(arg_node));

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTboolean
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node Boolean node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTbool(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTbool");

    if (BOOL_VALUE(arg_node))
    {
        printf("true");
    }
    else
    {
        printf("false");
    }

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTwhile
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node if node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTwhile(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTwhile");

    if (WHILE_ISDO(arg_node))
    {
        printf("do {\n");
        WHILE_BLOCK(arg_node) = TRAVopt(WHILE_BLOCK(arg_node), arg_info);
        printf("} while (");
        WHILE_CONDITION(arg_node) = TRAVopt(WHILE_CONDITION(arg_node), arg_info);
        printf(");\n");
    }
    else
    {
        printf("while (");
        WHILE_CONDITION(arg_node) = TRAVopt(WHILE_CONDITION(arg_node), arg_info);
        printf(") {\n");
        WHILE_BLOCK(arg_node) = TRAVopt(WHILE_BLOCK(arg_node), arg_info);
        printf("}");
    }

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTfor
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node if node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTfor(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTfor");

    printf("for (int %s = ", FOR_VARID(arg_node));
    FOR_VARINITVAL(arg_node) = TRAVopt(FOR_VARINITVAL(arg_node), arg_info);
    printf(", ");
    FOR_VARLIMVAL(arg_node) = TRAVopt(FOR_VARLIMVAL(arg_node), arg_info);
    if (FOR_VARSTEPVAL(arg_node))
    {
        printf(", ");
        FOR_VARSTEPVAL(arg_node) = TRAVopt(FOR_VARSTEPVAL(arg_node), arg_info);
    }
    printf(") {\n");
    FOR_BLOCK(arg_node) = TRAVopt(FOR_BLOCK(arg_node), arg_info);
    printf("}");

    DBUG_RETURN(arg_node);
}

node* PRTids(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTids");

    for (node* id = arg_node; id != NULL; id = IDS_NEXT(id))
    {
        printf("%s", IDS_NAME(id));
        if (IDS_NEXT(id) != NULL)
        {
            printf(", ");
        }
    }

    DBUG_RETURN(arg_node);
}

node* PRTarrexpr(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTarrexpr");

    printf("[ ");
    ARREXPR_EXPRS(arg_node) = TRAVopt(ARREXPR_EXPRS(arg_node), arg_info);
    printf(" ]");

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTif
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node if node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTif(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTif");

    printf("if (");
    IF_CONDITION(arg_node) = TRAVopt(IF_CONDITION(arg_node), arg_info);
    printf(") {\n");
    IF_BLOCK(arg_node) = TRAVopt(IF_BLOCK(arg_node), arg_info);
    printf("}");

    if (IF_ELSEBLOCK(arg_node))
    {
        printf(" else {\n");
        IF_ELSEBLOCK(arg_node) = TRAVopt(IF_ELSEBLOCK(arg_node), arg_info);
        printf("}");
    }

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTreturn
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node return node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTreturn(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTreturn");

    printf("return ");
    RETURN_RETVAL(arg_node) = TRAVopt(RETURN_RETVAL(arg_node), arg_info);
    printf(";");

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTvar
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node letrec node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTvar(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTvar");

    printf("%s", VAR_NAME(arg_node));

    if (VAR_INDICES(arg_node))
    {
        printf("[");
        TO(VAR_INDICES);
        printf("]");
    }

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTvarlet
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node letrec node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTvarlet(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTvarlet");

    printf("%s", VARLET_NAME(arg_node));

    if (VARLET_INDICES(arg_node))
    {
        printf("[");
        TO(VARLET_INDICES);
        printf("]");
    }

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTcondexpr
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node letrec node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTcondexpr(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTcondexpr");

    TO(CONDEXPR_PREDEXPR);

    printf(" ? ");

    TO(CONDEXPR_TRUEEXPR);

    printf(" : ");

    TO(CONDEXPR_FALSEEXPR);

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTsymboltableentry
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node letrec node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTsymboltableentry(node* arg_node, info* arg_info)
{
    DBUG_ENTER("PRTsymboltableentry");

    DBUG_RETURN(arg_node);
}

/** <!--******************************************************************-->
 *
 * @fn PRTerror
 *
 * @brief Prints the node and its sons/attributes
 *
 * @param arg_node letrec node to process
 * @param arg_info pointer to info structure
 *
 * @return processed node
 *
 ***************************************************************************/

node* PRTerror(node* arg_node, info* arg_info)
{
    bool first_error;

    DBUG_ENTER("PRTerror");

    if (NODE_ERROR(arg_node) != NULL)
    {
        NODE_ERROR(arg_node) = TRAVopt(NODE_ERROR(arg_node), arg_info);
    }

    first_error = INFO_FIRSTERROR(arg_info);

    if ((global.outfile != NULL) && (ERROR_ANYPHASE(arg_node) == global.compiler_anyphase))
    {
        if (first_error)
        {
            printf("\n/******* BEGIN TREE CORRUPTION ********\n");
            INFO_FIRSTERROR(arg_info) = FALSE;
        }

        printf("%s\n", ERROR_MESSAGE(arg_node));

        if (ERROR_NEXT(arg_node) != NULL)
        {
            TRAVopt(ERROR_NEXT(arg_node), arg_info);
        }

        if (first_error)
        {
            printf("********  END TREE CORRUPTION  *******/\n");
            INFO_FIRSTERROR(arg_info) = TRUE;
        }
    }

    DBUG_RETURN(arg_node);
}

/** <!-- ****************************************************************** -->
 * @brief Prints the given syntaxtree
 *
 * @param syntaxtree a node structure
 *
 * @return the unchanged nodestructure
 ******************************************************************************/

node* PRTdoPrint(node* syntaxtree)
{
    info* info;

    DBUG_ENTER("PRTdoPrint");

    DBUG_ASSERT((syntaxtree != NULL), "PRTdoPrint called with empty syntaxtree");

    printf("\n\n------------------------------\n\n");

    info = MakeInfo();

    TRAVpush(TR_prt);

    syntaxtree = TRAVopt(syntaxtree, info);

    TRAVpop();

    info = FreeInfo(info);

    printf("\n------------------------------\n\n");

    DBUG_RETURN(syntaxtree);
}

/**
 * @}
 */
