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/SkSLConstructorStruct.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/sksl/SkSLErrorReporter.h"
11cb93a386Sopenharmony_ci#include "src/sksl/SkSLContext.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_cinamespace SkSL {
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cistd::unique_ptr<Expression> ConstructorStruct::Convert(const Context& context,
16cb93a386Sopenharmony_ci                                                       int line,
17cb93a386Sopenharmony_ci                                                       const Type& type,
18cb93a386Sopenharmony_ci                                                       ExpressionArray args) {
19cb93a386Sopenharmony_ci    SkASSERTF(type.isStruct() && type.fields().size() > 0, "%s", type.description().c_str());
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci    // Check that the number of constructor arguments matches the array size.
22cb93a386Sopenharmony_ci    if (type.fields().size() != args.size()) {
23cb93a386Sopenharmony_ci        context.fErrors->error(line,
24cb93a386Sopenharmony_ci                               String::printf("invalid arguments to '%s' constructor "
25cb93a386Sopenharmony_ci                                              "(expected %zu elements, but found %zu)",
26cb93a386Sopenharmony_ci                                              type.displayName().c_str(), type.fields().size(),
27cb93a386Sopenharmony_ci                                              args.size()));
28cb93a386Sopenharmony_ci        return nullptr;
29cb93a386Sopenharmony_ci    }
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci    // Convert each constructor argument to the struct's field type.
32cb93a386Sopenharmony_ci    for (int index=0; index<args.count(); ++index) {
33cb93a386Sopenharmony_ci        std::unique_ptr<Expression>& argument = args[index];
34cb93a386Sopenharmony_ci        const Type::Field& field = type.fields()[index];
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci        argument = field.fType->coerceExpression(std::move(argument), context);
37cb93a386Sopenharmony_ci        if (!argument) {
38cb93a386Sopenharmony_ci            return nullptr;
39cb93a386Sopenharmony_ci        }
40cb93a386Sopenharmony_ci    }
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci    return ConstructorStruct::Make(context, line, type, std::move(args));
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci[[maybe_unused]] static bool arguments_match_field_types(const ExpressionArray& args,
46cb93a386Sopenharmony_ci                                                         const Type& type) {
47cb93a386Sopenharmony_ci    SkASSERT(type.fields().size() == args.size());
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    for (int index = 0; index < args.count(); ++index) {
50cb93a386Sopenharmony_ci        const std::unique_ptr<Expression>& argument = args[index];
51cb93a386Sopenharmony_ci        const Type::Field& field = type.fields()[index];
52cb93a386Sopenharmony_ci        if (argument->type() != *field.fType) {
53cb93a386Sopenharmony_ci            return false;
54cb93a386Sopenharmony_ci        }
55cb93a386Sopenharmony_ci    }
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci    return true;
58cb93a386Sopenharmony_ci}
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_cistd::unique_ptr<Expression> ConstructorStruct::Make(const Context& context,
61cb93a386Sopenharmony_ci                                                    int line,
62cb93a386Sopenharmony_ci                                                    const Type& type,
63cb93a386Sopenharmony_ci                                                    ExpressionArray args) {
64cb93a386Sopenharmony_ci    SkASSERT(type.isAllowedInES2(context));
65cb93a386Sopenharmony_ci    SkASSERT(arguments_match_field_types(args, type));
66cb93a386Sopenharmony_ci    return std::make_unique<ConstructorStruct>(line, type, std::move(args));
67cb93a386Sopenharmony_ci}
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci}  // namespace SkSL
70