//
// Copyright 2016 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.
//
// ShaderCompileTreeTest.cpp:
//   Test that shader validation results in the correct compile status.
//

#include "tests/test_utils/ShaderCompileTreeTest.h"

#include "compiler/translator/TranslatorESSL.h"
#include "compiler/translator/tree_util/IntermTraverse.h"

namespace sh
{

namespace
{

// Checks that the node traversed is a zero node. It can be made out of multiple constructors and
// constant union nodes as long as there's no arithmetic involved and all constants are zero.
class OnlyContainsZeroConstantsTraverser final : public TIntermTraverser
{
  public:
    OnlyContainsZeroConstantsTraverser()
        : TIntermTraverser(true, false, false), mOnlyContainsConstantZeros(true)
    {}

    bool visitUnary(Visit, TIntermUnary *node) override
    {
        mOnlyContainsConstantZeros = false;
        return false;
    }

    bool visitBinary(Visit, TIntermBinary *node) override
    {
        mOnlyContainsConstantZeros = false;
        return false;
    }

    bool visitTernary(Visit, TIntermTernary *node) override
    {
        mOnlyContainsConstantZeros = false;
        return false;
    }

    bool visitSwizzle(Visit, TIntermSwizzle *node) override
    {
        mOnlyContainsConstantZeros = false;
        return false;
    }

    bool visitAggregate(Visit, TIntermAggregate *node) override
    {
        if (node->getOp() != EOpConstruct)
        {
            mOnlyContainsConstantZeros = false;
            return false;
        }
        return true;
    }

    void visitSymbol(TIntermSymbol *node) override { mOnlyContainsConstantZeros = false; }

    void visitConstantUnion(TIntermConstantUnion *node) override
    {
        if (!mOnlyContainsConstantZeros)
        {
            return;
        }

        const TType &type = node->getType();
        size_t objectSize = type.getObjectSize();
        for (size_t i = 0u; i < objectSize && mOnlyContainsConstantZeros; ++i)
        {
            bool isZero = false;
            switch (type.getBasicType())
            {
                case EbtFloat:
                    isZero = (node->getFConst(i) == 0.0f);
                    break;
                case EbtInt:
                    isZero = (node->getIConst(i) == 0);
                    break;
                case EbtUInt:
                    isZero = (node->getUConst(i) == 0u);
                    break;
                case EbtBool:
                    isZero = (node->getBConst(i) == false);
                    break;
                default:
                    // Cannot handle.
                    break;
            }
            if (!isZero)
            {
                mOnlyContainsConstantZeros = false;
                return;
            }
        }
    }

    bool onlyContainsConstantZeros() const { return mOnlyContainsConstantZeros; }

  private:
    bool mOnlyContainsConstantZeros;
};

}  // anonymous namespace

void ShaderCompileTreeTest::SetUp()
{
    mAllocator.push();
    SetGlobalPoolAllocator(&mAllocator);

    ShBuiltInResources resources;
    sh::InitBuiltInResources(&resources);

    initResources(&resources);

    mTranslator = new TranslatorESSL(getShaderType(), getShaderSpec());
    ASSERT_TRUE(mTranslator->Init(resources));
}

void ShaderCompileTreeTest::TearDown()
{
    delete mTranslator;

    SetGlobalPoolAllocator(nullptr);
    mAllocator.pop();
}

bool ShaderCompileTreeTest::compile(const std::string &shaderString)
{
    const char *shaderStrings[] = {shaderString.c_str()};
    mASTRoot = mTranslator->compileTreeForTesting(shaderStrings, 1, mExtraCompileOptions);
    TInfoSink &infoSink = mTranslator->getInfoSink();
    mInfoLog            = infoSink.info.c_str();
    return mASTRoot != nullptr;
}

void ShaderCompileTreeTest::compileAssumeSuccess(const std::string &shaderString)
{
    if (!compile(shaderString))
    {
        FAIL() << "Shader compilation into ESSL failed, log:\n" << mInfoLog;
    }
}

bool ShaderCompileTreeTest::hasWarning() const
{
    return mInfoLog.find("WARNING: ") != std::string::npos;
}

const std::vector<sh::ShaderVariable> &ShaderCompileTreeTest::getUniforms() const
{
    ASSERT(mExtraCompileOptions & SH_VARIABLES);
    return mTranslator->getUniforms();
}

const std::vector<sh::ShaderVariable> &ShaderCompileTreeTest::getAttributes() const
{
    ASSERT(mExtraCompileOptions & SH_VARIABLES);
    return mTranslator->getAttributes();
}

bool IsZero(TIntermNode *node)
{
    if (!node->getAsTyped())
    {
        return false;
    }
    OnlyContainsZeroConstantsTraverser traverser;
    node->traverse(&traverser);
    return traverser.onlyContainsConstantZeros();
}

}  // namespace sh
