/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Commercial Usage ** ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ #include "glslsemantic.h" #include "glslengine.h" #include "glslparser.h" #include "glslsymbols.h" #include "glsltypes.h" #include using namespace GLSL; Semantic::Semantic() : _engine(0) , _scope(0) , _type(0) { } Semantic::~Semantic() { } Engine *Semantic::switchEngine(Engine *engine) { Engine *previousEngine = _engine; _engine = engine; return previousEngine; } Scope *Semantic::switchScope(Scope *scope) { Scope *previousScope = _scope; _scope = scope; return previousScope; } Semantic::ExprResult Semantic::expression(ExpressionAST *ast) { Semantic::ExprResult r(_engine->undefinedType()); std::swap(_expr, r); accept(ast); std::swap(_expr, r); return r; } void Semantic::statement(StatementAST *ast) { accept(ast); } const Type *Semantic::type(TypeAST *ast) { const Type *t = _engine->undefinedType(); std::swap(_type, t); accept(ast); std::swap(_type, t); return t; } void Semantic::declaration(DeclarationAST *ast) { accept(ast); } void Semantic::translationUnit(TranslationUnitAST *ast, Scope *globalScope, Engine *engine) { Engine *previousEngine = switchEngine(engine); Scope *previousScope = switchScope(globalScope); if (ast) { for (List *it = ast->declarations; it; it = it->next) { DeclarationAST *decl = it->value; declaration(decl); } } (void) switchScope(previousScope); (void) switchEngine(previousEngine); } Semantic::ExprResult Semantic::functionIdentifier(FunctionIdentifierAST *ast) { ExprResult result; if (ast) { if (ast->name) { if (Symbol *s = _scope->lookup(*ast->name)) { if (s->asOverloadSet() != 0 || s->asFunction() != 0) result.type = s->type(); else _engine->error(ast->lineno, QString("`%1' cannot be used as a function").arg(*ast->name)); } else { _engine->error(ast->lineno, QString("`%1' was not declared in this scope").arg(*ast->name)); } } else if (ast->type) { const Type *ty = type(ast->type); result.type = ty; } } return result; } Symbol *Semantic::field(StructTypeAST::Field *ast) { // ast->name const Type *ty = type(ast->type); QString name; if (ast->name) name = *ast->name; return _engine->newVariable(_scope, name, ty); } void Semantic::parameterDeclaration(ParameterDeclarationAST *ast, Function *fun) { const Type *ty = type(ast->type); QString name; if (ast->name) name = *ast->name; Argument *arg = _engine->newArgument(fun, name, ty); fun->addArgument(arg); } bool Semantic::visit(TranslationUnitAST *ast) { Q_UNUSED(ast); Q_ASSERT(!"unreachable"); return false; } bool Semantic::visit(FunctionIdentifierAST *ast) { Q_UNUSED(ast); Q_ASSERT(!"unreachable"); return false; } bool Semantic::visit(StructTypeAST::Field *ast) { Q_UNUSED(ast); Q_ASSERT(!"unreachable"); return false; } // expressions bool Semantic::visit(IdentifierExpressionAST *ast) { if (ast->name) { if (Symbol *s = _scope->lookup(*ast->name)) { _expr.type = s->type(); } else { if (ast->name->startsWith(QLatin1String("gl_")) || ast->name->startsWith(QLatin1String("qgl_"))) { // ### well, at least for now. } else { _engine->error(ast->lineno, QString("`%1' was not declared in this scope").arg(*ast->name)); } } } return false; } bool Semantic::visit(LiteralExpressionAST *ast) { if (ast->value) { _expr.isConstant = true; if (ast->value->endsWith(QLatin1Char('u')) || ast->value->endsWith(QLatin1Char('U'))) _expr.type = _engine->uintType(); else if (ast->value->endsWith(QLatin1Char('d')) || ast->value->endsWith(QLatin1Char('d'))) _expr.type = _engine->doubleType(); else if (ast->value->endsWith(QLatin1Char('f')) || ast->value->endsWith(QLatin1Char('f')) || ast->value->contains(QLatin1Char('.'))) _expr.type = _engine->floatType(); else _expr.type = _engine->intType(); } return false; } bool Semantic::visit(BinaryExpressionAST *ast) { ExprResult left = expression(ast->left); ExprResult right = expression(ast->right); _expr.isConstant = left.isConstant && right.isConstant; return false; } bool Semantic::visit(UnaryExpressionAST *ast) { ExprResult expr = expression(ast->expr); _expr.isConstant = expr.isConstant; return false; } bool Semantic::visit(TernaryExpressionAST *ast) { ExprResult first = expression(ast->first); ExprResult second = expression(ast->second); ExprResult third = expression(ast->third); _expr.isConstant = first.isConstant && second.isConstant && third.isConstant; return false; } bool Semantic::visit(AssignmentExpressionAST *ast) { ExprResult variable = expression(ast->variable); ExprResult value = expression(ast->value); return false; } bool Semantic::visit(MemberAccessExpressionAST *ast) { ExprResult expr = expression(ast->expr); // ast->field return false; } bool Semantic::visit(FunctionCallExpressionAST *ast) { ExprResult expr = expression(ast->expr); ExprResult id = functionIdentifier(ast->id); for (List *it = ast->arguments; it; it = it->next) { ExprResult arg = expression(it->value); } return false; } bool Semantic::visit(DeclarationExpressionAST *ast) { const Type *ty = type(ast->type); Q_UNUSED(ty); // ast->name ExprResult initializer = expression(ast->initializer); return false; } // statements bool Semantic::visit(ExpressionStatementAST *ast) { ExprResult expr = expression(ast->expr); return false; } bool Semantic::visit(CompoundStatementAST *ast) { Scope *previousScope = switchScope(_engine->newBlock(_scope)); for (List *it = ast->statements; it; it = it->next) { StatementAST *stmt = it->value; statement(stmt); } (void) switchScope(previousScope); return false; } bool Semantic::visit(IfStatementAST *ast) { ExprResult condition = expression(ast->condition); statement(ast->thenClause); statement(ast->elseClause); return false; } bool Semantic::visit(WhileStatementAST *ast) { ExprResult condition = expression(ast->condition); statement(ast->body); return false; } bool Semantic::visit(DoStatementAST *ast) { statement(ast->body); ExprResult condition = expression(ast->condition); return false; } bool Semantic::visit(ForStatementAST *ast) { statement(ast->init); ExprResult condition = expression(ast->condition); ExprResult increment = expression(ast->increment); statement(ast->body); return false; } bool Semantic::visit(JumpStatementAST *ast) { Q_UNUSED(ast); return false; } bool Semantic::visit(ReturnStatementAST *ast) { ExprResult expr = expression(ast->expr); return false; } bool Semantic::visit(SwitchStatementAST *ast) { ExprResult expr = expression(ast->expr); statement(ast->body); return false; } bool Semantic::visit(CaseLabelStatementAST *ast) { ExprResult expr = expression(ast->expr); return false; } bool Semantic::visit(DeclarationStatementAST *ast) { declaration(ast->decl); return false; } // types bool Semantic::visit(BasicTypeAST *ast) { switch (ast->token) { case Parser::T_VOID: _type = _engine->voidType(); break; case Parser::T_BOOL: _type = _engine->boolType(); break; case Parser::T_INT: _type = _engine->intType(); break; case Parser::T_UINT: _type = _engine->uintType(); break; case Parser::T_FLOAT: _type = _engine->floatType(); break; case Parser::T_DOUBLE: _type = _engine->doubleType(); break; // bvec case Parser::T_BVEC2: _type = _engine->vectorType(_engine->boolType(), 2); break; case Parser::T_BVEC3: _type = _engine->vectorType(_engine->boolType(), 3); break; case Parser::T_BVEC4: _type = _engine->vectorType(_engine->boolType(), 4); break; // ivec case Parser::T_IVEC2: _type = _engine->vectorType(_engine->intType(), 2); break; case Parser::T_IVEC3: _type = _engine->vectorType(_engine->intType(), 3); break; case Parser::T_IVEC4: _type = _engine->vectorType(_engine->intType(), 4); break; // uvec case Parser::T_UVEC2: _type = _engine->vectorType(_engine->uintType(), 2); break; case Parser::T_UVEC3: _type = _engine->vectorType(_engine->uintType(), 3); break; case Parser::T_UVEC4: _type = _engine->vectorType(_engine->uintType(), 4); break; // vec case Parser::T_VEC2: _type = _engine->vectorType(_engine->floatType(), 2); break; case Parser::T_VEC3: _type = _engine->vectorType(_engine->floatType(), 3); break; case Parser::T_VEC4: _type = _engine->vectorType(_engine->floatType(), 4); break; // dvec case Parser::T_DVEC2: _type = _engine->vectorType(_engine->doubleType(), 2); break; case Parser::T_DVEC3: _type = _engine->vectorType(_engine->doubleType(), 3); break; case Parser::T_DVEC4: _type = _engine->vectorType(_engine->doubleType(), 4); break; // mat2 case Parser::T_MAT2: case Parser::T_MAT2X2: _type = _engine->matrixType(_engine->floatType(), 2, 2); break; case Parser::T_MAT2X3: _type = _engine->matrixType(_engine->floatType(), 2, 3); break; case Parser::T_MAT2X4: _type = _engine->matrixType(_engine->floatType(), 2, 4); break; // mat3 case Parser::T_MAT3X2: _type = _engine->matrixType(_engine->floatType(), 3, 2); break; case Parser::T_MAT3: case Parser::T_MAT3X3: _type = _engine->matrixType(_engine->floatType(), 3, 3); break; case Parser::T_MAT3X4: _type = _engine->matrixType(_engine->floatType(), 3, 4); break; // mat4 case Parser::T_MAT4X2: _type = _engine->matrixType(_engine->floatType(), 4, 2); break; case Parser::T_MAT4X3: _type = _engine->matrixType(_engine->floatType(), 4, 3); break; case Parser::T_MAT4: case Parser::T_MAT4X4: _type = _engine->matrixType(_engine->floatType(), 4, 4); break; // dmat2 case Parser::T_DMAT2: case Parser::T_DMAT2X2: _type = _engine->matrixType(_engine->doubleType(), 2, 2); break; case Parser::T_DMAT2X3: _type = _engine->matrixType(_engine->doubleType(), 2, 3); break; case Parser::T_DMAT2X4: _type = _engine->matrixType(_engine->doubleType(), 2, 4); break; // dmat3 case Parser::T_DMAT3X2: _type = _engine->matrixType(_engine->doubleType(), 3, 2); break; case Parser::T_DMAT3: case Parser::T_DMAT3X3: _type = _engine->matrixType(_engine->doubleType(), 3, 3); break; case Parser::T_DMAT3X4: _type = _engine->matrixType(_engine->doubleType(), 3, 4); break; // dmat4 case Parser::T_DMAT4X2: _type = _engine->matrixType(_engine->doubleType(), 4, 2); break; case Parser::T_DMAT4X3: _type = _engine->matrixType(_engine->doubleType(), 4, 3); break; case Parser::T_DMAT4: case Parser::T_DMAT4X4: _type = _engine->matrixType(_engine->doubleType(), 4, 4); break; // samplers case Parser::T_SAMPLER1D: case Parser::T_SAMPLER2D: case Parser::T_SAMPLER3D: case Parser::T_SAMPLERCUBE: case Parser::T_SAMPLER1DSHADOW: case Parser::T_SAMPLER2DSHADOW: case Parser::T_SAMPLERCUBESHADOW: case Parser::T_SAMPLER1DARRAY: case Parser::T_SAMPLER2DARRAY: case Parser::T_SAMPLER1DARRAYSHADOW: case Parser::T_SAMPLER2DARRAYSHADOW: case Parser::T_SAMPLERCUBEARRAY: case Parser::T_SAMPLERCUBEARRAYSHADOW: case Parser::T_SAMPLER2DRECT: case Parser::T_SAMPLER2DRECTSHADOW: case Parser::T_SAMPLERBUFFER: case Parser::T_SAMPLER2DMS: case Parser::T_SAMPLER2DMSARRAY: case Parser::T_ISAMPLER1D: case Parser::T_ISAMPLER2D: case Parser::T_ISAMPLER3D: case Parser::T_ISAMPLERCUBE: case Parser::T_ISAMPLER1DARRAY: case Parser::T_ISAMPLER2DARRAY: case Parser::T_ISAMPLERCUBEARRAY: case Parser::T_ISAMPLER2DRECT: case Parser::T_ISAMPLERBUFFER: case Parser::T_ISAMPLER2DMS: case Parser::T_ISAMPLER2DMSARRAY: case Parser::T_USAMPLER1D: case Parser::T_USAMPLER2D: case Parser::T_USAMPLER3D: case Parser::T_USAMPLERCUBE: case Parser::T_USAMPLER1DARRAY: case Parser::T_USAMPLER2DARRAY: case Parser::T_USAMPLERCUBEARRAY: case Parser::T_USAMPLER2DRECT: case Parser::T_USAMPLERBUFFER: case Parser::T_USAMPLER2DMS: case Parser::T_USAMPLER2DMSARRAY: _type = _engine->samplerType(ast->token); break; default: _engine->error(ast->lineno, QString("Unknown type `%1'").arg(QLatin1String(GLSLParserTable::spell[ast->token]))); } return false; } bool Semantic::visit(NamedTypeAST *ast) { if (ast->name) { if (Symbol *s = _scope->lookup(*ast->name)) { if (Struct *ty = s->asStruct()) { _type = ty; return false; } } _engine->error(ast->lineno, QString("Undefined type `%1'").arg(*ast->name)); } return false; } bool Semantic::visit(ArrayTypeAST *ast) { const Type *elementType = type(ast->elementType); Q_UNUSED(elementType); ExprResult size = expression(ast->size); return false; } bool Semantic::visit(StructTypeAST *ast) { Struct *s = _engine->newStruct(_scope); if (ast->name) s->setName(*ast->name); if (Scope *e = s->scope()) e->add(s); Scope *previousScope = switchScope(s); for (List *it = ast->fields; it; it = it->next) { StructTypeAST::Field *f = it->value; if (Symbol *member = field(f)) s->add(member); } (void) switchScope(previousScope); return false; } bool Semantic::visit(QualifiedTypeAST *ast) { _type = type(ast->type); for (List *it = ast->layout_list; it; it = it->next) { LayoutQualifier *q = it->value; // q->name; // q->number; Q_UNUSED(q); } return false; } // declarations bool Semantic::visit(PrecisionDeclarationAST *ast) { const Type *ty = type(ast->type); Q_UNUSED(ty); return false; } bool Semantic::visit(ParameterDeclarationAST *ast) { Q_UNUSED(ast); Q_ASSERT(!"unreachable"); return false; } bool Semantic::visit(VariableDeclarationAST *ast) { const Type *ty = type(ast->type); ExprResult initializer = expression(ast->initializer); if (ast->name) { Variable *var = _engine->newVariable(_scope, *ast->name, ty); _scope->add(var); } return false; } bool Semantic::visit(TypeDeclarationAST *ast) { const Type *ty = type(ast->type); Q_UNUSED(ty); return false; } bool Semantic::visit(TypeAndVariableDeclarationAST *ast) { declaration(ast->typeDecl); declaration(ast->varDecl); return false; } bool Semantic::visit(InvariantDeclarationAST *ast) { Q_UNUSED(ast); return false; } bool Semantic::visit(InitDeclarationAST *ast) { for (List *it = ast->decls; it; it = it->next) { DeclarationAST *decl = it->value; declaration(decl); } return false; } bool Semantic::visit(FunctionDeclarationAST *ast) { Function *fun = _engine->newFunction(_scope); if (ast->name) fun->setName(*ast->name); fun->setReturnType(type(ast->returnType)); for (List *it = ast->params; it; it = it->next) { ParameterDeclarationAST *decl = it->value; parameterDeclaration(decl, fun); } if (Scope *enclosingScope = fun->scope()) enclosingScope->add(fun); Scope *previousScope = switchScope(fun); statement(ast->body); (void) switchScope(previousScope); return false; }