chromium/third_party/glslang/src/glslang/HLSL/hlslParseHelper.cpp

//
// Copyright (C) 2017-2018 Google, Inc.
// Copyright (C) 2017 LunarG, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above
//    copyright notice, this list of conditions and the following
//    disclaimer in the documentation and/or other materials provided
//    with the distribution.
//
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include "hlslParseHelper.h"
#include "hlslScanContext.h"
#include "hlslGrammar.h"
#include "hlslAttributes.h"

#include "../Include/Common.h"
#include "../MachineIndependent/Scan.h"
#include "../MachineIndependent/preprocessor/PpContext.h"

#include <algorithm>
#include <functional>
#include <cctype>
#include <array>
#include <set>

namespace glslang {

HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
                                   int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
                                   TInfoSink& infoSink,
                                   const TString sourceEntryPointName,
                                   bool forwardCompatible, EShMessages messages) :{}

HlslParseContext::~HlslParseContext()
{}

void HlslParseContext::initializeExtensionBehavior()
{}

void HlslParseContext::setLimits(const TBuiltInResource& r)
{}

//
// Parse an array of strings using the parser in HlslRules.
//
// Returns true for successful acceptance of the shader, false if any errors.
//
bool HlslParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& input, bool versionWillBeError)
{}

//
// Return true if this l-value node should be converted in some manner.
// For instance: turning a load aggregate into a store in an l-value.
//
bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const
{}

void HlslParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName,
                                              TTypeList* newTypeList)
{}

//
// Return a TLayoutFormat corresponding to the given texture type.
//
TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const TType& txType)
{}

//
// Both test and if necessary, spit out an error, to see if the node is really
// an l-value that can be operated on this way.
//
// Returns true if there was an error.
//
bool HlslParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{}

//
// This function handles l-value conversions and verifications.  It uses, but is not synonymous
// with lValueErrorCheck.  That function accepts an l-value directly, while this one must be
// given the surrounding tree - e.g, with an assignment, so we can convert the assign into a
// series of other image operations.
//
// Most things are passed through unmodified, except for error checking.
//
TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* op, TIntermTyped*& node)
{}

void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
{}

//
// Look at a '.' matrix selector string and change it into components
// for a matrix. There are two types:
//
//   _21    second row, first column (one based)
//   _m21   third row, second column (zero based)
//
// Returns true if there is no error.
//
bool HlslParseContext::parseMatrixSwizzleSelector(const TSourceLoc& loc, const TString& fields, int cols, int rows,
                                                  TSwizzleSelectors<TMatrixSelector>& components)
{}

// If the 'comps' express a column of a matrix,
// return the column.  Column means the first coords all match.
//
// Otherwise, return -1.
//
int HlslParseContext::getMatrixComponentsColumn(int rows, const TSwizzleSelectors<TMatrixSelector>& selector)
{}

//
// Handle seeing a variable identifier in the grammar.
//
TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TString* string)
{}

//
// Handle operator[] on any objects it applies to.  Currently:
//    Textures
//    Buffers
//
TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index)
{}

//
// Cast index value to a uint if it isn't already (for operator[], load indexes, etc)
TIntermTyped* HlslParseContext::makeIntegerIndex(TIntermTyped* index)
{}

//
// Handle seeing a base[index] dereference in the grammar.
//
TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index)
{}

// Handle seeing a binary node with a math operation.
TIntermTyped* HlslParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op,
                                                 TIntermTyped* left, TIntermTyped* right)
{}

// Handle seeing a unary node with a math operation.
TIntermTyped* HlslParseContext::handleUnaryMath(const TSourceLoc& loc, const char* str, TOperator op,
                                                TIntermTyped* childNode)
{}
//
// Return true if the name is a struct buffer method
//
bool HlslParseContext::isStructBufferMethod(const TString& name) const
{}

//
// Handle seeing a base.field dereference in the grammar, where 'field' is a
// swizzle or member variable.
//
TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TIntermTyped* base, const TString& field)
{}

//
// Return true if the field should be treated as a built-in method.
// Return false otherwise.
//
bool HlslParseContext::isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field)
{}

// Independently establish a built-in that is a member of a structure.
// 'arraySizes' are what's desired for the independent built-in, whatever
// the higher-level source/expression of them was.
void HlslParseContext::splitBuiltIn(const TString& baseName, const TType& memberType, const TArraySizes* arraySizes,
                                    const TQualifier& outerQualifier)
{}

// Split a type into
//   1. a struct of non-I/O members
//   2. a collection of independent I/O variables
void HlslParseContext::split(const TVariable& variable)
{}

// Recursive implementation of split().
// Returns reference to the modified type.
const TType& HlslParseContext::split(const TType& type, const TString& name, const TQualifier& outerQualifier)
{}

// Is this an aggregate that should be flattened?
// Can be applied to intermediate levels of type in a hierarchy.
// Some things like flattening uniform arrays are only about the top level
// of the aggregate, triggered on 'topLevel'.
bool HlslParseContext::shouldFlatten(const TType& type, TStorageQualifier qualifier, bool topLevel) const
{}

// Top level variable flattening: construct data
void HlslParseContext::flatten(const TVariable& variable, bool linkage, bool arrayed)
{}

// Recursively flatten the given variable at the provided type, building the flattenData as we go.
//
// This is mutually recursive with flattenStruct and flattenArray.
// We are going to flatten an arbitrarily nested composite structure into a linear sequence of
// members, and later on, we want to turn a path through the tree structure into a final
// location in this linear sequence.
//
// If the tree was N-ary, that can be directly calculated.  However, we are dealing with
// arbitrary numbers - perhaps a struct of 7 members containing an array of 3.  Thus, we must
// build a data structure to allow the sequence of bracket and dot operators on arrays and
// structs to arrive at the proper member.
//
// To avoid storing a tree with pointers, we are going to flatten the tree into a vector of integers.
// The leaves are the indexes into the flattened member array.
// Each level will have the next location for the Nth item stored sequentially, so for instance:
//
// struct { float2 a[2]; int b; float4 c[3] };
//
// This will produce the following flattened tree:
// Pos: 0  1   2    3  4    5  6   7     8   9  10   11  12 13
//     (3, 7,  8,   5, 6,   0, 1,  2,   11, 12, 13,   3,  4, 5}
//
// Given a reference to mystruct.c[1], the access chain is (2,1), so we traverse:
//   (0+2) = 8  -->  (8+1) = 12 -->   12 = 4
//
// so the 4th flattened member in traversal order is ours.
//
int HlslParseContext::flatten(const TVariable& variable, const TType& type,
                              TFlattenData& flattenData, TString name, bool linkage,
                              const TQualifier& outerQualifier,
                              const TArraySizes* builtInArraySizes)
{}

// Add a single flattened member to the flattened data being tracked for the composite
// Returns true for the final flattening level.
int HlslParseContext::addFlattenedMember(const TVariable& variable, const TType& type, TFlattenData& flattenData,
                                         const TString& memberName, bool linkage,
                                         const TQualifier& outerQualifier,
                                         const TArraySizes* builtInArraySizes)
{}

// Figure out the mapping between an aggregate's top members and an
// equivalent set of individual variables.
//
// Assumes shouldFlatten() or equivalent was called first.
int HlslParseContext::flattenStruct(const TVariable& variable, const TType& type,
                                    TFlattenData& flattenData, TString name, bool linkage,
                                    const TQualifier& outerQualifier,
                                    const TArraySizes* builtInArraySizes)
{}

// Figure out mapping between an array's members and an
// equivalent set of individual variables.
//
// Assumes shouldFlatten() or equivalent was called first.
int HlslParseContext::flattenArray(const TVariable& variable, const TType& type,
                                   TFlattenData& flattenData, TString name, bool linkage,
                                   const TQualifier& outerQualifier)
{}

// Return true if we have flattened this node.
bool HlslParseContext::wasFlattened(const TIntermTyped* node) const
{}

// Return true if we have split this structure
bool HlslParseContext::wasSplit(const TIntermTyped* node) const
{}

// Turn an access into an aggregate that was flattened to instead be
// an access to the individual variable the member was flattened to.
// Assumes wasFlattened() or equivalent was called first.
TIntermTyped* HlslParseContext::flattenAccess(TIntermTyped* base, int member)
{}
TIntermTyped* HlslParseContext::flattenAccess(long long uniqueId, int member, TStorageQualifier outerStorage,
    const TType& dereferencedType, int subset)
{}

// For finding where the first leaf is in a subtree of a multi-level aggregate
// that is just getting a subset assigned. Follows the same logic as flattenAccess,
// but logically going down the "left-most" tree branch each step of the way.
//
// Returns the offset into the first leaf of the subset.
int HlslParseContext::findSubtreeOffset(const TIntermNode& node) const
{}
// Recursively do the desent
int HlslParseContext::findSubtreeOffset(const TType& type, int subset, const TVector<int>& offsets) const
{
    if (!type.isArray() && !type.isStruct())
        return offsets[subset];
    TType derefType(type, 0);
    return findSubtreeOffset(derefType, offsets[subset], offsets);
};

// Find and return the split IO TVariable for id, or nullptr if none.
TVariable* HlslParseContext::getSplitNonIoVar(long long id) const
{}

// Pass through to base class after remembering built-in mappings.
void HlslParseContext::trackLinkage(TSymbol& symbol)
{}


// Returns true if the built-in is a clip or cull distance variable.
bool HlslParseContext::isClipOrCullDistance(TBuiltInVariable builtIn)
{}

// Some types require fixed array sizes in SPIR-V, but can be scalars or
// arrays of sizes SPIR-V doesn't allow.  For example, tessellation factors.
// This creates the right size.  A conversion is performed when the internal
// type is copied to or from the external type.  This corrects the externally
// facing input or output type to abide downstream semantics.
void HlslParseContext::fixBuiltInIoType(TType& type)
{}

// Variables that correspond to the user-interface in and out of a stage
// (not the built-in interface) are
//  - assigned locations
//  - registered as a linkage node (part of the stage's external interface).
// Assumes it is called in the order in which locations should be assigned.
void HlslParseContext::assignToInterface(TVariable& variable)
{}

//
// Handle seeing a function declarator in the grammar.  This is the precursor
// to recognizing a function prototype or function definition.
//
void HlslParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunction& function, bool prototype)
{}

// For struct buffers with counters, we must pass the counter buffer as hidden parameter.
// This adds the hidden parameter to the parameter list in 'paramNodes' if needed.
// Otherwise, it's a no-op
void HlslParseContext::addStructBufferHiddenCounterParam(const TSourceLoc& loc, TParameter& param,
                                                         TIntermAggregate*& paramNodes)
{}

//
// Handle seeing the function prototype in front of a function definition in the grammar.
// The body is handled after this function returns.
//
// Returns an aggregate of parameter-symbol nodes.
//
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
                                                             const TAttributes& attributes,
                                                             TIntermNode*& entryPointTree)
{}

// Handle all [attrib] attribute for the shader entry point
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributes& attributes)
{}

// Update the given type with any type-like attribute information in the
// attributes.
void HlslParseContext::transferTypeAttributes(const TSourceLoc& loc, const TAttributes& attributes, TType& type,
    bool allowEntry)
{}

//
// Do all special handling for the entry point, including wrapping
// the shader's entry point with the official entry point that will call it.
//
// The following:
//
//    retType shaderEntryPoint(args...) // shader declared entry point
//    { body }
//
// Becomes
//
//    out retType ret;
//    in iargs<that are input>...;
//    out oargs<that are output> ...;
//
//    void shaderEntryPoint()    // synthesized, but official, entry point
//    {
//        args<that are input> = iargs...;
//        ret = @shaderEntryPoint(args...);
//        oargs = args<that are output>...;
//    }
//    retType @shaderEntryPoint(args...)
//    { body }
//
// The symbol table will still map the original entry point name to the
// the modified function and its new name:
//
//    symbol table:  shaderEntryPoint  ->   @shaderEntryPoint
//
// Returns nullptr if no entry-point tree was built, otherwise, returns
// a subtree that creates the entry point.
//
TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction,
                                                   const TAttributes& attributes)
{}

void HlslParseContext::handleFunctionBody(const TSourceLoc& loc, TFunction& function, TIntermNode* functionBody,
                                          TIntermNode*& node)
{}

// AST I/O is done through shader globals declared in the 'in' or 'out'
// storage class.  An HLSL entry point has a return value, input parameters
// and output parameters.  These need to get remapped to the AST I/O.
void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& returnValue,
    TVector<TVariable*>& inputs, TVector<TVariable*>& outputs)
{}

// An HLSL function that looks like an entry point, but is not,
// declares entry point IO built-ins, but these have to be undone.
void HlslParseContext::remapNonEntryPointIO(TFunction& function)
{}

TIntermNode* HlslParseContext::handleDeclare(const TSourceLoc& loc, TIntermTyped* var)
{}

// Handle function returns, including type conversions to the function return type
// if necessary.
TIntermNode* HlslParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value)
{}

void HlslParseContext::handleFunctionArgument(TFunction* function,
                                              TIntermTyped*& arguments, TIntermTyped* newArg)
{}

// FragCoord may require special loading: we can optionally reciprocate W.
TIntermTyped* HlslParseContext::assignFromFragCoord(const TSourceLoc& loc, TOperator op,
                                                    TIntermTyped* left, TIntermTyped* right)
{}

// Position may require special handling: we can optionally invert Y.
// See: https://github.com/KhronosGroup/glslang/issues/1173
//      https://github.com/KhronosGroup/glslang/issues/494
TIntermTyped* HlslParseContext::assignPosition(const TSourceLoc& loc, TOperator op,
                                               TIntermTyped* left, TIntermTyped* right)
{}

// Clip and cull distance require special handling due to a semantic mismatch.  In HLSL,
// these can be float scalar, float vector, or arrays of float scalar or float vector.
// In SPIR-V, they are arrays of scalar floats in all cases.  We must copy individual components
// (e.g, both x and y components of a float2) out into the destination float array.
//
// The values are assigned to sequential members of the output array.  The inner dimension
// is vector components.  The outer dimension is array elements.
TIntermAggregate* HlslParseContext::assignClipCullDistance(const TSourceLoc& loc, TOperator op, int semanticId,
                                                           TIntermTyped* left, TIntermTyped* right)
{}

// Some simple source assignments need to be flattened to a sequence
// of AST assignments. Catch these and flatten, otherwise, pass through
// to intermediate.addAssign().
//
// Also, assignment to matrix swizzles requires multiple component assignments,
// intercept those as well.
TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left,
                                             TIntermTyped* right)
{}

// An assignment to matrix swizzle must be decomposed into individual assignments.
// These must be selected component-wise from the RHS and stored component-wise
// into the LHS.
TIntermTyped* HlslParseContext::handleAssignToMatrixSwizzle(const TSourceLoc& loc, TOperator op, TIntermTyped* left,
                                                            TIntermTyped* right)
{}

//
// HLSL atomic operations have slightly different arguments than
// GLSL/AST/SPIRV.  The semantics are converted below in decomposeIntrinsic.
// This provides the post-decomposition equivalent opcode.
//
TOperator HlslParseContext::mapAtomicOp(const TSourceLoc& loc, TOperator op, bool isImage)
{}

//
// Create a combined sampler/texture from separate sampler and texture.
//
TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex,
                                                                TIntermTyped* argSampler)
{}

// Return true if this a buffer type that has an associated counter buffer.
bool HlslParseContext::hasStructBuffCounter(const TType& type) const
{}

void HlslParseContext::counterBufferType(const TSourceLoc& loc, TType& type)
{}

// declare counter for a structured buffer type
void HlslParseContext::declareStructBufferCounter(const TSourceLoc& loc, const TType& bufferType, const TString& name)
{}

// return the counter that goes with a given structuredbuffer
TIntermTyped* HlslParseContext::getStructBufferCounter(const TSourceLoc& loc, TIntermTyped* buffer)
{}

//
// Decompose structure buffer methods into AST
//
void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
{}

// Create array of standard sample positions for given sample count.
// TODO: remove when a real method to query sample pos exists in SPIR-V.
TIntermConstantUnion* HlslParseContext::getSamplePosArray(int count)
{}

//
// Decompose DX9 and DX10 sample intrinsics & object methods into AST
//
void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
{}

//
// Decompose geometry shader methods
//
void HlslParseContext::decomposeGeometryMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
{}

//
// Optionally decompose intrinsics to AST opcodes.
//
void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
{}

//
// Handle seeing function call syntax in the grammar, which could be any of
//  - .length() method
//  - constructor
//  - a call to a built-in function mapped to an operator
//  - a call to a built-in function that will remain a function call (e.g., texturing)
//  - user function
//  - subroutine call (not implemented yet)
//
TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermTyped* arguments)
{}

// An initial argument list is difficult: it can be null, or a single node,
// or an aggregate if more than one argument.  Add one to the front, maintaining
// this lack of uniformity.
void HlslParseContext::pushFrontArguments(TIntermTyped* front, TIntermTyped*& arguments)
{}

//
// HLSL allows mismatched dimensions on vec*mat, mat*vec, vec*vec, and mat*mat.  This is a
// situation not well suited to resolution in intrinsic selection, but we can do so here, since we
// can look at both arguments insert explicit shape changes if required.
//
void HlslParseContext::addGenMulArgumentConversion(const TSourceLoc& loc, TFunction& call, TIntermTyped*& args)
{}

//
// Add any needed implicit conversions for function-call arguments to input parameters.
//
void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermTyped*& arguments)
{}

//
// Add any needed implicit expansion of calling arguments from what the shader listed to what's
// internally needed for the AST (given the constraints downstream).
//
void HlslParseContext::expandArguments(const TSourceLoc& loc, const TFunction& function, TIntermTyped*& arguments)
{}

//
// Add any needed implicit output conversions for function-call arguments.  This
// can require a new tree topology, complicated further by whether the function
// has a return value.
//
// Returns a node of a subtree that evaluates to the return value of the function.
//
TIntermTyped* HlslParseContext::addOutputArgumentConversions(const TFunction& function, TIntermOperator& intermNode)
{}

//
// Add any needed "hidden" counter buffer arguments for function calls.
//
// Modifies the 'aggregate' argument if needed.  Otherwise, is no-op.
//
void HlslParseContext::addStructBuffArguments(const TSourceLoc& loc, TIntermAggregate*& aggregate)
{}


//
// Do additional checking of built-in function calls that is not caught
// by normal semantic checks on argument type, extension tagging, etc.
//
// Assumes there has been a semantically correct match to a built-in function prototype.
//
void HlslParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermOperator& callNode)
{}

//
// Handle seeing something in a grammar production that can be done by calling
// a constructor.
//
// The constructor still must be "handled" by handleFunctionCall(), which will
// then call handleConstructor().
//
TFunction* HlslParseContext::makeConstructorCall(const TSourceLoc& loc, const TType& type)
{}

//
// Handle seeing a "COLON semantic" at the end of a type declaration,
// by updating the type according to the semantic.
//
void HlslParseContext::handleSemantic(TSourceLoc loc, TQualifier& qualifier, TBuiltInVariable builtIn,
                                      const TString& upperCase)
{}

//
// Handle seeing something like "PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN"
//
// 'location' has the "c[Subcomponent]" part.
// 'component' points to the "component" part, or nullptr if not present.
//
void HlslParseContext::handlePackOffset(const TSourceLoc& loc, TQualifier& qualifier, const glslang::TString& location,
                                        const glslang::TString* component)
{}

//
// Handle seeing something like "REGISTER LEFT_PAREN [shader_profile,] Type# RIGHT_PAREN"
//
// 'profile' points to the shader_profile part, or nullptr if not present.
// 'desc' is the type# part.
//
void HlslParseContext::handleRegister(const TSourceLoc& loc, TQualifier& qualifier, const glslang::TString* profile,
                                      const glslang::TString& desc, int subComponent, const glslang::TString* spaceDesc)
{}

// Convert to a scalar boolean, or if not allowed by HLSL semantics,
// report an error and return nullptr.
TIntermTyped* HlslParseContext::convertConditionalExpression(const TSourceLoc& loc, TIntermTyped* condition,
                                                             bool mustBeScalar)
{}

//
// Same error message for all places assignments don't work.
//
void HlslParseContext::assignError(const TSourceLoc& loc, const char* op, TString left, TString right)
{}

//
// Same error message for all places unary operations don't work.
//
void HlslParseContext::unaryOpError(const TSourceLoc& loc, const char* op, TString operand)
{}

//
// Same error message for all binary operations don't work.
//
void HlslParseContext::binaryOpError(const TSourceLoc& loc, const char* op, TString left, TString right)
{}

//
// A basic type of EbtVoid is a key that the name string was seen in the source, but
// it was not found as a variable in the symbol table.  If so, give the error
// message and insert a dummy variable in the symbol table to prevent future errors.
//
void HlslParseContext::variableCheck(TIntermTyped*& nodePtr)
{}

//
// Both test, and if necessary spit out an error, to see if the node is really
// a constant.
//
void HlslParseContext::constantValueCheck(TIntermTyped* node, const char* token)
{}

//
// Both test, and if necessary spit out an error, to see if the node is really
// an integer.
//
void HlslParseContext::integerCheck(const TIntermTyped* node, const char* token)
{}

//
// Both test, and if necessary spit out an error, to see if we are currently
// globally scoped.
//
void HlslParseContext::globalCheck(const TSourceLoc& loc, const char* token)
{}

bool HlslParseContext::builtInName(const TString& /*identifier*/)
{}

//
// Make sure there is enough data and not too many arguments provided to the
// constructor to build something of the type of the constructor.  Also returns
// the type of the constructor.
//
// Returns true if there was an error in construction.
//
bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, TFunction& function,
                                        TOperator op, TType& type)
{}

// See if 'node', in the context of constructing aggregates, is a scalar argument
// to a constructor.
//
bool HlslParseContext::isScalarConstructor(const TIntermNode* node)
{}

// Checks to see if a void variable has been declared and raise an error message for such a case
//
// returns true in case of an error
//
bool HlslParseContext::voidErrorCheck(const TSourceLoc& loc, const TString& identifier, const TBasicType basicType)
{}

//
// Fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
//
void HlslParseContext::globalQualifierFix(const TSourceLoc&, TQualifier& qualifier)
{}

//
// Merge characteristics of the 'src' qualifier into the 'dst'.
//
void HlslParseContext::mergeQualifiers(TQualifier& dst, const TQualifier& src)
{}

// used to flatten the sampler type space into a single dimension
// correlates with the declaration of defaultSamplerPrecision[]
int HlslParseContext::computeSamplerTypeIndex(TSampler& sampler)
{}

//
// Do size checking for an array type's size.
//
void HlslParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair)
{}

//
// Require array to be completely sized
//
void HlslParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes)
{}

void HlslParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& type)
{}

//
// Do all the semantic checking for declaring or redeclaring an array, with and
// without a size, and make the right changes to the symbol table.
//
void HlslParseContext::declareArray(const TSourceLoc& loc, const TString& identifier, const TType& type,
                                    TSymbol*& symbol, bool track)
{}

//
// Enforce non-initializer type/qualifier rules.
//
void HlslParseContext::fixConstInit(const TSourceLoc& loc, const TString& identifier, TType& type,
                                    TIntermTyped*& initializer)
{}

//
// See if the identifier is a built-in symbol that can be redeclared, and if so,
// copy the symbol table's read-only built-in variable to the current
// global level, where it can be modified based on the passed in type.
//
// Returns nullptr if no redeclaration took place; meaning a normal declaration still
// needs to occur for it, not necessarily an error.
//
// Returns a redeclared and type-modified variable if a redeclared occurred.
//
TSymbol* HlslParseContext::redeclareBuiltinVariable(const TSourceLoc& /*loc*/, const TString& identifier,
                                                    const TQualifier& /*qualifier*/,
                                                    const TShaderQualifiers& /*publicType*/)
{}

//
// Generate index to the array element in a structure buffer (SSBO)
//
TIntermTyped* HlslParseContext::indexStructBufferContent(const TSourceLoc& loc, TIntermTyped* buffer) const
{}

//
// IFF type is a structuredbuffer/byteaddressbuffer type, return the content
// (template) type.   E.g, StructuredBuffer<MyType> -> MyType.  Else return nullptr.
//
TType* HlslParseContext::getStructBufferContentType(const TType& type) const
{}

//
// If an existing struct buffer has a sharable type, then share it.
//
void HlslParseContext::shareStructBufferType(TType& type)
{}

void HlslParseContext::paramFix(TType& type)
{}

void HlslParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op)
{}

//
// Layout qualifier stuff.
//

// Put the id's layout qualification into the public type, for qualifiers not having a number set.
// This is before we know any type information for error checking.
void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TQualifier& qualifier, TString& id)
{}

// Put the id's layout qualifier value into the public type, for qualifiers having a number set.
// This is before we know any type information for error checking.
void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TQualifier& qualifier, TString& id,
                                          const TIntermTyped* node)
{}

void HlslParseContext::setSpecConstantId(const TSourceLoc& loc, TQualifier& qualifier, int value)
{}

// Merge any layout qualifier information from src into dst, leaving everything else in dst alone
//
// "More than one layout qualifier may appear in a single declaration.
// Additionally, the same layout-qualifier-name can occur multiple times
// within a layout qualifier or across multiple layout qualifiers in the
// same declaration. When the same layout-qualifier-name occurs
// multiple times, in a single declaration, the last occurrence overrides
// the former occurrence(s).  Further, if such a layout-qualifier-name
// will effect subsequent declarations or other observable behavior, it
// is only the last occurrence that will have any effect, behaving as if
// the earlier occurrence(s) within the declaration are not present.
// This is also true for overriding layout-qualifier-names, where one
// overrides the other (e.g., row_major vs. column_major); only the last
// occurrence has any effect."
//
void HlslParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifier& src, bool inheritOnly)
{}


//
// Look up a function name in the symbol table, and make sure it is a function.
//
// First, look for an exact match.  If there is none, use the generic selector
// TParseContextBase::selectFunction() to find one, parameterized by the
// convertible() and better() predicates defined below.
//
// Return the function symbol if found, otherwise nullptr.
//
const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, int& thisDepth,
                                                TIntermTyped*& args)
{}

//
// Do everything necessary to handle a typedef declaration, for a single symbol.
//
// 'parseType' is the type part of the declaration (to the left)
// 'arraySizes' is the arrayness tagged on the identifier (to the right)
//
void HlslParseContext::declareTypedef(const TSourceLoc& loc, const TString& identifier, const TType& parseType)
{}

// Do everything necessary to handle a struct declaration, including
// making IO aliases because HLSL allows mixed IO in a struct that specializes
// based on the usage (input, output, uniform, none).
void HlslParseContext::declareStruct(const TSourceLoc& loc, TString& structName, TType& type)
{}

// Lookup a user-type by name.
// If found, fill in the type and return the defining symbol.
// If not found, return nullptr.
TSymbol* HlslParseContext::lookupUserType(const TString& typeName, TType& type)
{}

//
// Do everything necessary to handle a variable (non-block) declaration.
// Either redeclaring a variable, or making a new one, updating the symbol
// table, and all error checking.
//
// Returns a subtree node that computes an initializer, if needed.
// Returns nullptr if there is no code to execute for initialization.
//
// 'parseType' is the type part of the declaration (to the left)
// 'arraySizes' is the arrayness tagged on the identifier (to the right)
//
TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, const TString& identifier, TType& type,
                                               TIntermTyped* initializer)
{}

// Pick up global defaults from the provide global defaults into dst.
void HlslParseContext::inheritGlobalDefaults(TQualifier& dst) const
{}

//
// Make an internal-only variable whose name is for debug purposes only
// and won't be searched for.  Callers will only use the return value to use
// the variable, not the name to look it up.  It is okay if the name
// is the same as other names; there won't be any conflict.
//
TVariable* HlslParseContext::makeInternalVariable(const char* name, const TType& type) const
{}

// Make a symbol node holding a new internal temporary variable.
TIntermSymbol* HlslParseContext::makeInternalVariableNode(const TSourceLoc& loc, const char* name,
                                                          const TType& type) const
{}

//
// Declare a non-array variable, the main point being there is no redeclaration
// for resizing allowed.
//
// Return the successfully declared variable.
//
TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, const TString& identifier, const TType& type,
                                             bool track)
{}

// Return a declaration of a temporary variable
//
// This is used to force a variable to be declared in the correct scope
// when debug information is being generated.

TIntermNode* HlslParseContext::executeDeclaration(const TSourceLoc& loc, TVariable* variable)
{}

//
// Handle all types of initializers from the grammar.
//
// Returning nullptr just means there is no code to execute to handle the
// initializer, which will, for example, be the case for constant initializers.
//
// Returns a subtree that accomplished the initialization.
//
TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
{}

//
// Reprocess any initializer-list { ... } parts of the initializer.
// Need to hierarchically assign correct types and implicit
// conversions. Will do this mimicking the same process used for
// creating a constructor-style initializer, ensuring we get the
// same form.
//
// Returns a node representing an expression for the initializer list expressed
// as the correct type.
//
// Returns nullptr if there is an error.
//
TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, const TType& type,
                                                       TIntermTyped* initializer, TIntermTyped* scalarInit)
{}

// Lengthen list to be long enough to cover any gap from the current list size
// to 'size'. If the list is longer, do nothing.
// The value to lengthen with is the default for short lists.
//
// By default, lists that are too short due to lack of initializers initialize to zero.
// Alternatively, it could be a scalar initializer for a structure. Both cases are handled,
// based on whether something is passed in as 'scalarInit'.
//
// 'scalarInit' must be safe to use each time this is called (no side effects replication).
//
void HlslParseContext::lengthenList(const TSourceLoc& loc, TIntermSequence& list, int size, TIntermTyped* scalarInit)
{}

//
// Test for the correctness of the parameters passed to various constructor functions
// and also convert them to the right data type, if allowed and required.
//
// Returns nullptr for an error or the constructed node (aggregate or typed) for no error.
//
TIntermTyped* HlslParseContext::handleConstructor(const TSourceLoc& loc, TIntermTyped* node, const TType& type)
{}

// Add a constructor, either from the grammar, or other programmatic reasons.
//
// 'node' is what to construct from.
// 'type' is what type to construct.
//
// Returns the constructed object.
// Return nullptr if it can't be done.
//
TIntermTyped* HlslParseContext::addConstructor(const TSourceLoc& loc, TIntermTyped* node, const TType& type)
{}

// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
// for the parameter to the constructor (passed to this function). Essentially, it converts
// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
// float, then float is converted to int.
//
// Returns nullptr for an error or the constructed node.
//
TIntermTyped* HlslParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node,
                                                 const TSourceLoc& loc, bool subset)
{}

// Convert the array in node to the requested type, which is also an array.
// Returns nullptr on failure, otherwise returns aggregate holding the list of
// elements needed to construct the array.
TIntermTyped* HlslParseContext::convertArray(TIntermTyped* node, const TType& type)
{}

// This function tests for the type of the parameters to the structure or array constructor. Raises
// an error message if the expected type does not match the parameter passed to the constructor.
//
// Returns nullptr for an error or the input node itself if the expected and the given parameter types match.
//
TIntermTyped* HlslParseContext::constructAggregate(TIntermNode* node, const TType& type, int paramCount,
                                                   const TSourceLoc& loc)
{}

//
// Do everything needed to add an interface block.
//
void HlslParseContext::declareBlock(const TSourceLoc& loc, TType& type, const TString* instanceName)
{}

//
// "For a block, this process applies to the entire block, or until the first member
// is reached that has a location layout qualifier. When a block member is declared with a location
// qualifier, its location comes from that qualifier: The member's location qualifier overrides the block-level
// declaration. Subsequent members are again assigned consecutive locations, based on the newest location,
// until the next member declared with a location qualifier. The values used for locations do not have to be
// declared in increasing order."
void HlslParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifier, TTypeList& typeList, bool memberWithLocation, bool memberWithoutLocation)
{}

void HlslParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
{}

// Calculate and save the offset of each block member, using the recursively
// defined block offset rules and the user-provided offset and align.
//
// Also, compute and save the total size of the block. For the block's size, arrayness
// is not taken into account, as each element is backed by a separate buffer.
//
void HlslParseContext::fixBlockUniformOffsets(const TQualifier& qualifier, TTypeList& typeList)
{}

// For an identifier that is already declared, add more qualification to it.
void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier)
{}

void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, TIdentifierList& identifiers)
{}

//
// Update the intermediate for the given input geometry
//
bool HlslParseContext::handleInputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry)
{}

//
// Update the intermediate for the given output geometry
//
bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry)
{}

//
// Selection attributes
//
void HlslParseContext::handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection* selection,
    const TAttributes& attributes)
{}

//
// Switch attributes
//
void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch* selection,
    const TAttributes& attributes)
{}

//
// Loop attributes
//
void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
    const TAttributes& attributes)
{}

//
// Updating default qualifier for the case of a declaration with just a qualifier,
// no type, block, or identifier.
//
void HlslParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, const TPublicType& publicType)
{}

//
// Take the sequence of statements that has been built up since the last case/default,
// put it on the list of top-level nodes for the current (inner-most) switch statement,
// and follow that by the case/default we are on now.  (See switch topology comment on
// TIntermSwitch.)
//
void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode)
{}

//
// Turn the top-level node sequence built up of wrapupSwitchSubsequence
// into a switch node.
//
TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression,
                                         TIntermAggregate* lastStatements, const TAttributes& attributes)
{}

// Make a new symbol-table level that is made out of the members of a structure.
// This should be done as an anonymous struct (name is "") so that the symbol table
// finds the members with no explicit reference to a 'this' variable.
void HlslParseContext::pushThisScope(const TType& thisStruct, const TVector<TFunctionDeclarator>& functionDeclarators)
{}

// Track levels of class/struct/namespace nesting with a prefix string using
// the type names separated by the scoping operator. E.g., two levels
// would look like:
//
//   outer::inner
//
// The string is empty when at normal global level.
//
void HlslParseContext::pushNamespace(const TString& typeName)
{}

// Opposite of pushNamespace(), see above
void HlslParseContext::popNamespace()
{}

// Use the class/struct nesting string to create a global name for
// a member of a class/struct.
void HlslParseContext::getFullNamespaceName(TString*& name) const
{}

// Helper function to add the namespace scope mangling syntax to a string.
void HlslParseContext::addScopeMangler(TString& name)
{}

// Return true if this has uniform-interface like decorations.
bool HlslParseContext::hasUniform(const TQualifier& qualifier) const
{}

// Potentially not the opposite of hasUniform(), as if some characteristic is
// ever used for more than one thing (e.g., uniform or input), hasUniform() should
// say it exists, but clearUniform() should leave it in place.
void HlslParseContext::clearUniform(TQualifier& qualifier)
{}

// Return false if builtIn by itself doesn't force this qualifier to be an input qualifier.
bool HlslParseContext::isInputBuiltIn(const TQualifier& qualifier) const
{}

// Return true if there are decorations to preserve for input-like storage.
bool HlslParseContext::hasInput(const TQualifier& qualifier) const
{}

// Return false if builtIn by itself doesn't force this qualifier to be an output qualifier.
bool HlslParseContext::isOutputBuiltIn(const TQualifier& qualifier) const
{}

// Return true if there are decorations to preserve for output-like storage.
bool HlslParseContext::hasOutput(const TQualifier& qualifier) const
{}

// Make the IO decorations etc. be appropriate only for an input interface.
void HlslParseContext::correctInput(TQualifier& qualifier)
{}

// Make the IO decorations etc. be appropriate only for an output interface.
void HlslParseContext::correctOutput(TQualifier& qualifier)
{}

// Make the IO decorations etc. be appropriate only for uniform type interfaces.
void HlslParseContext::correctUniform(TQualifier& qualifier)
{}

// Clear out all IO/Uniform stuff, so this has nothing to do with being an IO interface.
void HlslParseContext::clearUniformInputOutput(TQualifier& qualifier)
{}


// Set texture return type.  Returns success (not all types are valid).
bool HlslParseContext::setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc)
{}

// Return the sampler return type in retType.
void HlslParseContext::getTextureReturnType(const TSampler& sampler, TType& retType) const
{}


// Return a symbol for the tessellation linkage variable of the given TBuiltInVariable type
TIntermSymbol* HlslParseContext::findTessLinkageSymbol(TBuiltInVariable biType) const
{}

// Find the patch constant function (issues error, returns nullptr if not found)
const TFunction* HlslParseContext::findPatchConstantFunction(const TSourceLoc& loc)
{}

// Finalization step: Add patch constant function invocation
void HlslParseContext::addPatchConstantInvocation()
{}

// Finalization step: remove unused buffer blocks from linkage (we don't know until the
// shader is entirely compiled).
// Preserve order of remaining symbols.
void HlslParseContext::removeUnusedStructBufferCounters()
{}

// Finalization step: patch texture shadow modes to match samplers they were combined with
void HlslParseContext::fixTextureShadowModes()
{}

// Finalization step: patch append methods to use proper stream output, which isn't known until
// main is parsed, which could happen after the append method is parsed.
void HlslParseContext::finalizeAppendMethods()
{}

// post-processing
void HlslParseContext::finish()
{}

} // end namespace glslang