1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/compiler/ParseHelper.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1600 @@ 1.4 +// 1.5 +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 1.6 +// Use of this source code is governed by a BSD-style license that can be 1.7 +// found in the LICENSE file. 1.8 +// 1.9 + 1.10 +#include "compiler/ParseHelper.h" 1.11 + 1.12 +#include <stdarg.h> 1.13 +#include <stdio.h> 1.14 + 1.15 +#include "compiler/glslang.h" 1.16 +#include "compiler/preprocessor/SourceLocation.h" 1.17 + 1.18 +/////////////////////////////////////////////////////////////////////// 1.19 +// 1.20 +// Sub- vector and matrix fields 1.21 +// 1.22 +//////////////////////////////////////////////////////////////////////// 1.23 + 1.24 +// 1.25 +// Look at a '.' field selector string and change it into offsets 1.26 +// for a vector. 1.27 +// 1.28 +bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line) 1.29 +{ 1.30 + fields.num = (int) compString.size(); 1.31 + if (fields.num > 4) { 1.32 + error(line, "illegal vector field selection", compString.c_str()); 1.33 + return false; 1.34 + } 1.35 + 1.36 + enum { 1.37 + exyzw, 1.38 + ergba, 1.39 + estpq 1.40 + } fieldSet[4]; 1.41 + 1.42 + for (int i = 0; i < fields.num; ++i) { 1.43 + switch (compString[i]) { 1.44 + case 'x': 1.45 + fields.offsets[i] = 0; 1.46 + fieldSet[i] = exyzw; 1.47 + break; 1.48 + case 'r': 1.49 + fields.offsets[i] = 0; 1.50 + fieldSet[i] = ergba; 1.51 + break; 1.52 + case 's': 1.53 + fields.offsets[i] = 0; 1.54 + fieldSet[i] = estpq; 1.55 + break; 1.56 + case 'y': 1.57 + fields.offsets[i] = 1; 1.58 + fieldSet[i] = exyzw; 1.59 + break; 1.60 + case 'g': 1.61 + fields.offsets[i] = 1; 1.62 + fieldSet[i] = ergba; 1.63 + break; 1.64 + case 't': 1.65 + fields.offsets[i] = 1; 1.66 + fieldSet[i] = estpq; 1.67 + break; 1.68 + case 'z': 1.69 + fields.offsets[i] = 2; 1.70 + fieldSet[i] = exyzw; 1.71 + break; 1.72 + case 'b': 1.73 + fields.offsets[i] = 2; 1.74 + fieldSet[i] = ergba; 1.75 + break; 1.76 + case 'p': 1.77 + fields.offsets[i] = 2; 1.78 + fieldSet[i] = estpq; 1.79 + break; 1.80 + 1.81 + case 'w': 1.82 + fields.offsets[i] = 3; 1.83 + fieldSet[i] = exyzw; 1.84 + break; 1.85 + case 'a': 1.86 + fields.offsets[i] = 3; 1.87 + fieldSet[i] = ergba; 1.88 + break; 1.89 + case 'q': 1.90 + fields.offsets[i] = 3; 1.91 + fieldSet[i] = estpq; 1.92 + break; 1.93 + default: 1.94 + error(line, "illegal vector field selection", compString.c_str()); 1.95 + return false; 1.96 + } 1.97 + } 1.98 + 1.99 + for (int i = 0; i < fields.num; ++i) { 1.100 + if (fields.offsets[i] >= vecSize) { 1.101 + error(line, "vector field selection out of range", compString.c_str()); 1.102 + return false; 1.103 + } 1.104 + 1.105 + if (i > 0) { 1.106 + if (fieldSet[i] != fieldSet[i-1]) { 1.107 + error(line, "illegal - vector component fields not from the same set", compString.c_str()); 1.108 + return false; 1.109 + } 1.110 + } 1.111 + } 1.112 + 1.113 + return true; 1.114 +} 1.115 + 1.116 + 1.117 +// 1.118 +// Look at a '.' field selector string and change it into offsets 1.119 +// for a matrix. 1.120 +// 1.121 +bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, const TSourceLoc& line) 1.122 +{ 1.123 + fields.wholeRow = false; 1.124 + fields.wholeCol = false; 1.125 + fields.row = -1; 1.126 + fields.col = -1; 1.127 + 1.128 + if (compString.size() != 2) { 1.129 + error(line, "illegal length of matrix field selection", compString.c_str()); 1.130 + return false; 1.131 + } 1.132 + 1.133 + if (compString[0] == '_') { 1.134 + if (compString[1] < '0' || compString[1] > '3') { 1.135 + error(line, "illegal matrix field selection", compString.c_str()); 1.136 + return false; 1.137 + } 1.138 + fields.wholeCol = true; 1.139 + fields.col = compString[1] - '0'; 1.140 + } else if (compString[1] == '_') { 1.141 + if (compString[0] < '0' || compString[0] > '3') { 1.142 + error(line, "illegal matrix field selection", compString.c_str()); 1.143 + return false; 1.144 + } 1.145 + fields.wholeRow = true; 1.146 + fields.row = compString[0] - '0'; 1.147 + } else { 1.148 + if (compString[0] < '0' || compString[0] > '3' || 1.149 + compString[1] < '0' || compString[1] > '3') { 1.150 + error(line, "illegal matrix field selection", compString.c_str()); 1.151 + return false; 1.152 + } 1.153 + fields.row = compString[0] - '0'; 1.154 + fields.col = compString[1] - '0'; 1.155 + } 1.156 + 1.157 + if (fields.row >= matSize || fields.col >= matSize) { 1.158 + error(line, "matrix field selection out of range", compString.c_str()); 1.159 + return false; 1.160 + } 1.161 + 1.162 + return true; 1.163 +} 1.164 + 1.165 +/////////////////////////////////////////////////////////////////////// 1.166 +// 1.167 +// Errors 1.168 +// 1.169 +//////////////////////////////////////////////////////////////////////// 1.170 + 1.171 +// 1.172 +// Track whether errors have occurred. 1.173 +// 1.174 +void TParseContext::recover() 1.175 +{ 1.176 +} 1.177 + 1.178 +// 1.179 +// Used by flex/bison to output all syntax and parsing errors. 1.180 +// 1.181 +void TParseContext::error(const TSourceLoc& loc, 1.182 + const char* reason, const char* token, 1.183 + const char* extraInfo) 1.184 +{ 1.185 + pp::SourceLocation srcLoc; 1.186 + srcLoc.file = loc.first_file; 1.187 + srcLoc.line = loc.first_line; 1.188 + diagnostics.writeInfo(pp::Diagnostics::ERROR, 1.189 + srcLoc, reason, token, extraInfo); 1.190 + 1.191 +} 1.192 + 1.193 +void TParseContext::warning(const TSourceLoc& loc, 1.194 + const char* reason, const char* token, 1.195 + const char* extraInfo) { 1.196 + pp::SourceLocation srcLoc; 1.197 + srcLoc.file = loc.first_file; 1.198 + srcLoc.line = loc.first_line; 1.199 + diagnostics.writeInfo(pp::Diagnostics::WARNING, 1.200 + srcLoc, reason, token, extraInfo); 1.201 +} 1.202 + 1.203 +void TParseContext::trace(const char* str) 1.204 +{ 1.205 + diagnostics.writeDebug(str); 1.206 +} 1.207 + 1.208 +// 1.209 +// Same error message for all places assignments don't work. 1.210 +// 1.211 +void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right) 1.212 +{ 1.213 + std::stringstream extraInfoStream; 1.214 + extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'"; 1.215 + std::string extraInfo = extraInfoStream.str(); 1.216 + error(line, "", op, extraInfo.c_str()); 1.217 +} 1.218 + 1.219 +// 1.220 +// Same error message for all places unary operations don't work. 1.221 +// 1.222 +void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand) 1.223 +{ 1.224 + std::stringstream extraInfoStream; 1.225 + extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand 1.226 + << " (or there is no acceptable conversion)"; 1.227 + std::string extraInfo = extraInfoStream.str(); 1.228 + error(line, " wrong operand type", op, extraInfo.c_str()); 1.229 +} 1.230 + 1.231 +// 1.232 +// Same error message for all binary operations don't work. 1.233 +// 1.234 +void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right) 1.235 +{ 1.236 + std::stringstream extraInfoStream; 1.237 + extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left 1.238 + << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)"; 1.239 + std::string extraInfo = extraInfoStream.str(); 1.240 + error(line, " wrong operand types ", op, extraInfo.c_str()); 1.241 +} 1.242 + 1.243 +bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){ 1.244 + if (!checksPrecisionErrors) 1.245 + return false; 1.246 + switch( type ){ 1.247 + case EbtFloat: 1.248 + if( precision == EbpUndefined ){ 1.249 + error( line, "No precision specified for (float)", "" ); 1.250 + return true; 1.251 + } 1.252 + break; 1.253 + case EbtInt: 1.254 + if( precision == EbpUndefined ){ 1.255 + error( line, "No precision specified (int)", "" ); 1.256 + return true; 1.257 + } 1.258 + break; 1.259 + default: 1.260 + return false; 1.261 + } 1.262 + return false; 1.263 +} 1.264 + 1.265 +// 1.266 +// Both test and if necessary, spit out an error, to see if the node is really 1.267 +// an l-value that can be operated on this way. 1.268 +// 1.269 +// Returns true if the was an error. 1.270 +// 1.271 +bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node) 1.272 +{ 1.273 + TIntermSymbol* symNode = node->getAsSymbolNode(); 1.274 + TIntermBinary* binaryNode = node->getAsBinaryNode(); 1.275 + 1.276 + if (binaryNode) { 1.277 + bool errorReturn; 1.278 + 1.279 + switch(binaryNode->getOp()) { 1.280 + case EOpIndexDirect: 1.281 + case EOpIndexIndirect: 1.282 + case EOpIndexDirectStruct: 1.283 + return lValueErrorCheck(line, op, binaryNode->getLeft()); 1.284 + case EOpVectorSwizzle: 1.285 + errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); 1.286 + if (!errorReturn) { 1.287 + int offset[4] = {0,0,0,0}; 1.288 + 1.289 + TIntermTyped* rightNode = binaryNode->getRight(); 1.290 + TIntermAggregate *aggrNode = rightNode->getAsAggregate(); 1.291 + 1.292 + for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); 1.293 + p != aggrNode->getSequence().end(); p++) { 1.294 + int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0); 1.295 + offset[value]++; 1.296 + if (offset[value] > 1) { 1.297 + error(line, " l-value of swizzle cannot have duplicate components", op); 1.298 + 1.299 + return true; 1.300 + } 1.301 + } 1.302 + } 1.303 + 1.304 + return errorReturn; 1.305 + default: 1.306 + break; 1.307 + } 1.308 + error(line, " l-value required", op); 1.309 + 1.310 + return true; 1.311 + } 1.312 + 1.313 + 1.314 + const char* symbol = 0; 1.315 + if (symNode != 0) 1.316 + symbol = symNode->getSymbol().c_str(); 1.317 + 1.318 + const char* message = 0; 1.319 + switch (node->getQualifier()) { 1.320 + case EvqConst: message = "can't modify a const"; break; 1.321 + case EvqConstReadOnly: message = "can't modify a const"; break; 1.322 + case EvqAttribute: message = "can't modify an attribute"; break; 1.323 + case EvqUniform: message = "can't modify a uniform"; break; 1.324 + case EvqVaryingIn: message = "can't modify a varying"; break; 1.325 + case EvqFragCoord: message = "can't modify gl_FragCoord"; break; 1.326 + case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break; 1.327 + case EvqPointCoord: message = "can't modify gl_PointCoord"; break; 1.328 + default: 1.329 + 1.330 + // 1.331 + // Type that can't be written to? 1.332 + // 1.333 + switch (node->getBasicType()) { 1.334 + case EbtSampler2D: 1.335 + case EbtSamplerCube: 1.336 + message = "can't modify a sampler"; 1.337 + break; 1.338 + case EbtVoid: 1.339 + message = "can't modify void"; 1.340 + break; 1.341 + default: 1.342 + break; 1.343 + } 1.344 + } 1.345 + 1.346 + if (message == 0 && binaryNode == 0 && symNode == 0) { 1.347 + error(line, " l-value required", op); 1.348 + 1.349 + return true; 1.350 + } 1.351 + 1.352 + 1.353 + // 1.354 + // Everything else is okay, no error. 1.355 + // 1.356 + if (message == 0) 1.357 + return false; 1.358 + 1.359 + // 1.360 + // If we get here, we have an error and a message. 1.361 + // 1.362 + if (symNode) { 1.363 + std::stringstream extraInfoStream; 1.364 + extraInfoStream << "\"" << symbol << "\" (" << message << ")"; 1.365 + std::string extraInfo = extraInfoStream.str(); 1.366 + error(line, " l-value required", op, extraInfo.c_str()); 1.367 + } 1.368 + else { 1.369 + std::stringstream extraInfoStream; 1.370 + extraInfoStream << "(" << message << ")"; 1.371 + std::string extraInfo = extraInfoStream.str(); 1.372 + error(line, " l-value required", op, extraInfo.c_str()); 1.373 + } 1.374 + 1.375 + return true; 1.376 +} 1.377 + 1.378 +// 1.379 +// Both test, and if necessary spit out an error, to see if the node is really 1.380 +// a constant. 1.381 +// 1.382 +// Returns true if the was an error. 1.383 +// 1.384 +bool TParseContext::constErrorCheck(TIntermTyped* node) 1.385 +{ 1.386 + if (node->getQualifier() == EvqConst) 1.387 + return false; 1.388 + 1.389 + error(node->getLine(), "constant expression required", ""); 1.390 + 1.391 + return true; 1.392 +} 1.393 + 1.394 +// 1.395 +// Both test, and if necessary spit out an error, to see if the node is really 1.396 +// an integer. 1.397 +// 1.398 +// Returns true if the was an error. 1.399 +// 1.400 +bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) 1.401 +{ 1.402 + if (node->getBasicType() == EbtInt && node->getNominalSize() == 1) 1.403 + return false; 1.404 + 1.405 + error(node->getLine(), "integer expression required", token); 1.406 + 1.407 + return true; 1.408 +} 1.409 + 1.410 +// 1.411 +// Both test, and if necessary spit out an error, to see if we are currently 1.412 +// globally scoped. 1.413 +// 1.414 +// Returns true if the was an error. 1.415 +// 1.416 +bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token) 1.417 +{ 1.418 + if (global) 1.419 + return false; 1.420 + 1.421 + error(line, "only allowed at global scope", token); 1.422 + 1.423 + return true; 1.424 +} 1.425 + 1.426 +// 1.427 +// For now, keep it simple: if it starts "gl_", it's reserved, independent 1.428 +// of scope. Except, if the symbol table is at the built-in push-level, 1.429 +// which is when we are parsing built-ins. 1.430 +// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a 1.431 +// webgl shader. 1.432 +// 1.433 +// Returns true if there was an error. 1.434 +// 1.435 +bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier) 1.436 +{ 1.437 + static const char* reservedErrMsg = "reserved built-in name"; 1.438 + if (!symbolTable.atBuiltInLevel()) { 1.439 + if (identifier.compare(0, 3, "gl_") == 0) { 1.440 + error(line, reservedErrMsg, "gl_"); 1.441 + return true; 1.442 + } 1.443 + if (isWebGLBasedSpec(shaderSpec)) { 1.444 + if (identifier.compare(0, 6, "webgl_") == 0) { 1.445 + error(line, reservedErrMsg, "webgl_"); 1.446 + return true; 1.447 + } 1.448 + if (identifier.compare(0, 7, "_webgl_") == 0) { 1.449 + error(line, reservedErrMsg, "_webgl_"); 1.450 + return true; 1.451 + } 1.452 + if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) { 1.453 + error(line, reservedErrMsg, "css_"); 1.454 + return true; 1.455 + } 1.456 + } 1.457 + if (identifier.find("__") != TString::npos) { 1.458 + error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str()); 1.459 + return true; 1.460 + } 1.461 + } 1.462 + 1.463 + return false; 1.464 +} 1.465 + 1.466 +// 1.467 +// Make sure there is enough data provided to the constructor to build 1.468 +// something of the type of the constructor. Also returns the type of 1.469 +// the constructor. 1.470 +// 1.471 +// Returns true if there was an error in construction. 1.472 +// 1.473 +bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type) 1.474 +{ 1.475 + *type = function.getReturnType(); 1.476 + 1.477 + bool constructingMatrix = false; 1.478 + switch(op) { 1.479 + case EOpConstructMat2: 1.480 + case EOpConstructMat3: 1.481 + case EOpConstructMat4: 1.482 + constructingMatrix = true; 1.483 + break; 1.484 + default: 1.485 + break; 1.486 + } 1.487 + 1.488 + // 1.489 + // Note: It's okay to have too many components available, but not okay to have unused 1.490 + // arguments. 'full' will go to true when enough args have been seen. If we loop 1.491 + // again, there is an extra argument, so 'overfull' will become true. 1.492 + // 1.493 + 1.494 + size_t size = 0; 1.495 + bool constType = true; 1.496 + bool full = false; 1.497 + bool overFull = false; 1.498 + bool matrixInMatrix = false; 1.499 + bool arrayArg = false; 1.500 + for (size_t i = 0; i < function.getParamCount(); ++i) { 1.501 + const TParameter& param = function.getParam(i); 1.502 + size += param.type->getObjectSize(); 1.503 + 1.504 + if (constructingMatrix && param.type->isMatrix()) 1.505 + matrixInMatrix = true; 1.506 + if (full) 1.507 + overFull = true; 1.508 + if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) 1.509 + full = true; 1.510 + if (param.type->getQualifier() != EvqConst) 1.511 + constType = false; 1.512 + if (param.type->isArray()) 1.513 + arrayArg = true; 1.514 + } 1.515 + 1.516 + if (constType) 1.517 + type->setQualifier(EvqConst); 1.518 + 1.519 + if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) { 1.520 + error(line, "array constructor needs one argument per array element", "constructor"); 1.521 + return true; 1.522 + } 1.523 + 1.524 + if (arrayArg && op != EOpConstructStruct) { 1.525 + error(line, "constructing from a non-dereferenced array", "constructor"); 1.526 + return true; 1.527 + } 1.528 + 1.529 + if (matrixInMatrix && !type->isArray()) { 1.530 + if (function.getParamCount() != 1) { 1.531 + error(line, "constructing matrix from matrix can only take one argument", "constructor"); 1.532 + return true; 1.533 + } 1.534 + } 1.535 + 1.536 + if (overFull) { 1.537 + error(line, "too many arguments", "constructor"); 1.538 + return true; 1.539 + } 1.540 + 1.541 + if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->fields().size()) != function.getParamCount()) { 1.542 + error(line, "Number of constructor parameters does not match the number of structure fields", "constructor"); 1.543 + return true; 1.544 + } 1.545 + 1.546 + if (!type->isMatrix() || !matrixInMatrix) { 1.547 + if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || 1.548 + (op == EOpConstructStruct && size < type->getObjectSize())) { 1.549 + error(line, "not enough data provided for construction", "constructor"); 1.550 + return true; 1.551 + } 1.552 + } 1.553 + 1.554 + TIntermTyped *typed = node ? node->getAsTyped() : 0; 1.555 + if (typed == 0) { 1.556 + error(line, "constructor argument does not have a type", "constructor"); 1.557 + return true; 1.558 + } 1.559 + if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { 1.560 + error(line, "cannot convert a sampler", "constructor"); 1.561 + return true; 1.562 + } 1.563 + if (typed->getBasicType() == EbtVoid) { 1.564 + error(line, "cannot convert a void", "constructor"); 1.565 + return true; 1.566 + } 1.567 + 1.568 + return false; 1.569 +} 1.570 + 1.571 +// This function checks to see if a void variable has been declared and raise an error message for such a case 1.572 +// 1.573 +// returns true in case of an error 1.574 +// 1.575 +bool TParseContext::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType) 1.576 +{ 1.577 + if (pubType.type == EbtVoid) { 1.578 + error(line, "illegal use of type 'void'", identifier.c_str()); 1.579 + return true; 1.580 + } 1.581 + 1.582 + return false; 1.583 +} 1.584 + 1.585 +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not 1.586 +// 1.587 +// returns true in case of an error 1.588 +// 1.589 +bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type) 1.590 +{ 1.591 + if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { 1.592 + error(line, "boolean expression expected", ""); 1.593 + return true; 1.594 + } 1.595 + 1.596 + return false; 1.597 +} 1.598 + 1.599 +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not 1.600 +// 1.601 +// returns true in case of an error 1.602 +// 1.603 +bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType) 1.604 +{ 1.605 + if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) { 1.606 + error(line, "boolean expression expected", ""); 1.607 + return true; 1.608 + } 1.609 + 1.610 + return false; 1.611 +} 1.612 + 1.613 +bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason) 1.614 +{ 1.615 + if (pType.type == EbtStruct) { 1.616 + if (containsSampler(*pType.userDef)) { 1.617 + error(line, reason, getBasicString(pType.type), "(structure contains a sampler)"); 1.618 + 1.619 + return true; 1.620 + } 1.621 + 1.622 + return false; 1.623 + } else if (IsSampler(pType.type)) { 1.624 + error(line, reason, getBasicString(pType.type)); 1.625 + 1.626 + return true; 1.627 + } 1.628 + 1.629 + return false; 1.630 +} 1.631 + 1.632 +bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType) 1.633 +{ 1.634 + if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) && 1.635 + pType.type == EbtStruct) { 1.636 + error(line, "cannot be used with a structure", getQualifierString(pType.qualifier)); 1.637 + 1.638 + return true; 1.639 + } 1.640 + 1.641 + if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform")) 1.642 + return true; 1.643 + 1.644 + return false; 1.645 +} 1.646 + 1.647 +bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type) 1.648 +{ 1.649 + if ((qualifier == EvqOut || qualifier == EvqInOut) && 1.650 + type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { 1.651 + error(line, "samplers cannot be output parameters", type.getBasicString()); 1.652 + return true; 1.653 + } 1.654 + 1.655 + return false; 1.656 +} 1.657 + 1.658 +bool TParseContext::containsSampler(TType& type) 1.659 +{ 1.660 + if (IsSampler(type.getBasicType())) 1.661 + return true; 1.662 + 1.663 + if (type.getBasicType() == EbtStruct) { 1.664 + const TFieldList& fields = type.getStruct()->fields(); 1.665 + for (unsigned int i = 0; i < fields.size(); ++i) { 1.666 + if (containsSampler(*fields[i]->type())) 1.667 + return true; 1.668 + } 1.669 + } 1.670 + 1.671 + return false; 1.672 +} 1.673 + 1.674 +// 1.675 +// Do size checking for an array type's size. 1.676 +// 1.677 +// Returns true if there was an error. 1.678 +// 1.679 +bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size) 1.680 +{ 1.681 + TIntermConstantUnion* constant = expr->getAsConstantUnion(); 1.682 + if (constant == 0 || constant->getBasicType() != EbtInt) { 1.683 + error(line, "array size must be a constant integer expression", ""); 1.684 + return true; 1.685 + } 1.686 + 1.687 + size = constant->getIConst(0); 1.688 + 1.689 + if (size <= 0) { 1.690 + error(line, "array size must be a positive integer", ""); 1.691 + size = 1; 1.692 + return true; 1.693 + } 1.694 + 1.695 + return false; 1.696 +} 1.697 + 1.698 +// 1.699 +// See if this qualifier can be an array. 1.700 +// 1.701 +// Returns true if there is an error. 1.702 +// 1.703 +bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type) 1.704 +{ 1.705 + if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) { 1.706 + error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str()); 1.707 + return true; 1.708 + } 1.709 + 1.710 + return false; 1.711 +} 1.712 + 1.713 +// 1.714 +// See if this type can be an array. 1.715 +// 1.716 +// Returns true if there is an error. 1.717 +// 1.718 +bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type) 1.719 +{ 1.720 + // 1.721 + // Can the type be an array? 1.722 + // 1.723 + if (type.array) { 1.724 + error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str()); 1.725 + return true; 1.726 + } 1.727 + 1.728 + return false; 1.729 +} 1.730 + 1.731 +// 1.732 +// Do all the semantic checking for declaring an array, with and 1.733 +// without a size, and make the right changes to the symbol table. 1.734 +// 1.735 +// size == 0 means no specified size. 1.736 +// 1.737 +// Returns true if there was an error. 1.738 +// 1.739 +bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable) 1.740 +{ 1.741 + // 1.742 + // Don't check for reserved word use until after we know it's not in the symbol table, 1.743 + // because reserved arrays can be redeclared. 1.744 + // 1.745 + 1.746 + bool builtIn = false; 1.747 + bool sameScope = false; 1.748 + TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope); 1.749 + if (symbol == 0 || !sameScope) { 1.750 + if (reservedErrorCheck(line, identifier)) 1.751 + return true; 1.752 + 1.753 + variable = new TVariable(&identifier, TType(type)); 1.754 + 1.755 + if (type.arraySize) 1.756 + variable->getType().setArraySize(type.arraySize); 1.757 + 1.758 + if (! symbolTable.insert(*variable)) { 1.759 + delete variable; 1.760 + error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str()); 1.761 + return true; 1.762 + } 1.763 + } else { 1.764 + if (! symbol->isVariable()) { 1.765 + error(line, "variable expected", identifier.c_str()); 1.766 + return true; 1.767 + } 1.768 + 1.769 + variable = static_cast<TVariable*>(symbol); 1.770 + if (! variable->getType().isArray()) { 1.771 + error(line, "redeclaring non-array as array", identifier.c_str()); 1.772 + return true; 1.773 + } 1.774 + if (variable->getType().getArraySize() > 0) { 1.775 + error(line, "redeclaration of array with size", identifier.c_str()); 1.776 + return true; 1.777 + } 1.778 + 1.779 + if (! variable->getType().sameElementType(TType(type))) { 1.780 + error(line, "redeclaration of array with a different type", identifier.c_str()); 1.781 + return true; 1.782 + } 1.783 + 1.784 + if (type.arraySize) 1.785 + variable->getType().setArraySize(type.arraySize); 1.786 + } 1.787 + 1.788 + if (voidErrorCheck(line, identifier, type)) 1.789 + return true; 1.790 + 1.791 + return false; 1.792 +} 1.793 + 1.794 +// 1.795 +// Enforce non-initializer type/qualifier rules. 1.796 +// 1.797 +// Returns true if there was an error. 1.798 +// 1.799 +bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array) 1.800 +{ 1.801 + if (type.qualifier == EvqConst) 1.802 + { 1.803 + // Make the qualifier make sense. 1.804 + type.qualifier = EvqTemporary; 1.805 + 1.806 + if (array) 1.807 + { 1.808 + error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str()); 1.809 + } 1.810 + else if (type.isStructureContainingArrays()) 1.811 + { 1.812 + error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str()); 1.813 + } 1.814 + else 1.815 + { 1.816 + error(line, "variables with qualifier 'const' must be initialized", identifier.c_str()); 1.817 + } 1.818 + 1.819 + return true; 1.820 + } 1.821 + 1.822 + return false; 1.823 +} 1.824 + 1.825 +// 1.826 +// Do semantic checking for a variable declaration that has no initializer, 1.827 +// and update the symbol table. 1.828 +// 1.829 +// Returns true if there was an error. 1.830 +// 1.831 +bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable) 1.832 +{ 1.833 + if (reservedErrorCheck(line, identifier)) 1.834 + recover(); 1.835 + 1.836 + variable = new TVariable(&identifier, TType(type)); 1.837 + 1.838 + if (! symbolTable.insert(*variable)) { 1.839 + error(line, "redefinition", variable->getName().c_str()); 1.840 + delete variable; 1.841 + variable = 0; 1.842 + return true; 1.843 + } 1.844 + 1.845 + if (voidErrorCheck(line, identifier, type)) 1.846 + return true; 1.847 + 1.848 + return false; 1.849 +} 1.850 + 1.851 +bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type) 1.852 +{ 1.853 + if (qualifier != EvqConst && qualifier != EvqTemporary) { 1.854 + error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier)); 1.855 + return true; 1.856 + } 1.857 + if (qualifier == EvqConst && paramQualifier != EvqIn) { 1.858 + error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier)); 1.859 + return true; 1.860 + } 1.861 + 1.862 + if (qualifier == EvqConst) 1.863 + type->setQualifier(EvqConstReadOnly); 1.864 + else 1.865 + type->setQualifier(paramQualifier); 1.866 + 1.867 + return false; 1.868 +} 1.869 + 1.870 +bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension) 1.871 +{ 1.872 + const TExtensionBehavior& extBehavior = extensionBehavior(); 1.873 + TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); 1.874 + if (iter == extBehavior.end()) { 1.875 + error(line, "extension", extension.c_str(), "is not supported"); 1.876 + return true; 1.877 + } 1.878 + // In GLSL ES, an extension's default behavior is "disable". 1.879 + if (iter->second == EBhDisable || iter->second == EBhUndefined) { 1.880 + error(line, "extension", extension.c_str(), "is disabled"); 1.881 + return true; 1.882 + } 1.883 + if (iter->second == EBhWarn) { 1.884 + warning(line, "extension", extension.c_str(), "is being used"); 1.885 + return false; 1.886 + } 1.887 + 1.888 + return false; 1.889 +} 1.890 + 1.891 +bool TParseContext::supportsExtension(const char* extension) 1.892 +{ 1.893 + const TExtensionBehavior& extbehavior = extensionBehavior(); 1.894 + TExtensionBehavior::const_iterator iter = extbehavior.find(extension); 1.895 + return (iter != extbehavior.end()); 1.896 +} 1.897 + 1.898 +bool TParseContext::isExtensionEnabled(const char* extension) const 1.899 +{ 1.900 + const TExtensionBehavior& extbehavior = extensionBehavior(); 1.901 + TExtensionBehavior::const_iterator iter = extbehavior.find(extension); 1.902 + 1.903 + if (iter == extbehavior.end()) 1.904 + { 1.905 + return false; 1.906 + } 1.907 + 1.908 + return (iter->second == EBhEnable || iter->second == EBhRequire); 1.909 +} 1.910 + 1.911 +///////////////////////////////////////////////////////////////////////////////// 1.912 +// 1.913 +// Non-Errors. 1.914 +// 1.915 +///////////////////////////////////////////////////////////////////////////////// 1.916 + 1.917 +// 1.918 +// Look up a function name in the symbol table, and make sure it is a function. 1.919 +// 1.920 +// Return the function symbol if found, otherwise 0. 1.921 +// 1.922 +const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, bool *builtIn) 1.923 +{ 1.924 + // First find by unmangled name to check whether the function name has been 1.925 + // hidden by a variable name or struct typename. 1.926 + // If a function is found, check for one with a matching argument list. 1.927 + const TSymbol* symbol = symbolTable.find(call->getName(), builtIn); 1.928 + if (symbol == 0 || symbol->isFunction()) { 1.929 + symbol = symbolTable.find(call->getMangledName(), builtIn); 1.930 + } 1.931 + 1.932 + if (symbol == 0) { 1.933 + error(line, "no matching overloaded function found", call->getName().c_str()); 1.934 + return 0; 1.935 + } 1.936 + 1.937 + if (!symbol->isFunction()) { 1.938 + error(line, "function name expected", call->getName().c_str()); 1.939 + return 0; 1.940 + } 1.941 + 1.942 + return static_cast<const TFunction*>(symbol); 1.943 +} 1.944 + 1.945 +// 1.946 +// Initializers show up in several places in the grammar. Have one set of 1.947 +// code to handle them here. 1.948 +// 1.949 +bool TParseContext::executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType, 1.950 + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) 1.951 +{ 1.952 + TType type = TType(pType); 1.953 + 1.954 + if (variable == 0) { 1.955 + if (reservedErrorCheck(line, identifier)) 1.956 + return true; 1.957 + 1.958 + if (voidErrorCheck(line, identifier, pType)) 1.959 + return true; 1.960 + 1.961 + // 1.962 + // add variable to symbol table 1.963 + // 1.964 + variable = new TVariable(&identifier, type); 1.965 + if (! symbolTable.insert(*variable)) { 1.966 + error(line, "redefinition", variable->getName().c_str()); 1.967 + return true; 1.968 + // don't delete variable, it's used by error recovery, and the pool 1.969 + // pop will take care of the memory 1.970 + } 1.971 + } 1.972 + 1.973 + // 1.974 + // identifier must be of type constant, a global, or a temporary 1.975 + // 1.976 + TQualifier qualifier = variable->getType().getQualifier(); 1.977 + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) { 1.978 + error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString()); 1.979 + return true; 1.980 + } 1.981 + // 1.982 + // test for and propagate constant 1.983 + // 1.984 + 1.985 + if (qualifier == EvqConst) { 1.986 + if (qualifier != initializer->getType().getQualifier()) { 1.987 + std::stringstream extraInfoStream; 1.988 + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; 1.989 + std::string extraInfo = extraInfoStream.str(); 1.990 + error(line, " assigning non-constant to", "=", extraInfo.c_str()); 1.991 + variable->getType().setQualifier(EvqTemporary); 1.992 + return true; 1.993 + } 1.994 + if (type != initializer->getType()) { 1.995 + error(line, " non-matching types for const initializer ", 1.996 + variable->getType().getQualifierString()); 1.997 + variable->getType().setQualifier(EvqTemporary); 1.998 + return true; 1.999 + } 1.1000 + if (initializer->getAsConstantUnion()) { 1.1001 + variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); 1.1002 + } else if (initializer->getAsSymbolNode()) { 1.1003 + const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); 1.1004 + const TVariable* tVar = static_cast<const TVariable*>(symbol); 1.1005 + 1.1006 + ConstantUnion* constArray = tVar->getConstPointer(); 1.1007 + variable->shareConstPointer(constArray); 1.1008 + } else { 1.1009 + std::stringstream extraInfoStream; 1.1010 + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; 1.1011 + std::string extraInfo = extraInfoStream.str(); 1.1012 + error(line, " cannot assign to", "=", extraInfo.c_str()); 1.1013 + variable->getType().setQualifier(EvqTemporary); 1.1014 + return true; 1.1015 + } 1.1016 + } 1.1017 + 1.1018 + if (qualifier != EvqConst) { 1.1019 + TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); 1.1020 + intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); 1.1021 + if (intermNode == 0) { 1.1022 + assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); 1.1023 + return true; 1.1024 + } 1.1025 + } else 1.1026 + intermNode = 0; 1.1027 + 1.1028 + return false; 1.1029 +} 1.1030 + 1.1031 +bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) 1.1032 +{ 1.1033 + ASSERT(aggrNode != NULL); 1.1034 + if (!aggrNode->isConstructor()) 1.1035 + return false; 1.1036 + 1.1037 + bool allConstant = true; 1.1038 + 1.1039 + // check if all the child nodes are constants so that they can be inserted into 1.1040 + // the parent node 1.1041 + TIntermSequence &sequence = aggrNode->getSequence() ; 1.1042 + for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) { 1.1043 + if (!(*p)->getAsTyped()->getAsConstantUnion()) 1.1044 + return false; 1.1045 + } 1.1046 + 1.1047 + return allConstant; 1.1048 +} 1.1049 + 1.1050 +// This function is used to test for the correctness of the parameters passed to various constructor functions 1.1051 +// and also convert them to the right datatype if it is allowed and required. 1.1052 +// 1.1053 +// Returns 0 for an error or the constructed node (aggregate or typed) for no error. 1.1054 +// 1.1055 +TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line) 1.1056 +{ 1.1057 + if (node == 0) 1.1058 + return 0; 1.1059 + 1.1060 + TIntermAggregate* aggrNode = node->getAsAggregate(); 1.1061 + 1.1062 + TFieldList::const_iterator memberFields; 1.1063 + if (op == EOpConstructStruct) 1.1064 + memberFields = type->getStruct()->fields().begin(); 1.1065 + 1.1066 + TType elementType = *type; 1.1067 + if (type->isArray()) 1.1068 + elementType.clearArrayness(); 1.1069 + 1.1070 + bool singleArg; 1.1071 + if (aggrNode) { 1.1072 + if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) 1.1073 + singleArg = true; 1.1074 + else 1.1075 + singleArg = false; 1.1076 + } else 1.1077 + singleArg = true; 1.1078 + 1.1079 + TIntermTyped *newNode; 1.1080 + if (singleArg) { 1.1081 + // If structure constructor or array constructor is being called 1.1082 + // for only one parameter inside the structure, we need to call constructStruct function once. 1.1083 + if (type->isArray()) 1.1084 + newNode = constructStruct(node, &elementType, 1, node->getLine(), false); 1.1085 + else if (op == EOpConstructStruct) 1.1086 + newNode = constructStruct(node, (*memberFields)->type(), 1, node->getLine(), false); 1.1087 + else 1.1088 + newNode = constructBuiltIn(type, op, node, node->getLine(), false); 1.1089 + 1.1090 + if (newNode && newNode->getAsAggregate()) { 1.1091 + TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type); 1.1092 + if (constConstructor) 1.1093 + return constConstructor; 1.1094 + } 1.1095 + 1.1096 + return newNode; 1.1097 + } 1.1098 + 1.1099 + // 1.1100 + // Handle list of arguments. 1.1101 + // 1.1102 + TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor 1.1103 + // if the structure constructor contains more than one parameter, then construct 1.1104 + // each parameter 1.1105 + 1.1106 + int paramCount = 0; // keeps a track of the constructor parameter number being checked 1.1107 + 1.1108 + // for each parameter to the constructor call, check to see if the right type is passed or convert them 1.1109 + // to the right type if possible (and allowed). 1.1110 + // for structure constructors, just check if the right type is passed, no conversion is allowed. 1.1111 + 1.1112 + for (TIntermSequence::iterator p = sequenceVector.begin(); 1.1113 + p != sequenceVector.end(); p++, paramCount++) { 1.1114 + if (type->isArray()) 1.1115 + newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true); 1.1116 + else if (op == EOpConstructStruct) 1.1117 + newNode = constructStruct(*p, memberFields[paramCount]->type(), paramCount+1, node->getLine(), true); 1.1118 + else 1.1119 + newNode = constructBuiltIn(type, op, *p, node->getLine(), true); 1.1120 + 1.1121 + if (newNode) { 1.1122 + *p = newNode; 1.1123 + } 1.1124 + } 1.1125 + 1.1126 + TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line); 1.1127 + TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); 1.1128 + if (constConstructor) 1.1129 + return constConstructor; 1.1130 + 1.1131 + return constructor; 1.1132 +} 1.1133 + 1.1134 +TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) 1.1135 +{ 1.1136 + bool canBeFolded = areAllChildConst(aggrNode); 1.1137 + aggrNode->setType(type); 1.1138 + if (canBeFolded) { 1.1139 + bool returnVal = false; 1.1140 + ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; 1.1141 + if (aggrNode->getSequence().size() == 1) { 1.1142 + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true); 1.1143 + } 1.1144 + else { 1.1145 + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type); 1.1146 + } 1.1147 + if (returnVal) 1.1148 + return 0; 1.1149 + 1.1150 + return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); 1.1151 + } 1.1152 + 1.1153 + return 0; 1.1154 +} 1.1155 + 1.1156 +// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value 1.1157 +// for the parameter to the constructor (passed to this function). Essentially, it converts 1.1158 +// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a 1.1159 +// float, then float is converted to int. 1.1160 +// 1.1161 +// Returns 0 for an error or the constructed node. 1.1162 +// 1.1163 +TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset) 1.1164 +{ 1.1165 + TIntermTyped* newNode; 1.1166 + TOperator basicOp; 1.1167 + 1.1168 + // 1.1169 + // First, convert types as needed. 1.1170 + // 1.1171 + switch (op) { 1.1172 + case EOpConstructVec2: 1.1173 + case EOpConstructVec3: 1.1174 + case EOpConstructVec4: 1.1175 + case EOpConstructMat2: 1.1176 + case EOpConstructMat3: 1.1177 + case EOpConstructMat4: 1.1178 + case EOpConstructFloat: 1.1179 + basicOp = EOpConstructFloat; 1.1180 + break; 1.1181 + 1.1182 + case EOpConstructIVec2: 1.1183 + case EOpConstructIVec3: 1.1184 + case EOpConstructIVec4: 1.1185 + case EOpConstructInt: 1.1186 + basicOp = EOpConstructInt; 1.1187 + break; 1.1188 + 1.1189 + case EOpConstructBVec2: 1.1190 + case EOpConstructBVec3: 1.1191 + case EOpConstructBVec4: 1.1192 + case EOpConstructBool: 1.1193 + basicOp = EOpConstructBool; 1.1194 + break; 1.1195 + 1.1196 + default: 1.1197 + error(line, "unsupported construction", ""); 1.1198 + recover(); 1.1199 + 1.1200 + return 0; 1.1201 + } 1.1202 + newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable); 1.1203 + if (newNode == 0) { 1.1204 + error(line, "can't convert", "constructor"); 1.1205 + return 0; 1.1206 + } 1.1207 + 1.1208 + // 1.1209 + // Now, if there still isn't an operation to do the construction, and we need one, add one. 1.1210 + // 1.1211 + 1.1212 + // Otherwise, skip out early. 1.1213 + if (subset || (newNode != node && newNode->getType() == *type)) 1.1214 + return newNode; 1.1215 + 1.1216 + // setAggregateOperator will insert a new node for the constructor, as needed. 1.1217 + return intermediate.setAggregateOperator(newNode, op, line); 1.1218 +} 1.1219 + 1.1220 +// This function tests for the type of the parameters to the structures constructors. Raises 1.1221 +// an error message if the expected type does not match the parameter passed to the constructor. 1.1222 +// 1.1223 +// Returns 0 for an error or the input node itself if the expected and the given parameter types match. 1.1224 +// 1.1225 +TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset) 1.1226 +{ 1.1227 + if (*type == node->getAsTyped()->getType()) { 1.1228 + if (subset) 1.1229 + return node->getAsTyped(); 1.1230 + else 1.1231 + return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); 1.1232 + } else { 1.1233 + std::stringstream extraInfoStream; 1.1234 + extraInfoStream << "cannot convert parameter " << paramCount 1.1235 + << " from '" << node->getAsTyped()->getType().getBasicString() 1.1236 + << "' to '" << type->getBasicString() << "'"; 1.1237 + std::string extraInfo = extraInfoStream.str(); 1.1238 + error(line, "", "constructor", extraInfo.c_str()); 1.1239 + recover(); 1.1240 + } 1.1241 + 1.1242 + return 0; 1.1243 +} 1.1244 + 1.1245 +// 1.1246 +// This function returns the tree representation for the vector field(s) being accessed from contant vector. 1.1247 +// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is 1.1248 +// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol 1.1249 +// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of 1.1250 +// a constant matrix. 1.1251 +// 1.1252 +TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line) 1.1253 +{ 1.1254 + TIntermTyped* typedNode; 1.1255 + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); 1.1256 + 1.1257 + ConstantUnion *unionArray; 1.1258 + if (tempConstantNode) { 1.1259 + unionArray = tempConstantNode->getUnionArrayPointer(); 1.1260 + 1.1261 + if (!unionArray) { 1.1262 + return node; 1.1263 + } 1.1264 + } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error 1.1265 + error(line, "Cannot offset into the vector", "Error"); 1.1266 + recover(); 1.1267 + 1.1268 + return 0; 1.1269 + } 1.1270 + 1.1271 + ConstantUnion* constArray = new ConstantUnion[fields.num]; 1.1272 + 1.1273 + for (int i = 0; i < fields.num; i++) { 1.1274 + if (fields.offsets[i] >= node->getType().getNominalSize()) { 1.1275 + std::stringstream extraInfoStream; 1.1276 + extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; 1.1277 + std::string extraInfo = extraInfoStream.str(); 1.1278 + error(line, "", "[", extraInfo.c_str()); 1.1279 + recover(); 1.1280 + fields.offsets[i] = 0; 1.1281 + } 1.1282 + 1.1283 + constArray[i] = unionArray[fields.offsets[i]]; 1.1284 + 1.1285 + } 1.1286 + typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); 1.1287 + return typedNode; 1.1288 +} 1.1289 + 1.1290 +// 1.1291 +// This function returns the column being accessed from a constant matrix. The values are retrieved from 1.1292 +// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input 1.1293 +// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a 1.1294 +// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) 1.1295 +// 1.1296 +TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line) 1.1297 +{ 1.1298 + TIntermTyped* typedNode; 1.1299 + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); 1.1300 + 1.1301 + if (index >= node->getType().getNominalSize()) { 1.1302 + std::stringstream extraInfoStream; 1.1303 + extraInfoStream << "matrix field selection out of range '" << index << "'"; 1.1304 + std::string extraInfo = extraInfoStream.str(); 1.1305 + error(line, "", "[", extraInfo.c_str()); 1.1306 + recover(); 1.1307 + index = 0; 1.1308 + } 1.1309 + 1.1310 + if (tempConstantNode) { 1.1311 + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); 1.1312 + int size = tempConstantNode->getType().getNominalSize(); 1.1313 + typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); 1.1314 + } else { 1.1315 + error(line, "Cannot offset into the matrix", "Error"); 1.1316 + recover(); 1.1317 + 1.1318 + return 0; 1.1319 + } 1.1320 + 1.1321 + return typedNode; 1.1322 +} 1.1323 + 1.1324 + 1.1325 +// 1.1326 +// This function returns an element of an array accessed from a constant array. The values are retrieved from 1.1327 +// the symbol table and parse-tree is built for the type of the element. The input 1.1328 +// to the function could either be a symbol node (a[0] where a is a constant array)that represents a 1.1329 +// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) 1.1330 +// 1.1331 +TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line) 1.1332 +{ 1.1333 + TIntermTyped* typedNode; 1.1334 + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); 1.1335 + TType arrayElementType = node->getType(); 1.1336 + arrayElementType.clearArrayness(); 1.1337 + 1.1338 + if (index >= node->getType().getArraySize()) { 1.1339 + std::stringstream extraInfoStream; 1.1340 + extraInfoStream << "array field selection out of range '" << index << "'"; 1.1341 + std::string extraInfo = extraInfoStream.str(); 1.1342 + error(line, "", "[", extraInfo.c_str()); 1.1343 + recover(); 1.1344 + index = 0; 1.1345 + } 1.1346 + 1.1347 + if (tempConstantNode) { 1.1348 + size_t arrayElementSize = arrayElementType.getObjectSize(); 1.1349 + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); 1.1350 + typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); 1.1351 + } else { 1.1352 + error(line, "Cannot offset into the array", "Error"); 1.1353 + recover(); 1.1354 + 1.1355 + return 0; 1.1356 + } 1.1357 + 1.1358 + return typedNode; 1.1359 +} 1.1360 + 1.1361 + 1.1362 +// 1.1363 +// This function returns the value of a particular field inside a constant structure from the symbol table. 1.1364 +// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr 1.1365 +// function and returns the parse-tree with the values of the embedded/nested struct. 1.1366 +// 1.1367 +TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, const TSourceLoc& line) 1.1368 +{ 1.1369 + const TFieldList& fields = node->getType().getStruct()->fields(); 1.1370 + 1.1371 + size_t instanceSize = 0; 1.1372 + for (size_t index = 0; index < fields.size(); ++index) { 1.1373 + if (fields[index]->name() == identifier) { 1.1374 + break; 1.1375 + } else { 1.1376 + instanceSize += fields[index]->type()->getObjectSize(); 1.1377 + } 1.1378 + } 1.1379 + 1.1380 + TIntermTyped* typedNode = 0; 1.1381 + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); 1.1382 + if (tempConstantNode) { 1.1383 + ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); 1.1384 + 1.1385 + typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function 1.1386 + } else { 1.1387 + error(line, "Cannot offset into the structure", "Error"); 1.1388 + recover(); 1.1389 + 1.1390 + return 0; 1.1391 + } 1.1392 + 1.1393 + return typedNode; 1.1394 +} 1.1395 + 1.1396 +bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier) 1.1397 +{ 1.1398 + ++structNestingLevel; 1.1399 + 1.1400 + // Embedded structure definitions are not supported per GLSL ES spec. 1.1401 + // They aren't allowed in GLSL either, but we need to detect this here 1.1402 + // so we don't rely on the GLSL compiler to catch it. 1.1403 + if (structNestingLevel > 1) { 1.1404 + error(line, "", "Embedded struct definitions are not allowed"); 1.1405 + return true; 1.1406 + } 1.1407 + 1.1408 + return false; 1.1409 +} 1.1410 + 1.1411 +void TParseContext::exitStructDeclaration() 1.1412 +{ 1.1413 + --structNestingLevel; 1.1414 +} 1.1415 + 1.1416 +namespace { 1.1417 + 1.1418 +const int kWebGLMaxStructNesting = 4; 1.1419 + 1.1420 +} // namespace 1.1421 + 1.1422 +bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field) 1.1423 +{ 1.1424 + if (!isWebGLBasedSpec(shaderSpec)) { 1.1425 + return false; 1.1426 + } 1.1427 + 1.1428 + if (field.type()->getBasicType() != EbtStruct) { 1.1429 + return false; 1.1430 + } 1.1431 + 1.1432 + // We're already inside a structure definition at this point, so add 1.1433 + // one to the field's struct nesting. 1.1434 + if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) { 1.1435 + std::stringstream extraInfoStream; 1.1436 + extraInfoStream << "Reference of struct type " << field.name() 1.1437 + << " exceeds maximum struct nesting of " << kWebGLMaxStructNesting; 1.1438 + std::string extraInfo = extraInfoStream.str(); 1.1439 + error(line, "", "", extraInfo.c_str()); 1.1440 + return true; 1.1441 + } 1.1442 + 1.1443 + return false; 1.1444 +} 1.1445 + 1.1446 +// 1.1447 +// Parse an array index expression 1.1448 +// 1.1449 +TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression) 1.1450 +{ 1.1451 + TIntermTyped *indexedExpression = NULL; 1.1452 + 1.1453 + if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) 1.1454 + { 1.1455 + if (baseExpression->getAsSymbolNode()) 1.1456 + { 1.1457 + error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str()); 1.1458 + } 1.1459 + else 1.1460 + { 1.1461 + error(location, " left of '[' is not of type array, matrix, or vector ", "expression"); 1.1462 + } 1.1463 + recover(); 1.1464 + } 1.1465 + 1.1466 + if (indexExpression->getQualifier() == EvqConst) 1.1467 + { 1.1468 + int index = indexExpression->getAsConstantUnion()->getIConst(0); 1.1469 + if (index < 0) 1.1470 + { 1.1471 + std::stringstream infoStream; 1.1472 + infoStream << index; 1.1473 + std::string info = infoStream.str(); 1.1474 + error(location, "negative index", info.c_str()); 1.1475 + recover(); 1.1476 + index = 0; 1.1477 + } 1.1478 + if (baseExpression->getType().getQualifier() == EvqConst) 1.1479 + { 1.1480 + if (baseExpression->isArray()) 1.1481 + { 1.1482 + // constant folding for arrays 1.1483 + indexedExpression = addConstArrayNode(index, baseExpression, location); 1.1484 + } 1.1485 + else if (baseExpression->isVector()) 1.1486 + { 1.1487 + // constant folding for vectors 1.1488 + TVectorFields fields; 1.1489 + fields.num = 1; 1.1490 + fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array 1.1491 + indexedExpression = addConstVectorNode(fields, baseExpression, location); 1.1492 + } 1.1493 + else if (baseExpression->isMatrix()) 1.1494 + { 1.1495 + // constant folding for matrices 1.1496 + indexedExpression = addConstMatrixNode(index, baseExpression, location); 1.1497 + } 1.1498 + } 1.1499 + else 1.1500 + { 1.1501 + if (baseExpression->isArray()) 1.1502 + { 1.1503 + if (index >= baseExpression->getType().getArraySize()) 1.1504 + { 1.1505 + std::stringstream extraInfoStream; 1.1506 + extraInfoStream << "array index out of range '" << index << "'"; 1.1507 + std::string extraInfo = extraInfoStream.str(); 1.1508 + error(location, "", "[", extraInfo.c_str()); 1.1509 + recover(); 1.1510 + index = baseExpression->getType().getArraySize() - 1; 1.1511 + } 1.1512 + else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers")) 1.1513 + { 1.1514 + error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled"); 1.1515 + recover(); 1.1516 + index = 0; 1.1517 + } 1.1518 + } 1.1519 + else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index) 1.1520 + { 1.1521 + std::stringstream extraInfoStream; 1.1522 + extraInfoStream << "field selection out of range '" << index << "'"; 1.1523 + std::string extraInfo = extraInfoStream.str(); 1.1524 + error(location, "", "[", extraInfo.c_str()); 1.1525 + recover(); 1.1526 + index = baseExpression->getType().getNominalSize() - 1; 1.1527 + } 1.1528 + 1.1529 + indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index); 1.1530 + indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); 1.1531 + } 1.1532 + } 1.1533 + else 1.1534 + { 1.1535 + indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location); 1.1536 + } 1.1537 + 1.1538 + if (indexedExpression == 0) 1.1539 + { 1.1540 + ConstantUnion *unionArray = new ConstantUnion[1]; 1.1541 + unionArray->setFConst(0.0f); 1.1542 + indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location); 1.1543 + } 1.1544 + else if (baseExpression->isArray()) 1.1545 + { 1.1546 + const TType &baseType = baseExpression->getType(); 1.1547 + if (baseType.getStruct()) 1.1548 + { 1.1549 + TType copyOfType(baseType.getStruct()); 1.1550 + indexedExpression->setType(copyOfType); 1.1551 + } 1.1552 + else 1.1553 + { 1.1554 + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->isMatrix())); 1.1555 + } 1.1556 + 1.1557 + if (baseExpression->getType().getQualifier() == EvqConst) 1.1558 + { 1.1559 + indexedExpression->getTypePointer()->setQualifier(EvqConst); 1.1560 + } 1.1561 + } 1.1562 + else if (baseExpression->isMatrix()) 1.1563 + { 1.1564 + TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary; 1.1565 + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getNominalSize())); 1.1566 + } 1.1567 + else if (baseExpression->isVector()) 1.1568 + { 1.1569 + TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary; 1.1570 + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier)); 1.1571 + } 1.1572 + else 1.1573 + { 1.1574 + indexedExpression->setType(baseExpression->getType()); 1.1575 + } 1.1576 + 1.1577 + return indexedExpression; 1.1578 +} 1.1579 + 1.1580 +// 1.1581 +// Parse an array of strings using yyparse. 1.1582 +// 1.1583 +// Returns 0 for success. 1.1584 +// 1.1585 +int PaParseStrings(size_t count, const char* const string[], const int length[], 1.1586 + TParseContext* context) { 1.1587 + if ((count == 0) || (string == NULL)) 1.1588 + return 1; 1.1589 + 1.1590 + if (glslang_initialize(context)) 1.1591 + return 1; 1.1592 + 1.1593 + int error = glslang_scan(count, string, length, context); 1.1594 + if (!error) 1.1595 + error = glslang_parse(context); 1.1596 + 1.1597 + glslang_finalize(context); 1.1598 + 1.1599 + return (error == 0) && (context->numErrors() == 0) ? 0 : 1; 1.1600 +} 1.1601 + 1.1602 + 1.1603 +