1//
2// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/translator/UnfoldShortCircuitAST.h"
8
9namespace
10{
11
12// "x || y" is equivalent to "x ? true : y".
13TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
14{
15    const TType boolType(EbtBool, EbpUndefined);
16    ConstantUnion *u = new ConstantUnion;
17    u->setBConst(true);
18    TIntermConstantUnion *trueNode = new TIntermConstantUnion(
19        u, TType(EbtBool, EbpUndefined, EvqConst, 1));
20    return new TIntermSelection(x, trueNode, y, boolType);
21}
22
23// "x && y" is equivalent to "x ? y : false".
24TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
25{
26    const TType boolType(EbtBool, EbpUndefined);
27    ConstantUnion *u = new ConstantUnion;
28    u->setBConst(false);
29    TIntermConstantUnion *falseNode = new TIntermConstantUnion(
30        u, TType(EbtBool, EbpUndefined, EvqConst, 1));
31    return new TIntermSelection(x, y, falseNode, boolType);
32}
33
34}  // namespace anonymous
35
36bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
37{
38    TIntermSelection *replacement = NULL;
39
40    switch (node->getOp())
41    {
42      case EOpLogicalOr:
43        replacement = UnfoldOR(node->getLeft(), node->getRight());
44        break;
45      case EOpLogicalAnd:
46        replacement = UnfoldAND(node->getLeft(), node->getRight());
47        break;
48      default:
49        break;
50    }
51    if (replacement)
52    {
53        replacements.push_back(
54            NodeUpdateEntry(getParentNode(), node, replacement));
55    }
56    return true;
57}
58
59void UnfoldShortCircuitAST::updateTree()
60{
61    for (size_t ii = 0; ii < replacements.size(); ++ii)
62    {
63        const NodeUpdateEntry& entry = replacements[ii];
64        ASSERT(entry.parent);
65        bool replaced = entry.parent->replaceChildNode(
66            entry.original, entry.replacement);
67        ASSERT(replaced);
68
69        // In AST traversing, a parent is visited before its children.
70        // After we replace a node, if an immediate child is to
71        // be replaced, we need to make sure we don't update the replaced
72	// node; instead, we update the replacement node.
73        for (size_t jj = ii + 1; jj < replacements.size(); ++jj)
74        {
75            NodeUpdateEntry& entry2 = replacements[jj];
76            if (entry2.parent == entry.original)
77                entry2.parent = entry.replacement;
78        }
79    }
80}
81
82