/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/sksl/ir/SkSLTernaryExpression.h" #include "include/sksl/SkSLErrorReporter.h" #include "src/sksl/SkSLConstantFolder.h" #include "src/sksl/SkSLContext.h" #include "src/sksl/SkSLOperators.h" #include "src/sksl/SkSLProgramSettings.h" #include "src/sksl/ir/SkSLLiteral.h" namespace SkSL { std::unique_ptr TernaryExpression::Convert(const Context& context, std::unique_ptr test, std::unique_ptr ifTrue, std::unique_ptr ifFalse) { test = context.fTypes.fBool->coerceExpression(std::move(test), context); if (!test || !ifTrue || !ifFalse) { return nullptr; } int line = test->fLine; const Type* trueType; const Type* falseType; const Type* resultType; Operator equalityOp(Token::Kind::TK_EQEQ); if (!equalityOp.determineBinaryType(context, ifTrue->type(), ifFalse->type(), &trueType, &falseType, &resultType) || (*trueType != *falseType)) { context.fErrors->error(line, "ternary operator result mismatch: '" + ifTrue->type().displayName() + "', '" + ifFalse->type().displayName() + "'"); return nullptr; } if (trueType->componentType().isOpaque()) { context.fErrors->error(line, "ternary expression of opaque type '" + trueType->displayName() + "' not allowed"); return nullptr; } if (context.fConfig->strictES2Mode() && trueType->isOrContainsArray()) { context.fErrors->error(line, "ternary operator result may not be an array (or struct " "containing an array)"); return nullptr; } ifTrue = trueType->coerceExpression(std::move(ifTrue), context); if (!ifTrue) { return nullptr; } ifFalse = falseType->coerceExpression(std::move(ifFalse), context); if (!ifFalse) { return nullptr; } return TernaryExpression::Make(context, std::move(test), std::move(ifTrue), std::move(ifFalse)); } std::unique_ptr TernaryExpression::Make(const Context& context, std::unique_ptr test, std::unique_ptr ifTrue, std::unique_ptr ifFalse) { SkASSERT(ifTrue->type() == ifFalse->type()); SkASSERT(!ifTrue->type().componentType().isOpaque()); SkASSERT(!context.fConfig->strictES2Mode() || !ifTrue->type().isOrContainsArray()); const Expression* testExpr = ConstantFolder::GetConstantValueForVariable(*test); if (testExpr->isBoolLiteral()) { // static boolean test, just return one of the branches return testExpr->as().boolValue() ? std::move(ifTrue) : std::move(ifFalse); } return std::make_unique(test->fLine, std::move(test), std::move(ifTrue), std::move(ifFalse)); } } // namespace SkSL