out vec4 pos;
out vec3 color;
-layout(shared, column_major, row_major) uniform mat4 m4; // default is now shared and row_major
+layout(shared, column_major, row_major) uniform mat4 badm4; // ERROR
+layout(shared, column_major, row_major) uniform; // default is now shared and row_major
layout(std140) uniform Transform { // layout of this block is std140
mat4 M1; // row_major
mat3 N1; // row_major
} tblock;
-//uniform T2 { // layout of this block is shared
-//...
-//};
-//
+uniform T2 { // layout of this block is shared
+ bool b;
+ mat4 t2m;
+};
+
layout(column_major) uniform T3 { // shared and column_major
mat4 M3; // column_major
- layout(row_major) mat4 m4; // row major
+ layout(row_major) mat4 M4; // row major
mat3 N2; // column_major
+ int b; // ERROR, redefinition (needs to be last member of block for testing, following members are skipped)
};
void main()
{
- pos = p * (m4 + tblock.M1 + tblock.M2);
+ pos = p * (tblock.M1 + tblock.M2 + M4 + M3 + t2m);
color = c * tblock.N1;
}
};\r
\r
layout(column_major) uniform T3 { // shared and column_major\r
- mat4 M3; // column_major\r
- layout(row_major) mat4 m4; // row major\r
- mat3 N2; // column_major\r
+ mat4 M13; // column_major\r
+ layout(row_major) mat4 m14; // row major\r
+ mat3 N12; // column_major\r
};\r
\r
// in one compilation unit...\r
-layout(binding=3) uniform sampler2D s; // s bound to unit 3\r
+layout(binding=3) uniform sampler2D s17; // s bound to unit 3\r
\r
// in another compilation unit...\r
-uniform sampler2D s; // okay, s still bound at 3\r
+uniform sampler2D s17; // okay, s still bound at 3\r
\r
// in another compilation unit...\r
//layout(binding=4) uniform sampler2D s; // ERROR: contradictory bindings\r
TType() {}
virtual ~TType() {}
- TType(const TType& type) { *this = type; }
+ // "dumb" copy, using built-in operator=(), not for use across pool pops.
+ // It will also cause multiple copies of TType to point to the same information.
+ // This only works if that information (like a structure's list of types) does not
+ // change.
+ explicit TType(const TType& type) { *this = type; }
void copyType(const TType& copyOf, const TStructureMap& remapper)
{
TArraySizes arraySizes;
TTypeList* structure; // 0 unless this is a struct
- mutable int structureSize;
+ mutable int structureSize; // a cache, updated on first access
int maxArraySize;
TType* arrayInformationType;
TString *fieldName; // for structure field names
bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray)
{
if (leftNodeType.isArray()) {
- TType typeWithoutArrayness = leftNodeType;
+ TType typeWithoutArrayness(leftNodeType);
typeWithoutArrayness.dereference();
int arraySize = leftNodeType.getArraySize();
// For most cases, the return type matches the argument type, so set that
// up and just code to exceptions below.
- TType returnType = getType();
+ TType returnType(getType());
//
// A pair of nodes is to be folded together
bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
{
- TType type = TType(pType);
+ TType type(pType);
if (variable == 0) {
if (reservedErrorCheck(line, identifier))
if (op == EOpConstructStruct)
memberTypes = type.getStruct()->begin();
- TType elementType = type;
+ TType elementType(type);
if (type.isArray())
elementType.dereference();
// Build and add the interface block as a new type named blockName
- TType* blockType = new TType(&typeList, blockName, qualifier.qualifier.storage);
- TVariable* userTypeDef = new TVariable(&blockName, *blockType, true);
+ TType blockType(&typeList, blockName, qualifier.qualifier.storage);
+ TVariable* userTypeDef = new TVariable(&blockName, blockType, true);
if (! symbolTable.insert(*userTypeDef)) {
error(line, "redefinition", blockName.c_str(), "block name");
recover();
if (! instanceName)
instanceName = new TString("");
- TVariable* variable = new TVariable(instanceName, *blockType);
-
+ TVariable* variable = new TVariable(instanceName, blockType);
if (! symbolTable.insert(*variable)) {
- error(line, "redefinition", variable->getName().c_str(), "");
- delete variable;
+ if (*instanceName == "")
+ error(line, "nameless block contains a member that already has a name at global scope", blockName.c_str(), "");
+ else
+ error(line, "block instance name redefinition", variable->getName().c_str(), "");
recover();
return;
TIntermTyped* typedNode;
TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
int arraySize = node->getType().getArraySize();
- TType arrayElementType = node->getType();
+ TType arrayElementType(node->getType());
arrayElementType.dereference();
if (index >= node->getType().getArraySize() || index < 0) {
// is guaranteed written. Not always possible to determine if
// it is written conditionally.
//
-// ?? It does not do this well yet, this is just a place holder
+// It does not do this well yet, this is just a place holder
// that simply determines if it was reference at all, anywhere.
//
bool QualifierWritten(TIntermNode* node, TStorageQualifier qualifier)
infoSink.debug << "\n";
}
-void TFunction::dump(TInfoSink &infoSink) const
+void TFunction::dump(TInfoSink& infoSink) const
{
infoSink.debug << getName().c_str() << ": " << returnType.getCompleteTypeString() << " " << getMangledName().c_str() << "\n";
}
+void TAnonMember::dump(TInfoSink& TInfoSink) const
+{
+ TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str() << "\n";
+}
+
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
{
tLevel::const_iterator it;
return function;
}
+TAnonMember* TAnonMember::clone(TStructureMap& remapper)
+{
+ // need to implement this once built-in symbols include interface blocks
+ assert(0);
+
+ return 0;
+}
+
TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
{
TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
+ symTableLevel->anonId = anonId;
tLevel::iterator iter;
for (iter = level.begin(); iter != level.end(); ++iter) {
symTableLevel->insert(*iter->second->clone(remapper));
// effort of creating and loading with the large numbers of built-in
// 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"
+// methods.
+//
// * Name mangling will be used to give each function a unique name
// so that symbol table lookups are never ambiguous. This allows
// a simpler symbol table structure.
//
class TVariable;
class TFunction;
+class TAnonMember;
class TSymbol {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
- TSymbol(const TString *n) : name(n) { }
- virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
+ explicit TSymbol(const TString *n) : name(n) { }
+ virtual TSymbol* clone(TStructureMap& remapper) = 0;
+ virtual ~TSymbol() { }
+
const TString& getName() const { return *name; }
+ void changeName(const char* buf) { name = new TString(buf); }
virtual const TString& getMangledName() const { return getName(); }
virtual TFunction* getAsFunction() { return 0; }
virtual TVariable* getAsVariable() { return 0; }
+ virtual TAnonMember* getAsAnonMember() { return 0; }
void setUniqueId(int id) { uniqueId = id; }
int getUniqueId() const { return uniqueId; }
- virtual void dump(TInfoSink &infoSink) const = 0;
- TSymbol(const TSymbol&);
- virtual TSymbol* clone(TStructureMap& remapper) = 0;
+ virtual void dump(TInfoSink &infoSink) const = 0;
protected:
+ explicit TSymbol(const TSymbol&);
+ TSymbol& operator=(const TSymbol&);
+
const TString *name;
- unsigned int uniqueId; // For real comparing during code generation
+ unsigned int uniqueId; // For cross-scope comparing during code generation
};
//
//
class TVariable : public TSymbol {
public:
- TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
+ TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
+ virtual TVariable* clone(TStructureMap& remapper);
virtual ~TVariable() { }
+
virtual TVariable* getAsVariable() { return this; }
TType& getType() { return type; }
const TType& getType() const { return type; }
delete unionArray;
unionArray = constArray;
}
- TVariable(const TVariable&, TStructureMap& remapper); // copy constructor
- virtual TVariable* clone(TStructureMap& remapper);
protected:
+ explicit TVariable(TVariable&);
+ TVariable(const TVariable&, TStructureMap& remapper);
+ TVariable& operator=(TVariable&);
+
TType type;
bool userType;
// we are assuming that Pool Allocator will free the memory allocated to unionArray
//
class TFunction : public TSymbol {
public:
- TFunction(TOperator o) :
+ explicit TFunction(TOperator o) :
TSymbol(0),
returnType(TType(EbtVoid)),
op(o),
returnType(retType),
mangledName(*name + '('),
op(tOp),
- defined(false) { }
- TFunction(const TFunction&, const TStructureMap& remapper);
+ defined(false) { }
+ virtual TFunction* clone(TStructureMap& remapper);
virtual ~TFunction();
+
virtual TFunction* getAsFunction() { return this; }
void addParameter(TParameter& p)
const TParameter& operator [](int i) const { return parameters[i]; }
virtual void dump(TInfoSink &infoSink) const;
- virtual TFunction* clone(TStructureMap& remapper);
protected:
+ explicit TFunction(TFunction&);
+ TFunction(const TFunction&, const TStructureMap& remapper);
+ TFunction& operator=(TFunction&);
+
typedef TVector<TParameter> TParamList;
TParamList parameters;
TType returnType;
bool defined;
};
+class TAnonMember : public TSymbol {
+public:
+ TAnonMember(const TString* n, unsigned int m, TSymbol& a) : TSymbol(n), anonContainer(a), memberNumber(m) { }
+ virtual TAnonMember* clone(TStructureMap& remapper);
+ virtual ~TAnonMember() { }
+
+ TAnonMember* getAsAnonMember() { return this; }
+ TSymbol& getAnonContainer() const { return anonContainer; }
+ unsigned int getMemberNumber() const { return memberNumber; }
+ virtual void dump(TInfoSink &infoSink) const;
+
+protected:
+ explicit TAnonMember(TAnonMember&);
+ TAnonMember& operator=(TAnonMember&);
+
+ TSymbol& anonContainer;
+ unsigned int memberNumber;
+};
class TSymbolTableLevel {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
- TSymbolTableLevel() : defaultPrecision (0) { }
+ TSymbolTableLevel() : defaultPrecision (0), anonId(0) { }
~TSymbolTableLevel();
bool insert(TSymbol& symbol)
// returning true means symbol was added to the table
//
tInsertResult result;
- result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
-
- return result.second;
+ if (symbol.getName() == "") {
+ // 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++);
+ symbol.changeName(buf);
+
+ bool isOkay = true;
+ 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);
+ result = level.insert(tLevelPair(member->getMangledName(), member));
+ if (! result.second)
+ isOkay = false;
+ }
+
+ return isOkay;
+ } else {
+ result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
+
+ return result.second;
+ }
}
TSymbol* find(const TString& name) const
{
tLevel::const_iterator it = level.find(name);
- if (it == level.end())
+ if (it == level.end())
return 0;
else
return (*it).second;
TSymbolTableLevel* clone(TStructureMap& remapper);
protected:
+ explicit TSymbolTableLevel(TSymbolTableLevel&);
+ TSymbolTableLevel& operator=(TSymbolTableLevel&);
+
typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
typedef const tLevel::value_type tLevelPair;
typedef std::pair<tLevel::iterator, bool> tInsertResult;
- tLevel level;
+ tLevel level; // named mappings
TPrecisionQualifier *defaultPrecision;
+ int anonId;
};
class TSymbolTable {
// that the symbol table has not been preloaded with built-ins.
//
}
-
- TSymbolTable(TSymbolTable& symTable)
+ explicit TSymbolTable(TSymbolTable& symTable)
{
table.push_back(symTable.table[0]);
uniqueId = symTable.uniqueId;
}
-
~TSymbolTable()
{
// level 0 is always built In symbols, so we never pop that out
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
protected:
+ TSymbolTable& operator=(TSymbolTableLevel&);
+
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
bool atDynamicBuiltInLevel() { return table.size() == 2; }
// if this is a new symbol, it won't find it, which is okay at this\r
// point in the grammar.\r
TSymbol* symbol = $1.symbol;\r
- const TVariable* variable = symbol ? symbol->getAsVariable() : 0;\r
- if (symbol && ! variable) {\r
- parseContext.error($1.line, "variable name expected", $1.string->c_str(), "");\r
- parseContext.recover();\r
- }\r
+ TAnonMember* anon = symbol ? symbol->getAsAnonMember() : 0;\r
+ if (anon) {\r
+ // it was a member of an anonymous container, have to insert its dereference\r
+ TVariable* variable = anon->getAnonContainer().getAsVariable();\r
+ TIntermTyped* container = parseContext.intermediate.addSymbol(variable->getUniqueId(),\r
+ variable->getName(),\r
+ variable->getType(), $1.line);\r
+ constUnion* unionArray = new constUnion[1];\r
+ unionArray->setUConst(anon->getMemberNumber());\r
+ TIntermTyped* constNode = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), $1.line);\r
+\r
+ $$ = parseContext.intermediate.addIndex(EOpIndexDirect, container, constNode, $1.line);\r
+ $$->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);\r
+ } else {\r
+ const TVariable* variable = symbol ? symbol->getAsVariable() : 0;\r
+ if (symbol && ! variable) {\r
+ parseContext.error($1.line, "variable name expected", $1.string->c_str(), "");\r
+ parseContext.recover();\r
+ }\r
\r
- if (! variable)\r
- variable = new TVariable($1.string, TType(EbtVoid));\r
+ if (! variable)\r
+ variable = new TVariable($1.string, TType(EbtVoid));\r
\r
- // don't delete $1.string, it's used by error recovery, and the pool\r
- // pop will reclaim the memory\r
+ // don't delete $1.string, it's used by error recovery, and the pool\r
+ // pop will reclaim the memory\r
\r
- if (variable->getType().getQualifier().storage == EvqConst ) {\r
- constUnion* constArray = variable->getConstUnionPointer();\r
- TType t(variable->getType());\r
- $$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line);\r
- } else\r
- $$ = parseContext.intermediate.addSymbol(variable->getUniqueId(),\r
- variable->getName(),\r
- variable->getType(), $1.line);\r
+ if (variable->getType().getQualifier().storage == EvqConst ) {\r
+ constUnion* constArray = variable->getConstUnionPointer();\r
+ TType t(variable->getType());\r
+ $$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line);\r
+ } else\r
+ $$ = parseContext.intermediate.addSymbol(variable->getUniqueId(),\r
+ variable->getName(),\r
+ variable->getType(), $1.line);\r
+ }\r
}\r
;\r
\r
unionArray->setFConst(0.0f);\r
$$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.line);\r
} else {\r
- TType newType = $1->getType();\r
+ TType newType($1->getType());\r
newType.dereference();\r
$$->setType(newType);\r
// TODO: testing: write a set of dereference tests\r
TString vectorString = *$3.string;\r
TIntermTyped* index = parseContext.intermediate.addSwizzle(fields, $3.line);\r
$$ = parseContext.intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line);\r
- $$->setType(TType($1->getBasicType(),EvqTemporary, (int) vectorString.size()));\r
+ $$->setType(TType($1->getBasicType(), EvqTemporary, (int) vectorString.size()));\r
}\r
}\r
} else if ($1->isMatrix()) {\r
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, TSourceLoc);
TIntermConstantUnion* addConstantUnion(constUnion*, const TType&, TSourceLoc);
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
- bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, TType, bool singleConstantParam = false);
+ bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, const TType&, bool singleConstantParam = false);
TIntermNode* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
TIntermBranch* addBranch(TOperator, TSourceLoc);
TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
//
class TConstTraverser : public TIntermTraverser {
public:
- TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t) : unionArray(cUnion), type(t),
+ TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, const TType& t) : unionArray(cUnion), type(t),
constructorType(constructType), singleConstantParam(singleConstParam), infoSink(sink), error(false), isMatrix(false),
matrixCols(0), matrixRows(0) { index = 0; tOp = EOpNull;}
int index ;
constUnion *unionArray;
TOperator tOp;
- TType type;
+ const TType& type;
TOperator constructorType;
bool singleConstantParam;
TInfoSink& infoSink;
// Individual functions can be initialized to 0 to skip processing of that
// type of node. It's children will still be processed.
//
-bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, constUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam)
+bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, constUnion* unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
{
if (root == 0)
return false;