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.
//