Commit e5246698 by Alexis Hetu Committed by Alexis Hétu

Adding unsized arrays to the glsl parser

Unsized arrays declare with an empty [] without a specified size are now supported properly in the glsl parser. Also moved the construction code from the parser into TParseContext. Change-Id: Ic7b3efeee51da1a264e26af4d7908e7d2fccebd9 Reviewed-on: https://swiftshader-review.googlesource.com/3520Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent 3713cd4b
......@@ -39,6 +39,7 @@ LOCAL_SRC_FILES += \
SymbolTable.cpp \
TranslatorASM.cpp \
util.cpp \
ValidateGlobalInitializer.cpp \
ValidateLimitations.cpp \
ValidateSwitch.cpp \
......
......@@ -213,6 +213,7 @@
<ClCompile Include="SymbolTable.cpp" />
<ClCompile Include="TranslatorASM.cpp" />
<ClCompile Include="util.cpp" />
<ClCompile Include="ValidateGlobalInitializer.cpp" />
<ClCompile Include="ValidateLimitations.cpp" />
<ClCompile Include="glslang_lex.cpp" />
<ClCompile Include="glslang_tab.cpp" />
......@@ -317,6 +318,7 @@
<ClInclude Include="TranslatorASM.h" />
<ClInclude Include="Types.h" />
<ClInclude Include="util.h" />
<ClInclude Include="ValidateGlobalInitializer.h" />
<ClInclude Include="ValidateLimitations.h" />
<ClInclude Include="glslang_tab.h" />
<ClInclude Include="ValidateSwitch.h" />
......
......@@ -86,6 +86,9 @@
<ClCompile Include="ValidateSwitch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ValidateGlobalInitializer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BaseTypes.h">
......@@ -175,6 +178,9 @@
<ClInclude Include="ValidateSwitch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ValidateGlobalInitializer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="glslang.l">
......
......@@ -780,11 +780,7 @@ bool TIntermUnary::promote(TInfoSink&)
//
bool TIntermBinary::promote(TInfoSink& infoSink)
{
// This function only handles scalars, vectors, and matrices.
if (left->isArray() || right->isArray()) {
infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
return false;
}
ASSERT(left->isArray() == right->isArray());
// GLSL ES 2.0 does not support implicit type casting.
// So the basic type should always match.
......
......@@ -11,6 +11,7 @@
#include "glslang.h"
#include "preprocessor/SourceLocation.h"
#include "ValidateGlobalInitializer.h"
#include "ValidateSwitch.h"
///////////////////////////////////////////////////////////////////////
......@@ -462,7 +463,13 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* n
bool constructingMatrix = false;
switch(op) {
case EOpConstructMat2:
case EOpConstructMat2x3:
case EOpConstructMat2x4:
case EOpConstructMat3x2:
case EOpConstructMat3:
case EOpConstructMat3x4:
case EOpConstructMat4x2:
case EOpConstructMat4x3:
case EOpConstructMat4:
constructingMatrix = true;
break;
......@@ -501,9 +508,13 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* n
if (constType)
type->setQualifier(EvqConstExpr);
if (type->isArray() && type->getArraySize() != function.getParamCount()) {
error(line, "array constructor needs one argument per array element", "constructor");
return true;
if(type->isArray()) {
if(type->getArraySize() == 0) {
type->setArraySize(function.getParamCount());
} else if(type->getArraySize() != function.getParamCount()) {
error(line, "array constructor needs one argument per array element", "constructor");
return true;
}
}
if (arrayArg && op != EOpConstructStruct) {
......@@ -833,79 +844,6 @@ bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type
return false;
}
//
// Do all the semantic checking for declaring an array, with and
// without a size, and make the right changes to the symbol table.
//
// size == 0 means no specified size.
//
// Returns true if there was an error.
//
bool TParseContext::arrayErrorCheck(const TSourceLoc &line, TString& identifier, TPublicType type, TVariable*& variable)
{
//
// Don't check for reserved word use until after we know it's not in the symbol table,
// because reserved arrays can be redeclared.
//
bool builtIn = false;
bool sameScope = false;
TSymbol* symbol = symbolTable.find(identifier, shaderVersion, &builtIn, &sameScope);
if (symbol == 0 || !sameScope) {
if (reservedErrorCheck(line, identifier))
return true;
variable = new TVariable(&identifier, TType(type));
if (type.arraySize)
variable->getType().setArraySize(type.arraySize);
if (! symbolTable.declare(*variable)) {
delete variable;
error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
return true;
}
} else {
if (! symbol->isVariable()) {
error(line, "variable expected", identifier.c_str());
return true;
}
variable = static_cast<TVariable*>(symbol);
if (! variable->getType().isArray()) {
error(line, "redeclaring non-array as array", identifier.c_str());
return true;
}
if (variable->getType().getArraySize() > 0) {
error(line, "redeclaration of array with size", identifier.c_str());
return true;
}
if (! variable->getType().sameElementType(TType(type))) {
error(line, "redeclaration of array with a different type", identifier.c_str());
return true;
}
TType* t = variable->getArrayInformationType();
while (t != 0) {
if (t->getMaxArraySize() > type.arraySize) {
error(line, "higher index value already used for the array", identifier.c_str());
return true;
}
t->setArraySize(type.arraySize);
t = t->getArrayInformationType();
}
if (type.arraySize)
variable->getType().setArraySize(type.arraySize);
}
if (voidErrorCheck(line, identifier, type.type))
return true;
return false;
}
bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, const TSourceLoc &line)
{
bool builtIn = false;
......@@ -1234,27 +1172,33 @@ const TFunction* TParseContext::findFunction(const TSourceLoc &line, TFunction*
// code to handle them here.
//
bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, const TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
TIntermTyped *initializer, TIntermNode **intermNode)
{
TType type = TType(pType);
ASSERT(intermNode != nullptr);
TType type = TType(pType);
if (variable == 0) {
if (reservedErrorCheck(line, identifier))
return true;
if (voidErrorCheck(line, identifier, pType.type))
return true;
TVariable *variable = nullptr;
if(type.isArray() && (type.getArraySize() == 0))
{
type.setArraySize(initializer->getArraySize());
}
if(!declareVariable(line, identifier, type, &variable))
{
return true;
}
//
// add variable to symbol table
//
variable = new TVariable(&identifier, type);
if (! symbolTable.declare(*variable)) {
error(line, "redefinition", variable->getName().c_str());
return true;
// don't delete variable, it's used by error recovery, and the pool
// pop will take care of the memory
}
bool globalInitWarning = false;
if(symbolTable.atGlobalLevel() && !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
{
// Error message does not completely match behavior with ESSL 1.00, but
// we want to steer developers towards only using constant expressions.
error(line, "global variable initializers must be constant expressions", "=");
return true;
}
if(globalInitWarning)
{
warning(line, "global variable initializers should be constant expressions "
"(uniforms and globals are allowed in global initializers for legacy compatibility)", "=");
}
//
......@@ -1285,15 +1229,9 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
return true;
}
if (initializer->getAsConstantUnion()) {
ConstantUnion* unionArray = variable->getConstPointer();
if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
*unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
} else {
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
}
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
} else if (initializer->getAsSymbolNode()) {
const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), shaderVersion);
const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
const TVariable* tVar = static_cast<const TVariable*>(symbol);
ConstantUnion* constArray = tVar->getConstPointer();
......@@ -1310,13 +1248,13 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
if (qualifier != EvqConstExpr) {
TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
if (intermNode == 0) {
*intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
if(*intermNode == nullptr) {
assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
return true;
}
} else
intermNode = 0;
*intermNode = nullptr;
return false;
}
......@@ -1500,7 +1438,7 @@ TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &p
recover();
TIntermNode *intermNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{
//
// Build intermediate representation
......@@ -1546,7 +1484,7 @@ TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(TPublicType &pu
// initNode will correspond to the whole of "type b[n] = initializer".
TIntermNode *initNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, initNode))
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{
return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
}
......@@ -1686,7 +1624,7 @@ TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicTy
recover();
TIntermNode *intermNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
if(!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{
//
// build the intermediate representation
......@@ -1745,7 +1683,7 @@ TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &pub
// initNode will correspond to the whole of "b[n] = initializer".
TIntermNode *initNode = nullptr;
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, initNode))
if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{
if(initNode)
{
......@@ -1799,6 +1737,108 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
}
}
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
{
TPublicType publicType = publicTypeIn;
TOperator op = EOpNull;
if(publicType.userDef)
{
op = EOpConstructStruct;
}
else
{
switch(publicType.type)
{
case EbtFloat:
if(publicType.isMatrix())
{
switch(publicType.getCols())
{
case 2:
switch(publicType.getRows())
{
case 2: op = EOpConstructMat2; break;
case 3: op = EOpConstructMat2x3; break;
case 4: op = EOpConstructMat2x4; break;
}
break;
case 3:
switch(publicType.getRows())
{
case 2: op = EOpConstructMat3x2; break;
case 3: op = EOpConstructMat3; break;
case 4: op = EOpConstructMat3x4; break;
}
break;
case 4:
switch(publicType.getRows())
{
case 2: op = EOpConstructMat4x2; break;
case 3: op = EOpConstructMat4x3; break;
case 4: op = EOpConstructMat4; break;
}
break;
}
}
else
{
switch(publicType.getNominalSize())
{
case 1: op = EOpConstructFloat; break;
case 2: op = EOpConstructVec2; break;
case 3: op = EOpConstructVec3; break;
case 4: op = EOpConstructVec4; break;
}
}
break;
case EbtInt:
switch(publicType.getNominalSize())
{
case 1: op = EOpConstructInt; break;
case 2: op = EOpConstructIVec2; break;
case 3: op = EOpConstructIVec3; break;
case 4: op = EOpConstructIVec4; break;
}
break;
case EbtUInt:
switch(publicType.getNominalSize())
{
case 1: op = EOpConstructUInt; break;
case 2: op = EOpConstructUVec2; break;
case 3: op = EOpConstructUVec3; break;
case 4: op = EOpConstructUVec4; break;
}
break;
case EbtBool:
switch(publicType.getNominalSize())
{
case 1: op = EOpConstructBool; break;
case 2: op = EOpConstructBVec2; break;
case 3: op = EOpConstructBVec3; break;
case 4: op = EOpConstructBVec4; break;
}
break;
default: break;
}
if(op == EOpNull)
{
error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
recover();
publicType.type = EbtFloat;
op = EOpConstructFloat;
}
}
TString tempString;
TType type(publicType);
return new TFunction(&tempString, type, op);
}
// 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.
//
......@@ -3054,6 +3094,26 @@ TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
}
return node;
}
TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc)
{
if(binaryOpCommonCheck(op, left, right, loc))
{
return intermediate.addAssign(op, left, right, loc);
}
return nullptr;
}
TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc)
{
TIntermTyped *node = createAssign(op, left, right, loc);
if(node == nullptr)
{
assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
recover();
return left;
}
return node;
}
TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc)
......
......@@ -106,7 +106,6 @@ struct TParseContext {
bool arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped* expr, int& size);
bool arrayQualifierErrorCheck(const TSourceLoc &line, TPublicType type);
bool arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type);
bool arrayErrorCheck(const TSourceLoc &line, TString& identifier, TPublicType type, TVariable*& variable);
bool voidErrorCheck(const TSourceLoc&, const TString&, const TBasicType&);
bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
......@@ -132,8 +131,8 @@ struct TParseContext {
bool containsSampler(TType& type);
bool areAllChildConst(TIntermAggregate* aggrNode);
const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line, const TString& identifier, const TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
bool executeInitializer(const TSourceLoc &line, const TString &identifier, const TPublicType &pType,
TIntermTyped *initializer, TIntermNode **intermNode);
TPublicType addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier);
bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, const TSourceLoc&);
......@@ -166,6 +165,7 @@ struct TParseContext {
const TSourceLoc &initLocation, TIntermTyped *initializer);
void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
TFunction *addConstructorFunc(const TPublicType &publicType);
TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&);
TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
......@@ -203,6 +203,8 @@ struct TParseContext {
TIntermTyped *addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
......@@ -210,6 +212,7 @@ private:
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
// The funcReturnType parameter is expected to be non-null when the operation is a built-in function.
// It is expected to be null for other unary operators.
......
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "ValidateGlobalInitializer.h"
#include "ParseHelper.h"
namespace
{
class ValidateGlobalInitializerTraverser : public TIntermTraverser
{
public:
ValidateGlobalInitializerTraverser(const TParseContext *context);
void visitSymbol(TIntermSymbol *node) override;
bool isValid() const { return mIsValid; }
bool issueWarning() const { return mIssueWarning; }
private:
const TParseContext *mContext;
bool mIsValid;
bool mIssueWarning;
};
void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
{
const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
if (sym->isVariable())
{
// ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
// Global initializers must be constant expressions.
const TVariable *var = static_cast<const TVariable *>(sym);
switch (var->getType().getQualifier())
{
case EvqConstExpr:
break;
case EvqGlobal:
case EvqTemporary:
case EvqUniform:
// We allow these cases to be compatible with legacy ESSL 1.00 content.
// Implement stricter rules for ESSL 3.00 since there's no legacy content to deal with.
if (mContext->getShaderVersion() >= 300)
{
mIsValid = false;
}
else
{
mIssueWarning = true;
}
break;
default:
mIsValid = false;
}
}
}
ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
: TIntermTraverser(true, false, false),
mContext(context),
mIsValid(true),
mIssueWarning(false)
{
}
} // namespace
bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
{
ValidateGlobalInitializerTraverser validate(context);
initializer->traverse(&validate);
ASSERT(warning != nullptr);
*warning = validate.issueWarning();
return validate.isValid();
}
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
#define COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
class TIntermTyped;
struct TParseContext;
// Returns true if the initializer is valid.
bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning);
#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
......@@ -448,82 +448,11 @@ function_call_header
// Grammar Note: Constructors look like functions, but are recognized as types.
function_identifier
: type_specifier_nonarray {
//
// Constructor
//
TOperator op = EOpNull;
if ($1.userDef) {
op = EOpConstructStruct;
} else {
switch ($1.type) {
case EbtFloat:
switch($1.primarySize) {
case 1:
op = EOpConstructFloat; break;
case 2:
switch($1.secondarySize) {
case 1: op = EOpConstructVec2; break;
case 2: op = EOpConstructMat2; break;
case 3: op = EOpConstructMat2x3; break;
case 4: op = EOpConstructMat2x4; break;
}
break;
case 3:
switch($1.secondarySize) {
case 1: op = EOpConstructVec3; break;
case 2: op = EOpConstructMat3x2; break;
case 3: op = EOpConstructMat3; break;
case 4: op = EOpConstructMat3x4; break;
}
break;
case 4:
switch($1.secondarySize) {
case 1: op = EOpConstructVec4; break;
case 2: op = EOpConstructMat4x2; break;
case 3: op = EOpConstructMat4x3; break;
case 4: op = EOpConstructMat4; break;
}
break;
}
break;
case EbtInt:
switch($1.primarySize) {
case 1: op = EOpConstructInt; break;
case 2: FRAG_VERT_ONLY("ivec2", @1); op = EOpConstructIVec2; break;
case 3: FRAG_VERT_ONLY("ivec3", @1); op = EOpConstructIVec3; break;
case 4: FRAG_VERT_ONLY("ivec4", @1); op = EOpConstructIVec4; break;
}
break;
case EbtUInt:
switch($1.primarySize) {
case 1: op = EOpConstructUInt; break;
case 2: FRAG_VERT_ONLY("uvec2", @1); op = EOpConstructUVec2; break;
case 3: FRAG_VERT_ONLY("uvec3", @1); op = EOpConstructUVec3; break;
case 4: FRAG_VERT_ONLY("uvec4", @1); op = EOpConstructUVec4; break;
}
break;
case EbtBool:
switch($1.primarySize) {
case 1: op = EOpConstructBool; break;
case 2: FRAG_VERT_ONLY("bvec2", @1); op = EOpConstructBVec2; break;
case 3: FRAG_VERT_ONLY("bvec3", @1); op = EOpConstructBVec3; break;
case 4: FRAG_VERT_ONLY("bvec4", @1); op = EOpConstructBVec4; break;
}
break;
default: break;
}
if (op == EOpNull) {
context->error(@1, "cannot construct this type", getBasicString($1.type));
context->recover();
$1.type = EbtFloat;
op = EOpConstructFloat;
}
: type_specifier_no_prec {
if ($1.array) {
ES3_ONLY("[]", @1);
}
TString tempString;
TType type($1);
TFunction *function = new TFunction(&tempString, type, op);
$$ = function;
$$ = context->addConstructorFunc($1);
}
| IDENTIFIER {
if (context->reservedErrorCheck(@1, *$1.string))
......@@ -730,12 +659,7 @@ assignment_expression
| unary_expression assignment_operator assignment_expression {
if (context->lValueErrorCheck(@2, "assign", $1))
context->recover();
$$ = context->intermediate.addAssign($2.op, $1, $3, @2);
if ($$ == 0) {
context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString());
context->recover();
$$ = $1;
}
$$ = context->addAssign($2.op, $1, $3, @2);
}
;
......@@ -783,7 +707,7 @@ constant_expression
enter_struct
: IDENTIFIER LEFT_BRACE {
if (context->enterStructDeclaration($1.line, *$1.string))
if (context->enterStructDeclaration(@1, *$1.string))
context->recover();
$$ = $1;
}
......@@ -831,16 +755,16 @@ declaration
$$ = 0;
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line);
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, NULL, $1.line, NULL, $1.line);
ES3_ONLY(getQualifierString($1.qualifier), @1);
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @1, NULL, @1);
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line);
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, $5.string, $5.line, NULL, $1.line);
ES3_ONLY(getQualifierString($1.qualifier), @1);
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @1);
}
| type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {
ES3_ONLY(getQualifierString($1.qualifier), $1.line);
$$ = context->addInterfaceBlock($1, $2.line, *$2.string, $3, $5.string, $5.line, $7, $6.line);
ES3_ONLY(getQualifierString($1.qualifier), @1);
$$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6);
}
| type_qualifier SEMICOLON {
context->parseGlobalLayoutQualifier($1);
......@@ -1352,6 +1276,11 @@ type_specifier_no_prec
: type_specifier_nonarray {
$$ = $1;
}
| type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
ES3_ONLY("[]", @2);
$$ = $1;
$$.setArray(true, 0);
}
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1;
......@@ -1769,17 +1698,17 @@ selection_rest_statement
switch_statement
: SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement {
$$ = context->addSwitch($3, $6, $1.line);
$$ = context->addSwitch($3, $6, @1);
context->decrSwitchNestingLevel();
}
;
case_label
: CASE constant_expression COLON {
$$ = context->addCase($2, $1.line);
$$ = context->addCase($2, @1);
}
| DEFAULT COLON {
$$ = context->addDefault($1.line);
$$ = context->addDefault(@1);
}
;
......@@ -1799,7 +1728,7 @@ condition
if (context->boolErrorCheck(@2, $1))
context->recover();
if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode))
if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode))
$$ = $4;
else {
context->recover();
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -295,6 +295,8 @@
<Unit filename="../compiler/TranslatorASM.cpp" />
<Unit filename="../compiler/TranslatorASM.h" />
<Unit filename="../compiler/Types.h" />
<Unit filename="../compiler/ValidateGlobalInitializer.cpp" />
<Unit filename="../compiler/ValidateGlobalInitializer.h" />
<Unit filename="../compiler/ValidateLimitations.cpp" />
<Unit filename="../compiler/ValidateLimitations.h" />
<Unit filename="../compiler/ValidateSwitch.cpp" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment