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:
John Kessenich 2013-10-11 17:29:19 +00:00
parent 4c70685382
commit 9d30218fb6
8 changed files with 217 additions and 155 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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, &currentScope);
symbol = symbolTable.find(identifier, 0, &currentScope);
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)

View File

@ -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&);

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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&);