Moved function creation code from glslang.y to TParseContext. Added TParseContext::addFunctionCallOrMethod() to move function creation functionality out of glslang.y. Change-Id: Ia23e8c2490ba9d2bb1fcd00a1ef06eab5cf60b80 Reviewed-on: https://swiftshader-review.googlesource.com/3640 Tested-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp index a14fd3a..899bac2 100644 --- a/src/OpenGL/compiler/ParseHelper.cpp +++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -3249,6 +3249,160 @@ return intermediate.addBranch(op, returnValue, loc); } +TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *paramNode, TIntermNode *thisNode, const TSourceLoc &loc, bool *fatalError) +{ + *fatalError = false; + TOperator op = fnCall->getBuiltInOp(); + TIntermTyped *callNode = nullptr; + + if(thisNode != nullptr) + { + ConstantUnion *unionArray = new ConstantUnion[1]; + int arraySize = 0; + TIntermTyped *typedThis = thisNode->getAsTyped(); + if(fnCall->getName() != "length") + { + error(loc, "invalid method", fnCall->getName().c_str()); + recover(); + } + else if(paramNode != nullptr) + { + error(loc, "method takes no parameters", "length"); + recover(); + } + else if(typedThis == nullptr || !typedThis->isArray()) + { + error(loc, "length can only be called on arrays", "length"); + recover(); + } + else + { + arraySize = typedThis->getArraySize(); + if(typedThis->getAsSymbolNode() == nullptr) + { + // This code path can be hit with expressions like these: + // (a = b).length() + // (func()).length() + // (int[3](0, 1, 2)).length() + // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid expression. + // It allows "An array name with the length method applied" in contrast to GLSL 4.4 spec section 5.9 + // which allows "An array, vector or matrix expression with the length method applied". + error(loc, "length can only be called on array names, not on array expressions", "length"); + recover(); + } + } + unionArray->setIConst(arraySize); + callNode = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), loc); + } + else if(op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if(!constructorErrorCheck(loc, paramNode, *fnCall, op, &type)) + { + // + // It's a constructor, of type 'type'. + // + callNode = addConstructor(paramNode, &type, op, fnCall, loc); + } + + if(callNode == nullptr) + { + recover(); + callNode = intermediate.setAggregateOperator(nullptr, op, loc); + } + callNode->setType(type); + } + else + { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction *fnCandidate; + bool builtIn; + fnCandidate = findFunction(loc, fnCall, &builtIn); + if(fnCandidate) + { + // + // A declared function. + // + if(builtIn && !fnCandidate->getExtension().empty() && + extensionErrorCheck(loc, fnCandidate->getExtension())) + { + recover(); + } + op = fnCandidate->getBuiltInOp(); + if(builtIn && op != EOpNull) + { + // + // A function call mapped to a built-in operation. + // + if(fnCandidate->getParamCount() == 1) + { + // + // Treat it like a built-in unary operator. + // + callNode = createUnaryMath(op, paramNode->getAsTyped(), loc, &fnCandidate->getReturnType()); + if(callNode == nullptr) + { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " + << static_cast<TIntermTyped*>(paramNode)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + error(paramNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + *fatalError = true; + return nullptr; + } + } + else + { + TIntermAggregate *aggregate = intermediate.setAggregateOperator(paramNode, op, loc); + aggregate->setType(fnCandidate->getReturnType()); + + // Some built-in functions have out parameters too. + functionCallLValueErrorCheck(fnCandidate, aggregate); + + callNode = aggregate; + } + } + else + { + // This is a real function call + + TIntermAggregate *aggregate = intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc); + aggregate->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if(!builtIn) + aggregate->setUserDefined(); + aggregate->setName(fnCandidate->getMangledName()); + + callNode = aggregate; + + functionCallLValueErrorCheck(fnCandidate, aggregate); + } + callNode->setType(fnCandidate->getReturnType()); + } + else + { + // error message was put out by findFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConstExpr), loc); + recover(); + } + } + delete fnCall; + return callNode; +} + // // Parse an array of strings using yyparse. //