//
// Copyright (c) 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/IntermTraverse.h"
#include "compiler/translator/TranslatorESSL.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::Uniform> &ShaderCompileTreeTest::getUniforms() const
{
    ASSERT(mExtraCompileOptions & SH_VARIABLES);
    return mTranslator->getUniforms();
}

const std::vector<sh::Attribute> &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
