• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "etsEnumType.h"
17 
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/conversion.h"
20 #include "ir/expressions/identifier.h"
21 #include "ir/expressions/literals/numberLiteral.h"
22 #include "ir/expressions/memberExpression.h"
23 #include "ir/ts/tsEnumMember.h"
24 
25 namespace panda::es2panda::checker {
ETSEnumInterface(const ir::TSEnumDeclaration * const enumDecl,UType ordinal,const ir::TSEnumMember * const member,TypeFlag const typeFlag)26 ETSEnumInterface::ETSEnumInterface(const ir::TSEnumDeclaration *const enumDecl, UType ordinal,
27                                    const ir::TSEnumMember *const member, TypeFlag const typeFlag)
28     : Type(typeFlag), decl_(enumDecl), ordinal_ {ordinal}, member_(member)
29 {
30 }
31 
AssignmentSource(TypeRelation * const relation,Type * const target)32 bool ETSEnumInterface::AssignmentSource(TypeRelation *const relation, Type *const target)
33 {
34     auto const result = target->IsETSEnumType()
35                             ? IsSameEnumType(target->AsETSEnumType())
36                             : (target->IsETSStringEnumType() ? IsSameEnumType(target->AsETSStringEnumType()) : false);
37     relation->Result(result);
38     return relation->IsTrue();
39 }
40 
AssignmentTarget(TypeRelation * const relation,Type * const source)41 void ETSEnumInterface::AssignmentTarget(TypeRelation *const relation, Type *const source)
42 {
43     auto const result = source->IsETSEnumType()
44                             ? IsSameEnumType(source->AsETSEnumType())
45                             : (source->IsETSStringEnumType() ? IsSameEnumType(source->AsETSStringEnumType()) : false);
46     relation->Result(result);
47 }
48 
Cast(TypeRelation * relation,Type * target)49 void ETSEnumInterface::Cast(TypeRelation *relation, Type *target)
50 {
51     if (target->IsIntType()) {
52         relation->Result(true);
53         return;
54     }
55 
56     conversion::Forbidden(relation);
57 }
58 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)59 Type *ETSEnumInterface::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
60                                     [[maybe_unused]] GlobalTypesHolder *globalTypes)
61 {
62     return this;
63 }
64 
Identical(TypeRelation * const relation,Type * const other)65 void ETSEnumInterface::Identical(TypeRelation *const relation, Type *const other)
66 {
67     ETSEnumInterface const *const otherEnumType = [other]() -> ETSEnumInterface const * {
68         if (other->IsETSEnumType()) {
69             return other->AsETSEnumType();
70         }
71         if (other->IsETSStringEnumType()) {
72             return other->AsETSStringEnumType();
73         }
74         return nullptr;
75     }();
76 
77     relation->Result(otherEnumType != nullptr && IsSameEnumType(otherEnumType) && member_ == otherEnumType->member_);
78 }
79 
ToAssemblerType(std::stringstream & ss) const80 void ETSEnumInterface::ToAssemblerType(std::stringstream &ss) const
81 {
82     ToAssemblerTypeImpl<UType>(ss);
83 }
84 
ToDebugInfoType(std::stringstream & ss) const85 void ETSEnumInterface::ToDebugInfoType(std::stringstream &ss) const
86 {
87     ToDebugInfoTypeImpl<UType>(ss);
88 }
89 
ToString(std::stringstream & ss) const90 void ETSEnumInterface::ToString(std::stringstream &ss) const
91 {
92     ss << decl_->Key()->Name();
93 }
94 
GetDecl() const95 const ir::TSEnumDeclaration *ETSEnumInterface::GetDecl() const noexcept
96 {
97     return decl_;
98 }
99 
GetMembers() const100 const ArenaVector<ir::AstNode *> &ETSEnumInterface::GetMembers() const noexcept
101 {
102     return decl_->Members();
103 }
104 
GetMemberVar() const105 varbinder::LocalVariable *ETSEnumInterface::GetMemberVar() const noexcept
106 {
107     ASSERT(IsLiteralType());
108     return member_->Key()->AsIdentifier()->Variable()->AsLocalVariable();
109 }
110 
GetName() const111 util::StringView ETSEnumInterface::GetName() const noexcept
112 {
113     return decl_->Key()->Name();
114 }
115 
GetOrdinal() const116 ETSEnumInterface::UType ETSEnumInterface::GetOrdinal() const noexcept
117 {
118     ASSERT(IsLiteralType());
119     return ordinal_;
120 }
121 
LookupConstant(ETSChecker * const checker,const ir::Expression * const expression,const ir::Identifier * const prop) const122 ETSEnumInterface *ETSEnumInterface::LookupConstant(ETSChecker *const checker, const ir::Expression *const expression,
123                                                    const ir::Identifier *const prop) const
124 {
125     if (!IsEnumTypeExpression(expression)) {
126         checker->ThrowTypeError({"Enum constant do not have property '", prop->Name(), "'"}, prop->Start());
127     }
128 
129     auto *const member = FindMember(prop->Name());
130     if (member == nullptr) {
131         checker->ThrowTypeError({"No enum constant named '", prop->Name(), "' in enum '", this, "'"}, prop->Start());
132     }
133 
134     auto *const enumInterface =
135         [enumType = member->Key()->AsIdentifier()->Variable()->TsType()]() -> checker::ETSEnumInterface * {
136         if (enumType->IsETSEnumType()) {
137             return enumType->AsETSEnumType();
138         }
139         return enumType->AsETSStringEnumType();
140     }();
141 
142     ASSERT(enumInterface->IsLiteralType());
143     return enumInterface;
144 }
145 
LookupMethod(ETSChecker * checker,const ir::Expression * const expression,const ir::Identifier * const prop) const146 ETSFunctionType *ETSEnumInterface::LookupMethod(ETSChecker *checker, const ir::Expression *const expression,
147                                                 const ir::Identifier *const prop) const
148 {
149     if (IsEnumTypeExpression(expression)) {
150         return LookupTypeMethod(checker, prop);
151     }
152 
153     ASSERT(IsEnumInstanceExpression(expression));
154     return LookupConstantMethod(checker, prop);
155 }
156 
IsSameEnumType(const ETSEnumInterface * const other) const157 bool ETSEnumInterface::IsSameEnumType(const ETSEnumInterface *const other) const noexcept
158 {
159     return other->decl_ == decl_;
160 }
161 
IsSameEnumLiteralType(const ETSEnumInterface * const other) const162 bool ETSEnumInterface::IsSameEnumLiteralType(const ETSEnumInterface *const other) const noexcept
163 {
164     ASSERT(IsLiteralType() && IsSameEnumType(other));
165     return member_ == other->member_;
166 }
167 
IsEnumInstanceExpression(const ir::Expression * const expression) const168 bool ETSEnumInterface::IsEnumInstanceExpression(const ir::Expression *const expression) const noexcept
169 {
170     [[maybe_unused]] ETSEnumInterface const *const enumInterface =
171         [enumType = expression->TsType()]() -> ETSEnumInterface const * {
172         if (enumType->IsETSEnumType()) {
173             return enumType->AsETSEnumType();
174         }
175         if (enumType->IsETSStringEnumType()) {
176             return enumType->AsETSStringEnumType();
177         }
178         return nullptr;
179     }();
180 
181     ASSERT(IsSameEnumType(enumInterface));
182 
183     return IsEnumLiteralExpression(expression) || !IsEnumTypeExpression(expression);
184 }
185 
IsEnumLiteralExpression(const ir::Expression * const expression) const186 bool ETSEnumInterface::IsEnumLiteralExpression(const ir::Expression *const expression) const noexcept
187 {
188     [[maybe_unused]] ETSEnumInterface const *const enumInterface =
189         [enumType = expression->TsType()]() -> ETSEnumInterface const * {
190         if (enumType->IsETSEnumType()) {
191             return enumType->AsETSEnumType();
192         }
193         if (enumType->IsETSStringEnumType()) {
194             return enumType->AsETSStringEnumType();
195         }
196         return nullptr;
197     }();
198 
199     ASSERT(IsSameEnumType(enumInterface));
200 
201     if (expression->IsMemberExpression()) {
202         const auto *const memberExpr = expression->AsMemberExpression();
203         return memberExpr->Kind() == ir::MemberExpressionKind::PROPERTY_ACCESS &&
204                IsEnumTypeExpression(memberExpr->Object());
205     }
206 
207     return false;
208 }
209 
IsEnumTypeExpression(const ir::Expression * const expression) const210 bool ETSEnumInterface::IsEnumTypeExpression(const ir::Expression *const expression) const noexcept
211 {
212     [[maybe_unused]] ETSEnumInterface const *const enumInterface =
213         [enumType = expression->TsType()]() -> ETSEnumInterface const * {
214         if (enumType->IsETSEnumType()) {
215             return enumType->AsETSEnumType();
216         }
217         if (enumType->IsETSStringEnumType()) {
218             return enumType->AsETSStringEnumType();
219         }
220         return nullptr;
221     }();
222 
223     ASSERT(IsSameEnumType(enumInterface));
224 
225     if (expression->IsCallExpression()) {
226         return false;
227     }
228 
229     const auto *const localVar = [expression]() -> const varbinder::LocalVariable * {
230         if (expression->IsMemberExpression()) {
231             const auto *const memberExpr = expression->AsMemberExpression();
232             return memberExpr->PropVar() != nullptr
233                        ? memberExpr->PropVar()
234                        : memberExpr->Object()->AsIdentifier()->Variable()->AsLocalVariable();
235         }
236         return expression->AsIdentifier()->Variable()->AsLocalVariable();
237     }();
238 
239     ASSERT(localVar->Declaration() == decl_->Key()->AsIdentifier()->Variable()->Declaration() ||
240            !localVar->HasFlag(varbinder::VariableFlags::ENUM_LITERAL));
241     return localVar->HasFlag(varbinder::VariableFlags::ENUM_LITERAL);
242 }
243 
FromIntMethod() const244 ETSEnumInterface::Method ETSEnumInterface::FromIntMethod() const noexcept
245 {
246     ASSERT(fromIntMethod_.globalSignature != nullptr && fromIntMethod_.memberProxyType == nullptr);
247     return fromIntMethod_;
248 }
249 
GetValueMethod() const250 ETSEnumInterface::Method ETSEnumInterface::GetValueMethod() const noexcept
251 {
252     ASSERT(getValueMethod_.globalSignature != nullptr && getValueMethod_.memberProxyType != nullptr);
253     return getValueMethod_;
254 }
255 
GetNameMethod() const256 ETSEnumInterface::Method ETSEnumInterface::GetNameMethod() const noexcept
257 {
258     ASSERT(getNameMethod_.globalSignature != nullptr && getNameMethod_.memberProxyType != nullptr);
259     return getNameMethod_;
260 }
261 
ToStringMethod() const262 ETSEnumInterface::Method ETSEnumInterface::ToStringMethod() const noexcept
263 {
264     ASSERT(toStringMethod_.globalSignature != nullptr && toStringMethod_.memberProxyType != nullptr);
265     return toStringMethod_;
266 }
267 
ValueOfMethod() const268 ETSEnumInterface::Method ETSEnumInterface::ValueOfMethod() const noexcept
269 {
270     ASSERT(valueOfMethod_.globalSignature != nullptr && valueOfMethod_.memberProxyType != nullptr);
271     return valueOfMethod_;
272 }
273 
ValuesMethod() const274 ETSEnumInterface::Method ETSEnumInterface::ValuesMethod() const noexcept
275 {
276     ASSERT(valuesMethod_.globalSignature != nullptr && valuesMethod_.memberProxyType != nullptr);
277     return valuesMethod_;
278 }
279 
IsLiteralType() const280 bool ETSEnumInterface::IsLiteralType() const noexcept
281 {
282     return member_ != nullptr;
283 }
284 
FindMember(const util::StringView & name) const285 ir::TSEnumMember *ETSEnumInterface::FindMember(const util::StringView &name) const noexcept
286 {
287     ASSERT(!IsLiteralType());
288     const auto &members = GetMembers();
289     auto memberIt = std::find_if(members.begin(), members.end(), [name](const ir::AstNode *const node) {
290         return node->AsTSEnumMember()->Key()->AsIdentifier()->Name() == name;
291     });
292     if (memberIt != members.end()) {
293         return (*memberIt)->AsTSEnumMember();
294     }
295 
296     return nullptr;
297 }
298 
LookupConstantMethod(ETSChecker * const checker,const ir::Identifier * const prop) const299 ETSFunctionType *ETSEnumInterface::LookupConstantMethod(ETSChecker *const checker,
300                                                         const ir::Identifier *const prop) const
301 {
302     if (prop->Name() == TO_STRING_METHOD_NAME) {
303         ASSERT(toStringMethod_.memberProxyType != nullptr);
304         return toStringMethod_.memberProxyType;
305     }
306 
307     if (prop->Name() == GET_VALUE_METHOD_NAME) {
308         ASSERT(getValueMethod_.memberProxyType != nullptr);
309         return getValueMethod_.memberProxyType;
310     }
311 
312     if (prop->Name() == GET_NAME_METHOD_NAME) {
313         ASSERT(getNameMethod_.memberProxyType != nullptr);
314         return getNameMethod_.memberProxyType;
315     }
316 
317     checker->ThrowTypeError({"No enum item method called '", prop->Name(), "'"}, prop->Start());
318 }
319 
LookupTypeMethod(ETSChecker * const checker,const ir::Identifier * const prop) const320 ETSFunctionType *ETSEnumInterface::LookupTypeMethod(ETSChecker *const checker, const ir::Identifier *const prop) const
321 {
322     if (prop->Name() == VALUES_METHOD_NAME) {
323         ASSERT(valuesMethod_.memberProxyType != nullptr);
324         return valuesMethod_.memberProxyType;
325     }
326 
327     if (prop->Name() == VALUE_OF_METHOD_NAME) {
328         ASSERT(valueOfMethod_.memberProxyType != nullptr);
329         return valueOfMethod_.memberProxyType;
330     }
331 
332     checker->ThrowTypeError({"No enum type method called '", prop->Name(), "'"}, prop->Start());
333 }
334 
335 }  // namespace panda::es2panda::checker
336