/*
 * Copyright (c) 2008-2015 Freescale Semiconductor, Inc.
 * Copyright 2016-2018 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "ElftosbAST.h"
#include <stdexcept>
#include <math.h>
#include <assert.h>
#include "ElftosbErrors.h"
#include "format_string.h"

using namespace elftosb;

#pragma mark = ASTNode =

void ASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s\n", nodeName().c_str());
}

void ASTNode::printIndent(int indent) const
{
    int i;
    for (i = 0; i < indent; ++i)
    {
        printf("   ");
    }
}

void ASTNode::setLocation(token_loc_t &first, token_loc_t &last)
{
    m_location.m_firstLine = first.m_firstLine;
    m_location.m_lastLine = last.m_lastLine;
}

void ASTNode::setLocation(ASTNode *first, ASTNode *last)
{
    m_location.m_firstLine = first->getLocation().m_firstLine;
    m_location.m_lastLine = last->getLocation().m_lastLine;
}

#pragma mark = ListASTNode =

ListASTNode::ListASTNode(const ListASTNode &other)
    : ASTNode(other)
    , m_list()
{
    // deep copy each item of the original's list
    const_iterator it = other.begin();
    for (; it != other.end(); ++it)
    {
        m_list.push_back((*it)->clone());
    }
}

//! Deletes child node in the list.
//!
ListASTNode::~ListASTNode()
{
    iterator it = begin();
    for (; it != end(); it++)
    {
        delete *it;
    }
}

//! If \a node is NULL then the list is left unmodified.
//!
//! The list node's location is automatically updated after the node is added by a call
//! to updateLocation().
void ListASTNode::appendNode(ASTNode *node)
{
    if (node)
    {
        m_list.push_back(node);
        updateLocation();
    }
}

void ListASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    int n = 0;
    const_iterator it = begin();
    for (; it != end(); it++, n++)
    {
        printIndent(indent + 1);
        printf("%d:\n", n);
        (*it)->printTree(indent + 2);
    }
}

void ListASTNode::updateLocation()
{
    token_loc_t current = { 0 };
    const_iterator it = begin();
    for (; it != end(); it++)
    {
        const ASTNode *node = *it;
        const token_loc_t &loc = node->getLocation();

        // handle first node
        if (current.m_firstLine == 0)
        {
            current = loc;
            continue;
        }

        if (loc.m_firstLine < current.m_firstLine)
        {
            current.m_firstLine = loc.m_firstLine;
        }

        if (loc.m_lastLine > current.m_lastLine)
        {
            current.m_lastLine = loc.m_lastLine;
        }
    }

    setLocation(current);
}

#pragma mark = CommandFileASTNode =

CommandFileASTNode::CommandFileASTNode()
    : ASTNode()
    , m_options()
    , m_constants()
    , m_sources()
    , m_sections()
{
}

CommandFileASTNode::CommandFileASTNode(const CommandFileASTNode &other)
    : ASTNode(other)
    , m_options()
    , m_constants()
    , m_sources()
    , m_sections()
{
    m_options = dynamic_cast<ListASTNode *>(other.m_options->clone());
    m_constants = dynamic_cast<ListASTNode *>(other.m_constants->clone());
    m_sources = dynamic_cast<ListASTNode *>(other.m_sources->clone());
    m_sections = dynamic_cast<ListASTNode *>(other.m_sections->clone());
}

void CommandFileASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("options:\n");
    if (m_options)
        m_options->printTree(indent + 2);

    printIndent(indent + 1);
    printf("constants:\n");
    if (m_constants)
        m_constants->printTree(indent + 2);

    printIndent(indent + 1);
    printf("sources:\n");
    if (m_sources)
        m_sources->printTree(indent + 2);

    printIndent(indent + 1);
    printf("sections:\n");
    if (m_sections)
        m_sections->printTree(indent + 2);
}

#pragma mark = ExprASTNode =

int_size_t ExprASTNode::resultIntSize(int_size_t a, int_size_t b)
{
    int_size_t result;
    switch (a)
    {
        case kWordSize:
            result = kWordSize;
            break;
        case kHalfWordSize:
            if (b == kWordSize)
            {
                result = kWordSize;
            }
            else
            {
                result = kHalfWordSize;
            }
            break;
        case kByteSize:
            if (b == kWordSize)
            {
                result = kWordSize;
            }
            else if (b == kHalfWordSize)
            {
                result = kHalfWordSize;
            }
            else
            {
                result = kByteSize;
            }
            break;
    }

    return result;
}

#pragma mark = IntConstExprASTNode =

IntConstExprASTNode::IntConstExprASTNode(const IntConstExprASTNode &other)
    : ExprASTNode(other)
    , m_value(other.m_value)
    , m_size(other.m_size)
{
}

void IntConstExprASTNode::printTree(int indent) const
{
    printIndent(indent);
    char sizeChar = '?';
    switch (m_size)
    {
        case kWordSize:
            sizeChar = 'w';
            break;
        case kHalfWordSize:
            sizeChar = 'h';
            break;
        case kByteSize:
            sizeChar = 'b';
            break;
    }
    printf("%s(%d:%c)\n", nodeName().c_str(), m_value, sizeChar);
}

#pragma mark = VariableExprASTNode =

VariableExprASTNode::VariableExprASTNode(const VariableExprASTNode &other)
    : ExprASTNode(other)
    , m_variable()
{
    m_variable = new std::string(*other.m_variable);
}

void VariableExprASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s(%s)\n", nodeName().c_str(), m_variable->c_str());
}

ExprASTNode *VariableExprASTNode::reduce(EvalContext &context)
{
    if (!context.isVariableDefined(*m_variable))
    {
        throw std::runtime_error(
            format_string("line %d: undefined variable '%s'", getFirstLine(), m_variable->c_str()));
    }

    uint32_t value = context.getVariableValue(*m_variable);
    int_size_t size = context.getVariableSize(*m_variable);
    return new IntConstExprASTNode(value, size);
}

#pragma mark = SymbolRefExprASTNode =

SymbolRefExprASTNode::SymbolRefExprASTNode(const SymbolRefExprASTNode &other)
    : ExprASTNode(other)
    , m_symbol(NULL)
{
    if (other.m_symbol)
    {
        m_symbol = dynamic_cast<SymbolASTNode *>(other.m_symbol->clone());
    }
}

void SymbolRefExprASTNode::printTree(int indent) const
{
}

ExprASTNode *SymbolRefExprASTNode::reduce(EvalContext &context)
{
    EvalContext::SourceFileManager *manager = context.getSourceFileManager();
    if (!manager)
    {
        throw std::runtime_error("no source manager available");
    }

    if (!m_symbol)
    {
        throw semantic_error("no symbol provided");
    }

    // Get the name of the symbol
    std::string *symbolName = m_symbol->getSymbolName();
    //	if (!symbolName)
    //	{
    //		throw semantic_error(format_string("line %d: no symbol name provided", getFirstLine()));
    //	}

    // Get the source file.
    std::string *sourceName = m_symbol->getSource();
    SourceFile *sourceFile;

    if (sourceName)
    {
        sourceFile = manager->getSourceFile(*sourceName);
        if (!sourceFile)
        {
            throw semantic_error(
                format_string("line %d: no source file named %s", getFirstLine(), sourceName->c_str()));
        }
    }
    else
    {
        sourceFile = manager->getDefaultSourceFile();
        if (!sourceFile)
        {
            throw semantic_error(format_string("line %d: no default source file is set", getFirstLine()));
        }
    }

    // open the file if it hasn't already been
    if (!sourceFile->isOpen())
    {
        sourceFile->open();
    }

    // Make sure the source file supports symbols before going any further
    if (symbolName && !sourceFile->supportsNamedSymbols())
    {
        throw semantic_error(format_string("line %d: source file %s does not support symbols", getFirstLine(),
                                           sourceFile->getPath().c_str()));
    }

    if (!symbolName && !sourceFile->hasEntryPoint())
    {
        throw semantic_error(format_string("line %d: source file %s does not have an entry point", getFirstLine(),
                                           sourceFile->getPath().c_str()));
    }

    // Returns a const expr node with the symbol's value.
    uint32_t value;
    if (symbolName)
    {
        value = sourceFile->getSymbolValue(*symbolName);
    }
    else
    {
        value = sourceFile->getEntryPointAddress();
    }
    return new IntConstExprASTNode(value);
}

#pragma mark = NegativeExprASTNode =

NegativeExprASTNode::NegativeExprASTNode(const NegativeExprASTNode &other)
    : ExprASTNode(other)
    , m_expr()
{
    m_expr = dynamic_cast<ExprASTNode *>(other.m_expr->clone());
}

void NegativeExprASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);
    if (m_expr)
        m_expr->printTree(indent + 1);
}

ExprASTNode *NegativeExprASTNode::reduce(EvalContext &context)
{
    if (!m_expr)
    {
        return this;
    }

    m_expr = m_expr->reduce(context);
    IntConstExprASTNode *intConst = dynamic_cast<IntConstExprASTNode *>(m_expr.get());
    if (intConst)
    {
        int32_t value = -(int32_t)intConst->getValue();
        return new IntConstExprASTNode((uint32_t)value, intConst->getSize());
    }
    else
    {
        return this;
    }
}

#pragma mark = BooleanNotExprASTNode =

BooleanNotExprASTNode::BooleanNotExprASTNode(const BooleanNotExprASTNode &other)
    : ExprASTNode(other)
    , m_expr()
{
    m_expr = dynamic_cast<ExprASTNode *>(other.m_expr->clone());
}

void BooleanNotExprASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);
    if (m_expr)
        m_expr->printTree(indent + 1);
}

ExprASTNode *BooleanNotExprASTNode::reduce(EvalContext &context)
{
    if (!m_expr)
    {
        return this;
    }

    m_expr = m_expr->reduce(context);
    IntConstExprASTNode *intConst = dynamic_cast<IntConstExprASTNode *>(m_expr.get());
    if (intConst)
    {
        int32_t value = !((int32_t)intConst->getValue());
        return new IntConstExprASTNode((uint32_t)value, intConst->getSize());
    }
    else
    {
        throw semantic_error(
            format_string("line %d: expression did not evaluate to an integer", m_expr->getFirstLine()));
    }
}

#pragma mark = SourceFileFunctionASTNode =

SourceFileFunctionASTNode::SourceFileFunctionASTNode(const SourceFileFunctionASTNode &other)
    : ExprASTNode(other)
    , m_functionName()
    , m_sourceFile()
{
    m_functionName = new std::string(*other.m_functionName);
    m_sourceFile = new std::string(*other.m_sourceFile);
}

void SourceFileFunctionASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);
    printIndent(indent + 1);

    // for some stupid reason the msft C++ compiler barfs on the following line if the ".get()" parts are remove,
    // even though the first line of reduce() below has the same expression, just in parentheses. stupid compiler.
    if (m_functionName.get() && m_sourceFile.get())
    {
        printf("%s ( %s )\n", m_functionName->c_str(), m_sourceFile->c_str());
    }
}

ExprASTNode *SourceFileFunctionASTNode::reduce(EvalContext &context)
{
    if (!(m_functionName && m_sourceFile))
    {
        throw std::runtime_error("unset function name or source file");
    }

    // Get source file manager from evaluation context. This will be the
    // conversion controller itself.
    EvalContext::SourceFileManager *mgr = context.getSourceFileManager();
    if (!mgr)
    {
        throw std::runtime_error("source file manager is not set");
    }

    // Perform function
    uint32_t functionResult = 0;
    if (*m_functionName == "exists")
    {
        functionResult = static_cast<uint32_t>(mgr->hasSourceFile(*m_sourceFile));
    }

    // Return function result as an expression node
    return new IntConstExprASTNode(functionResult);
}

#pragma mark = DefinedOperatorASTNode =

DefinedOperatorASTNode::DefinedOperatorASTNode(const DefinedOperatorASTNode &other)
    : ExprASTNode(other)
    , m_constantName()
{
    m_constantName = new std::string(*other.m_constantName);
}

void DefinedOperatorASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);
    printIndent(indent + 1);

    if (m_constantName)
    {
        printf("defined ( %s )\n", m_constantName->c_str());
    }
}

ExprASTNode *DefinedOperatorASTNode::reduce(EvalContext &context)
{
    assert(m_constantName);

    // Return function result as an expression node
    return new IntConstExprASTNode(context.isVariableDefined(m_constantName) ? 1 : 0);
}

#pragma mark = SizeofOperatorASTNode =

SizeofOperatorASTNode::SizeofOperatorASTNode(const SizeofOperatorASTNode &other)
    : ExprASTNode(other)
    , m_constantName()
    , m_symbol()
{
    m_constantName = new std::string(*other.m_constantName);
    m_symbol = dynamic_cast<SymbolASTNode *>(other.m_symbol->clone());
}

void SizeofOperatorASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);

    printIndent(indent + 1);

    if (m_constantName)
    {
        printf("sizeof: %s\n", m_constantName->c_str());
    }
    else if (m_symbol)
    {
        printf("sizeof:\n");
        m_symbol->printTree(indent + 2);
    }
}

ExprASTNode *SizeofOperatorASTNode::reduce(EvalContext &context)
{
    // One or the other must be defined.
    assert(m_constantName || m_symbol);

    EvalContext::SourceFileManager *manager = context.getSourceFileManager();
    assert(manager);

    unsigned sizeInBytes = 0;
    SourceFile *sourceFile;

    if (m_symbol)
    {
        // Get the symbol name.
        std::string *symbolName = m_symbol->getSymbolName();
        assert(symbolName);

        // Get the source file, using the default if one is not specified.
        std::string *sourceName = m_symbol->getSource();
        if (sourceName)
        {
            sourceFile = manager->getSourceFile(*sourceName);
            if (!sourceFile)
            {
                throw semantic_error(
                    format_string("line %d: invalid source file: %s", getFirstLine(), sourceName->c_str()));
            }
        }
        else
        {
            sourceFile = manager->getDefaultSourceFile();
            if (!sourceFile)
            {
                throw semantic_error(format_string("line %d: no default source file is set", getFirstLine()));
            }
        }

        // open the file if it hasn't already been
        if (!sourceFile->isOpen())
        {
            sourceFile->open();
        }

        // Make sure the source file supports symbols before going any further
        if (!sourceFile->supportsNamedSymbols())
        {
            throw semantic_error(format_string("line %d: source file %s does not support symbols", getFirstLine(),
                                               sourceFile->getPath().c_str()));
        }

        // Get the size of the symbol.
        if (sourceFile->hasSymbol(*symbolName))
        {
            sizeInBytes = sourceFile->getSymbolSize(*symbolName);
        }
    }
    else if (m_constantName)
    {
        // See if the "constant" is really a constant or if it's a source name.
        if (manager->hasSourceFile(m_constantName))
        {
            sourceFile = manager->getSourceFile(m_constantName);
            if (sourceFile)
            {
                sizeInBytes = sourceFile->getSize();
            }
        }
        else
        {
            // Regular constant.
            if (!context.isVariableDefined(*m_constantName))
            {
                throw semantic_error(format_string("line %d: cannot get size of undefined constant %s", getFirstLine(),
                                                   m_constantName->c_str()));
            }

            int_size_t intSize = context.getVariableSize(*m_constantName);
            switch (intSize)
            {
                case kWordSize:
                    sizeInBytes = sizeof(uint32_t);
                    break;
                case kHalfWordSize:
                    sizeInBytes = sizeof(uint16_t);
                    break;
                case kByteSize:
                    sizeInBytes = sizeof(uint8_t);
                    break;
            }
        }
    }

    // Return function result as an expression node
    return new IntConstExprASTNode(sizeInBytes);
}

#pragma mark = BinaryOpExprASTNode =

BinaryOpExprASTNode::BinaryOpExprASTNode(const BinaryOpExprASTNode &other)
    : ExprASTNode(other)
    , m_left()
    , m_op(other.m_op)
    , m_right()
{
    m_left = dynamic_cast<ExprASTNode *>(other.m_left->clone());
    m_right = dynamic_cast<ExprASTNode *>(other.m_right->clone());
}

void BinaryOpExprASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("left:\n");
    if (m_left)
        m_left->printTree(indent + 2);

    printIndent(indent + 1);
    printf("op: %s\n", getOperatorName().c_str());

    printIndent(indent + 1);
    printf("right:\n");
    if (m_right)
        m_right->printTree(indent + 2);
}

std::string BinaryOpExprASTNode::getOperatorName() const
{
    switch (m_op)
    {
        case kAdd:
            return "+";
        case kSubtract:
            return "-";
        case kMultiply:
            return "*";
        case kDivide:
            return "/";
        case kModulus:
            return "%";
        case kPower:
            return "**";
        case kBitwiseAnd:
            return "&";
        case kBitwiseOr:
            return "|";
        case kBitwiseXor:
            return "^";
        case kShiftLeft:
            return "<<";
        case kShiftRight:
            return ">>";
        case kLessThan:
            return "<";
        case kGreaterThan:
            return ">";
        case kLessThanEqual:
            return "<=";
        case kGreaterThanEqual:
            return ">";
        case kEqual:
            return "==";
        case kNotEqual:
            return "!=";
        case kBooleanAnd:
            return "&&";
        case kBooleanOr:
            return "||";
    }

    return "???";
}

//! \todo Fix power operator under windows!!!
//!
ExprASTNode *BinaryOpExprASTNode::reduce(EvalContext &context)
{
    if (!m_left || !m_right)
    {
        return this;
    }

    IntConstExprASTNode *leftIntConst = NULL;
    IntConstExprASTNode *rightIntConst = NULL;
    uint32_t leftValue;
    uint32_t rightValue;
    uint32_t result = 0;

    // Always reduce the left hand side.
    m_left = m_left->reduce(context);
    leftIntConst = dynamic_cast<IntConstExprASTNode *>(m_left.get());
    if (!leftIntConst)
    {
        throw semantic_error(
            format_string("left hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
    }
    leftValue = leftIntConst->getValue();

    // Boolean && and || operators are handled separately so that we can perform
    // short-circuit evaluation.
    if (m_op == kBooleanAnd || m_op == kBooleanOr)
    {
        // Reduce right hand side only if required to evaluate the boolean operator.
        if ((m_op == kBooleanAnd && leftValue != 0) || (m_op == kBooleanOr && leftValue == 0))
        {
            m_right = m_right->reduce(context);
            rightIntConst = dynamic_cast<IntConstExprASTNode *>(m_right.get());
            if (!rightIntConst)
            {
                throw semantic_error(format_string("right hand side of %s operator failed to evaluate to an integer",
                                                   getOperatorName().c_str()));
            }
            rightValue = rightIntConst->getValue();

            // Perform the boolean operation.
            switch (m_op)
            {
                case kBooleanAnd:
                    result = leftValue && rightValue;
                    break;

                case kBooleanOr:
                    result = leftValue && rightValue;
                    break;

                default:;
            }
        }
        else if (m_op == kBooleanAnd)
        {
            // The left hand side is false, so the && operator's result must be false
            // without regard to the right hand side.
            result = 0;
        }
        else if (m_op == kBooleanOr)
        {
            // The left hand value is true so the || result is automatically true.
            result = 1;
        }
    }
    else
    {
        // Reduce right hand side always for most operators.
        m_right = m_right->reduce(context);
        rightIntConst = dynamic_cast<IntConstExprASTNode *>(m_right.get());
        if (!rightIntConst)
        {
            throw semantic_error(format_string("right hand side of %s operator failed to evaluate to an integer",
                                               getOperatorName().c_str()));
        }
        rightValue = rightIntConst->getValue();

        switch (m_op)
        {
            case kAdd:
                result = leftValue + rightValue;
                break;
            case kSubtract:
                result = leftValue - rightValue;
                break;
            case kMultiply:
                result = leftValue * rightValue;
                break;
            case kDivide:
                result = leftValue / rightValue;
                break;
            case kModulus:
                result = leftValue % rightValue;
                break;
            case kPower:
#ifdef WIN32
                result = 0;
#else
                result = lroundf(powf(float(leftValue), float(rightValue)));
#endif
                break;
            case kBitwiseAnd:
                result = leftValue & rightValue;
                break;
            case kBitwiseOr:
                result = leftValue | rightValue;
                break;
            case kBitwiseXor:
                result = leftValue ^ rightValue;
                break;
            case kShiftLeft:
                result = leftValue << rightValue;
                break;
            case kShiftRight:
                result = leftValue >> rightValue;
                break;
            case kLessThan:
                result = leftValue < rightValue;
                break;
            case kGreaterThan:
                result = leftValue > rightValue;
                break;
            case kLessThanEqual:
                result = leftValue <= rightValue;
                break;
            case kGreaterThanEqual:
                result = leftValue >= rightValue;
                break;
            case kEqual:
                result = leftValue == rightValue;
                break;
            case kNotEqual:
                result = leftValue != rightValue;
                break;
            default:;
        }
    }

    // Create the result value.
    int_size_t resultSize;
    if (leftIntConst && rightIntConst)
    {
        resultSize = resultIntSize(leftIntConst->getSize(), rightIntConst->getSize());
    }
    else if (leftIntConst)
    {
        resultSize = leftIntConst->getSize();
    }
    else
    {
        // This shouldn't really be possible, but just in case.
        resultSize = kWordSize;
    }
    return new IntConstExprASTNode(result, resultSize);
}

#pragma mark = IntSizeExprASTNode =

IntSizeExprASTNode::IntSizeExprASTNode(const IntSizeExprASTNode &other)
    : ExprASTNode(other)
    , m_expr()
    , m_size(other.m_size)
{
    m_expr = dynamic_cast<ExprASTNode *>(other.m_expr->clone());
}

void IntSizeExprASTNode::printTree(int indent) const
{
    ExprASTNode::printTree(indent);

    char sizeChar = '?';
    switch (m_size)
    {
        case kWordSize:
            sizeChar = 'w';
            break;
        case kHalfWordSize:
            sizeChar = 'h';
            break;
        case kByteSize:
            sizeChar = 'b';
            break;
    }
    printIndent(indent + 1);
    printf("size: %c\n", sizeChar);

    printIndent(indent + 1);
    printf("expr:\n");
    if (m_expr)
        m_expr->printTree(indent + 2);
}

ExprASTNode *IntSizeExprASTNode::reduce(EvalContext &context)
{
    if (!m_expr)
    {
        return this;
    }

    m_expr = m_expr->reduce(context);
    IntConstExprASTNode *intConst = dynamic_cast<IntConstExprASTNode *>(m_expr.get());
    if (!intConst)
    {
        return this;
    }

    return new IntConstExprASTNode(intConst->getValue(), m_size);
}

#pragma mark = ExprConstASTNode =

ExprConstASTNode::ExprConstASTNode(const ExprConstASTNode &other)
    : ConstASTNode(other)
    , m_expr()
{
    m_expr = dynamic_cast<ExprASTNode *>(other.m_expr->clone());
}

void ExprConstASTNode::printTree(int indent) const
{
    ConstASTNode::printTree(indent);
    if (m_expr)
        m_expr->printTree(indent + 1);
}

#pragma mark = StringConstASTNode =

StringConstASTNode::StringConstASTNode(const StringConstASTNode &other)
    : ConstASTNode(other)
    , m_value()
{
    m_value = new std::string(other.m_value);
}

void StringConstASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s(%s)\n", nodeName().c_str(), m_value->c_str());
}

#pragma mark = BlobConstASTNode =

BlobConstASTNode::BlobConstASTNode(const BlobConstASTNode &other)
    : ConstASTNode(other)
    , m_blob()
{
    m_blob = new Blob(*other.m_blob);
}

void BlobConstASTNode::printTree(int indent) const
{
    printIndent(indent);

    const uint8_t *dataPtr = m_blob->getData();
    unsigned dataLen = m_blob->getLength();
    printf("%s(%p:%d)\n", nodeName().c_str(), dataPtr, dataLen);
}

#pragma mark = IVTConstASTNode =

IVTConstASTNode::IVTConstASTNode(const IVTConstASTNode &other)
    : ConstASTNode(other)
    , m_fields()
{
    m_fields = dynamic_cast<ListASTNode *>(other.m_fields->clone());
}

void IVTConstASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s:\n", nodeName().c_str());
    if (m_fields)
    {
        m_fields->printTree(indent + 1);
    }
}

#pragma mark = AssignmentASTNode =

AssignmentASTNode::AssignmentASTNode(const AssignmentASTNode &other)
    : ASTNode(other)
    , m_ident()
    , m_value()
{
    m_ident = new std::string(*other.m_ident);
    m_value = dynamic_cast<ConstASTNode *>(other.m_value->clone());
}

void AssignmentASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s(%s)\n", nodeName().c_str(), m_ident->c_str());

    if (m_value)
        m_value->printTree(indent + 1);
}

#pragma mark = SourceDefASTNode =

SourceDefASTNode::SourceDefASTNode(const SourceDefASTNode &other)
    : ASTNode(other)
    , m_name()
{
    m_name = new std::string(*other.m_name);
}

#pragma mark = PathSourceDefASTNode =

PathSourceDefASTNode::PathSourceDefASTNode(const PathSourceDefASTNode &other)
    : SourceDefASTNode(other)
    , m_path()
{
    m_path = new std::string(*other.m_path);
}

void PathSourceDefASTNode::printTree(int indent) const
{
    SourceDefASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("path: %s\n", m_path->c_str());

    printIndent(indent + 1);
    printf("attributes:\n");
    if (m_attributes)
    {
        m_attributes->printTree(indent + 2);
    }
}

#pragma mark = ExternSourceDefASTNode =

ExternSourceDefASTNode::ExternSourceDefASTNode(const ExternSourceDefASTNode &other)
    : SourceDefASTNode(other)
    , m_expr()
{
    m_expr = dynamic_cast<ExprASTNode *>(other.m_expr->clone());
}

void ExternSourceDefASTNode::printTree(int indent) const
{
    SourceDefASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("expr:\n");
    if (m_expr)
        m_expr->printTree(indent + 2);

    printIndent(indent + 1);
    printf("attributes:\n");
    if (m_attributes)
    {
        m_attributes->printTree(indent + 2);
    }
}

#pragma mark = SectionContentsASTNode =

SectionContentsASTNode::SectionContentsASTNode(const SectionContentsASTNode &other)
    : ASTNode(other)
    , m_sectionExpr()
{
    m_sectionExpr = dynamic_cast<ExprASTNode *>(other.m_sectionExpr->clone());
}

void SectionContentsASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("section#:\n");
    if (m_sectionExpr)
        m_sectionExpr->printTree(indent + 2);
}

#pragma mark = DataSectionContentsASTNode =

DataSectionContentsASTNode::DataSectionContentsASTNode(const DataSectionContentsASTNode &other)
    : SectionContentsASTNode(other)
    , m_contents()
{
    m_contents = dynamic_cast<ASTNode *>(other.m_contents->clone());
}

void DataSectionContentsASTNode::printTree(int indent) const
{
    SectionContentsASTNode::printTree(indent);

    if (m_contents)
    {
        m_contents->printTree(indent + 1);
    }
}

#pragma mark = BootableSectionContentsASTNode =

BootableSectionContentsASTNode::BootableSectionContentsASTNode(const BootableSectionContentsASTNode &other)
    : SectionContentsASTNode(other)
    , m_statements()
{
    m_statements = dynamic_cast<ListASTNode *>(other.m_statements->clone());
}

void BootableSectionContentsASTNode::printTree(int indent) const
{
    SectionContentsASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("statements:\n");
    if (m_statements)
        m_statements->printTree(indent + 2);
}

#pragma mark = KeyblobEntryASTNode =

KeyblobEntryASTNode::KeyblobEntryASTNode(const KeyblobEntryASTNode &other)
    : ConstASTNode(other)
    , m_fields()
{
    m_fields = dynamic_cast<ListASTNode *>(other.m_fields->clone());
}

void KeyblobEntryASTNode::printTree(int indent) const
{
    ConstASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("fields:\n");
    if (m_fields)
        m_fields->printTree(indent + 2);
}

#pragma mark = IfStatementASTNode =

//! \warning Be careful; this method could enter an infinite loop if m_nextIf feeds
//!		back onto itself. m_nextIf must be NULL at some point down the next if list.
IfStatementASTNode::IfStatementASTNode(const IfStatementASTNode &other)
    : StatementASTNode()
    , m_conditionExpr()
    , m_ifStatements()
    , m_nextIf()
    , m_elseStatements()
{
    m_conditionExpr = dynamic_cast<ExprASTNode *>(other.m_conditionExpr->clone());
    m_ifStatements = dynamic_cast<ListASTNode *>(other.m_ifStatements->clone());
    m_nextIf = dynamic_cast<IfStatementASTNode *>(other.m_nextIf->clone());
    m_elseStatements = dynamic_cast<ListASTNode *>(other.m_elseStatements->clone());
}

#pragma mark = ModeStatementASTNode =

ModeStatementASTNode::ModeStatementASTNode(const ModeStatementASTNode &other)
    : StatementASTNode(other)
    , m_modeExpr()
{
    m_modeExpr = dynamic_cast<ExprASTNode *>(other.m_modeExpr->clone());
}

void ModeStatementASTNode::printTree(int indent) const
{
    StatementASTNode::printTree(indent);
    printIndent(indent + 1);
    printf("mode:\n");
    if (m_modeExpr)
        m_modeExpr->printTree(indent + 2);
}

#pragma mark = EraseStatementASTNode =

EraseStatementASTNode::EraseStatementASTNode(const EraseStatementASTNode &other)
    : StatementASTNode(other)
    , m_doEraseAll(other.m_doEraseAll)
    , m_doEraseAllUnsecure(other.m_doEraseAllUnsecure)
    , m_memOption()
    , m_rangeExpr()
{
    m_rangeExpr = dynamic_cast<ExprASTNode *>(other.m_rangeExpr->clone());
    m_memOption = dynamic_cast<ExprASTNode *>(other.m_memOption->clone());
}

void EraseStatementASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s%s%s\n", nodeName().c_str(), (m_doEraseAll ? "/ALL" : ""), (m_doEraseAllUnsecure ? "/UNSEC" : ""));

    printIndent(indent + 1);
    printf("range:\n");
    if (m_rangeExpr)
        m_rangeExpr->printTree(indent + 2);

    printIndent(indent + 1);
    printf("mem option:\n");
    if (m_memOption)
        m_memOption->printTree(indent + 2);
}

#pragma mark = MessageStatementASTNode =

MessageStatementASTNode::MessageStatementASTNode(const MessageStatementASTNode &other)
    : StatementASTNode(other)
    , m_type(other.m_type)
    , m_message()
{
    m_message = new std::string(*other.m_message);
}

void MessageStatementASTNode::printTree(int indent) const
{
    StatementASTNode::printTree(indent);
    printIndent(indent + 1);
    printf("%s: %s\n", getTypeName(), m_message->c_str());
}

const char *MessageStatementASTNode::getTypeName() const
{
    switch (m_type)
    {
        case kInfo:
            return "info";

        case kWarning:
            return "warning";

        case kError:
            return "error";
    }

    return "unknown";
}

#pragma mark = LoadStatementASTNode =

LoadStatementASTNode::LoadStatementASTNode(const LoadStatementASTNode &other)
    : StatementASTNode(other)
    , m_data()
    , m_target()
    , m_loadOption()
{
    m_data = other.m_data->clone();
    m_target = other.m_target->clone();
    m_loadOption = dynamic_cast<ExprASTNode *>(other.m_loadOption->clone());
}

void LoadStatementASTNode::printTree(int indent) const
{
    StatementASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("data:\n");
    if (m_data)
        m_data->printTree(indent + 2);

    printIndent(indent + 1);
    printf("target:\n");
    if (m_target)
        m_target->printTree(indent + 2);

    printIndent(indent + 1);
    printf("load option:\n");
    if (m_loadOption)
        m_loadOption->printTree(indent + 2);
}

#pragma mark = CallStatementASTNode =

CallStatementASTNode::CallStatementASTNode(const CallStatementASTNode &other)
    : StatementASTNode(other)
    , m_type(other.m_type)
    , m_target()
    , m_arg()
{
    m_target = other.m_target->clone();
    m_arg = other.m_arg->clone();
    m_stackPointer = other.m_stackPointer->clone();
}

void CallStatementASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s%s%s\n", nodeName().c_str(), (m_type == kCallType ? "call" : "jump"), (m_isHAB ? "/HAB" : ""));

    printIndent(indent + 1);
    printf("target:\n");
    if (m_target)
        m_target->printTree(indent + 2);

    printIndent(indent + 1);
    printf("arg:\n");
    if (m_arg)
        m_arg->printTree(indent + 2);

    printIndent(indent + 1);
    printf("sp:\n");
    if (m_stackPointer)
        m_stackPointer->printTree(indent + 2);
}

#pragma mark = ResetStatementASTNode =

void ResetStatementASTNode::printTree(int indent) const
{
    StatementASTNode::printTree(indent);
}

#pragma mark = MemEnableStatementASTNode =

MemEnableStatementASTNode::MemEnableStatementASTNode(const MemEnableStatementASTNode &other)
    : StatementASTNode(other)
    , m_memOption()
    , m_rangeExpr()
{
    m_rangeExpr = dynamic_cast<ExprASTNode *>(other.m_rangeExpr->clone());
    m_memOption = dynamic_cast<ExprASTNode *>(other.m_memOption->clone());
}

void MemEnableStatementASTNode::printTree(int indent) const
{
    StatementASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("range:\n");
    if (m_rangeExpr)
        m_rangeExpr->printTree(indent + 2);

    printIndent(indent + 1);
    printf("mem option:\n");
    if (m_memOption)
        m_memOption->printTree(indent + 2);
}

#pragma mark = SourceASTNode =

SourceASTNode::SourceASTNode(const SourceASTNode &other)
    : ASTNode(other)
    , m_name()
{
    m_name = new std::string(*other.m_name);
}

void SourceASTNode::printTree(int indent) const
{
    printIndent(indent);
    printf("%s(%s)\n", nodeName().c_str(), m_name->c_str());
}

#pragma mark = SectionMatchListASTNode =

SectionMatchListASTNode::SectionMatchListASTNode(const SectionMatchListASTNode &other)
    : ASTNode(other)
    , m_sections()
    , m_source()
{
    if (other.m_sections)
    {
        m_sections = dynamic_cast<ListASTNode *>(other.m_sections->clone());
    }

    if (other.m_source)
    {
        m_source = new std::string(*other.m_source);
    }
}

void SectionMatchListASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("sections:\n");
    if (m_sections)
    {
        m_sections->printTree(indent + 2);
    }

    printIndent(indent + 1);
    printf("source: ");
    if (m_source)
    {
        printf("%s\n", m_source->c_str());
    }
    else
    {
        printf("\n");
    }
}

#pragma mark = SectionASTNode =

SectionASTNode::SectionASTNode(const SectionASTNode &other)
    : ASTNode(other)
    , m_name()
    , m_source()
{
    m_action = other.m_action;

    if (other.m_name)
    {
        m_name = new std::string(*other.m_name);
    }

    if (other.m_source)
    {
        m_source = new std::string(*other.m_source);
    }
}

void SectionASTNode::printTree(int indent) const
{
    printIndent(indent);

    const char *actionName;
    switch (m_action)
    {
        case kInclude:
            actionName = "include";
            break;
        case kExclude:
            actionName = "exclude";
            break;
    }

    if (m_source)
    {
        printf("%s(%s:%s:%s)\n", nodeName().c_str(), actionName, m_name->c_str(), m_source->c_str());
    }
    else
    {
        printf("%s(%s:%s)\n", nodeName().c_str(), actionName, m_name->c_str());
    }
}

#pragma mark = SymbolASTNode =

SymbolASTNode::SymbolASTNode(const SymbolASTNode &other)
    : ASTNode(other)
    , m_symbol()
    , m_source()
{
    m_symbol = new std::string(*other.m_symbol);
    m_source = new std::string(*other.m_source);
}

void SymbolASTNode::printTree(int indent) const
{
    printIndent(indent);

    const char *symbol = NULL;
    if (m_symbol)
    {
        symbol = m_symbol->c_str();
    }

    const char *source = NULL;
    if (m_source)
    {
        source = m_source->c_str();
    }

    printf("%s(", nodeName().c_str());
    if (source)
    {
        printf("%s", source);
    }
    else
    {
        printf(".");
    }
    printf(":");
    if (symbol)
    {
        printf("%s", symbol);
    }
    else
    {
        printf(".");
    }
    printf(")\n");
}

#pragma mark = AddressRangeASTNode =

AddressRangeASTNode::AddressRangeASTNode(const AddressRangeASTNode &other)
    : ASTNode(other)
    , m_begin()
    , m_end()
{
    m_begin = other.m_begin->clone();
    m_end = other.m_end->clone();
}

void AddressRangeASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("begin:\n");
    if (m_begin)
        m_begin->printTree(indent + 2);

    printIndent(indent + 1);
    printf("end:\n");
    if (m_end)
        m_end->printTree(indent + 2);
}

#pragma mark = FromStatementASTNode =

FromStatementASTNode::FromStatementASTNode(std::string *source, ListASTNode *statements)
    : StatementASTNode()
    , m_source(source)
    , m_statements(statements)
{
}

FromStatementASTNode::FromStatementASTNode(const FromStatementASTNode &other)
    : StatementASTNode()
    , m_source()
    , m_statements()
{
    m_source = new std::string(*other.m_source);
    m_statements = dynamic_cast<ListASTNode *>(other.m_statements->clone());
}

void FromStatementASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("source: ");
    if (m_source)
        printf("%s\n", m_source->c_str());

    printIndent(indent + 1);
    printf("statements:\n");
    if (m_statements)
        m_statements->printTree(indent + 2);
}

#pragma mark = EncryptStatementASTNode =

EncryptStatementASTNode::EncryptStatementASTNode()
    : StatementASTNode()
    , m_statements()
    , m_keyblobNumberExpr()
{
}

EncryptStatementASTNode::EncryptStatementASTNode(const EncryptStatementASTNode &other)
    : StatementASTNode()
    , m_statements()
    , m_keyblobNumberExpr()
{
    m_statements = dynamic_cast<ListASTNode *>(other.m_statements->clone());
    m_keyblobNumberExpr = dynamic_cast<ExprASTNode *>(other.m_keyblobNumberExpr->clone());
}

void EncryptStatementASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("Key blob Num:\n");
    if (m_keyblobNumberExpr)
        m_keyblobNumberExpr->printTree(indent + 2);

    printIndent(indent + 1);
    printf("statements:\n");
    if (m_statements)
        m_statements->printTree(indent + 2);
}

#pragma mark = KeywrapStatementASTNode =

KeywrapStatementASTNode::KeywrapStatementASTNode()
    : StatementASTNode()
    , m_statements()
    , m_keyblobNumberExpr()
{
}

KeywrapStatementASTNode::KeywrapStatementASTNode(const KeywrapStatementASTNode &other)
    : StatementASTNode()
    , m_statements()
    , m_keyblobNumberExpr()
{
    m_statements = dynamic_cast<ListASTNode *>(other.m_statements->clone());
    m_keyblobNumberExpr = dynamic_cast<ExprASTNode *>(other.m_keyblobNumberExpr->clone());
}

void KeywrapStatementASTNode::printTree(int indent) const
{
    ASTNode::printTree(indent);

    printIndent(indent + 1);
    printf("Key blob Num:\n");
    if (m_keyblobNumberExpr)
        m_keyblobNumberExpr->printTree(indent + 2);

    printIndent(indent + 1);
    printf("statements:\n");
    if (m_statements)
        m_statements->printTree(indent + 2);
}
