postDeclQualifier.clear();
bool postDeclsFound = acceptPostDecls(postDeclQualifier);
- // LEFT_BRACE
+ // LEFT_BRACE, or
// struct_type IDENTIFIER
if (! acceptTokenClass(EHTokLeftBrace)) {
if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
}
}
+
// struct_declaration_list
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");
return false;
}
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
// | IDENTIFIER array_specifier post_decls
// | 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();
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 {
// success on seeing the RIGHT_BRACE coming up
if (peekTokenClass(EHTokRightBrace))
if (!declarator_list) {
declarators.resize(declarators.size() + 1);
// request a token stream for deferred processing
- TVector<HlslToken>* deferredTokens = new TVector<HlslToken>;
- functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, typeName, memberType,
- *idToken.string, declarators.back(),
- deferredTokens);
- memberBodies.push_back(deferredTokens);
+ functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
+ declarators.back());
if (functionDefinitionAccepted)
break;
}
} 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;
}
//
// Expects type to have EvqGlobal for a static member and
// EvqTemporary for non-static member.
-bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TString& typeName,
- const TType& type, const TString& memberName,
- TFunctionDeclarator& declarator, TVector<HlslToken>* deferredTokens)
+bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
+ TFunctionDeclarator& declarator)
{
- // watch early returns...
- parseContext.pushThis(typeName);
bool accepted = false;
- TString* functionName = parseContext.getFullMemberFunctionName(memberName, type.getQualifier().storage == EvqGlobal);
+ TString* functionName = parseContext.getFullNamespaceName(memberName);
declarator.function = new TFunction(functionName, type);
// function_parameters
}
declarator.loc = token.loc;
- accepted = acceptFunctionDefinition(declarator, nodeList, deferredTokens);
+ declarator.body = new TVector<HlslToken>;
+ accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
}
} else
expected("function parameter list");
- parseContext.popThis();
return accepted;
}
functionName = callToken.string;
else {
functionName = NewPoolTString("");
- if (baseObject != nullptr) {
- functionName->append(baseObject->getType().getTypeName().c_str());
- functionName->append(".");
- } else if (baseType != nullptr) {
- functionName->append(baseType->getType().getTypeName());
- functionName->append("::");
- }
+ functionName->append(baseType->getType().getTypeName());
+ parseContext.addScopeMangler(*functionName);
functionName->append(*callToken.string);
}
TFunction* function = new TFunction(functionName, TType(EbtVoid));
// arguments
- // Non-static member functions have an implicit first argument of the base object.
TIntermTyped* arguments = nullptr;
if (baseObject != nullptr)
parseContext.handleFunctionArgument(function, arguments, baseObject);
bool acceptTextureType(TType&);
bool acceptStructBufferType(TType&);
bool acceptStruct(TType&, TIntermNode*& nodeList);
- bool acceptStructDeclarationList(TTypeList*&, TIntermNode*& nodeList, const TString& typeName);
- bool acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TString& typeName,
- const TType&, const TString& memberName, TFunctionDeclarator&,
- TVector<HlslToken>* deferredTokens);
+ bool acceptStructDeclarationList(TTypeList*&, TIntermNode*& nodeList, const TString& typeName,
+ TVector<TFunctionDeclarator>&);
+ bool acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType&, const TString& memberName,
+ TFunctionDeclarator&);
bool acceptFunctionParameters(TFunction&);
bool acceptParameterDeclaration(TFunction&);
bool acceptFunctionDefinition(TFunctionDeclarator&, TIntermNode*& nodeList, TVector<HlslToken>* deferredTokens);
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
// would look like:
//
//
// 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
TString newPrefix;
if (currentTypePrefix.size() > 0) {
newPrefix = currentTypePrefix.back();
- newPrefix.append("::");
+ newPrefix.append(scopeMangler);
}
newPrefix.append(typeName);
currentTypePrefix.push_back(newPrefix);
}
-// Opposite of pushThis(), see above
-void HlslParseContext::popThis()
+// Opposite of pushNamespace(), see above
+void HlslParseContext::popNamespace()
{
currentTypePrefix.pop_back();
}
// Use the class/struct nesting string to create a global name for
-// a member of a class/struct. Static members use "::" for the final
-// step, while non-static members use ".".
-TString* HlslParseContext::getFullMemberFunctionName(const TString& memberName, bool isStatic) const
+// a member of a class/struct.
+TString* HlslParseContext::getFullNamespaceName(const TString& localName) const
{
TString* name = NewPoolTString("");
if (currentTypePrefix.size() > 0)
name->append(currentTypePrefix.back());
- if (isStatic)
- name->append("::");
- else
- name->append(".");
- name->append(memberName);
+ name->append(scopeMangler);
+ name->append(localName);
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
void HlslParseContext::renameShaderFunction(TString*& name) const
{