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