blob: 6cbdc88fdb58999267edbde97a8e4c353843ce8a [file] [log] [blame]
/*
* 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<Expression> TernaryExpression::Convert(const Context& context,
std::unique_ptr<Expression> test,
std::unique_ptr<Expression> ifTrue,
std::unique_ptr<Expression> 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<Expression> TernaryExpression::Make(const Context& context,
std::unique_ptr<Expression> test,
std::unique_ptr<Expression> ifTrue,
std::unique_ptr<Expression> ifFalse) {
SkASSERT(ifTrue->type() == ifFalse->type());
SkASSERT(!ifTrue->type().componentType().isOpaque());
SkASSERT(!context.fConfig->strictES2Mode() || !ifTrue->type().isOrContainsArray());
if (context.fConfig->fSettings.fOptimize) {
const Expression* testExpr = ConstantFolder::GetConstantValueForVariable(*test);
if (testExpr->isBoolLiteral()) {
// static boolean test, just return one of the branches
return testExpr->as<Literal>().boolValue() ? std::move(ifTrue)
: std::move(ifFalse);
}
}
return std::make_unique<TernaryExpression>(test->fLine, std::move(test), std::move(ifTrue),
std::move(ifFalse));
}
} // namespace SkSL