1/* 2 * Copyright 2021 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "src/sksl/ir/SkSLTernaryExpression.h" 9 10#include "include/sksl/SkSLErrorReporter.h" 11#include "src/sksl/SkSLConstantFolder.h" 12#include "src/sksl/SkSLContext.h" 13#include "src/sksl/SkSLOperators.h" 14#include "src/sksl/SkSLProgramSettings.h" 15#include "src/sksl/ir/SkSLLiteral.h" 16 17namespace SkSL { 18 19std::unique_ptr<Expression> TernaryExpression::Convert(const Context& context, 20 std::unique_ptr<Expression> test, 21 std::unique_ptr<Expression> ifTrue, 22 std::unique_ptr<Expression> ifFalse) { 23 test = context.fTypes.fBool->coerceExpression(std::move(test), context); 24 if (!test || !ifTrue || !ifFalse) { 25 return nullptr; 26 } 27 int line = test->fLine; 28 const Type* trueType; 29 const Type* falseType; 30 const Type* resultType; 31 Operator equalityOp(Token::Kind::TK_EQEQ); 32 if (!equalityOp.determineBinaryType(context, ifTrue->type(), ifFalse->type(), 33 &trueType, &falseType, &resultType) || 34 (*trueType != *falseType)) { 35 context.fErrors->error(line, "ternary operator result mismatch: '" + 36 ifTrue->type().displayName() + "', '" + 37 ifFalse->type().displayName() + "'"); 38 return nullptr; 39 } 40 if (trueType->componentType().isOpaque()) { 41 context.fErrors->error(line, "ternary expression of opaque type '" + 42 trueType->displayName() + "' not allowed"); 43 return nullptr; 44 } 45 if (context.fConfig->strictES2Mode() && trueType->isOrContainsArray()) { 46 context.fErrors->error(line, "ternary operator result may not be an array (or struct " 47 "containing an array)"); 48 return nullptr; 49 } 50 ifTrue = trueType->coerceExpression(std::move(ifTrue), context); 51 if (!ifTrue) { 52 return nullptr; 53 } 54 ifFalse = falseType->coerceExpression(std::move(ifFalse), context); 55 if (!ifFalse) { 56 return nullptr; 57 } 58 return TernaryExpression::Make(context, std::move(test), std::move(ifTrue), std::move(ifFalse)); 59} 60 61std::unique_ptr<Expression> TernaryExpression::Make(const Context& context, 62 std::unique_ptr<Expression> test, 63 std::unique_ptr<Expression> ifTrue, 64 std::unique_ptr<Expression> ifFalse) { 65 SkASSERT(ifTrue->type() == ifFalse->type()); 66 SkASSERT(!ifTrue->type().componentType().isOpaque()); 67 SkASSERT(!context.fConfig->strictES2Mode() || !ifTrue->type().isOrContainsArray()); 68 69 const Expression* testExpr = ConstantFolder::GetConstantValueForVariable(*test); 70 if (testExpr->isBoolLiteral()) { 71 // static boolean test, just return one of the branches 72 return testExpr->as<Literal>().boolValue() ? std::move(ifTrue) 73 : std::move(ifFalse); 74 } 75 76 return std::make_unique<TernaryExpression>(test->fLine, std::move(test), std::move(ifTrue), 77 std::move(ifFalse)); 78} 79 80} // namespace SkSL 81