// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "Compiler.h"

#include "AnalyzeCallDepth.h"
#include "Initialize.h"
#include "InitializeParseContext.h"
#include "InitializeGlobals.h"
#include "ParseHelper.h"
#include "ValidateLimitations.h"

namespace
{
class TScopedPoolAllocator {
public:
	TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
		: mAllocator(allocator), mPushPopAllocator(pushPop)
	{
		if (mPushPopAllocator) mAllocator->push();
		SetGlobalPoolAllocator(mAllocator);
	}
	~TScopedPoolAllocator()
	{
		SetGlobalPoolAllocator(nullptr);
		if (mPushPopAllocator) mAllocator->pop();
	}

private:
	TPoolAllocator* mAllocator;
	bool mPushPopAllocator;
};
}  // namespace

//
// Initialize built-in resources with minimum expected values.
//
ShBuiltInResources::ShBuiltInResources()
{
	// Constants.
	MaxVertexAttribs = 8;
	MaxVertexUniformVectors = 128;
	MaxVaryingVectors = 8;
	MaxVertexTextureImageUnits = 0;
	MaxCombinedTextureImageUnits = 8;
	MaxTextureImageUnits = 8;
	MaxFragmentUniformVectors = 16;
	MaxDrawBuffers = 1;
	MaxVertexOutputVectors = 16;
	MaxFragmentInputVectors = 15;
	MinProgramTexelOffset = -8;
	MaxProgramTexelOffset = 7;

	// Extensions.
	OES_standard_derivatives = 0;
	OES_fragment_precision_high = 0;
	OES_EGL_image_external = 0;
	OES_EGL_image_external_essl3 = 0;

	MaxCallStackDepth = UINT_MAX;
}

TCompiler::TCompiler(GLenum type)
	: shaderType(type),
	  maxCallStackDepth(UINT_MAX)
{
	allocator.push();
	SetGlobalPoolAllocator(&allocator);
}

TCompiler::~TCompiler()
{
	SetGlobalPoolAllocator(nullptr);
	allocator.popAll();
}

bool TCompiler::Init(const ShBuiltInResources& resources)
{
	shaderVersion = 100;
	maxCallStackDepth = resources.MaxCallStackDepth;
	TScopedPoolAllocator scopedAlloc(&allocator, false);

	// Generate built-in symbol table.
	if (!InitBuiltInSymbolTable(resources))
		return false;
	InitExtensionBehavior(resources, extensionBehavior);

	return true;
}

bool TCompiler::compile(const char* const shaderStrings[],
                        const int numStrings,
                        int compileOptions)
{
	TScopedPoolAllocator scopedAlloc(&allocator, true);
	clearResults();

	if (numStrings == 0)
		return true;

	// First string is path of source file if flag is set. The actual source follows.
	const char* sourcePath = nullptr;
	int firstSource = 0;
	if (compileOptions & SH_SOURCE_PATH)
	{
		sourcePath = shaderStrings[0];
		++firstSource;
	}

	TIntermediate intermediate(infoSink);
	TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
	                           shaderType, compileOptions, true,
	                           sourcePath, infoSink);
	SetGlobalParseContext(&parseContext);

	// We preserve symbols at the built-in level from compile-to-compile.
	// Start pushing the user-defined symbols at global level.
	symbolTable.push();
	if (!symbolTable.atGlobalLevel())
		infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");

	// Parse shader.
	bool success =
		(PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
		(parseContext.getTreeRoot() != nullptr);

	shaderVersion = parseContext.getShaderVersion();

	if (success) {
		TIntermNode* root = parseContext.getTreeRoot();
		success = intermediate.postProcess(root);

		if (success)
			success = validateCallDepth(root, infoSink);

		if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
			success = validateLimitations(root);

		if (success && (compileOptions & SH_INTERMEDIATE_TREE))
			intermediate.outputTree(root);

		if (success && (compileOptions & SH_OBJECT_CODE))
			success = translate(root);
	}

	// Ensure symbol table is returned to the built-in level,
	// throwing away all but the built-ins.
	while (!symbolTable.atBuiltInLevel())
		symbolTable.pop();

	return success;
}

bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
{
	assert(symbolTable.isEmpty());
	symbolTable.push();   // COMMON_BUILTINS
	symbolTable.push();   // ESSL1_BUILTINS
	symbolTable.push();   // ESSL3_BUILTINS

	TPublicType integer;
	integer.type = EbtInt;
	integer.primarySize = 1;
	integer.secondarySize = 1;
	integer.array = false;

	TPublicType floatingPoint;
	floatingPoint.type = EbtFloat;
	floatingPoint.primarySize = 1;
	floatingPoint.secondarySize = 1;
	floatingPoint.array = false;

	switch(shaderType)
	{
	case GL_FRAGMENT_SHADER:
		symbolTable.setDefaultPrecision(integer, EbpMedium);
		break;
	case GL_VERTEX_SHADER:
		symbolTable.setDefaultPrecision(integer, EbpHigh);
		symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
		break;
	default: assert(false && "Language not supported");
	}

	InsertBuiltInFunctions(shaderType, resources, symbolTable);

	IdentifyBuiltIns(shaderType, resources, symbolTable);

	return true;
}

void TCompiler::clearResults()
{
	infoSink.info.erase();
	infoSink.obj.erase();
	infoSink.debug.erase();
}

bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
{
	AnalyzeCallDepth validator(root);

	unsigned int depth = validator.analyzeCallDepth();

	if(depth == 0)
	{
		infoSink.info.prefix(EPrefixError);
		infoSink.info << "Missing main()";
		return false;
	}
	else if(depth == UINT_MAX)
	{
		infoSink.info.prefix(EPrefixError);
		infoSink.info << "Function recursion detected";
		return false;
	}
	else if(depth > maxCallStackDepth)
	{
		infoSink.info.prefix(EPrefixError);
		infoSink.info << "Function call stack too deep (depth was ";
		infoSink.info << depth;
		infoSink.info << " while maximum call stack depth is ";
		infoSink.info << maxCallStackDepth;
		infoSink.info << ")";
		return false;
	}

	return true;
}

bool TCompiler::validateLimitations(TIntermNode* root) {
	ValidateLimitations validate(shaderType, infoSink.info);
	root->traverse(&validate);
	return validate.numErrors() == 0;
}

const TExtensionBehavior& TCompiler::getExtensionBehavior() const
{
	return extensionBehavior;
}

bool InitCompilerGlobals()
{
	if(!InitializePoolIndex())
	{
		assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
		return false;
	}

	if(!InitializeParseContextIndex())
	{
		assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
		return false;
	}

	return true;
}

void FreeCompilerGlobals()
{
	FreeParseContextIndex();
	FreePoolIndex();
}
