Move the complex pieces of C++ code from glslang.y to ParseHelper.cpp. Updated some tests.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@22846 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-08-27 05:57:15 +00:00
parent d46b31fdc5
commit 23bdb29eac
6 changed files with 557 additions and 464 deletions

View File

@ -4,6 +4,46 @@ ERROR: 0:7: '' : vertex input cannot be further qualified
ERROR: 0:11: '' : can only have one interpolation qualifier (flat, smooth, noperspective)
ERROR: 0:12: '' : can only have one auxiliary qualifier (centroid, patch, and sample)
ERROR: 0:13: 'uniform' : too many storage qualifiers
ERROR: 5 compilation errors. No code generated.
ERROR: 0:21: 'j' : undeclared identifier
ERROR: 0:21: '=' : cannot convert from 'float' to 'int'
ERROR: 0:22: 'k' : undeclared identifier
ERROR: 0:22: '=' : cannot convert from 'float' to 'int'
ERROR: 0:23: 'j' : undeclared identifier
ERROR: 0:23: '=' : cannot convert from 'float' to 'int'
ERROR: 0:27: 'jj' : undeclared identifier
ERROR: 0:27: '=' : cannot convert from 'float' to 'int'
ERROR: 13 compilation errors. No code generated.
ERROR: node is still EOpNull!
0:15 Function Definition: main( (void)
0:15 Function Parameters:
0:? Sequence
0:18 Test condition and select (void)
0:18 Condition
0:18 Compare Equal (bool)
0:18 'i' (int)
0:18 3 (const int)
0:18 true case
0:19 Sequence
0:19 move second child to first child (int)
0:19 'j' (int)
0:19 'i' (int)
0:25 Loop with condition tested first
0:25 Loop Condition
0:25 true (const bool)
0:25 No loop body
0:30 Function Definition: bar(vf4; (void)
0:30 Function Parameters:
0:30 'v' (in 4-component vector of float)
0:? Linker Objects
0:? 'v2' (smooth out 2-component vector of float)
0:? 'badorder' (in 4-component vector of float)
0:? 'badorder2' (invariant smooth out 4-component vector of float)
0:? 'badorder4' (centroid in 4-component vector of float)
0:? 'badorder3' (flat out 4-component vector of float)
0:? 'rep' (smooth flat out 4-component vector of float)
0:? 'rep2' (centroid smooth sample out 4-component vector of float)
0:? 'rep3' (in 4-component vector of float)
0:? 'gl_VertexID' (gl_VertexId int)
0:? 'gl_InstanceID' (gl_InstanceId int)

View File

@ -22,7 +22,11 @@ ERROR: node is still EOpNull!
0:21 'm23' (2X3 matrix of float)
0:21 'm32' (uniform 3X2 matrix of float)
0:21 'v3' (in 3-component vector of float)
0:21 'm24' (float)
0:21 direct index (float)
0:21 direct index (4-component vector of float)
0:21 'm24' (2X4 matrix of float)
0:21 2 (const int)
0:21 4 (const int)
0:? Linker Objects
0:? 'v3' (in 3-component vector of float)
0:? 'm32' (uniform 3X2 matrix of float)

View File

@ -7,16 +7,16 @@ uniform mat3x2 m32;
const mat2x4 m24 = mat2x4(1.0, 2.0,
3.0, 4.0,
3.0, 4.0,
3.0, 4.0, 5.0);
3.0, 4.0, 5.0); // ERROR, too many arguments
void main()
{
mat2x3 m23;
vec3 a, b;
a = v3 * m23;
b = m32 * v3;
m23.xy;
a = v3 * m23; // ERROR, type mismatch
b = m32 * v3; // ERROR, type mismatch
m23.xy; // ERROR, can't use .
gl_Position = vec4(m23 * m32 * v3, m24[2][4]);
gl_Position = vec4(m23 * m32 * v3, m24[2][4]); // ERROR, 2 and 4 are out of range
}

View File

@ -446,6 +446,9 @@ void C_DECL TParseContext::warn(TSourceLoc loc, const char *szReason, const char
va_end(marker);
}
//
// Handle seeing a variable identifier in the grammar.
//
TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TString* string)
{
TIntermTyped* node = 0;
@ -485,6 +488,495 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
return node;
}
//
// Handle seeing a base[index] dereference in the grammar.
//
TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyped* base, TIntermTyped* index)
{
TIntermTyped* result = 0;
variableCheck(base);
if (! base->isArray() && ! base->isMatrix() && ! base->isVector()) {
if (base->getAsSymbolNode())
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
else
error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
} else if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) {
if (base->isArray()) {
// constant folding for arrays
result = addConstArrayNode(index->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), base, loc);
} else if (base->isVector()) {
// constant folding for vectors
TVectorFields fields;
fields.num = 1;
fields.offsets[0] = index->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array
result = addConstVectorNode(fields, base, loc);
} else if (base->isMatrix()) {
// constant folding for matrices
result = addConstMatrixNode(index->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), base, loc);
}
} else {
if (index->getQualifier().storage == EvqConst) {
int indexValue = index->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
if (! base->isArray() && (base->isVector() && base->getType().getVectorSize() <= indexValue ||
base->isMatrix() && base->getType().getMatrixCols() <= indexValue))
error(loc, "", "[", "index out of range '%d'", index->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
if (base->isArray()) {
if (base->getType().getArraySize() == 0) {
if (base->getType().getMaxArraySize() <= index->getAsConstantUnion()->getUnionArrayPointer()->getIConst())
arraySetMaxSize(base->getAsSymbolNode(), base->getTypePointer(), index->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, loc);
else
arraySetMaxSize(base->getAsSymbolNode(), base->getTypePointer(), 0, false, loc);
} else if ( index->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= base->getType().getArraySize() ||
index->getAsConstantUnion()->getUnionArrayPointer()->getIConst() < 0)
error(loc, "", "[", "array index out of range '%d'", index->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
}
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
} else {
if (base->isArray() && base->getType().getArraySize() == 0)
error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
if (base->getBasicType() == EbtBlock)
requireProfile(base->getLoc(), static_cast<EProfileMask>(~EEsProfileMask), "variable indexing block array");
if (base->getBasicType() == EbtSampler) {
requireProfile(base->getLoc(), static_cast<EProfileMask>(ECoreProfileMask | ECompatibilityProfileMask), "variable indexing sampler array");
profileRequires(base->getLoc(), ECoreProfile, 400, 0, "variable indexing sampler array");
}
result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
}
}
if (result == 0) {
constUnion *unionArray = new constUnion[1];
unionArray->setDConst(0.0);
result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc);
} else {
TType newType(base->getType());
if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst)
newType.getQualifier().storage = EvqConst;
newType.dereference();
result->setType(newType);
}
return result;
}
//
// Handle seeing a base.field dereference in the grammar.
//
TIntermTyped* TParseContext::handleDotDereference(TSourceLoc loc, TIntermTyped* base, TString& field)
{
TIntermTyped* result = base;
variableCheck(base);
if (base->isArray()) {
//
// It can only be a method (e.g., length), which can't be resolved until
// we later see the function calling syntax. Save away the name for now.
//
if (field == "length") {
profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", ".length");
result = intermediate.addMethod(base, TType(EbtInt), &field, loc);
} else
error(loc, "only the length method is supported for array", field.c_str(), "");
} else if (base->isVector()) {
TVectorFields fields;
if (! parseVectorFields(loc, field, base->getVectorSize(), fields)) {
fields.num = 1;
fields.offsets[0] = 0;
}
if (base->getType().getQualifier().storage == EvqConst) { // constant folding for vector fields
result = addConstVectorNode(fields, base, loc);
if (result == 0)
result = base;
else
result->setType(TType(base->getBasicType(), EvqConst, (int) (field).size()));
} else {
if (fields.num == 1) {
constUnion *unionArray = new constUnion[1];
unionArray->setIConst(fields.offsets[0]);
TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc);
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision));
} else {
TString vectorString = field;
TIntermTyped* index = intermediate.addSwizzle(fields, loc);
result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int) vectorString.size()));
}
}
} else if (base->isMatrix())
error(loc, "field selection not allowed on matrix", ".", "");
else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
bool fieldFound = false;
TTypeList* fields = base->getType().getStruct();
if (fields == 0)
error(loc, "structure has no fields", "Internal Error", "");
else {
unsigned int i;
for (i = 0; i < fields->size(); ++i) {
if ((*fields)[i].type->getFieldName() == field) {
fieldFound = true;
break;
}
}
if (fieldFound) {
if (base->getType().getQualifier().storage == EvqConst) {
result = addConstStruct(field, base, loc);
if (result == 0)
result = base;
else {
result->setType(*(*fields)[i].type);
// change the qualifier of the return type, not of the structure field
// as the structure definition is shared between various structures.
result->getTypePointer()->getQualifier().storage = EvqConst;
}
} else {
constUnion *unionArray = new constUnion[1];
unionArray->setIConst(i);
TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc);
result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
result->setType(*(*fields)[i].type);
}
} else
error(loc, " no such field in structure", field.c_str(), "");
}
} else
error(loc, " dot operator requires structure, array, vector, or matrix on left hand side", field.c_str(), "");
return result;
}
//
// Handle seeing a function prototype in the grammar.
//
TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFunction& function)
{
TSymbol* symbol = symbolTable.find(function.getMangledName());
TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
if (! prevDec)
error(loc, "can't find function name", function.getName().c_str(), "");
//
// Note: 'prevDec' could be 'function' if this is the first time we've seen function
// as it would have just been put in the symbol table. Otherwise, we're looking up
// an earlier occurance.
//
if (prevDec && prevDec->isDefined()) {
//
// Then this function already has a body.
//
error(loc, "function already has a body", function.getName().c_str(), "");
}
if (prevDec) {
prevDec->setDefined();
//
// Remember the return type for later checking for RETURN statements.
//
currentFunctionType = &(prevDec->getReturnType());
} else
currentFunctionType = new TType(EbtVoid);
functionReturnsValue = false;
//
// Raise error message if main function takes any parameters or return anything other than void
//
if (function.getName() == "main") {
if (function.getParamCount() > 0)
error(loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
if (function.getReturnType().getBasicType() != EbtVoid)
error(loc, "", function.getReturnType().getCompleteTypeString().c_str(), "main function cannot return a value");
}
//
// New symbol table scope for body of function plus its arguments
//
symbolTable.push();
//
// Insert parameters into the symbol table.
// If the parameter has no name, it's not an error, just don't insert it
// (could be used for unused args).
//
// Also, accumulate the list of parameters into the HIL, so lower level code
// knows where to find parameters.
//
TIntermAggregate* paramNodes = new TIntermAggregate;
for (int i = 0; i < function.getParamCount(); i++) {
TParameter& param = function[i];
if (param.name != 0) {
TVariable *variable = new TVariable(param.name, *param.type);
//
// Insert the parameters with name in the symbol table.
//
if (! symbolTable.insert(*variable)) {
error(loc, "redefinition", variable->getName().c_str(), "");
delete variable;
}
//
// Transfer ownership of name pointer to symbol table.
//
param.name = 0;
//
// Add the parameter to the HIL
//
paramNodes = intermediate.growAggregate(paramNodes,
intermediate.addSymbol(variable->getUniqueId(),
variable->getName(),
variable->getType(), loc),
loc);
} else
paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(0, "", *param.type, loc), loc);
}
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
loopNestingLevel = 0;
return paramNodes;
}
//
// Handle seeing a function call in the grammar.
//
TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode, TIntermAggregate* intermAggregate)
{
TIntermTyped* result = 0;
TOperator op = fnCall->getBuiltInOp();
if (op == EOpArrayLength) {
if (fnCall->getParamCount() > 0)
error(loc, "method does not accept any arguments", fnCall->getName().c_str(), "");
int length;
if (intermNode->getAsTyped() == 0 || ! intermNode->getAsTyped()->getType().isArray() || intermNode->getAsTyped()->getType().getArraySize() == 0) {
error(loc, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");
length = 1;
} else
length = intermNode->getAsTyped()->getType().getArraySize();
constUnion *unionArray = new constUnion[1];
unionArray->setIConst(length);
result = intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), 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); // use this to get the type back
if (constructorError(loc, intermNode, *fnCall, op, type)) {
result = 0;
} else {
//
// It's a constructor, of type 'type'.
//
result = addConstructor(intermNode, type, op, fnCall, loc);
if (result == 0)
error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), "");
}
if (result == 0)
result = intermediate.setAggregateOperator(0, op, type, loc);
} 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. But, it might still map to a built-in
// operation.
//
op = fnCandidate->getBuiltInOp();
if (builtIn && op != EOpNull) {
// A function call mapped to a built-in operation.
result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getReturnType());
if (result == 0) {
error(intermNode->getLoc(), " wrong operand type", "Internal Error",
"built in unary operator function. Type: %s",
static_cast<TIntermTyped*>(intermNode)->getCompleteString().c_str());
return 0;
}
} else {
// This is a real function call
result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getReturnType(), loc);
// 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)
result->getAsAggregate()->setUserDefined();
result->getAsAggregate()->setName(fnCandidate->getMangledName());
TStorageQualifier qual;
TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
qual = (*fnCandidate)[i].type->getQualifier().storage;
if (qual == EvqOut || qual == EvqInOut) {
if (lValueErrorCheck(result->getLoc(), "assign", result->getAsAggregate()->getSequence()[i]->getAsTyped()))
error(intermNode->getLoc(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
}
qualifierList.push_back(qual);
}
// built-in texturing functions get their return value precision from the precision of the sampler
if (builtIn && fnCandidate->getReturnType().getQualifier().precision == EpqNone &&
fnCandidate->getParamCount() > 0 && (*fnCandidate)[0].type->getBasicType() == EbtSampler)
result->getQualifier().precision = result->getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision;
}
} else {
// error message was put out by PaFindFunction()
// Put on a dummy node for error recovery
constUnion *unionArray = new constUnion[1];
unionArray->setDConst(0.0);
result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc);
}
}
return result;
}
//
// Handle seeing a built-in-type constructor call in the grammar.
//
TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, TPublicType& publicType)
{
if (publicType.arraySizes) {
profileRequires(loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed constructor");
profileRequires(loc, EEsProfile, 300, "GL_3DL_array_objects", "arrayed constructor");
}
publicType.qualifier.precision = EpqNone;
if (publicType.userDef) {
TString tempString = "";
TType type(publicType);
return new TFunction(&tempString, type, EOpConstructStruct);
}
TOperator op = EOpNull;
switch (publicType.basicType) {
case EbtFloat:
if (publicType.matrixCols) {
switch (publicType.matrixCols) {
case 2:
switch (publicType.matrixRows) {
case 2: op = EOpConstructMat2x2; break;
case 3: op = EOpConstructMat2x3; break;
case 4: op = EOpConstructMat2x4; break;
default: break; // some compilers want this
}
break;
case 3:
switch (publicType.matrixRows) {
case 2: op = EOpConstructMat3x2; break;
case 3: op = EOpConstructMat3x3; break;
case 4: op = EOpConstructMat3x4; break;
default: break; // some compilers want this
}
break;
case 4:
switch (publicType.matrixRows) {
case 2: op = EOpConstructMat4x2; break;
case 3: op = EOpConstructMat4x3; break;
case 4: op = EOpConstructMat4x4; break;
default: break; // some compilers want this
}
break;
default: break; // some compilers want this
}
} else {
switch(publicType.vectorSize) {
case 1: op = EOpConstructFloat; break;
case 2: op = EOpConstructVec2; break;
case 3: op = EOpConstructVec3; break;
case 4: op = EOpConstructVec4; break;
default: break; // some compilers want this
}
}
break;
case EbtDouble:
if (publicType.matrixCols) {
switch (publicType.matrixCols) {
case 2:
switch (publicType.matrixRows) {
case 2: op = EOpConstructDMat2x2; break;
case 3: op = EOpConstructDMat2x3; break;
case 4: op = EOpConstructDMat2x4; break;
default: break; // some compilers want this
}
break;
case 3:
switch (publicType.matrixRows) {
case 2: op = EOpConstructDMat3x2; break;
case 3: op = EOpConstructDMat3x3; break;
case 4: op = EOpConstructDMat3x4; break;
default: break; // some compilers want this
}
break;
case 4:
switch (publicType.matrixRows) {
case 2: op = EOpConstructDMat4x2; break;
case 3: op = EOpConstructDMat4x3; break;
case 4: op = EOpConstructDMat4x4; break;
default: break; // some compilers want this
}
break;
}
} else {
switch(publicType.vectorSize) {
case 1: op = EOpConstructDouble; break;
case 2: op = EOpConstructDVec2; break;
case 3: op = EOpConstructDVec3; break;
case 4: op = EOpConstructDVec4; break;
default: break; // some compilers want this
}
}
break;
case EbtInt:
switch(publicType.vectorSize) {
case 1: op = EOpConstructInt; break;
case 2: op = EOpConstructIVec2; break;
case 3: op = EOpConstructIVec3; break;
case 4: op = EOpConstructIVec4; break;
default: break; // some compilers want this
}
break;
case EbtUint:
switch(publicType.vectorSize) {
case 1: op = EOpConstructUint; break;
case 2: op = EOpConstructUVec2; break;
case 3: op = EOpConstructUVec3; break;
case 4: op = EOpConstructUVec4; break;
default: break; // some compilers want this
}
break;
case EbtBool:
switch(publicType.vectorSize) {
case 1: op = EOpConstructBool; break;
case 2: op = EOpConstructBVec2; break;
case 3: op = EOpConstructBVec3; break;
case 4: op = EOpConstructBVec4; break;
default: break; // some compilers want this
}
break;
default: break; // some compilers want this
}
if (op == EOpNull) {
error(loc, "cannot construct this type", TType::getBasicString(publicType.basicType), "");
publicType.basicType = EbtFloat;
op = EOpConstructFloat;
}
TString tempString = "";
TType type(publicType);
return new TFunction(&tempString, type, op);
}
//
// Same error message for all places assignments don't work.
//

View File

@ -122,6 +122,12 @@ public:
bool reservedErrorCheck(TSourceLoc, const TString& identifier);
TIntermTyped* handleVariable(TSourceLoc, TSymbol* symbol, TString* string);
TIntermTyped* handleBracketDereference(TSourceLoc, TIntermTyped* base, TIntermTyped* index);
TIntermTyped* handleDotDereference(TSourceLoc, TIntermTyped* base, TString& field);
TIntermAggregate* handleFunctionPrototype(TSourceLoc, TFunction&);
TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*, TIntermAggregate*);
TFunction* handleConstructorCall(TSourceLoc, TPublicType&);
bool parseVectorFields(TSourceLoc, const TString&, int vecSize, TVectorFields&);
void assignError(TSourceLoc, const char* op, TString left, TString right);
void unaryOpError(TSourceLoc, const char* op, TString operand);

View File

@ -260,157 +260,13 @@ postfix_expression
$$ = $1;
}
| postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
parseContext.variableCheck($1);
if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) {
if ($1->getAsSymbolNode())
parseContext.error($2.loc, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getName().c_str(), "");
else
parseContext.error($2.loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
}
if ($1->getType().getQualifier().storage == EvqConst && $3->getQualifier().storage == EvqConst) {
if ($1->isArray()) { // constant folding for arrays
$$ = parseContext.addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.loc);
} else if ($1->isVector()) { // constant folding for vectors
TVectorFields fields;
fields.num = 1;
fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array
$$ = parseContext.addConstVectorNode(fields, $1, $2.loc);
} else if ($1->isMatrix()) { // constant folding for matrices
$$ = parseContext.addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.loc);
}
} else {
if ($3->getQualifier().storage == EvqConst) {
int index = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
if (! $1->isArray() && ($1->isVector() && $1->getType().getVectorSize() <= index ||
$1->isMatrix() && $1->getType().getMatrixCols() <= index))
parseContext.error($2.loc, "", "[", "index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
else {
if ($1->isArray()) {
if ($1->getType().getArraySize() == 0) {
if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst())
parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.loc);
else
parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.loc);
} else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize() ||
$3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() < 0)
parseContext.error($2.loc, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
}
$$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, $3, $2.loc);
}
} else {
if ($1->isArray() && $1->getType().getArraySize() == 0)
parseContext.error($2.loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
if ($1->getBasicType() == EbtBlock)
parseContext.requireProfile($1->getLoc(), static_cast<EProfileMask>(~EEsProfileMask), "variable indexing block array");
if ($1->getBasicType() == EbtSampler) {
parseContext.requireProfile($1->getLoc(), static_cast<EProfileMask>(ECoreProfileMask | ECompatibilityProfileMask), "variable indexing sampler array");
parseContext.profileRequires($1->getLoc(), ECoreProfile, 400, 0, "variable indexing sampler array");
}
$$ = parseContext.intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.loc);
}
}
if ($$ == 0) {
constUnion *unionArray = new constUnion[1];
unionArray->setDConst(0.0);
$$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.loc);
} else {
TType newType($1->getType());
newType.dereference();
$$->setType(newType);
// TODO: functionality: does this drop const qualification for const[const] ?
}
$$ = parseContext.handleBracketDereference($2.loc, $1, $3);
}
| function_call {
$$ = $1;
}
| postfix_expression DOT FIELD_SELECTION {
parseContext.variableCheck($1);
if ($1->isArray()) {
//
// It can only be a method (e.g., length), which can't be resolved until
// we later see the function calling syntax. Save away the name for now.
//
if (*$3.string == "length") {
parseContext.profileRequires($3.loc, ENoProfile, 120, "GL_3DL_array_objects", ".length");
$$ = parseContext.intermediate.addMethod($1, TType(EbtInt), $3.string, $2.loc);
} else {
parseContext.error($3.loc, "only the length method is supported for array", $3.string->c_str(), "");
$$ = $1;
}
} else if ($1->isVector()) {
TVectorFields fields;
if (! parseContext.parseVectorFields($3.loc, *$3.string, $1->getVectorSize(), fields)) {
fields.num = 1;
fields.offsets[0] = 0;
}
if ($1->getType().getQualifier().storage == EvqConst) { // constant folding for vector fields
$$ = parseContext.addConstVectorNode(fields, $1, $3.loc);
if ($$ == 0)
$$ = $1;
else
$$->setType(TType($1->getBasicType(), EvqConst, (int) (*$3.string).size()));
} else {
if (fields.num == 1) {
constUnion *unionArray = new constUnion[1];
unionArray->setIConst(fields.offsets[0]);
TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.loc);
$$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.loc);
$$->setType(TType($1->getBasicType(), EvqTemporary, $1->getType().getQualifier().precision));
} else {
TString vectorString = *$3.string;
TIntermTyped* index = parseContext.intermediate.addSwizzle(fields, $3.loc);
$$ = parseContext.intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.loc);
$$->setType(TType($1->getBasicType(), EvqTemporary, $1->getType().getQualifier().precision, (int) vectorString.size()));
}
}
} else if ($1->isMatrix())
parseContext.error($2.loc, "field selection not allowed on matrix", ".", "");
else if ($1->getBasicType() == EbtStruct || $1->getBasicType() == EbtBlock) {
bool fieldFound = false;
TTypeList* fields = $1->getType().getStruct();
if (fields == 0) {
parseContext.error($2.loc, "structure has no fields", "Internal Error", "");
$$ = $1;
} else {
unsigned int i;
for (i = 0; i < fields->size(); ++i) {
if ((*fields)[i].type->getFieldName() == *$3.string) {
fieldFound = true;
break;
}
}
if (fieldFound) {
if ($1->getType().getQualifier().storage == EvqConst) {
$$ = parseContext.addConstStruct(*$3.string, $1, $2.loc);
if ($$ == 0)
$$ = $1;
else {
$$->setType(*(*fields)[i].type);
// change the qualifier of the return type, not of the structure field
// as the structure definition is shared between various structures.
$$->getTypePointer()->getQualifier().storage = EvqConst;
}
} else {
constUnion *unionArray = new constUnion[1];
unionArray->setIConst(i);
TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.loc);
$$ = parseContext.intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.loc);
$$->setType(*(*fields)[i].type);
}
} else {
parseContext.error($2.loc, " no such field in structure", $3.string->c_str(), "");
$$ = $1;
}
}
} else {
parseContext.error($2.loc, " dot operator requires structure, array, vector, or matrix on left hand side", $3.string->c_str(), "");
$$ = $1;
}
// don't delete $3.string, it's from the pool
$$ = parseContext.handleDotDereference($3.loc, $1, *$3.string);
}
| postfix_expression INC_OP {
parseContext.variableCheck($1);
@ -441,99 +297,10 @@ integer_expression
function_call
: function_call_or_method {
TFunction* fnCall = $1.function;
TOperator op = fnCall->getBuiltInOp();
if (op == EOpArrayLength) {
if (fnCall->getParamCount() > 0)
parseContext.error($1.loc, "method does not accept any arguments", fnCall->getName().c_str(), "");
int length;
if ($1.intermNode->getAsTyped() == 0 || ! $1.intermNode->getAsTyped()->getType().isArray() || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) {
parseContext.error($1.loc, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");
length = 1;
} else
length = $1.intermNode->getAsTyped()->getType().getArraySize();
constUnion *unionArray = new constUnion[1];
unionArray->setIConst(length);
$$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.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); // use this to get the type back
if (parseContext.constructorError($1.loc, $1.intermNode, *fnCall, op, type)) {
$$ = 0;
} else {
//
// It's a constructor, of type 'type'.
//
$$ = parseContext.addConstructor($1.intermNode, type, op, fnCall, $1.loc);
if ($$ == 0)
parseContext.error($1.loc, "cannot construct with these arguments", type.getCompleteString().c_str(), "");
}
if ($$ == 0)
$$ = parseContext.intermediate.setAggregateOperator(0, op, type, $1.loc);
} else {
//
// Not a constructor. Find it in the symbol table.
//
const TFunction* fnCandidate;
bool builtIn;
fnCandidate = parseContext.findFunction($1.loc, fnCall, &builtIn);
if (fnCandidate) {
//
// A declared function. But, it might still map to a built-in
// operation.
//
op = fnCandidate->getBuiltInOp();
if (builtIn && op != EOpNull) {
// A function call mapped to a built-in operation.
$$ = parseContext.intermediate.addBuiltInFunctionCall($1.loc, op, fnCandidate->getParamCount() == 1, $1.intermNode, fnCandidate->getReturnType());
if ($$ == 0) {
parseContext.error($1.intermNode->getLoc(), " wrong operand type", "Internal Error",
"built in unary operator function. Type: %s",
static_cast<TIntermTyped*>($1.intermNode)->getCompleteString().c_str());
YYERROR;
}
} else {
// This is a real function call
$$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, fnCandidate->getReturnType(), $1.loc);
// 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)
$$->getAsAggregate()->setUserDefined();
$$->getAsAggregate()->setName(fnCandidate->getMangledName());
TStorageQualifier qual;
TQualifierList& qualifierList = $$->getAsAggregate()->getQualifierList();
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
qual = (*fnCandidate)[i].type->getQualifier().storage;
if (qual == EvqOut || qual == EvqInOut) {
if (parseContext.lValueErrorCheck($$->getLoc(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped()))
parseContext.error($1.intermNode->getLoc(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
}
qualifierList.push_back(qual);
}
// built-in texturing functions get their return value precision from the precision of the sampler
if (builtIn && fnCandidate->getReturnType().getQualifier().precision == EpqNone &&
fnCandidate->getParamCount() > 0 && (*fnCandidate)[0].type->getBasicType() == EbtSampler)
$$->getQualifier().precision = $$->getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision;
}
} else {
// error message was put out by PaFindFunction()
// Put on a dummy node for error recovery
constUnion *unionArray = new constUnion[1];
unionArray->setDConst(0.0);
$$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.loc);
}
}
delete fnCall;
$$ = parseContext.handleFunctionCall($1.loc, $1.function, $1.intermNode, $1.intermAggregate);
if ($$ == 0)
YYERROR;
delete $1.function;
}
;
@ -588,142 +355,9 @@ function_call_header
function_identifier
: type_specifier {
//
// Constructor
//
$$.function = 0;
$$.intermNode = 0;
if ($1.arraySizes) {
parseContext.profileRequires($1.loc, ENoProfile, 120, "GL_3DL_array_objects", "arrayed constructor");
parseContext.profileRequires($1.loc, EEsProfile, 300, "GL_3DL_array_objects", "arrayed constructor");
}
$1.qualifier.precision = EpqNone;
if ($1.userDef) {
TString tempString = "";
TType type($1);
TFunction *function = new TFunction(&tempString, type, EOpConstructStruct);
$$.function = function;
} else {
TOperator op = EOpNull;
switch ($1.basicType) {
case EbtFloat:
if ($1.matrixCols) {
switch ($1.matrixCols) {
case 2:
switch ($1.matrixRows) {
case 2: op = EOpConstructMat2x2; break;
case 3: op = EOpConstructMat2x3; break;
case 4: op = EOpConstructMat2x4; break;
default: break; // some compilers want this
}
break;
case 3:
switch ($1.matrixRows) {
case 2: op = EOpConstructMat3x2; break;
case 3: op = EOpConstructMat3x3; break;
case 4: op = EOpConstructMat3x4; break;
default: break; // some compilers want this
}
break;
case 4:
switch ($1.matrixRows) {
case 2: op = EOpConstructMat4x2; break;
case 3: op = EOpConstructMat4x3; break;
case 4: op = EOpConstructMat4x4; break;
default: break; // some compilers want this
}
break;
default: break; // some compilers want this
}
} else {
switch($1.vectorSize) {
case 1: op = EOpConstructFloat; break;
case 2: op = EOpConstructVec2; break;
case 3: op = EOpConstructVec3; break;
case 4: op = EOpConstructVec4; break;
default: break; // some compilers want this
}
}
break;
case EbtDouble:
if ($1.matrixCols) {
switch ($1.matrixCols) {
case 2:
switch ($1.matrixRows) {
case 2: op = EOpConstructDMat2x2; break;
case 3: op = EOpConstructDMat2x3; break;
case 4: op = EOpConstructDMat2x4; break;
default: break; // some compilers want this
}
break;
case 3:
switch ($1.matrixRows) {
case 2: op = EOpConstructDMat3x2; break;
case 3: op = EOpConstructDMat3x3; break;
case 4: op = EOpConstructDMat3x4; break;
default: break; // some compilers want this
}
break;
case 4:
switch ($1.matrixRows) {
case 2: op = EOpConstructDMat4x2; break;
case 3: op = EOpConstructDMat4x3; break;
case 4: op = EOpConstructDMat4x4; break;
default: break; // some compilers want this
}
break;
}
} else {
switch($1.vectorSize) {
case 1: op = EOpConstructDouble; break;
case 2: op = EOpConstructDVec2; break;
case 3: op = EOpConstructDVec3; break;
case 4: op = EOpConstructDVec4; break;
default: break; // some compilers want this
}
}
break;
case EbtInt:
switch($1.vectorSize) {
case 1: op = EOpConstructInt; break;
case 2: op = EOpConstructIVec2; break;
case 3: op = EOpConstructIVec3; break;
case 4: op = EOpConstructIVec4; break;
default: break; // some compilers want this
}
break;
case EbtUint:
switch($1.vectorSize) {
case 1: op = EOpConstructUint; break;
case 2: op = EOpConstructUVec2; break;
case 3: op = EOpConstructUVec3; break;
case 4: op = EOpConstructUVec4; break;
default: break; // some compilers want this
}
break;
case EbtBool:
switch($1.vectorSize) {
case 1: op = EOpConstructBool; break;
case 2: op = EOpConstructBVec2; break;
case 3: op = EOpConstructBVec3; break;
case 4: op = EOpConstructBVec4; break;
default: break; // some compilers want this
}
break;
default: break; // some compilers want this
}
if (op == EOpNull) {
parseContext.error($1.loc, "cannot construct this type", TType::getBasicString($1.basicType), "");
$1.basicType = EbtFloat;
op = EOpConstructFloat;
}
TString tempString = "";
TType type($1);
TFunction *function = new TFunction(&tempString, type, op);
$$.function = function;
}
$$.function = parseContext.handleConstructorCall($1.loc, $1);
}
| postfix_expression {
//
@ -2821,90 +2455,7 @@ external_declaration
function_definition
: function_prototype {
TFunction& function = *($1.function);
TSymbol* symbol = parseContext.symbolTable.find(function.getMangledName());
TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
if (! prevDec)
parseContext.error($1.loc, "can't find function name", function.getName().c_str(), "");
//
// Note: 'prevDec' could be 'function' if this is the first time we've seen function
// as it would have just been put in the symbol table. Otherwise, we're looking up
// an earlier occurance.
//
if (prevDec && prevDec->isDefined()) {
//
// Then this function already has a body.
//
parseContext.error($1.loc, "function already has a body", function.getName().c_str(), "");
}
if (prevDec) {
prevDec->setDefined();
//
// Remember the return type for later checking for RETURN statements.
//
parseContext.currentFunctionType = &(prevDec->getReturnType());
} else
parseContext.currentFunctionType = new TType(EbtVoid);
parseContext.functionReturnsValue = false;
//
// Raise error message if main function takes any parameters or return anything other than void
//
if (function.getName() == "main") {
if (function.getParamCount() > 0)
parseContext.error($1.loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
if (function.getReturnType().getBasicType() != EbtVoid)
parseContext.error($1.loc, "", function.getReturnType().getCompleteTypeString().c_str(), "main function cannot return a value");
}
//
// New symbol table scope for body of function plus its arguments
//
parseContext.symbolTable.push();
//
// Insert parameters into the symbol table.
// If the parameter has no name, it's not an error, just don't insert it
// (could be used for unused args).
//
// Also, accumulate the list of parameters into the HIL, so lower level code
// knows where to find parameters.
//
TIntermAggregate* paramNodes = new TIntermAggregate;
for (int i = 0; i < function.getParamCount(); i++) {
TParameter& param = function[i];
if (param.name != 0) {
TVariable *variable = new TVariable(param.name, *param.type);
//
// Insert the parameters with name in the symbol table.
//
if (! parseContext.symbolTable.insert(*variable)) {
parseContext.error($1.loc, "redefinition", variable->getName().c_str(), "");
delete variable;
}
//
// Transfer ownership of name pointer to symbol table.
//
param.name = 0;
//
// Add the parameter to the HIL
//
paramNodes = parseContext.intermediate.growAggregate(
paramNodes,
parseContext.intermediate.addSymbol(variable->getUniqueId(),
variable->getName(),
variable->getType(), $1.loc),
$1.loc);
} else {
paramNodes = parseContext.intermediate.growAggregate(paramNodes, parseContext.intermediate.addSymbol(0, "", *param.type, $1.loc), $1.loc);
}
}
parseContext.intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), $1.loc);
$1.intermAggregate = paramNodes;
parseContext.loopNestingLevel = 0;
$1.intermAggregate = parseContext.handleFunctionPrototype($1.loc, *$1.function);
}
compound_statement_no_new_scope {
// May be best done as post process phase on intermediate code