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_IR_EXPRESSION_MEMBER_EXPRESSION_H
17 #define ES2PANDA_IR_EXPRESSION_MEMBER_EXPRESSION_H
18 
19 #include "checker/types/ets/etsObjectType.h"
20 #include "ir/expression.h"
21 
22 namespace ark::es2panda::compiler {
23 class JSCompiler;
24 class ETSCompiler;
25 }  // namespace ark::es2panda::compiler
26 
27 namespace ark::es2panda::checker {
28 class ETSObjectType;
29 class ETSAnalyzer;
30 }  // namespace ark::es2panda::checker
31 
32 namespace ark::es2panda::ir {
33 
34 // NOLINTBEGIN(modernize-avoid-c-arrays)
35 inline constexpr char const PREDEFINED_METHOD[] = "The special predefined method '";
36 // NOLINTEND(modernize-avoid-c-arrays)
37 
38 using ENUMBITOPS_OPERATORS;
39 
40 enum class MemberExpressionKind : uint32_t {
41     NONE = 0,
42     ELEMENT_ACCESS = 1U << 0U,
43     PROPERTY_ACCESS = 1U << 1U,
44     GETTER = 1U << 2U,
45     SETTER = 1U << 3U,
46 };
47 
48 }  // namespace ark::es2panda::ir
49 
50 template <>
51 struct enumbitops::IsAllowedType<ark::es2panda::ir::MemberExpressionKind> : std::true_type {
52 };
53 
54 namespace ark::es2panda::ir {
55 
56 class MemberExpression : public MaybeOptionalExpression {
57     friend class checker::ETSAnalyzer;
58 
59 private:
60     struct Tag {};
61 
62 public:
63     MemberExpression() = delete;
64     ~MemberExpression() override = default;
65 
66     NO_COPY_OPERATOR(MemberExpression);
67     NO_MOVE_SEMANTIC(MemberExpression);
68 
MemberExpression(Expression *object, Expression *property, MemberExpressionKind kind, bool computed, bool optional)69     explicit MemberExpression(Expression *object, Expression *property, MemberExpressionKind kind, bool computed,
70                               bool optional)
71         : MaybeOptionalExpression(AstNodeType::MEMBER_EXPRESSION, optional),
72           object_(object),
73           property_(property),
74           kind_(kind),
75           computed_(computed)
76     {
77     }
78 
79     explicit MemberExpression(Tag tag, MemberExpression const &other, ArenaAllocator *allocator);
80 
81     // NOTE (csabahurton): these friend relationships can be removed once there are getters for private fields
82     friend class compiler::JSCompiler;
83     friend class compiler::ETSCompiler;
84 
85     [[nodiscard]] Expression *Object() noexcept
86     {
87         return object_;
88     }
89 
90     [[nodiscard]] const Expression *Object() const noexcept
91     {
92         return object_;
93     }
94 
95     void SetObject(Expression *object) noexcept
96     {
97         object_ = object;
98         object_->SetParent(this);
99     }
100 
101     [[nodiscard]] Expression *Property() noexcept
102     {
103         return property_;
104     }
105 
106     [[nodiscard]] const Expression *Property() const noexcept
107     {
108         return property_;
109     }
110 
111     [[nodiscard]] varbinder::LocalVariable *PropVar() noexcept
112     {
113         if (Kind() == MemberExpressionKind::ELEMENT_ACCESS) {
114             return nullptr;
115         }
116         return Property()->Variable() != nullptr ? Property()->Variable()->AsLocalVariable() : nullptr;
117     }
118 
119     [[nodiscard]] const varbinder::LocalVariable *PropVar() const noexcept
120     {
121         if (Kind() == MemberExpressionKind::ELEMENT_ACCESS) {
122             return nullptr;
123         }
124         return Property()->Variable() != nullptr ? Property()->Variable()->AsLocalVariable() : nullptr;
125     }
126 
127     [[nodiscard]] bool IsComputed() const noexcept
128     {
129         return computed_;
130     }
131 
132     [[nodiscard]] MemberExpressionKind Kind() const noexcept
133     {
134         return kind_;
135     }
136 
137     void AddMemberKind(MemberExpressionKind kind) noexcept
138     {
139         kind_ |= kind;
140     }
141 
142     [[nodiscard]] bool HasMemberKind(MemberExpressionKind kind) const noexcept
143     {
144         return (kind_ & kind) != 0;
145     }
146 
147     void RemoveMemberKind(MemberExpressionKind const kind) noexcept
148     {
149         kind_ &= ~kind;
150     }
151 
152     [[nodiscard]] checker::ETSObjectType *ObjType() const noexcept
153     {
154         return objType_;
155     }
156 
157     void SetPropVar(varbinder::LocalVariable *propVar) noexcept
158     {
159         ASSERT(Property());
160         Property()->SetVariable(propVar);
161     }
162 
163     void SetObjectType(checker::ETSObjectType *objType) noexcept
164     {
165         objType_ = objType;
166     }
167 
168     [[nodiscard]] bool IsIgnoreBox() const noexcept
169     {
170         return ignoreBox_;
171     }
172 
173     void SetIgnoreBox() noexcept
174     {
175         ignoreBox_ = true;
176     }
177 
178     [[nodiscard]] checker::Type *UncheckedType() const noexcept
179     {
180         return uncheckedType_;
181     }
182 
183     [[nodiscard]] bool IsPrivateReference() const noexcept;
184 
185     [[nodiscard]] MemberExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override;
186 
187     void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override;
188     void Iterate(const NodeTraverser &cb) const override;
189     void Dump(ir::AstDumper *dumper) const override;
190     void Dump(ir::SrcDumper *dumper) const override;
191     bool CompileComputed(compiler::ETSGen *etsg) const;
192     void Compile(compiler::PandaGen *pg) const override;
193     void Compile(compiler::ETSGen *etsg) const override;
194     void CompileToReg(compiler::PandaGen *pg, compiler::VReg objReg) const;
195     void CompileToRegs(compiler::PandaGen *pg, compiler::VReg object, compiler::VReg property) const;
196     checker::Type *Check(checker::TSChecker *checker) override;
197     checker::Type *Check(checker::ETSChecker *checker) override;
198 
199     void Accept(ASTVisitorT *v) override
200     {
201         v->Accept(this);
202     }
203 
204 protected:
MemberExpression(MemberExpression const &other)205     MemberExpression(MemberExpression const &other) : MaybeOptionalExpression(other)
206     {
207         kind_ = other.kind_;
208         computed_ = other.computed_;
209         ignoreBox_ = other.ignoreBox_;
210         // Note! Probably, we need to do 'Instantiate(...)' but we haven't access to 'Relation()' here...
211         uncheckedType_ = other.uncheckedType_;
212         objType_ = other.objType_;
213     }
214 
215 private:
216     std::pair<checker::Type *, varbinder::LocalVariable *> ResolveEnumMember(checker::ETSChecker *checker,
217                                                                              checker::Type *type) const;
218     std::pair<checker::Type *, varbinder::LocalVariable *> ResolveObjectMember(checker::ETSChecker *checker) const;
219 
220     checker::Type *AdjustType(checker::ETSChecker *checker, checker::Type *type);
221     checker::Type *SetAndAdjustType(checker::ETSChecker *checker, checker::ETSObjectType *objectType);
222     checker::Type *CheckComputed(checker::ETSChecker *checker, checker::Type *baseType);
223     checker::Type *CheckUnionMember(checker::ETSChecker *checker, checker::Type *baseType);
224     checker::Type *TraverseUnionMember(checker::ETSChecker *checker, checker::ETSUnionType *unionType,
225                                        checker::Type *commonPropType);
226 
227     bool CheckArrayIndexValue(checker::ETSChecker *checker) const;
228     checker::Type *CheckIndexAccessMethod(checker::ETSChecker *checker);
229     checker::Type *CheckTupleAccessMethod(checker::ETSChecker *checker, checker::Type *baseType);
230 
231     void LoadRhs(compiler::PandaGen *pg) const;
232 
233     Expression *object_ = nullptr;
234     Expression *property_ = nullptr;
235     MemberExpressionKind kind_;
236     bool computed_;
237     bool ignoreBox_ {false};
238     checker::Type *uncheckedType_ {};
239     checker::ETSObjectType *objType_ {};
240 };
241 }  // namespace ark::es2panda::ir
242 
243 #endif
244