HLSL non-functional: Generalize namespace nesting.

Also use this to move deferred member-function-body parsing to a better
place.

This should also be well poised for implementing the 'namespace' keyword.
This commit is contained in:
John Kessenich 2017-03-19 12:24:29 -06:00
parent e751bca75c
commit f3d88bd498
7 changed files with 64 additions and 60 deletions

View File

@ -2,5 +2,5 @@
// For the version, it uses the latest git tag followed by the number of commits. // For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run). // For the date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1920" #define GLSLANG_REVISION "Overload400-PrecQual.1921"
#define GLSLANG_DATE "16-Mar-2017" #define GLSLANG_DATE "19-Mar-2017"

View File

@ -145,6 +145,8 @@ public:
virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
virtual void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); virtual void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
const char* const scopeMangler = "::";
protected: protected:
TParseContextBase(TParseContextBase&); TParseContextBase(TParseContextBase&);
TParseContextBase& operator=(TParseContextBase&); TParseContextBase& operator=(TParseContextBase&);

View File

@ -95,9 +95,11 @@ namespace glslang {
class TFunctionDeclarator { class TFunctionDeclarator {
public: public:
TFunctionDeclarator() : function(nullptr), body(nullptr) { }
TSourceLoc loc; TSourceLoc loc;
TFunction* function; TFunction* function;
TAttributeMap attributes; TAttributeMap attributes;
TVector<HlslToken>* body;
}; };
} // end namespace glslang } // end namespace glslang

View File

@ -1788,7 +1788,7 @@ bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
postDeclQualifier.clear(); postDeclQualifier.clear();
bool postDeclsFound = acceptPostDecls(postDeclQualifier); bool postDeclsFound = acceptPostDecls(postDeclQualifier);
// LEFT_BRACE // LEFT_BRACE, or
// struct_type IDENTIFIER // struct_type IDENTIFIER
if (! acceptTokenClass(EHTokLeftBrace)) { if (! acceptTokenClass(EHTokLeftBrace)) {
if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) { if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
@ -1800,9 +1800,17 @@ bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
} }
} }
// struct_declaration_list // struct_declaration_list
TTypeList* typeList; TTypeList* typeList;
if (! acceptStructDeclarationList(typeList, nodeList, structName)) { // Save each member function so they can be processed after we have a fully formed 'this'.
TVector<TFunctionDeclarator> functionDeclarators;
parseContext.pushNamespace(structName);
bool acceptedList = acceptStructDeclarationList(typeList, nodeList, structName, functionDeclarators);
parseContext.popNamespace();
if (! acceptedList) {
expected("struct member declarations"); expected("struct member declarations");
return false; return false;
} }
@ -1823,7 +1831,20 @@ bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
parseContext.declareStruct(token.loc, structName, type); parseContext.declareStruct(token.loc, structName, type);
return true; // All member functions get parsed inside the class/struct namespace and with the
// class/struct members in a symbol-table level.
parseContext.pushNamespace(structName);
bool deferredSuccess = true;
for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
// parse body
pushTokenStream(functionDeclarators[b].body);
if (! acceptFunctionBody(functionDeclarators[b], nodeList))
deferredSuccess = false;
popTokenStream();
}
parseContext.popNamespace();
return deferredSuccess;
} }
// struct_buffer // struct_buffer
@ -1934,16 +1955,12 @@ bool HlslGrammar::acceptStructBufferType(TType& type)
// | IDENTIFIER array_specifier post_decls // | IDENTIFIER array_specifier post_decls
// | IDENTIFIER function_parameters post_decls // member-function prototype // | IDENTIFIER function_parameters post_decls // member-function prototype
// //
bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, const TString& typeName) bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, const TString& typeName,
TVector<TFunctionDeclarator>& declarators)
{ {
typeList = new TTypeList(); typeList = new TTypeList();
HlslToken idToken; HlslToken idToken;
// Save these away for each member function so they can be processed after
// all member variables/types have been declared.
TVector<TVector<HlslToken>*> memberBodies;
TVector<TFunctionDeclarator> declarators;
do { do {
// success on seeing the RIGHT_BRACE coming up // success on seeing the RIGHT_BRACE coming up
if (peekTokenClass(EHTokRightBrace)) if (peekTokenClass(EHTokRightBrace))
@ -1973,11 +1990,8 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
if (!declarator_list) { if (!declarator_list) {
declarators.resize(declarators.size() + 1); declarators.resize(declarators.size() + 1);
// request a token stream for deferred processing // request a token stream for deferred processing
TVector<HlslToken>* deferredTokens = new TVector<HlslToken>; functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, typeName, memberType, declarators.back());
*idToken.string, declarators.back(),
deferredTokens);
memberBodies.push_back(deferredTokens);
if (functionDefinitionAccepted) if (functionDefinitionAccepted)
break; break;
} }
@ -2030,14 +2044,6 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
} while (true); } while (true);
// parse member-function bodies now
for (int b = 0; b < (int)memberBodies.size(); ++b) {
pushTokenStream(memberBodies[b]);
if (! acceptFunctionBody(declarators[b], nodeList))
return false;
popTokenStream();
}
return true; return true;
} }
@ -2046,15 +2052,12 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
// //
// Expects type to have EvqGlobal for a static member and // Expects type to have EvqGlobal for a static member and
// EvqTemporary for non-static member. // EvqTemporary for non-static member.
bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TString& typeName, bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
const TType& type, const TString& memberName, TFunctionDeclarator& declarator)
TFunctionDeclarator& declarator, TVector<HlslToken>* deferredTokens)
{ {
// watch early returns...
parseContext.pushThis(typeName);
bool accepted = false; bool accepted = false;
TString* functionName = parseContext.getFullMemberFunctionName(memberName, type.getQualifier().storage == EvqGlobal); TString* functionName = parseContext.getFullNamespaceName(memberName);
declarator.function = new TFunction(functionName, type); declarator.function = new TFunction(functionName, type);
// function_parameters // function_parameters
@ -2070,12 +2073,12 @@ bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const T
} }
declarator.loc = token.loc; declarator.loc = token.loc;
accepted = acceptFunctionDefinition(declarator, nodeList, deferredTokens); declarator.body = new TVector<HlslToken>;
accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
} }
} else } else
expected("function parameter list"); expected("function parameter list");
parseContext.popThis();
return accepted; return accepted;
} }
@ -2781,13 +2784,8 @@ bool HlslGrammar::acceptFunctionCall(HlslToken callToken, TIntermTyped*& node, T
functionName = callToken.string; functionName = callToken.string;
else { else {
functionName = NewPoolTString(""); functionName = NewPoolTString("");
if (baseObject != nullptr) { functionName->append(baseType->getType().getTypeName());
functionName->append(baseObject->getType().getTypeName().c_str()); parseContext.addScopeMangler(*functionName);
functionName->append(".");
} else if (baseType != nullptr) {
functionName->append(baseType->getType().getTypeName());
functionName->append("::");
}
functionName->append(*callToken.string); functionName->append(*callToken.string);
} }
@ -2795,7 +2793,6 @@ bool HlslGrammar::acceptFunctionCall(HlslToken callToken, TIntermTyped*& node, T
TFunction* function = new TFunction(functionName, TType(EbtVoid)); TFunction* function = new TFunction(functionName, TType(EbtVoid));
// arguments // arguments
// Non-static member functions have an implicit first argument of the base object.
TIntermTyped* arguments = nullptr; TIntermTyped* arguments = nullptr;
if (baseObject != nullptr) if (baseObject != nullptr)
parseContext.handleFunctionArgument(function, arguments, baseObject); parseContext.handleFunctionArgument(function, arguments, baseObject);

View File

@ -87,10 +87,10 @@ namespace glslang {
bool acceptTextureType(TType&); bool acceptTextureType(TType&);
bool acceptStructBufferType(TType&); bool acceptStructBufferType(TType&);
bool acceptStruct(TType&, TIntermNode*& nodeList); bool acceptStruct(TType&, TIntermNode*& nodeList);
bool acceptStructDeclarationList(TTypeList*&, TIntermNode*& nodeList, const TString& typeName); bool acceptStructDeclarationList(TTypeList*&, TIntermNode*& nodeList, const TString& typeName,
bool acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TString& typeName, TVector<TFunctionDeclarator>&);
const TType&, const TString& memberName, TFunctionDeclarator&, bool acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType&, const TString& memberName,
TVector<HlslToken>* deferredTokens); TFunctionDeclarator&);
bool acceptFunctionParameters(TFunction&); bool acceptFunctionParameters(TFunction&);
bool acceptParameterDeclaration(TFunction&); bool acceptParameterDeclaration(TFunction&);
bool acceptFunctionDefinition(TFunctionDeclarator&, TIntermNode*& nodeList, TVector<HlslToken>* deferredTokens); bool acceptFunctionDefinition(TFunctionDeclarator&, TIntermNode*& nodeList, TVector<HlslToken>* deferredTokens);

View File

@ -7085,7 +7085,7 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
return switchNode; return switchNode;
} }
// Track levels of class/struct nesting with a prefix string using // Track levels of class/struct/namespace nesting with a prefix string using
// the type names separated by the scoping operator. E.g., two levels // the type names separated by the scoping operator. E.g., two levels
// would look like: // would look like:
// //
@ -7093,41 +7093,43 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
// //
// The string is empty when at normal global level. // The string is empty when at normal global level.
// //
void HlslParseContext::pushThis(const TString& typeName) void HlslParseContext::pushNamespace(const TString& typeName)
{ {
// make new type prefix // make new type prefix
TString newPrefix; TString newPrefix;
if (currentTypePrefix.size() > 0) { if (currentTypePrefix.size() > 0) {
newPrefix = currentTypePrefix.back(); newPrefix = currentTypePrefix.back();
newPrefix.append("::"); newPrefix.append(scopeMangler);
} }
newPrefix.append(typeName); newPrefix.append(typeName);
currentTypePrefix.push_back(newPrefix); currentTypePrefix.push_back(newPrefix);
} }
// Opposite of pushThis(), see above // Opposite of pushNamespace(), see above
void HlslParseContext::popThis() void HlslParseContext::popNamespace()
{ {
currentTypePrefix.pop_back(); currentTypePrefix.pop_back();
} }
// Use the class/struct nesting string to create a global name for // Use the class/struct nesting string to create a global name for
// a member of a class/struct. Static members use "::" for the final // a member of a class/struct.
// step, while non-static members use ".". TString* HlslParseContext::getFullNamespaceName(const TString& localName) const
TString* HlslParseContext::getFullMemberFunctionName(const TString& memberName, bool isStatic) const
{ {
TString* name = NewPoolTString(""); TString* name = NewPoolTString("");
if (currentTypePrefix.size() > 0) if (currentTypePrefix.size() > 0)
name->append(currentTypePrefix.back()); name->append(currentTypePrefix.back());
if (isStatic) name->append(scopeMangler);
name->append("::"); name->append(localName);
else
name->append(".");
name->append(memberName);
return name; return name;
} }
// Helper function to add the namespace scope mangling syntax to a string.
void HlslParseContext::addScopeMangler(TString& name)
{
name.append(scopeMangler);
}
// Potentially rename shader entry point function // Potentially rename shader entry point function
void HlslParseContext::renameShaderFunction(TString*& name) const void HlslParseContext::renameShaderFunction(TString*& name) const
{ {

View File

@ -160,9 +160,10 @@ public:
void pushScope() { symbolTable.push(); } void pushScope() { symbolTable.push(); }
void popScope() { symbolTable.pop(0); } void popScope() { symbolTable.pop(0); }
void pushThis(const TString& name); void pushNamespace(const TString& name);
void popThis(); void popNamespace();
TString* getFullMemberFunctionName(const TString& name, bool isStatic) const; TString* getFullNamespaceName(const TString& localName) const;
void addScopeMangler(TString&);
void pushSwitchSequence(TIntermSequence* sequence) { switchSequenceStack.push_back(sequence); } void pushSwitchSequence(TIntermSequence* sequence) { switchSequenceStack.push_back(sequence); }
void popSwitchSequence() { switchSequenceStack.pop_back(); } void popSwitchSequence() { switchSequenceStack.pop_back(); }