//
// 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.
//

#include "compiler/translator/InitializeVariables.h"

#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"

namespace sh
{

namespace
{

bool IsNamelessStruct(const TIntermTyped *node)
{
    return (node->getBasicType() == EbtStruct && node->getType().getStruct()->name() == "");
}

void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
                              TIntermSequence *initSequenceOut);

TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
{
    TIntermTyped *zero = TIntermTyped::CreateZero(initializedNode->getType());
    return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
}

void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
                               TIntermSequence *initSequenceOut)
{
    ASSERT(initializedNode->getBasicType() == EbtStruct);
    TStructure *structType = initializedNode->getType().getStruct();
    for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
    {
        TIntermBinary *element = new TIntermBinary(
            EOpIndexDirectStruct, initializedNode->deepCopy(), TIntermTyped::CreateIndexNode(i));
        if (element->isArray())
        {
            AddArrayZeroInitSequence(element, initSequenceOut);
        }
        else if (element->getType().isStructureContainingArrays())
        {
            AddStructZeroInitSequence(element, initSequenceOut);
        }
        else
        {
            // Structs can't be defined inside structs, so the type of a struct field can't be a
            // nameless struct.
            ASSERT(!IsNamelessStruct(element));
            initSequenceOut->push_back(CreateZeroInitAssignment(element));
        }
    }
}

void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequence *initSequenceOut)
{
    ASSERT(initializedNode->isArray());
    // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
    // doesn't have array assignment.
    // Note that it is important to have the array init in the right order to workaround
    // http://crbug.com/709317
    for (unsigned int i = 0; i < initializedNode->getArraySize(); ++i)
    {
        TIntermBinary *element = new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(),
                                                   TIntermTyped::CreateIndexNode(i));
        if (element->getType().isStructureContainingArrays())
        {
            AddStructZeroInitSequence(element, initSequenceOut);
        }
        else
        {
            initSequenceOut->push_back(CreateZeroInitAssignment(element));
        }
    }
}

void InsertInitCode(TIntermSequence *mainBody,
                    const InitVariableList &variables,
                    const TSymbolTable &symbolTable)
{
    for (const auto &var : variables)
    {
        TString name = TString(var.name.c_str());

        TIntermSymbol *initializedSymbol = nullptr;
        if (var.isArray())
        {
            size_t pos = name.find_last_of('[');
            if (pos != TString::npos)
            {
                name = name.substr(0, pos);
            }
            TType arrayType = sh::GetShaderVariableBasicType(var);
            arrayType.setArraySize(var.elementCount());
            initializedSymbol = new TIntermSymbol(0, name, arrayType);
        }
        else if (var.isStruct())
        {
            TVariable *structInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
            ASSERT(structInfo);

            initializedSymbol = new TIntermSymbol(0, name, structInfo->getType());
        }
        else
        {
            TType type        = sh::GetShaderVariableBasicType(var);
            initializedSymbol = new TIntermSymbol(0, name, type);
        }
        TIntermSequence *initCode = CreateInitCode(initializedSymbol);
        mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
    }
}

class InitializeLocalsTraverser : public TIntermTraverser
{
  public:
    InitializeLocalsTraverser(int shaderVersion)
        : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
    {
    }

  protected:
    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
    {
        for (TIntermNode *declarator : *node->getSequence())
        {
            if (!mInGlobalScope && !declarator->getAsBinaryNode())
            {
                TIntermSymbol *symbol = declarator->getAsSymbolNode();
                ASSERT(symbol);
                if (symbol->getSymbol() == "")
                {
                    continue;
                }

                // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
                // support array constructors or assigning arrays.
                bool arrayConstructorUnavailable =
                    (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
                    mShaderVersion == 100;
                // Nameless struct constructors can't be referred to, so they also need to be
                // initialized one element at a time.
                if (arrayConstructorUnavailable || IsNamelessStruct(symbol))
                {
                    // SimplifyLoopConditions should have been run so the parent node of this node
                    // should not be a loop.
                    ASSERT(getParentNode()->getAsLoopNode() == nullptr);
                    // SeparateDeclarations should have already been run, so we don't need to worry
                    // about further declarators in this declaration depending on the effects of
                    // this declarator.
                    ASSERT(node->getSequence()->size() == 1);
                    insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
                }
                else
                {
                    TIntermBinary *init = new TIntermBinary(
                        EOpInitialize, symbol, TIntermTyped::CreateZero(symbol->getType()));
                    queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
                }
            }
        }
        return false;
    }

  private:
    int mShaderVersion;
};

}  // namespace anonymous

TIntermSequence *CreateInitCode(const TIntermSymbol *initializedSymbol)
{
    TIntermSequence *initCode = new TIntermSequence();
    if (initializedSymbol->isArray())
    {
        AddArrayZeroInitSequence(initializedSymbol, initCode);
    }
    else if (initializedSymbol->getType().isStructureContainingArrays() ||
             IsNamelessStruct(initializedSymbol))
    {
        AddStructZeroInitSequence(initializedSymbol, initCode);
    }
    else
    {
        initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
    }
    return initCode;
}

void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
{
    InitializeLocalsTraverser traverser(shaderVersion);
    root->traverse(&traverser);
    traverser.updateTree();
}

void InitializeVariables(TIntermBlock *root,
                         const InitVariableList &vars,
                         const TSymbolTable &symbolTable)
{
    TIntermFunctionDefinition *main = FindMain(root);
    ASSERT(main != nullptr);
    TIntermBlock *body = main->getBody();
    InsertInitCode(body->getSequence(), vars, symbolTable);
}

}  // namespace sh
