Remove most of the remaining logic from glslang.y
Move most of the logic in glslang.y to ParseContext. This will make it
easier to change the code in the future.
Only a few specific bits of logic are kept in glslang.y:
* Disabling a parsing rule when a given shading language version is
being parsed. This makes it easier to check the grammar against the
grammar in the GLSL ES specs.
* Scoping calls that need to be paired with another call. It's much
easier to check these for correctness when the paired calls are next
to each other.
BUG=angleproject:911
TEST=angle_unittests
Change-Id: I52f42a1fc0f28463ca4b237dc6e88345e5173064
Reviewed-on: https://chromium-review.googlesource.com/539640
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 73994f6..975fade 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -67,6 +67,25 @@
return "image";
}
+bool CanSetDefaultPrecisionOnType(const TPublicType &type)
+{
+ if (!SupportsPrecision(type.getBasicType()))
+ {
+ return false;
+ }
+ if (type.getBasicType() == EbtUInt)
+ {
+ // ESSL 3.00.4 section 4.5.4
+ return false;
+ }
+ if (type.isAggregate())
+ {
+ // Not allowed to set for aggregate types
+ return false;
+ }
+ return true;
+}
+
} // namespace
// This tracks each binding point's current default offset for inheritance of subsequent
@@ -1030,6 +1049,7 @@
const TTypeQualifierBuilder &typeQualifierBuilder,
TType *type)
{
+ // The only parameter qualifiers a parameter can have are in, out, inout or const.
TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics);
if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
@@ -1839,11 +1859,22 @@
}
if (cond == nullptr || typedCond)
{
+ if (type == ELoopDoWhile)
+ {
+ checkIsScalarBool(line, typedCond);
+ }
+ // In the case of other loops, it was checked before that the condition is a scalar boolean.
+ ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr ||
+ (typedCond->getBasicType() == EbtBool && !typedCond->isArray() &&
+ !typedCond->isVector()));
+
node = new TIntermLoop(type, init, typedCond, expr, TIntermediate::EnsureBlock(body));
node->setLine(line);
return node;
}
+ ASSERT(type != ELoopDoWhile);
+
TIntermDeclaration *declaration = cond->getAsDeclarationNode();
ASSERT(declaration);
TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode();
@@ -1868,6 +1899,32 @@
return block;
}
+TIntermNode *TParseContext::addIfElse(TIntermTyped *cond,
+ TIntermNodePair code,
+ const TSourceLoc &loc)
+{
+ checkIsScalarBool(loc, cond);
+
+ // For compile time constant conditions, prune the code now.
+ if (cond->getAsConstantUnion())
+ {
+ if (cond->getAsConstantUnion()->getBConst(0) == true)
+ {
+ return TIntermediate::EnsureBlock(code.node1);
+ }
+ else
+ {
+ return TIntermediate::EnsureBlock(code.node2);
+ }
+ }
+
+ TIntermIfElse *node = new TIntermIfElse(cond, TIntermediate::EnsureBlock(code.node1),
+ TIntermediate::EnsureBlock(code.node2));
+ node->setLine(loc);
+
+ return node;
+}
+
void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
{
checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision,
@@ -2514,6 +2571,25 @@
mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset);
}
+void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision,
+ const TPublicType &type,
+ const TSourceLoc &loc)
+{
+ if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER) &&
+ !getFragmentPrecisionHigh())
+ {
+ error(loc, "precision is not supported in fragment shader", "highp");
+ }
+
+ if (!CanSetDefaultPrecisionOnType(type))
+ {
+ error(loc, "illegal type argument for default precision qualifier",
+ getBasicString(type.getBasicType()));
+ return;
+ }
+ symbolTable.setDefaultPrecision(type.getBasicType(), precision);
+}
+
void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
{
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
@@ -2919,8 +2995,20 @@
return new TFunction(name, new TType(type));
}
+TFunction *TParseContext::addNonConstructorFunc(const TString *name, const TSourceLoc &loc)
+{
+ checkIsNotReserved(loc, *name);
+ const TType *returnType = TCache::getType(EbtVoid, EbpUndefined);
+ return new TFunction(name, returnType);
+}
+
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicType)
{
+ if (mShaderVersion < 300 && publicType.array)
+ {
+ error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only",
+ "[]");
+ }
if (publicType.isStructSpecifier())
{
error(publicType.getLine(), "constructor can't be a structure definition",
@@ -2938,6 +3026,32 @@
return new TFunction(nullptr, type, EOpConstruct);
}
+TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType,
+ const TString *name,
+ const TSourceLoc &nameLoc)
+{
+ if (publicType.getBasicType() == EbtVoid)
+ {
+ error(nameLoc, "illegal use of type 'void'", name->c_str());
+ }
+ checkIsNotReserved(nameLoc, *name);
+ TType *type = new TType(publicType);
+ TParameter param = {name, type};
+ return param;
+}
+
+TParameter TParseContext::parseParameterArrayDeclarator(const TString *identifier,
+ const TSourceLoc &identifierLoc,
+ TIntermTyped *arraySize,
+ const TSourceLoc &arrayLoc,
+ TPublicType *type)
+{
+ checkIsValidTypeForArray(arrayLoc, *type);
+ unsigned int size = checkIsValidArraySize(arrayLoc, arraySize);
+ type->setArraySize(size);
+ return parseParameterDeclarator(*type, identifier, identifierLoc);
+}
+
// This function is used to test for the correctness of the parameters passed to various constructor
// functions and also convert them to the right datatype if it is allowed and required.
//
@@ -3695,6 +3809,77 @@
mShaderVersion);
}
+TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier,
+ const TSourceLoc &loc)
+{
+ checkIsAtGlobalLevel(loc, getQualifierString(qualifier));
+ return new TStorageQualifierWrapper(qualifier, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc)
+{
+ if (getShaderType() == GL_VERTEX_SHADER)
+ {
+ return parseGlobalStorageQualifier(EvqVaryingOut, loc);
+ }
+ return parseGlobalStorageQualifier(EvqVaryingIn, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc)
+{
+ if (declaringFunction())
+ {
+ return new TStorageQualifierWrapper(EvqIn, loc);
+ }
+ if (getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ if (mShaderVersion < 300)
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+ }
+ return new TStorageQualifierWrapper(EvqFragmentIn, loc);
+ }
+ if (getShaderType() == GL_VERTEX_SHADER)
+ {
+ if (mShaderVersion < 300 && !isMultiviewExtensionEnabled())
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+ }
+ return new TStorageQualifierWrapper(EvqVertexIn, loc);
+ }
+ return new TStorageQualifierWrapper(EvqComputeIn, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc)
+{
+ if (declaringFunction())
+ {
+ return new TStorageQualifierWrapper(EvqOut, loc);
+ }
+ if (mShaderVersion < 300)
+ {
+ error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
+ }
+ if (getShaderType() != GL_VERTEX_SHADER && getShaderType() != GL_FRAGMENT_SHADER)
+ {
+ error(loc, "storage qualifier supported in vertex and fragment shaders only", "out");
+ }
+ if (getShaderType() == GL_VERTEX_SHADER)
+ {
+ return new TStorageQualifierWrapper(EvqVertexOut, loc);
+ }
+ return new TStorageQualifierWrapper(EvqFragmentOut, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc)
+{
+ if (!declaringFunction())
+ {
+ error(loc, "invalid qualifier: can be only used with function parameters", "inout");
+ }
+ return new TStorageQualifierWrapper(EvqInOut, loc);
+}
+
TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation)
@@ -3703,6 +3888,27 @@
mDiagnostics);
}
+TField *TParseContext::parseStructDeclarator(TString *identifier, const TSourceLoc &loc)
+{
+ checkIsNotReserved(loc, *identifier);
+ TType *type = new TType(EbtVoid, EbpUndefined);
+ return new TField(type, identifier, loc);
+}
+
+TField *TParseContext::parseStructArrayDeclarator(TString *identifier,
+ const TSourceLoc &loc,
+ TIntermTyped *arraySize,
+ const TSourceLoc &arraySizeLoc)
+{
+ checkIsNotReserved(loc, *identifier);
+
+ TType *type = new TType(EbtVoid, EbpUndefined);
+ unsigned int size = checkIsValidArraySize(arraySizeLoc, arraySize);
+ type->setArraySize(size);
+
+ return new TField(type, identifier, loc);
+}
+
TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
const TFieldList *newlyAddedFields,
const TSourceLoc &location)
@@ -3837,9 +4043,7 @@
}
TTypeSpecifierNonArray typeSpecifierNonArray;
- typeSpecifierNonArray.initialize(EbtStruct, structLine);
- typeSpecifierNonArray.userDef = structureType;
- typeSpecifierNonArray.isStructSpecifier = true;
+ typeSpecifierNonArray.initializeStruct(structureType, true, structLine);
exitStructDeclaration();
return typeSpecifierNonArray;
@@ -3979,6 +4183,7 @@
TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
{
+ ASSERT(op != EOpNull);
TIntermTyped *node = createUnaryMath(op, child, loc);
if (node == nullptr)
{
@@ -4397,6 +4602,7 @@
TIntermTyped *right,
const TSourceLoc &loc)
{
+ checkCanBeLValue(loc, "assign", left);
TIntermTyped *node = createAssign(op, left, right, loc);
if (node == nullptr)
{
@@ -4447,28 +4653,39 @@
error(loc, "non-void function must return a value", "return");
}
break;
+ case EOpKill:
+ if (mShaderType != GL_FRAGMENT_SHADER)
+ {
+ error(loc, "discard supported in fragment shaders only", "discard");
+ }
+ break;
default:
- // No checks for discard
+ UNREACHABLE();
break;
}
- return intermediate.addBranch(op, loc);
+ return addBranch(op, nullptr, loc);
}
TIntermBranch *TParseContext::addBranch(TOperator op,
- TIntermTyped *returnValue,
+ TIntermTyped *expression,
const TSourceLoc &loc)
{
- ASSERT(op == EOpReturn);
- mFunctionReturnsValue = true;
- if (mCurrentFunctionType->getBasicType() == EbtVoid)
+ if (expression != nullptr)
{
- error(loc, "void function cannot return a value", "return");
+ ASSERT(op == EOpReturn);
+ mFunctionReturnsValue = true;
+ if (mCurrentFunctionType->getBasicType() == EbtVoid)
+ {
+ error(loc, "void function cannot return a value", "return");
+ }
+ else if (*mCurrentFunctionType != expression->getType())
+ {
+ error(loc, "function return is not matching type:", "return");
+ }
}
- else if (*mCurrentFunctionType != returnValue->getType())
- {
- error(loc, "function return is not matching type:", "return");
- }
- return intermediate.addBranch(op, returnValue, loc);
+ TIntermBranch *node = new TIntermBranch(op, expression);
+ node->setLine(loc);
+ return node;
}
void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)