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