diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index 5dc46ee5..2418b21f 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // 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). -#define GLSLANG_REVISION "Overload400-PrecQual.1885" +#define GLSLANG_REVISION "Overload400-PrecQual.1886" #define GLSLANG_DATE "08-Mar-2017" diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 01f9c122..4b4b0de0 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -2489,6 +2489,7 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) // | function_call // | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET // | postfix_expression DOT IDENTIFIER +// | postfix_expression DOT IDENTIFIER arguments // | postfix_expression INC_OP // | postfix_expression DEC_OP // @@ -2570,23 +2571,29 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) case EOpIndexDirectStruct: { // DOT IDENTIFIER - // includes swizzles and struct members + // includes swizzles, member variables, and member functions HlslToken field; if (! acceptIdentifier(field)) { expected("swizzle or member"); return false; } - TIntermTyped* base = node; // preserve for method function calls - node = parseContext.handleDotDereference(field.loc, node, *field.string); + if (peekTokenClass(EHTokLeftParen)) { + // member function + TIntermTyped* thisNode = node; + node = parseContext.handleBuiltInMethod(field.loc, node, *field.string); + if (node == nullptr) { + expected("built-in method"); + return false; + } - // In the event of a method node, we look for an open paren and accept the function call. - if (node != nullptr && node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) { - if (! acceptFunctionCall(field, node, base)) { + // arguments + if (! acceptFunctionCall(field, node, thisNode)) { expected("function parameters"); return false; } - } + } else + node = parseContext.handleDotDereference(field.loc, node, *field.string); break; } diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 0c63871f..eace4258 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -862,47 +862,18 @@ bool HlslParseContext::isStructBufferMethod(const TString& name) const } // -// Handle seeing a base.field dereference in the grammar. +// Handle seeing a base.field dereference in the grammar, where 'field' is a +// swizzle or member variable. // TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TIntermTyped* base, const TString& field) { variableCheck(base); - // - // methods can't be resolved until we later see the function-calling syntax. - // Save away the name in the AST for now. Processing is completed in - // handleLengthMethod(), etc. - // - if (field == "length") { - return intermediate.addMethod(base, TType(EbtInt), &field, loc); - } else if (isSamplerMethod(field) && base->getType().getBasicType() == EbtSampler) { - // If it's not a method on a sampler object, we fall through to let other objects have a go. - const TSampler& sampler = base->getType().getSampler(); - if (! sampler.isPureSampler()) { - const int vecSize = sampler.isShadow() ? 1 : 4; // TODO: handle arbitrary sample return sizes - return intermediate.addMethod(base, TType(sampler.type, EvqTemporary, vecSize), &field, loc); - } - } else if (isStructBufferType(base->getType())) { - TType retType(base->getType(), 0); - return intermediate.addMethod(base, retType, &field, loc); - } else if (field == "Append" || - field == "RestartStrip") { - // We cannot check the type here: it may be sanitized if we're not compiling a geometry shader, but - // the code is around in the shader source. - return intermediate.addMethod(base, TType(EbtVoid), &field, loc); - } - - // It's not .length() if we get to here. - if (base->isArray()) { error(loc, "cannot apply to an array:", ".", field.c_str()); - return base; } - // It's neither an array nor .length() if we get here, - // leaving swizzles and struct/block dereferences. - TIntermTyped* result = base; if (base->isVector() || base->isScalar()) { TSwizzleSelectors selectors; @@ -1011,6 +982,43 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt return result; } +// +// Handle seeing a base.field dereference in the grammar, where 'field' is a +// built-in method. +// +// Return nullptr if 'field' is not a built-in method. +// +TIntermTyped* HlslParseContext::handleBuiltInMethod(const TSourceLoc& loc, TIntermTyped* base, const TString& field) +{ + variableCheck(base); + + // + // methods can't be resolved until we later see the function-calling syntax. + // Save away the name in the AST for now. Processing is completed in + // handleLengthMethod(), etc. + // + if (field == "length") { + return intermediate.addMethod(base, TType(EbtInt), &field, loc); + } else if (isSamplerMethod(field) && base->getType().getBasicType() == EbtSampler) { + // If it's not a method on a sampler object, we fall through to let other objects have a go. + const TSampler& sampler = base->getType().getSampler(); + if (! sampler.isPureSampler()) { + const int vecSize = sampler.isShadow() ? 1 : 4; // TODO: handle arbitrary sample return sizes + return intermediate.addMethod(base, TType(sampler.type, EvqTemporary, vecSize), &field, loc); + } + } else if (isStructBufferType(base->getType())) { + TType retType(base->getType(), 0); + return intermediate.addMethod(base, retType, &field, loc); + } else if (field == "Append" || + field == "RestartStrip") { + // We cannot check the type here: it may be sanitized if we're not compiling a geometry shader, but + // the code is around in the shader source. + return intermediate.addMethod(base, TType(EbtVoid), &field, loc); + } + + return nullptr; +} + // Split the type of the given node into two structs: // 1. interstage IO // 2. everything else diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 5b585dcd..ecac1b31 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -70,6 +70,7 @@ public: TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode); TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field); + TIntermTyped* handleBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field); void assignLocations(TVariable& variable); TFunction& handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);