Commit dd7ff7a5 by Alexis Hetu Committed by Alexis Hétu

Initializer cleanup

Cleaned up the initialer methods in the parser and added first-class array initializers. Passes all WebGL tests. Change-Id: Ia73db8bfd461f36b717444a8ba4c9ec77d1cee36 Reviewed-on: https://swiftshader-review.googlesource.com/3473Reviewed-by: 's avatarNicolas Capens <capn@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com>
parent efe9232c
......@@ -556,9 +556,9 @@ bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction
//
// returns true in case of an error
//
bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType)
bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TBasicType& type)
{
if (pubType.type == EbtVoid) {
if(type == EbtVoid) {
error(line, "illegal use of type 'void'", identifier.c_str());
return true;
}
......@@ -654,6 +654,60 @@ bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType
return false;
}
// These checks are common for all declarations starting a declarator list, and declarators that follow an empty
// declaration.
//
bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation)
{
switch(publicType.qualifier)
{
case EvqVaryingIn:
case EvqVaryingOut:
case EvqAttribute:
case EvqVertexIn:
case EvqFragmentOut:
if(publicType.type == EbtStruct)
{
error(identifierLocation, "cannot be used with a structure",
getQualifierString(publicType.qualifier));
return true;
}
default: break;
}
if(publicType.qualifier != EvqUniform && samplerErrorCheck(identifierLocation, publicType,
"samplers must be uniform"))
{
return true;
}
// check for layout qualifier issues
const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
if(layoutQualifier.matrixPacking != EmpUnspecified)
{
error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking),
"only valid for interface blocks");
return true;
}
if(layoutQualifier.blockStorage != EbsUnspecified)
{
error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage),
"only valid for interface blocks");
return true;
}
if(publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut &&
layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
{
return true;
}
return false;
}
bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier)
{
if(layoutQualifier.location != -1)
......@@ -665,6 +719,17 @@ bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location, const T
return false;
}
bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType)
{
if(pType.layoutQualifier.location != -1)
{
error(line, "location must only be specified for a single input or output variable", "location");
return true;
}
return false;
}
bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
{
if ((qualifier == EvqOut || qualifier == EvqInOut) &&
......@@ -834,7 +899,7 @@ bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType t
variable->getType().setArraySize(type.arraySize);
}
if (voidErrorCheck(line, identifier, type))
if (voidErrorCheck(line, identifier, type.type))
return true;
return false;
......@@ -921,24 +986,74 @@ bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPubli
//
// Returns true if there was an error.
//
bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable)
bool TParseContext::nonInitErrorCheck(int line, const TString& identifier, TPublicType& type)
{
if (reservedErrorCheck(line, identifier))
recover();
if(type.qualifier == EvqConstExpr)
{
// Make the qualifier make sense.
type.qualifier = EvqTemporary;
variable = new TVariable(&identifier, TType(type));
// Generate informative error messages for ESSL1.
// In ESSL3 arrays and structures containing arrays can be constant.
if(shaderVersion < 300 && type.isStructureContainingArrays())
{
error(line,
"structures containing arrays may not be declared constant since they cannot be initialized",
identifier.c_str());
}
else
{
error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
}
if (! symbolTable.declare(*variable)) {
error(line, "redefinition", variable->getName().c_str());
delete variable;
variable = 0;
return true;
}
return true;
}
if(type.isUnsizedArray())
{
error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
return true;
}
return false;
}
if (voidErrorCheck(line, identifier, type))
return true;
// Do some simple checks that are shared between all variable declarations,
// and update the symbol table.
//
// Returns true if declaring the variable succeeded.
//
bool TParseContext::declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type,
TVariable **variable)
{
ASSERT((*variable) == nullptr);
return false;
// gl_LastFragData may be redeclared with a new precision qualifier
if(type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
{
const TVariable *maxDrawBuffers =
static_cast<const TVariable *>(symbolTable.findBuiltIn("gl_MaxDrawBuffers", shaderVersion));
if(type.getArraySize() != maxDrawBuffers->getConstPointer()->getIConst())
{
error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers", identifier.c_str());
return false;
}
}
if(reservedErrorCheck(line, identifier))
return false;
(*variable) = new TVariable(&identifier, type);
if(!symbolTable.declare(**variable))
{
error(line, "redefinition", identifier.c_str());
delete (*variable);
(*variable) = nullptr;
return false;
}
if(voidErrorCheck(line, identifier, type.getBasicType()))
return false;
return true;
}
bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
......@@ -1028,6 +1143,64 @@ void TParseContext::handlePragmaDirective(int line, const char* name, const char
//
/////////////////////////////////////////////////////////////////////////////////
const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
const TString *name,
const TSymbol *symbol)
{
const TVariable *variable = NULL;
if(!symbol)
{
error(location, "undeclared identifier", name->c_str());
recover();
}
else if(!symbol->isVariable())
{
error(location, "variable expected", name->c_str());
recover();
}
else
{
variable = static_cast<const TVariable*>(symbol);
if(symbolTable.findBuiltIn(variable->getName(), shaderVersion))
{
recover();
}
// Reject shaders using both gl_FragData and gl_FragColor
TQualifier qualifier = variable->getType().getQualifier();
if(qualifier == EvqFragData)
{
mUsesFragData = true;
}
else if(qualifier == EvqFragColor)
{
mUsesFragColor = true;
}
// This validation is not quite correct - it's only an error to write to
// both FragData and FragColor. For simplicity, and because users shouldn't
// be rewarded for reading from undefined varaibles, return an error
// if they are both referenced, rather than assigned.
if(mUsesFragData && mUsesFragColor)
{
error(location, "cannot use both gl_FragData and gl_FragColor", name->c_str());
recover();
}
}
if(!variable)
{
TType type(EbtFloat, EbpUndefined);
TVariable *fakeVariable = new TVariable(name, type);
symbolTable.declare(*fakeVariable);
variable = fakeVariable;
}
return variable;
}
//
// Look up a function name in the symbol table, and make sure it is a function.
//
......@@ -1059,7 +1232,7 @@ const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *bu
// Initializers show up in several places in the grammar. Have one set of
// code to handle them here.
//
bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
bool TParseContext::executeInitializer(TSourceLoc line, const TString& identifier, const TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
{
TType type = TType(pType);
......@@ -1068,7 +1241,7 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
if (reservedErrorCheck(line, identifier))
return true;
if (voidErrorCheck(line, identifier, pType))
if (voidErrorCheck(line, identifier, pType.type))
return true;
//
......@@ -1235,6 +1408,360 @@ TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, bool inva
return returnType;
}
TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation,
const TString &identifier)
{
TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation);
bool emptyDeclaration = (identifier == "");
mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
if(emptyDeclaration)
{
if(publicType.isUnsizedArray())
{
// ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an error.
// It is assumed that this applies to empty declarations as well.
error(identifierOrTypeLocation, "empty array declaration needs to specify a size", identifier.c_str());
}
}
else
{
if(singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
recover();
if(nonInitErrorCheck(identifierOrTypeLocation, identifier, publicType))
recover();
TVariable *variable = nullptr;
if(!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable))
recover();
if(variable && symbol)
symbol->setId(variable->getUniqueId());
}
return intermediate.makeAggregate(symbol, identifierOrTypeLocation);
}
TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression)
{
mDeferredSingleDeclarationErrorCheck = false;
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
if(nonInitErrorCheck(identifierLocation, identifier, publicType))
recover();
if(arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
{
recover();
}
TType arrayType(publicType);
int size;
if(arraySizeErrorCheck(identifierLocation, indexExpression, size))
{
recover();
}
// Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArraySize(size);
TVariable *variable = nullptr;
if(!declareVariable(identifierLocation, identifier, arrayType, &variable))
recover();
TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
if(variable && symbol)
symbol->setId(variable->getUniqueId());
return intermediate.makeAggregate(symbol, identifierLocation);
}
TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &initLocation,
TIntermTyped *initializer)
{
mDeferredSingleDeclarationErrorCheck = false;
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
TIntermNode *intermNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
{
//
// Build intermediate representation
//
return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr;
}
else
{
recover();
return nullptr;
}
}
TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
const TSourceLoc &initLocation,
TIntermTyped *initializer)
{
mDeferredSingleDeclarationErrorCheck = false;
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
if(arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
{
recover();
}
TPublicType arrayType(publicType);
int size = 0;
// If indexExpression is nullptr, then the array will eventually get its size implicitly from the initializer.
if(indexExpression != nullptr && arraySizeErrorCheck(identifierLocation, indexExpression, size))
{
recover();
}
// Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArray(true, size);
// initNode will correspond to the whole of "type b[n] = initializer".
TIntermNode *initNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, initNode))
{
return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
}
else
{
recover();
return nullptr;
}
}
TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
const TSourceLoc &identifierLoc,
const TString *identifier,
const TSymbol *symbol)
{
// invariant declaration
if(globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
{
recover();
}
if(!symbol)
{
error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
recover();
return nullptr;
}
else
{
const TString kGlFrontFacing("gl_FrontFacing");
if(*identifier == kGlFrontFacing)
{
error(identifierLoc, "identifier should not be declared as invariant", identifier->c_str());
recover();
return nullptr;
}
symbolTable.addInvariantVarying(std::string(identifier->c_str()));
const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
ASSERT(variable);
const TType &type = variable->getType();
TIntermSymbol *intermSymbol = intermediate.addSymbol(variable->getUniqueId(),
*identifier, type, identifierLoc);
TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
aggregate->setOp(EOpInvariantDeclaration);
return aggregate;
}
}
TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration,
const TSourceLoc &identifierLocation, const TString &identifier)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
if(mDeferredSingleDeclarationErrorCheck)
{
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
mDeferredSingleDeclarationErrorCheck = false;
}
if(locationDeclaratorListCheck(identifierLocation, publicType))
recover();
if(nonInitErrorCheck(identifierLocation, identifier, publicType))
recover();
TVariable *variable = nullptr;
if(!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
recover();
TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
if(variable && symbol)
symbol->setId(variable->getUniqueId());
return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
}
TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration,
const TSourceLoc &identifierLocation, const TString &identifier,
const TSourceLoc &arrayLocation, TIntermTyped *indexExpression)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
if(mDeferredSingleDeclarationErrorCheck)
{
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
mDeferredSingleDeclarationErrorCheck = false;
}
if(locationDeclaratorListCheck(identifierLocation, publicType))
recover();
if(nonInitErrorCheck(identifierLocation, identifier, publicType))
recover();
if(arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
{
recover();
}
else
{
TType arrayType = TType(publicType);
int size;
if(arraySizeErrorCheck(arrayLocation, indexExpression, size))
{
recover();
}
arrayType.setArraySize(size);
TVariable *variable = nullptr;
if(!declareVariable(identifierLocation, identifier, arrayType, &variable))
recover();
TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
if(variable && symbol)
symbol->setId(variable->getUniqueId());
return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
}
return nullptr;
}
TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType, TIntermAggregate *aggregateDeclaration,
const TSourceLoc &identifierLocation, const TString &identifier,
const TSourceLoc &initLocation, TIntermTyped *initializer)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
if(mDeferredSingleDeclarationErrorCheck)
{
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
mDeferredSingleDeclarationErrorCheck = false;
}
if(locationDeclaratorListCheck(identifierLocation, publicType))
recover();
TIntermNode *intermNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
{
//
// build the intermediate representation
//
if(intermNode)
{
return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
}
else
{
return aggregateDeclaration;
}
}
else
{
recover();
return nullptr;
}
}
TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
TIntermAggregate *aggregateDeclaration,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
const TSourceLoc &initLocation, TIntermTyped *initializer)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
if(mDeferredSingleDeclarationErrorCheck)
{
if(singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
mDeferredSingleDeclarationErrorCheck = false;
}
if(locationDeclaratorListCheck(identifierLocation, publicType))
recover();
if(arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
{
recover();
}
TPublicType arrayType(publicType);
int size = 0;
// If indexExpression is nullptr, then the array will eventually get its size implicitly from the initializer.
if(indexExpression != nullptr && arraySizeErrorCheck(identifierLocation, indexExpression, size))
{
recover();
}
// Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArray(true, size);
// initNode will correspond to the whole of "b[n] = initializer".
TIntermNode *initNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, initNode))
{
if(initNode)
{
return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
}
else
{
return aggregateDeclaration;
}
}
else
{
recover();
return nullptr;
}
}
// This function is used to test for the correctness of the parameters passed to various constructor functions
// and also convert them to the right datatype if it is allowed and required.
//
......@@ -1952,7 +2479,7 @@ TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpo
TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList)
{
if(voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier))
if(voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
{
recover();
}
......
......@@ -45,7 +45,10 @@ struct TParseContext {
shaderVersion(100),
directiveHandler(ext, diagnostics, shaderVersion),
preprocessor(&diagnostics, &directiveHandler),
scanner(NULL) { }
scanner(NULL),
mDeferredSingleDeclarationErrorCheck(false),
mUsesFragData(false),
mUsesFragColor(false) { }
TIntermediate& intermediate; // to hold and build a parse tree
TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
GLenum shaderType; // vertex or fragment language (future: pack or unpack)
......@@ -79,6 +82,9 @@ struct TParseContext {
void trace(const char* str);
void recover();
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line);
bool parseMatrixFields(const TString&, int matCols, int matRows, TMatrixFields&, int line);
......@@ -96,16 +102,18 @@ struct TParseContext {
bool arrayQualifierErrorCheck(int line, TPublicType type);
bool arrayTypeErrorCheck(int line, TPublicType type);
bool arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable);
bool voidErrorCheck(int, const TString&, const TPublicType&);
bool voidErrorCheck(int, const TString&, const TBasicType&);
bool boolErrorCheck(int, const TIntermTyped*);
bool boolErrorCheck(int, const TPublicType&);
bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
bool locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType);
bool structQualifierErrorCheck(int line, const TPublicType& pType);
bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type);
bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array);
bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable);
bool nonInitErrorCheck(int line, const TString& identifier, TPublicType& type);
bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
bool extensionErrorCheck(int line, const TString&);
bool singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation);
bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier);
bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *);
......@@ -119,12 +127,39 @@ struct TParseContext {
bool containsSampler(TType& type);
bool areAllChildConst(TIntermAggregate* aggrNode);
const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
bool executeInitializer(TSourceLoc line, const TString& identifier, const TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
TPublicType addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier);
bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
TIntermAggregate *parseSingleDeclaration(TPublicType &publicType, const TSourceLoc &identifierOrTypeLocation, const TString &identifier);
TIntermAggregate *parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc &identifierLocation, const TString &identifier,
const TSourceLoc &indexLocation, TIntermTyped *indexExpression);
TIntermAggregate *parseSingleInitDeclaration(const TPublicType &publicType, const TSourceLoc &identifierLocation, const TString &identifier,
const TSourceLoc &initLocation, TIntermTyped *initializer);
// Parse a declaration like "type a[n] = initializer"
// Note that this does not apply to declarations like "type[n] a = initializer"
TIntermAggregate *parseSingleArrayInitDeclaration(TPublicType &publicType, const TSourceLoc &identifierLocation, const TString &identifier,
const TSourceLoc &indexLocation, TIntermTyped *indexExpression,
const TSourceLoc &initLocation, TIntermTyped *initializer);
TIntermAggregate *parseInvariantDeclaration(const TSourceLoc &invariantLoc, const TSourceLoc &identifierLoc, const TString *identifier,
const TSymbol *symbol);
TIntermAggregate *parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, const TSourceLoc &identifierLocation,
const TString &identifier);
TIntermAggregate *parseArrayDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, const TSourceLoc &identifierLocation,
const TString &identifier, const TSourceLoc &arrayLocation, TIntermTyped *indexExpression);
TIntermAggregate *parseInitDeclarator(const TPublicType &publicType, TIntermAggregate *aggregateDeclaration, const TSourceLoc &identifierLocation,
const TString &identifier, const TSourceLoc &initLocation, TIntermTyped *initializer);
// Parse a declarator like "a[n] = initializer"
TIntermAggregate *parseArrayInitDeclarator(const TPublicType &publicType, TIntermAggregate *aggregateDeclaration, const TSourceLoc &identifierLocation,
const TString &identifier, const TSourceLoc &indexLocation, TIntermTyped *indexExpression,
const TSourceLoc &initLocation, TIntermTyped *initializer);
TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc);
TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
......@@ -154,12 +189,18 @@ struct TParseContext {
TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
private:
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
// The funcReturnType parameter is expected to be non-null when the operation is a built-in function.
// It is expected to be null for other unary operators.
TIntermTyped *createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc, const TType *funcReturnType);
// Return true if the checks pass
bool binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
bool mDeferredSingleDeclarationErrorCheck;
bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
bool mUsesFragColor;
};
int PaParseStrings(int count, const char* const string[], const int length[],
......
......@@ -38,6 +38,7 @@
#include "InfoSink.h"
#include "intermediate.h"
#include <set>
//
// Symbol base class. (Can build functions or variables out of these...)
......@@ -300,6 +301,7 @@ class TSymbolTable
{
public:
TSymbolTable()
: mGlobalInvariant(false)
{
//
// The symbol table cannot be used until push() is called, but
......@@ -483,12 +485,34 @@ public:
return prec;
}
// This records invariant varyings declared through
// "invariant varying_name;".
void addInvariantVarying(const std::string &originalName)
{
mInvariantVaryings.insert(originalName);
}
// If this returns false, the varying could still be invariant
// if it is set as invariant during the varying variable
// declaration - this piece of information is stored in the
// variable's type, not here.
bool isVaryingInvariant(const std::string &originalName) const
{
return (mGlobalInvariant ||
mInvariantVaryings.count(originalName) > 0);
}
void setGlobalInvariant() { mGlobalInvariant = true; }
bool getGlobalInvariant() const { return mGlobalInvariant; }
protected:
ESymbolLevel currentLevel() const { return static_cast<ESymbolLevel>(table.size() - 1); }
std::vector<TSymbolTableLevel*> table;
typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
std::vector< PrecisionStackLevel > precisionStack;
std::set<std::string> mInvariantVaryings;
bool mGlobalInvariant;
};
#endif // _SYMBOL_TABLE_INCLUDED_
......@@ -917,9 +917,10 @@ declaration
context->symbolTable.pop();
}
| init_declarator_list SEMICOLON {
if ($1.intermAggregate)
$1.intermAggregate->setOp(EOpDeclaration);
$$ = $1.intermAggregate;
TIntermAggregate *aggNode = $1.intermAggregate;
if (aggNode && aggNode->getOp() == EOpNull)
aggNode->setOp(EOpDeclaration);
$$ = aggNode;
}
| PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
......@@ -1125,191 +1126,61 @@ init_declarator_list
$$ = $1;
}
| init_declarator_list COMMA IDENTIFIER {
if ($1.type.type == EbtInvariant && !$3.symbol)
{
context->error($3.line, "undeclared identifier declared as invariant", $3.string->c_str());
context->recover();
}
TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), $3.line);
$$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, $3.line);
if (context->structQualifierErrorCheck($3.line, $$.type))
context->recover();
if (context->nonInitConstErrorCheck($3.line, *$3.string, $$.type, false))
context->recover();
TVariable* variable = 0;
if (context->nonInitErrorCheck($3.line, *$3.string, $$.type, variable))
context->recover();
if (symbol && variable)
symbol->setId(variable->getUniqueId());
}
| init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
if (context->structQualifierErrorCheck($3.line, $1.type))
context->recover();
if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true))
context->recover();
$$ = $1;
if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type))
context->recover();
else {
$1.type.setArray(true);
TVariable* variable;
if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable))
context->recover();
}
$$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, $3.line, *$3.string);
}
| init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
if (context->structQualifierErrorCheck($3.line, $1.type))
context->recover();
if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true))
context->recover();
$$ = $1;
if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type))
context->recover();
else {
int size;
if (context->arraySizeErrorCheck($4.line, $5, size))
context->recover();
$1.type.setArray(true, size);
TVariable* variable = 0;
if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable))
context->recover();
TType type = TType($1.type);
type.setArraySize(size);
$$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, $3.line), $3.line);
}
$$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, $3.line, *$3.string, $4.line, $5);
}
| init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("[]", $3.line);
$$ = $1;
$$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, $3.line, *$3.string, $4.line, nullptr, $6.line, $7);
}
| init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("=", $7.line);
$$ = $1;
$$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, $3.line, *$3.string, $4.line, $5, $7.line, $8);
}
| init_declarator_list COMMA IDENTIFIER EQUAL initializer {
if (context->structQualifierErrorCheck($3.line, $1.type))
context->recover();
$$ = $1;
TIntermNode* intermNode;
if (!context->executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) {
//
// build the intermediate representation
//
if (intermNode)
$$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, $4.line);
else
$$.intermAggregate = $1.intermAggregate;
} else {
context->recover();
$$.intermAggregate = 0;
}
$$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, $3.line, *$3.string, $4.line, $5);
}
;
single_declaration
: fully_specified_type {
$$.type = $1;
$$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), $1.line), $1.line);
$$.intermAggregate = context->parseSingleDeclaration($$.type, $1.line, "");
}
| fully_specified_type IDENTIFIER {
TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line);
$$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
if (context->structQualifierErrorCheck($2.line, $$.type))
context->recover();
if (context->nonInitConstErrorCheck($2.line, *$2.string, $$.type, false))
context->recover();
$$.type = $1;
TVariable* variable = 0;
if (context->nonInitErrorCheck($2.line, *$2.string, $$.type, variable))
context->recover();
if (variable && symbol)
symbol->setId(variable->getUniqueId());
}
| fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
context->error($2.line, "unsized array declarations not supported", $2.string->c_str());
context->recover();
TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line);
$$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
$$.type = $1;
$$.intermAggregate = context->parseSingleDeclaration($$.type, $2.line, *$2.string);
}
| fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
TType type = TType($1);
int size;
if (context->arraySizeErrorCheck($2.line, $4, size))
context->recover();
type.setArraySize(size);
TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, $2.line);
$$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
if (context->structQualifierErrorCheck($2.line, $1))
context->recover();
if (context->nonInitConstErrorCheck($2.line, *$2.string, $1, true))
context->recover();
$$.type = $1;
if (context->arrayTypeErrorCheck($3.line, $1) || context->arrayQualifierErrorCheck($3.line, $1))
context->recover();
else {
int size;
if (context->arraySizeErrorCheck($3.line, $4, size))
context->recover();
$1.setArray(true, size);
TVariable* variable = 0;
if (context->arrayErrorCheck($3.line, *$2.string, $1, variable))
context->recover();
if (variable && symbol)
symbol->setId(variable->getUniqueId());
}
$$.intermAggregate = context->parseSingleArrayDeclaration($$.type, $2.line, *$2.string, $3.line, $4);
}
| fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("[]", $3.line);
$$.type = $1;
$$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, $2.line, *$2.string, $3.line, nullptr, $5.line, $6);
}
| fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
ES3_ONLY("=", $6.line);
$$.type = $1;
$$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, $2.line, *$2.string, $3.line, $4, $6.line, $7);
}
| fully_specified_type IDENTIFIER EQUAL initializer {
if (context->structQualifierErrorCheck($2.line, $1))
context->recover();
$$.type = $1;
TIntermNode* intermNode;
if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) {
//
// Build intermediate representation
//
if(intermNode)
$$.intermAggregate = context->intermediate.makeAggregate(intermNode, $3.line);
else
$$.intermAggregate = 0;
} else {
context->recover();
$$.intermAggregate = 0;
}
$$.intermAggregate = context->parseSingleInitDeclaration($$.type, $2.line, *$2.string, $3.line, $4);
}
| INVARIANT IDENTIFIER {
if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying"))
context->recover();
$$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, $2.line);
if (!$2.symbol)
{
context->error($2.line, "undeclared identifier declared as invariant", $2.string->c_str());
context->recover();
$$.intermAggregate = 0;
}
else
{
TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), $2.line);
$$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
}
// $$.type is not used in invariant declarations.
$$.intermAggregate = context->parseInvariantDeclaration($1.line, $2.line, $2.string, $2.symbol);
}
;
//
// Place holder for the pack/unpack languages.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -31,6 +31,7 @@ enum TOperator {
EOpParameters, // an aggregate listing the parameters to a function
EOpDeclaration,
EOpInvariantDeclaration, // Specialized declarations for attributing invariance
EOpPrototype,
//
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment