//
// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else
// statements.
// The results are assigned to s# temporaries, which are used by the main translator instead of
// the original expression.
//

#include "compiler/translator/UnfoldShortCircuitToIf.h"

#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNodePatternMatcher.h"

namespace sh
{

namespace
{

// Traverser that unfolds one short-circuiting operation at a time.
class UnfoldShortCircuitTraverser : public TIntermTraverser
{
  public:
    UnfoldShortCircuitTraverser();

    bool visitBinary(Visit visit, TIntermBinary *node) override;
    bool visitTernary(Visit visit, TIntermTernary *node) override;

    void nextIteration();
    bool foundShortCircuit() const { return mFoundShortCircuit; }

  protected:
    // Marked to true once an operation that needs to be unfolded has been found.
    // After that, no more unfolding is performed on that traversal.
    bool mFoundShortCircuit;

    IntermNodePatternMatcher mPatternToUnfoldMatcher;
};

UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser()
    : TIntermTraverser(true, false, true),
      mFoundShortCircuit(false),
      mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression)
{
}

bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
{
    if (mFoundShortCircuit)
        return false;

    if (visit != PreVisit)
        return true;

    if (!mPatternToUnfoldMatcher.match(node, getParentNode()))
        return true;

    // If our right node doesn't have side effects, we know we don't need to unfold this
    // expression: there will be no short-circuiting side effects to avoid
    // (note: unfolding doesn't depend on the left node -- it will always be evaluated)
    ASSERT(node->getRight()->hasSideEffects());

    mFoundShortCircuit = true;

    switch (node->getOp())
    {
        case EOpLogicalOr:
        {
            // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true;
            // else s = y;",
            // and then further simplifies down to "bool s = x; if(!s) s = y;".

            TIntermSequence insertions;
            TType boolType(EbtBool, EbpUndefined, EvqTemporary);

            ASSERT(node->getLeft()->getType() == boolType);
            insertions.push_back(createTempInitDeclaration(node->getLeft()));

            TIntermBlock *assignRightBlock = new TIntermBlock();
            ASSERT(node->getRight()->getType() == boolType);
            assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));

            TIntermUnary *notTempSymbol =
                new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType));
            TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr);
            insertions.push_back(ifNode);

            insertStatementsInParentBlock(insertions);

            queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED);
            return false;
        }
        case EOpLogicalAnd:
        {
            // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y;
            // else s = false;",
            // and then further simplifies down to "bool s = x; if(s) s = y;".
            TIntermSequence insertions;
            TType boolType(EbtBool, EbpUndefined, EvqTemporary);

            ASSERT(node->getLeft()->getType() == boolType);
            insertions.push_back(createTempInitDeclaration(node->getLeft()));

            TIntermBlock *assignRightBlock = new TIntermBlock();
            ASSERT(node->getRight()->getType() == boolType);
            assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));

            TIntermIfElse *ifNode =
                new TIntermIfElse(createTempSymbol(boolType), assignRightBlock, nullptr);
            insertions.push_back(ifNode);

            insertStatementsInParentBlock(insertions);

            queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED);
            return false;
        }
        default:
            UNREACHABLE();
            return true;
    }
}

bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *node)
{
    if (mFoundShortCircuit)
        return false;

    if (visit != PreVisit)
        return true;

    if (!mPatternToUnfoldMatcher.match(node))
        return true;

    mFoundShortCircuit = true;

    // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
    TIntermSequence insertions;

    TIntermDeclaration *tempDeclaration = createTempDeclaration(node->getType());
    insertions.push_back(tempDeclaration);

    TIntermBlock *trueBlock       = new TIntermBlock();
    TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression());
    trueBlock->getSequence()->push_back(trueAssignment);

    TIntermBlock *falseBlock       = new TIntermBlock();
    TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression());
    falseBlock->getSequence()->push_back(falseAssignment);

    TIntermIfElse *ifNode =
        new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
    insertions.push_back(ifNode);

    insertStatementsInParentBlock(insertions);

    TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
    queueReplacement(node, ternaryResult, OriginalNode::IS_DROPPED);

    return false;
}

void UnfoldShortCircuitTraverser::nextIteration()
{
    mFoundShortCircuit = false;
    nextTemporaryIndex();
}

}  // namespace

void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex)
{
    UnfoldShortCircuitTraverser traverser;
    ASSERT(temporaryIndex != nullptr);
    traverser.useTemporaryIndex(temporaryIndex);
    // Unfold one operator at a time, and reset the traverser between iterations.
    do
    {
        traverser.nextIteration();
        root->traverse(&traverser);
        if (traverser.foundShortCircuit())
            traverser.updateTree();
    } while (traverser.foundShortCircuit());
}

}  // namespace sh
