mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 20:10:06 +00:00
Generalize the symbol hierarchy to transparently handle anonymous-block members better.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23469 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
4c70685382
commit
9d30218fb6
1
Todo.txt
1
Todo.txt
@ -24,6 +24,7 @@ Link Validation
|
||||
+ Non ES: value checking of global const initializers
|
||||
+ Non ES: value checking of uniform initializers
|
||||
+ Non ES: location match
|
||||
- gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords
|
||||
- location aliasing/overlap (except desktop vertex shader inputs)
|
||||
- 1.0: count the number of uniforms and varyings, compare against limits
|
||||
+ recursion for functions
|
||||
|
@ -885,6 +885,11 @@ void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguag
|
||||
treeRoot = growAggregate(treeRoot, linkage);
|
||||
}
|
||||
|
||||
//
|
||||
// Add the given name or symbol to the list of nodes at the end of the tree used
|
||||
// for link-time checking and external linkage.
|
||||
//
|
||||
|
||||
void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
|
||||
{
|
||||
TSymbol* symbol = symbolTable.find(name);
|
||||
@ -892,10 +897,16 @@ void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTabl
|
||||
addSymbolLinkageNode(linkage, *symbol->getAsVariable());
|
||||
}
|
||||
|
||||
void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable& variable)
|
||||
void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol)
|
||||
{
|
||||
TIntermSymbol* node = new TIntermSymbol(variable.getUniqueId(), variable.getName(), variable.getType());
|
||||
node->setConstArray(variable.getConstArray());
|
||||
const TVariable* variable = symbol.getAsVariable();
|
||||
if (! variable) {
|
||||
// This must be a member of an anonymous block, and we need to add the whole block
|
||||
const TAnonMember* anon = symbol.getAsAnonMember();
|
||||
variable = &anon->getAnonContainer();
|
||||
}
|
||||
TIntermSymbol* node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType());
|
||||
node->setConstArray(variable->getConstArray());
|
||||
linkage = growAggregate(linkage, node);
|
||||
}
|
||||
|
||||
|
@ -473,11 +473,10 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
|
||||
(base->isMatrix() && base->getType().getMatrixCols() <= indexValue)))
|
||||
error(loc, "", "[", "index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
if (base->isArray()) {
|
||||
if (base->getType().getArraySize() == 0) {
|
||||
if (base->getType().getMaxArraySize() <= index->getAsConstantUnion()->getConstArray()[0].getIConst())
|
||||
arraySetMaxSize(loc, base->getAsSymbolNode(), index->getAsConstantUnion()->getConstArray()[0].getIConst() + 1);
|
||||
} else if ( index->getAsConstantUnion()->getConstArray()[0].getIConst() >= base->getType().getArraySize() ||
|
||||
index->getAsConstantUnion()->getConstArray()[0].getIConst() < 0)
|
||||
if (base->getType().getArraySize() == 0)
|
||||
updateMaxArraySize(loc, base, index->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
else if (index->getAsConstantUnion()->getConstArray()[0].getIConst() >= base->getType().getArraySize() ||
|
||||
index->getAsConstantUnion()->getConstArray()[0].getIConst() < 0)
|
||||
error(loc, "", "[", "array index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
}
|
||||
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
||||
@ -627,8 +626,8 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu
|
||||
requireNotRemoved(loc, EEsProfile, 300, "redeclaration of built-in function");
|
||||
const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
|
||||
if (prevDec) {
|
||||
if (prevDec->getReturnType() != function.getReturnType()) {
|
||||
error(loc, "overloaded functions must have the same return type", function.getReturnType().getCompleteTypeString().c_str(), "");
|
||||
if (prevDec->getType() != function.getType()) {
|
||||
error(loc, "overloaded functions must have the same return type", function.getType().getCompleteTypeString().c_str(), "");
|
||||
}
|
||||
for (int i = 0; i < prevDec->getParamCount(); ++i) {
|
||||
if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
|
||||
@ -679,7 +678,7 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti
|
||||
//
|
||||
// Remember the return type for later checking for RETURN statements.
|
||||
//
|
||||
currentFunctionType = &(prevDec->getReturnType());
|
||||
currentFunctionType = &(prevDec->getType());
|
||||
} else
|
||||
currentFunctionType = new TType(EbtVoid);
|
||||
functionReturnsValue = false;
|
||||
@ -690,8 +689,8 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti
|
||||
if (function.getName() == "main") {
|
||||
if (function.getParamCount() > 0)
|
||||
error(loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
|
||||
if (function.getReturnType().getBasicType() != EbtVoid)
|
||||
error(loc, "", function.getReturnType().getCompleteTypeString().c_str(), "main function cannot return a value");
|
||||
if (function.getType().getBasicType() != EbtVoid)
|
||||
error(loc, "", function.getType().getCompleteTypeString().c_str(), "main function cannot return a value");
|
||||
intermediate.addMainCount();
|
||||
}
|
||||
|
||||
@ -798,7 +797,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
|
||||
op = fnCandidate->getBuiltInOp();
|
||||
if (builtIn && op != EOpNull) {
|
||||
// A function call mapped to a built-in operation.
|
||||
result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getReturnType());
|
||||
result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getType());
|
||||
if (result == 0) {
|
||||
error(intermNode->getLoc(), " wrong operand type", "Internal Error",
|
||||
"built in unary operator function. Type: %s",
|
||||
@ -807,7 +806,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
|
||||
}
|
||||
} else {
|
||||
// This is a function call not mapped to built-in operation
|
||||
result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getReturnType(), loc);
|
||||
result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getType(), loc);
|
||||
result->getAsAggregate()->setName(fnCandidate->getMangledName());
|
||||
|
||||
// this is how we know whether the given function is a built-in function or a user-defined function
|
||||
@ -830,7 +829,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
|
||||
}
|
||||
|
||||
// built-in texturing functions get their return value precision from the precision of the sampler
|
||||
if (builtIn && fnCandidate->getReturnType().getQualifier().precision == EpqNone &&
|
||||
if (builtIn && fnCandidate->getType().getQualifier().precision == EpqNone &&
|
||||
fnCandidate->getParamCount() > 0 && (*fnCandidate)[0].type->getBasicType() == EbtSampler)
|
||||
result->getQualifier().precision = result->getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision;
|
||||
}
|
||||
@ -1228,7 +1227,7 @@ bool TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier
|
||||
//
|
||||
bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
|
||||
{
|
||||
type.shallowCopy(function.getReturnType());
|
||||
type.shallowCopy(function.getType());
|
||||
|
||||
bool constructingMatrix = false;
|
||||
switch(op) {
|
||||
@ -1713,89 +1712,86 @@ void TParseContext::arrayDimCheck(TSourceLoc loc, const TType* type, TArraySizes
|
||||
//
|
||||
// size == 0 means no specified size.
|
||||
//
|
||||
void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TType& type, TVariable*& variable, bool& newDeclaration)
|
||||
void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration)
|
||||
{
|
||||
//
|
||||
// Don't check for reserved word use until after we know it's not in the symbol table,
|
||||
// because reserved arrays can be redeclared.
|
||||
//
|
||||
// However, reserved arrays cannot be modified in a shared symbol table, so add a new
|
||||
// one at a non-shared level in the table.
|
||||
//
|
||||
// Redeclarations have to take place at the same scope; otherwise they are hiding declarations
|
||||
//
|
||||
|
||||
if (! variable) {
|
||||
if (! symbol) {
|
||||
bool currentScope;
|
||||
TSymbol* symbol = symbolTable.find(identifier, 0, ¤tScope);
|
||||
symbol = symbolTable.find(identifier, 0, ¤tScope);
|
||||
if (symbol == 0 || ! currentScope) {
|
||||
variable = new TVariable(&identifier, type);
|
||||
symbolTable.insert(*variable);
|
||||
//
|
||||
// Successfully process a new definition.
|
||||
// (Redeclarations have to take place at the same scope; otherwise they are hiding declarations)
|
||||
//
|
||||
symbol = new TVariable(&identifier, type);
|
||||
symbolTable.insert(*symbol);
|
||||
newDeclaration = true;
|
||||
|
||||
return;
|
||||
}
|
||||
variable = symbol->getAsVariable();
|
||||
if (symbol->getAsAnonMember()) {
|
||||
error(loc, "cannot redeclare a user-block member array", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! variable) {
|
||||
//
|
||||
// Process a redeclaration.
|
||||
//
|
||||
|
||||
if (! symbol) {
|
||||
error(loc, "array variable name expected", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! variable->getType().isArray()) {
|
||||
TType& newType = symbol->getWritableType();
|
||||
|
||||
if (! newType.isArray()) {
|
||||
error(loc, "redeclaring non-array as array", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
if (variable->getType().getArraySize() > 0) {
|
||||
if (newType.getArraySize() > 0) {
|
||||
error(loc, "redeclaration of array with size", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! variable->getType().sameElementType(type)) {
|
||||
error(loc, "redeclaration of array with a different type", identifier.c_str(), "");
|
||||
if (! newType.sameElementType(type)) {
|
||||
error(loc, "redeclaration of array with a different newType", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
variable->getWritableType().shareArraySizes(type);
|
||||
newType.shareArraySizes(type);
|
||||
}
|
||||
|
||||
bool TParseContext::arraySetMaxSize(TSourceLoc loc, TIntermSymbol *node, int size)
|
||||
void TParseContext::updateMaxArraySize(TSourceLoc loc, TIntermNode *node, int index)
|
||||
{
|
||||
TSymbol* symbol = symbolTable.find(node->getName());
|
||||
if (symbol == 0) {
|
||||
error(loc, " undeclared identifier", node->getName().c_str(), "");
|
||||
return true;
|
||||
TIntermSymbol* symbolNode = node->getAsSymbolNode();
|
||||
if (! symbolNode) {
|
||||
// TODO: functionality: unsized arrays: handle members of blocks
|
||||
return;
|
||||
}
|
||||
|
||||
TVariable* variable = symbol->getAsVariable();
|
||||
if (! variable) {
|
||||
error(loc, "array variable name expected", node->getName().c_str(), "");
|
||||
return true;
|
||||
// maybe there is nothing to do...
|
||||
// TODO: functionality: unsized arrays: is the node sharing the array type with the symbol table?
|
||||
if (symbolNode->getType().getMaxArraySize() > index)
|
||||
return;
|
||||
|
||||
// something to do...
|
||||
|
||||
TSymbol* symbol = symbolTable.find(symbolNode->getName());
|
||||
assert(symbol);
|
||||
if (symbol == 0)
|
||||
return;
|
||||
|
||||
if (symbol->getAsFunction()) {
|
||||
error(loc, "array variable name expected", symbolNode->getName().c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: desktop linker: make this a link-time check (note if it's here, an explicit declaration skips it)
|
||||
//if (node->getName() == "gl_TexCoord") {
|
||||
// TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords");
|
||||
// if (! texCoord || ! texCoord->getAsVariable()) {
|
||||
// infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", loc);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// int texCoordValue = texCoord->getAsVariable()->getConstArray()[0].getIConst();
|
||||
// if (texCoordValue <= size) {
|
||||
// error(loc, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", "");
|
||||
// return true;
|
||||
// }
|
||||
//}
|
||||
|
||||
// For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array.
|
||||
if (variable->isReadOnly())
|
||||
variable = symbolTable.copyUp(variable);
|
||||
// TODO: functionality: unsized arrays: is this new array type shared with the node?
|
||||
if (symbol->isReadOnly())
|
||||
symbol = symbolTable.copyUp(symbol);
|
||||
|
||||
variable->getWritableType().setMaxArraySize(size);
|
||||
|
||||
return false;
|
||||
symbol->getWritableType().setMaxArraySize(index + 1);
|
||||
}
|
||||
|
||||
//
|
||||
@ -1822,9 +1818,7 @@ void TParseContext::nonInitConstCheck(TSourceLoc loc, TString& identifier, TType
|
||||
//
|
||||
// Returns a redeclared and type-modified variable if a redeclarated occurred.
|
||||
//
|
||||
// Will emit
|
||||
//
|
||||
TVariable* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identifier, bool& newDeclaration)
|
||||
TSymbol* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identifier, bool& newDeclaration)
|
||||
{
|
||||
if (profile == EEsProfile || identifier.compare(0, 3, "gl_") != 0 || symbolTable.atBuiltInLevel())
|
||||
return 0;
|
||||
@ -1853,21 +1847,19 @@ TVariable* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identi
|
||||
if (! symbol)
|
||||
return 0;
|
||||
|
||||
TVariable* variable = symbol->getAsVariable();
|
||||
|
||||
// If it wasn't at a built-in level, then it's already been redeclared;
|
||||
// that is, this is a redeclaration of a redeclaration, reuse that initial
|
||||
// redeclaration. Otherwise, make the new one.
|
||||
if (builtIn) {
|
||||
// Copy the symbol up to make a writable version
|
||||
newDeclaration = true;
|
||||
variable = symbolTable.copyUp(variable);
|
||||
symbol = symbolTable.copyUp(symbol)->getAsVariable();
|
||||
}
|
||||
|
||||
// Now, modify the type of the copy, as per the type of the current redeclaration.
|
||||
// TODO: functionality: verify type change is allowed and make the change in type
|
||||
|
||||
return variable;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2029,8 +2021,8 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
|
||||
|
||||
// Check for redeclaration of built-ins and/or attempting to declare a reserved name
|
||||
bool newDeclaration = false; // true if a new entry gets added to the symbol table
|
||||
TVariable* variable = redeclareBuiltin(loc, identifier, newDeclaration);
|
||||
if (! variable)
|
||||
TSymbol* symbol = redeclareBuiltin(loc, identifier, newDeclaration);
|
||||
if (! symbol)
|
||||
reservedErrorCheck(loc, identifier);
|
||||
|
||||
// Declare the variable
|
||||
@ -2042,7 +2034,7 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
|
||||
arrayDimCheck(loc, &type, arraySizes);
|
||||
if (! arrayQualifierError(loc, type.getQualifier())) {
|
||||
type.setArraySizes(arraySizes);
|
||||
declareArray(loc, identifier, type, variable, newDeclaration);
|
||||
declareArray(loc, identifier, type, symbol, newDeclaration);
|
||||
}
|
||||
|
||||
if (initializer) {
|
||||
@ -2051,18 +2043,24 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
|
||||
}
|
||||
} else {
|
||||
// non-array case
|
||||
if (! variable)
|
||||
variable = declareNonArray(loc, identifier, type, newDeclaration);
|
||||
if (! symbol)
|
||||
symbol = declareNonArray(loc, identifier, type, newDeclaration);
|
||||
}
|
||||
|
||||
// Deal with initializer
|
||||
TIntermNode* initNode = 0;
|
||||
if (variable && initializer)
|
||||
if (symbol && initializer) {
|
||||
TVariable* variable = symbol->getAsVariable();
|
||||
if (! variable) {
|
||||
error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
|
||||
return 0;
|
||||
}
|
||||
initNode = executeInitializer(loc, identifier, initializer, variable);
|
||||
}
|
||||
|
||||
// see if it's a linker-level object to track
|
||||
if (newDeclaration && symbolTable.atGlobalLevel())
|
||||
intermediate.addSymbolLinkageNode(linkage, *variable);
|
||||
if (symbol && newDeclaration && symbolTable.atGlobalLevel())
|
||||
intermediate.addSymbolLinkageNode(linkage, *symbol);
|
||||
|
||||
return initNode;
|
||||
}
|
||||
@ -2435,11 +2433,13 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
|
||||
// For an identifier that is already declared, add more qualification to it.
|
||||
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier)
|
||||
{
|
||||
TSymbol* existing = symbolTable.find(identifier);
|
||||
TVariable* variable = existing ? existing->getAsVariable() : 0;
|
||||
if (! variable) {
|
||||
TSymbol* symbol = symbolTable.find(identifier);
|
||||
if (! symbol) {
|
||||
error(loc, "identifier not previously declared", identifier.c_str(), "");
|
||||
|
||||
return;
|
||||
}
|
||||
if (symbol->getAsFunction()) {
|
||||
error(loc, "cannot re-qualify a function name", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2453,12 +2453,13 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier,
|
||||
return;
|
||||
}
|
||||
|
||||
// For read-only built-ins, add a new variable for holding the modified qualifier.
|
||||
if (variable->isReadOnly())
|
||||
variable = symbolTable.copyUp(variable);
|
||||
// For read-only built-ins, add a new symbol for holding the modified qualifier.
|
||||
// This will bring up an entire block, if a block type has to be modified (e.g., gl_Position inside a block)
|
||||
if (symbol->isReadOnly())
|
||||
symbol = symbolTable.copyUp(symbol);
|
||||
|
||||
if (qualifier.invariant)
|
||||
variable->getWritableType().getQualifier().invariant = true;
|
||||
symbol->getWritableType().getQualifier().invariant = true;
|
||||
}
|
||||
|
||||
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers)
|
||||
|
@ -111,7 +111,7 @@ public:
|
||||
void precisionQualifierCheck(TSourceLoc, TPublicType&);
|
||||
void parameterSamplerCheck(TSourceLoc, TStorageQualifier qualifier, const TType& type);
|
||||
bool containsSampler(const TType& type);
|
||||
TVariable* redeclareBuiltin(TSourceLoc, const TString&, bool& newDeclaration);
|
||||
TSymbol* redeclareBuiltin(TSourceLoc, const TString&, bool& newDeclaration);
|
||||
void paramCheck(TSourceLoc, TStorageQualifier qualifier, TType* type);
|
||||
void nestedBlockCheck(TSourceLoc);
|
||||
void nestedStructCheck(TSourceLoc);
|
||||
@ -139,7 +139,7 @@ public:
|
||||
TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc);
|
||||
TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
|
||||
|
||||
bool arraySetMaxSize(TSourceLoc, TIntermSymbol*, int);
|
||||
void updateMaxArraySize(TSourceLoc, TIntermNode*, int index);
|
||||
|
||||
void setScanContext(TScanContext* c) { scanContext = c; }
|
||||
TScanContext* getScanContext() const { return scanContext; }
|
||||
@ -164,7 +164,7 @@ protected:
|
||||
const char* getPreamble();
|
||||
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
|
||||
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
|
||||
void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration);
|
||||
void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
|
||||
TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
|
||||
TOperator mapTypeToConstructorOp(const TType&);
|
||||
|
||||
|
@ -240,7 +240,7 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
|
||||
}
|
||||
}
|
||||
|
||||
TVariable* TVariable::clone()
|
||||
TVariable* TVariable::clone() const
|
||||
{
|
||||
TVariable *variable = new TVariable(*this);
|
||||
|
||||
@ -261,28 +261,45 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
|
||||
defined = copyOf.defined;
|
||||
}
|
||||
|
||||
TFunction* TFunction::clone()
|
||||
TFunction* TFunction::clone() const
|
||||
{
|
||||
TFunction *function = new TFunction(*this);
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
TAnonMember* TAnonMember::clone()
|
||||
TAnonMember* TAnonMember::clone() const
|
||||
{
|
||||
// need to implement this once built-in symbols include interface blocks
|
||||
// Anonymous members of a given block should be cloned at a higher level,
|
||||
// where they can all be assured to still end up pointing to a single
|
||||
// copy of the original container.
|
||||
assert(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TSymbolTableLevel* TSymbolTableLevel::clone()
|
||||
TSymbolTableLevel* TSymbolTableLevel::clone() const
|
||||
{
|
||||
TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
|
||||
symTableLevel->anonId = anonId;
|
||||
tLevel::iterator iter;
|
||||
for (iter = level.begin(); iter != level.end(); ++iter)
|
||||
symTableLevel->insert(*iter->second->clone());
|
||||
std::vector<bool> containerCopied(anonId, false);
|
||||
tLevel::const_iterator iter;
|
||||
for (iter = level.begin(); iter != level.end(); ++iter) {
|
||||
const TAnonMember* anon = iter->second->getAsAnonMember();
|
||||
if (anon) {
|
||||
// Insert all the anonymous members of this same container at once,
|
||||
// avoid inserting the other members in the future, once this has been done,
|
||||
// allowing them to all be part of the same new container.
|
||||
if (! containerCopied[anon->getAnonId()]) {
|
||||
TVariable* container = anon->getAnonContainer().clone();
|
||||
container->changeName(NewPoolTString(""));
|
||||
// insert the whole container
|
||||
symTableLevel->insert(*container);
|
||||
containerCopied[anon->getAnonId()] = true;
|
||||
}
|
||||
} else
|
||||
symTableLevel->insert(*iter->second->clone());
|
||||
}
|
||||
|
||||
return symTableLevel;
|
||||
}
|
||||
|
@ -45,8 +45,7 @@
|
||||
// symbols.
|
||||
//
|
||||
// --> This requires a copy mechanism, so initial pools used to create
|
||||
// the shared information can be popped. So, care is taken with
|
||||
// copying pointers to point to new copies. Done through "clone"
|
||||
// the shared information can be popped. Done through "clone"
|
||||
// methods.
|
||||
//
|
||||
// * Name mangling will be used to give each function a unique name
|
||||
@ -74,30 +73,34 @@ namespace glslang {
|
||||
//
|
||||
// Symbol base class. (Can build functions or variables out of these...)
|
||||
//
|
||||
|
||||
class TVariable;
|
||||
class TFunction;
|
||||
class TAnonMember;
|
||||
|
||||
class TSymbol {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
explicit TSymbol(const TString *n) : name(n), writable(true) { }
|
||||
virtual TSymbol* clone() = 0;
|
||||
virtual TSymbol* clone() const = 0;
|
||||
virtual ~TSymbol() { }
|
||||
|
||||
const TString& getName() const { return *name; }
|
||||
void changeName(const TString* newName) { name = newName; }
|
||||
virtual const TString& getName() const { return *name; }
|
||||
virtual void changeName(const TString* newName) { name = newName; }
|
||||
virtual const TString& getMangledName() const { return getName(); }
|
||||
virtual TFunction* getAsFunction() { return 0; }
|
||||
virtual const TFunction* getAsFunction() const { return 0; }
|
||||
virtual TVariable* getAsVariable() { return 0; }
|
||||
virtual const TVariable* getAsVariable() const { return 0; }
|
||||
virtual const TAnonMember* getAsAnonMember() const { return 0; }
|
||||
void setUniqueId(int id) { uniqueId = id; }
|
||||
int getUniqueId() const { return uniqueId; }
|
||||
virtual const TType& getType() const = 0;
|
||||
virtual TType& getWritableType() = 0;
|
||||
virtual void setUniqueId(int id) { uniqueId = id; }
|
||||
virtual int getUniqueId() const { return uniqueId; }
|
||||
virtual void dump(TInfoSink &infoSink) const = 0;
|
||||
|
||||
bool isReadOnly() { return ! writable; }
|
||||
void makeReadOnly() { writable = false; }
|
||||
virtual bool isReadOnly() { return ! writable; }
|
||||
virtual void makeReadOnly() { writable = false; }
|
||||
|
||||
protected:
|
||||
explicit TSymbol(const TSymbol&);
|
||||
@ -126,20 +129,19 @@ protected:
|
||||
class TVariable : public TSymbol {
|
||||
public:
|
||||
TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), userType(uT) { type.shallowCopy(t); }
|
||||
virtual TVariable* clone();
|
||||
virtual TVariable* clone() const;
|
||||
virtual ~TVariable() { }
|
||||
|
||||
virtual TVariable* getAsVariable() { return this; }
|
||||
virtual const TVariable* getAsVariable() const { return this; }
|
||||
TType& getWritableType() { assert(writable); return type; }
|
||||
const TType& getType() const { return type; }
|
||||
bool isUserType() const { return userType; }
|
||||
virtual const TType& getType() const { return type; }
|
||||
virtual TType& getWritableType() { assert(writable); return type; }
|
||||
virtual bool isUserType() const { return userType; }
|
||||
virtual const TConstUnionArray& getConstArray() const { return unionArray; }
|
||||
virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; }
|
||||
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
const TConstUnionArray& getConstArray() const { return unionArray; }
|
||||
void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; }
|
||||
|
||||
protected:
|
||||
explicit TVariable(const TVariable&);
|
||||
TVariable& operator=(const TVariable&);
|
||||
@ -182,35 +184,36 @@ public:
|
||||
mangledName(*name + '('),
|
||||
op(tOp),
|
||||
defined(false) { returnType.shallowCopy(retType); }
|
||||
virtual TFunction* clone();
|
||||
virtual TFunction* clone() const;
|
||||
virtual ~TFunction();
|
||||
|
||||
virtual TFunction* getAsFunction() { return this; }
|
||||
virtual const TFunction* getAsFunction() const { return this; }
|
||||
|
||||
void addParameter(TParameter& p)
|
||||
virtual void addParameter(TParameter& p)
|
||||
{
|
||||
assert(writable);
|
||||
parameters.push_back(p);
|
||||
p.type->appendMangledName(mangledName);
|
||||
}
|
||||
|
||||
const TString& getMangledName() const { return mangledName; }
|
||||
const TType& getReturnType() const { return returnType; }
|
||||
void relateToOperator(TOperator o) { assert(writable); op = o; }
|
||||
TOperator getBuiltInOp() const { return op; }
|
||||
void setDefined() { assert(writable); defined = true; }
|
||||
bool isDefined() const { return defined; }
|
||||
virtual const TString& getMangledName() const { return mangledName; }
|
||||
virtual const TType& getType() const { return returnType; }
|
||||
virtual TType& getWritableType() { return returnType; }
|
||||
virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
|
||||
virtual TOperator getBuiltInOp() const { return op; }
|
||||
virtual void setDefined() { assert(writable); defined = true; }
|
||||
virtual bool isDefined() const { return defined; }
|
||||
|
||||
int getParamCount() const { return static_cast<int>(parameters.size()); }
|
||||
TParameter& operator [](int i) { assert(writable); return parameters[i]; }
|
||||
const TParameter& operator [](int i) const { return parameters[i]; }
|
||||
virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
|
||||
virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
|
||||
virtual const TParameter& operator[](int i) const { return parameters[i]; }
|
||||
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
protected:
|
||||
explicit TFunction(const TFunction&);
|
||||
TFunction& operator=(TFunction&);
|
||||
TFunction& operator=(const TFunction&);
|
||||
|
||||
typedef TVector<TParameter> TParamList;
|
||||
TParamList parameters;
|
||||
@ -222,21 +225,37 @@ protected:
|
||||
|
||||
class TAnonMember : public TSymbol {
|
||||
public:
|
||||
TAnonMember(const TString* n, unsigned int m, TSymbol& a) : TSymbol(n), anonContainer(a), memberNumber(m) { }
|
||||
virtual TAnonMember* clone();
|
||||
TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
|
||||
virtual TAnonMember* clone() const;
|
||||
virtual ~TAnonMember() { }
|
||||
|
||||
const TAnonMember* getAsAnonMember() const { return this; }
|
||||
TSymbol& getAnonContainer() const { return anonContainer; }
|
||||
unsigned int getMemberNumber() const { return memberNumber; }
|
||||
virtual const TAnonMember* getAsAnonMember() const { return this; }
|
||||
virtual const TVariable& getAnonContainer() const { return anonContainer; }
|
||||
virtual unsigned int getMemberNumber() const { return memberNumber; }
|
||||
|
||||
virtual const TType& getType() const
|
||||
{
|
||||
TTypeList& types = *anonContainer.getType().getStruct();
|
||||
return *types[memberNumber].type;
|
||||
}
|
||||
|
||||
virtual TType& getWritableType()
|
||||
{
|
||||
assert(writable);
|
||||
TTypeList& types = *anonContainer.getType().getStruct();
|
||||
return *types[memberNumber].type;
|
||||
}
|
||||
|
||||
virtual int getAnonId() const { return anonId; }
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
protected:
|
||||
explicit TAnonMember(TAnonMember&);
|
||||
TAnonMember& operator=(TAnonMember&);
|
||||
explicit TAnonMember(const TAnonMember&);
|
||||
TAnonMember& operator=(const TAnonMember&);
|
||||
|
||||
TSymbol& anonContainer;
|
||||
const TVariable& anonContainer;
|
||||
unsigned int memberNumber;
|
||||
int anonId;
|
||||
};
|
||||
|
||||
class TSymbolTableLevel {
|
||||
@ -256,18 +275,20 @@ public:
|
||||
// An empty name means an anonymous container, exposing its members to the external scope.
|
||||
// Give it a name and insert its members in the symbol table, pointing to the container.
|
||||
char buf[20];
|
||||
snprintf(buf, 20, "__anon__%d", anonId++);
|
||||
snprintf(buf, 20, "__anon__%d", anonId);
|
||||
symbol.changeName(NewPoolTString(buf));
|
||||
|
||||
bool isOkay = true;
|
||||
const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
|
||||
for (unsigned int m = 0; m < types.size(); ++m) {
|
||||
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, symbol);
|
||||
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), anonId);
|
||||
result = level.insert(tLevelPair(member->getMangledName(), member));
|
||||
if (! result.second)
|
||||
isOkay = false;
|
||||
}
|
||||
|
||||
++anonId;
|
||||
|
||||
return isOkay;
|
||||
} else {
|
||||
// Check for redefinition errors:
|
||||
@ -344,7 +365,7 @@ public:
|
||||
|
||||
void relateToOperator(const char* name, TOperator op);
|
||||
void dump(TInfoSink &infoSink) const;
|
||||
TSymbolTableLevel* clone();
|
||||
TSymbolTableLevel* clone() const;
|
||||
void readOnly();
|
||||
|
||||
protected:
|
||||
@ -422,7 +443,7 @@ public:
|
||||
{
|
||||
symbol.setUniqueId(++uniqueId);
|
||||
|
||||
if (symbol.getAsVariable()) {
|
||||
if (! symbol.getAsFunction()) {
|
||||
// make sure there isn't a function of this name
|
||||
if (table[currentLevel()]->hasFunctionName(symbol.getName()))
|
||||
return false;
|
||||
@ -438,16 +459,27 @@ public:
|
||||
}
|
||||
|
||||
//
|
||||
// To copy a variable from a shared level up to the current level, so it can be
|
||||
// modified without impacting other users of the shared table.
|
||||
// Copy a variable or anonymous member's structure from a shared level up
|
||||
// to the current level, so it can be modified without impacting other users
|
||||
// of the shared table.
|
||||
//
|
||||
TVariable* copyUp(TVariable* shared)
|
||||
{
|
||||
TVariable* variable = shared->clone();
|
||||
variable->setUniqueId(shared->getUniqueId());
|
||||
table[currentLevel()]->insert(*variable);
|
||||
|
||||
return variable;
|
||||
TSymbol* copyUp(TSymbol* shared)
|
||||
{
|
||||
TSymbol* copy;
|
||||
if (shared->getAsVariable()) {
|
||||
copy = shared->clone();
|
||||
copy->setUniqueId(shared->getUniqueId());
|
||||
table[currentLevel()]->insert(*copy);
|
||||
return copy;
|
||||
} else {
|
||||
const TAnonMember* anon = shared->getAsAnonMember();
|
||||
assert(anon);
|
||||
TVariable* container = anon->getAnonContainer().clone();
|
||||
container->changeName(NewPoolTString(""));
|
||||
container->setUniqueId(anon->getAnonContainer().getUniqueId());
|
||||
table[currentLevel()]->insert(*container);
|
||||
return table[currentLevel()]->find(shared->getName());
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0)
|
||||
|
@ -2378,7 +2378,7 @@ function_definition
|
||||
parseContext.error($1.loc, "function does not return a value:", "", $1.function->getName().c_str());
|
||||
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
|
||||
$$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3);
|
||||
parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getReturnType(), $1.loc);
|
||||
parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getType(), $1.loc);
|
||||
$$->getAsAggregate()->setName($1.function->getMangledName().c_str());
|
||||
|
||||
// store the pragma information for debug and optimize and other vendor specific
|
||||
|
@ -49,7 +49,7 @@ struct TVectorFields {
|
||||
};
|
||||
|
||||
class TSymbolTable;
|
||||
class TVariable;
|
||||
class TSymbol;
|
||||
|
||||
//
|
||||
// Set of helper functions to help parse and build the tree.
|
||||
@ -97,7 +97,7 @@ public:
|
||||
bool postProcess(TIntermNode*, EShLanguage);
|
||||
void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
|
||||
|
||||
void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
|
||||
void merge(TInfoSink&, TIntermediate&);
|
||||
|
Loading…
Reference in New Issue
Block a user