1/*
2 * Copyright (c) 2021 - 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ES2PANDA_COMPILER_CHECKER_ETS_WIDENING_CONVERTER_H
17#define ES2PANDA_COMPILER_CHECKER_ETS_WIDENING_CONVERTER_H
18
19#include "checker/ets/typeConverter.h"
20#include "checker/ETSchecker.h"
21
22namespace ark::es2panda::checker {
23
24class WideningConverter : public TypeConverter {
25public:
26    explicit WideningConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source)
27        : TypeConverter(checker, relation, target, source)
28    {
29        if (!Relation()->ApplyWidening()) {
30            return;
31        }
32
33        if (!Source()->HasTypeFlag(TypeFlag::CONSTANT)) {
34            ApplyGlobalWidening();
35        } else {
36            ApplyConstWidening();
37        }
38    }
39
40private:
41    void ApplyConstWidening()
42    {
43        switch (ETSChecker::ETSChecker::ETSType(Target())) {
44            case TypeFlag::SHORT: {
45                ApplyWidening<ShortType>(TypeFlag::WIDENABLE_TO_SHORT);
46                break;
47            }
48            case TypeFlag::INT: {
49                ApplyWidening<IntType>(TypeFlag::WIDENABLE_TO_INT);
50                break;
51            }
52            case TypeFlag::LONG: {
53                ApplyWidening<LongType>(TypeFlag::WIDENABLE_TO_LONG);
54                break;
55            }
56            case TypeFlag::FLOAT: {
57                ApplyWidening<FloatType>(TypeFlag::WIDENABLE_TO_FLOAT);
58                break;
59            }
60            case TypeFlag::DOUBLE: {
61                ApplyWidening<DoubleType>(TypeFlag::WIDENABLE_TO_DOUBLE);
62                break;
63            }
64            default: {
65                break;
66            }
67        }
68    }
69
70    void ApplyGlobalWidening()
71    {
72        switch (ETSChecker::ETSChecker::ETSType(Target())) {
73            case TypeFlag::CHAR: {
74                ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_CHAR);
75                break;
76            }
77            case TypeFlag::SHORT: {
78                ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_SHORT);
79                break;
80            }
81            case TypeFlag::INT: {
82                ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_INT);
83                break;
84            }
85            case TypeFlag::LONG: {
86                ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_LONG);
87                break;
88            }
89            case TypeFlag::FLOAT: {
90                ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_FLOAT);
91                break;
92            }
93            case TypeFlag::DOUBLE: {
94                ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_DOUBLE);
95                break;
96            }
97            default: {
98                break;
99            }
100        }
101    }
102
103    void ApplyGlobalWidening(TypeFlag flag)
104    {
105        if (!Source()->HasTypeFlag(flag)) {
106            return;
107        }
108
109        if (!Relation()->OnlyCheckWidening()) {
110            ASSERT(Relation()->GetNode());
111            switch (ETSChecker::ETSChecker::ETSType(Source())) {
112                case TypeFlag::BYTE: {
113                    Relation()->GetNode()->SetTsType(Checker()->GlobalByteType());
114                    break;
115                }
116                case TypeFlag::SHORT: {
117                    Relation()->GetNode()->SetTsType(Checker()->GlobalShortType());
118                    break;
119                }
120                case TypeFlag::CHAR: {
121                    Relation()->GetNode()->SetTsType(Checker()->GlobalCharType());
122                    break;
123                }
124                case TypeFlag::INT: {
125                    Relation()->GetNode()->SetTsType(Checker()->GlobalIntType());
126                    break;
127                }
128                case TypeFlag::LONG: {
129                    Relation()->GetNode()->SetTsType(Checker()->GlobalLongType());
130                    break;
131                }
132                case TypeFlag::FLOAT: {
133                    Relation()->GetNode()->SetTsType(Checker()->GlobalFloatType());
134                    break;
135                }
136                case TypeFlag::DOUBLE: {
137                    Relation()->GetNode()->SetTsType(Checker()->GlobalDoubleType());
138                    break;
139                }
140                default: {
141                    return;
142                }
143            }
144        }
145
146        Relation()->Result(true);
147    }
148
149    template <typename TargetType>
150    void ApplyWidening(TypeFlag flag)
151    {
152        if (!Source()->HasTypeFlag(flag)) {
153            return;
154        }
155
156        switch (ETSChecker::ETSChecker::ETSType(Source())) {
157            case TypeFlag::BYTE: {
158                ApplyWidening<TargetType, ByteType>();
159                break;
160            }
161            case TypeFlag::CHAR: {
162                ApplyWidening<TargetType, CharType>();
163                break;
164            }
165            case TypeFlag::SHORT: {
166                ApplyWidening<TargetType, ShortType>();
167                break;
168            }
169            case TypeFlag::INT: {
170                ApplyWidening<TargetType, IntType>();
171                break;
172            }
173            case TypeFlag::LONG: {
174                ApplyWidening<TargetType, LongType>();
175                break;
176            }
177            case TypeFlag::FLOAT: {
178                ApplyWidening<TargetType, FloatType>();
179                break;
180            }
181            case TypeFlag::DOUBLE: {
182                ApplyWidening<TargetType, DoubleType>();
183                break;
184            }
185            default: {
186                return;
187            }
188        }
189        Relation()->Result(true);
190    }
191
192    template <typename TargetType, typename SourceType>
193    void ApplyWidening()
194    {
195        using SType = typename SourceType::UType;
196        using TType = typename TargetType::UType;
197        SType value = reinterpret_cast<SourceType *>(Source())->GetValue();
198
199        if (!Relation()->OnlyCheckWidening()) {
200            ASSERT(Relation()->GetNode());
201            Relation()->GetNode()->SetTsType(Checker()->Allocator()->New<TargetType>(static_cast<TType>(value)));
202        }
203    }
204};
205}  // namespace ark::es2panda::checker
206
207#endif
208