13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#ifndef ES2PANDA_IR_EXPRESSION_MEMBER_EXPRESSION_H
173af6ab5fSopenharmony_ci#define ES2PANDA_IR_EXPRESSION_MEMBER_EXPRESSION_H
183af6ab5fSopenharmony_ci
193af6ab5fSopenharmony_ci#include "checker/types/ets/etsObjectType.h"
203af6ab5fSopenharmony_ci#include "ir/expression.h"
213af6ab5fSopenharmony_ci
223af6ab5fSopenharmony_cinamespace ark::es2panda::compiler {
233af6ab5fSopenharmony_ciclass JSCompiler;
243af6ab5fSopenharmony_ciclass ETSCompiler;
253af6ab5fSopenharmony_ci}  // namespace ark::es2panda::compiler
263af6ab5fSopenharmony_ci
273af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
283af6ab5fSopenharmony_ciclass ETSObjectType;
293af6ab5fSopenharmony_ciclass ETSAnalyzer;
303af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
313af6ab5fSopenharmony_ci
323af6ab5fSopenharmony_cinamespace ark::es2panda::ir {
333af6ab5fSopenharmony_ci
343af6ab5fSopenharmony_ci// NOLINTBEGIN(modernize-avoid-c-arrays)
353af6ab5fSopenharmony_ciinline constexpr char const PREDEFINED_METHOD[] = "The special predefined method '";
363af6ab5fSopenharmony_ci// NOLINTEND(modernize-avoid-c-arrays)
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_ciusing ENUMBITOPS_OPERATORS;
393af6ab5fSopenharmony_ci
403af6ab5fSopenharmony_cienum class MemberExpressionKind : uint32_t {
413af6ab5fSopenharmony_ci    NONE = 0,
423af6ab5fSopenharmony_ci    ELEMENT_ACCESS = 1U << 0U,
433af6ab5fSopenharmony_ci    PROPERTY_ACCESS = 1U << 1U,
443af6ab5fSopenharmony_ci    GETTER = 1U << 2U,
453af6ab5fSopenharmony_ci    SETTER = 1U << 3U,
463af6ab5fSopenharmony_ci};
473af6ab5fSopenharmony_ci
483af6ab5fSopenharmony_ci}  // namespace ark::es2panda::ir
493af6ab5fSopenharmony_ci
503af6ab5fSopenharmony_citemplate <>
513af6ab5fSopenharmony_cistruct enumbitops::IsAllowedType<ark::es2panda::ir::MemberExpressionKind> : std::true_type {
523af6ab5fSopenharmony_ci};
533af6ab5fSopenharmony_ci
543af6ab5fSopenharmony_cinamespace ark::es2panda::ir {
553af6ab5fSopenharmony_ci
563af6ab5fSopenharmony_ciclass MemberExpression : public MaybeOptionalExpression {
573af6ab5fSopenharmony_ci    friend class checker::ETSAnalyzer;
583af6ab5fSopenharmony_ci
593af6ab5fSopenharmony_ciprivate:
603af6ab5fSopenharmony_ci    struct Tag {};
613af6ab5fSopenharmony_ci
623af6ab5fSopenharmony_cipublic:
633af6ab5fSopenharmony_ci    MemberExpression() = delete;
643af6ab5fSopenharmony_ci    ~MemberExpression() override = default;
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci    NO_COPY_OPERATOR(MemberExpression);
673af6ab5fSopenharmony_ci    NO_MOVE_SEMANTIC(MemberExpression);
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci    explicit MemberExpression(Expression *object, Expression *property, MemberExpressionKind kind, bool computed,
703af6ab5fSopenharmony_ci                              bool optional)
713af6ab5fSopenharmony_ci        : MaybeOptionalExpression(AstNodeType::MEMBER_EXPRESSION, optional),
723af6ab5fSopenharmony_ci          object_(object),
733af6ab5fSopenharmony_ci          property_(property),
743af6ab5fSopenharmony_ci          kind_(kind),
753af6ab5fSopenharmony_ci          computed_(computed)
763af6ab5fSopenharmony_ci    {
773af6ab5fSopenharmony_ci    }
783af6ab5fSopenharmony_ci
793af6ab5fSopenharmony_ci    explicit MemberExpression(Tag tag, MemberExpression const &other, ArenaAllocator *allocator);
803af6ab5fSopenharmony_ci
813af6ab5fSopenharmony_ci    // NOTE (csabahurton): these friend relationships can be removed once there are getters for private fields
823af6ab5fSopenharmony_ci    friend class compiler::JSCompiler;
833af6ab5fSopenharmony_ci    friend class compiler::ETSCompiler;
843af6ab5fSopenharmony_ci
853af6ab5fSopenharmony_ci    [[nodiscard]] Expression *Object() noexcept
863af6ab5fSopenharmony_ci    {
873af6ab5fSopenharmony_ci        return object_;
883af6ab5fSopenharmony_ci    }
893af6ab5fSopenharmony_ci
903af6ab5fSopenharmony_ci    [[nodiscard]] const Expression *Object() const noexcept
913af6ab5fSopenharmony_ci    {
923af6ab5fSopenharmony_ci        return object_;
933af6ab5fSopenharmony_ci    }
943af6ab5fSopenharmony_ci
953af6ab5fSopenharmony_ci    void SetObject(Expression *object) noexcept
963af6ab5fSopenharmony_ci    {
973af6ab5fSopenharmony_ci        object_ = object;
983af6ab5fSopenharmony_ci        object_->SetParent(this);
993af6ab5fSopenharmony_ci    }
1003af6ab5fSopenharmony_ci
1013af6ab5fSopenharmony_ci    [[nodiscard]] Expression *Property() noexcept
1023af6ab5fSopenharmony_ci    {
1033af6ab5fSopenharmony_ci        return property_;
1043af6ab5fSopenharmony_ci    }
1053af6ab5fSopenharmony_ci
1063af6ab5fSopenharmony_ci    [[nodiscard]] const Expression *Property() const noexcept
1073af6ab5fSopenharmony_ci    {
1083af6ab5fSopenharmony_ci        return property_;
1093af6ab5fSopenharmony_ci    }
1103af6ab5fSopenharmony_ci
1113af6ab5fSopenharmony_ci    [[nodiscard]] varbinder::LocalVariable *PropVar() noexcept
1123af6ab5fSopenharmony_ci    {
1133af6ab5fSopenharmony_ci        if (Kind() == MemberExpressionKind::ELEMENT_ACCESS) {
1143af6ab5fSopenharmony_ci            return nullptr;
1153af6ab5fSopenharmony_ci        }
1163af6ab5fSopenharmony_ci        return Property()->Variable() != nullptr ? Property()->Variable()->AsLocalVariable() : nullptr;
1173af6ab5fSopenharmony_ci    }
1183af6ab5fSopenharmony_ci
1193af6ab5fSopenharmony_ci    [[nodiscard]] const varbinder::LocalVariable *PropVar() const noexcept
1203af6ab5fSopenharmony_ci    {
1213af6ab5fSopenharmony_ci        if (Kind() == MemberExpressionKind::ELEMENT_ACCESS) {
1223af6ab5fSopenharmony_ci            return nullptr;
1233af6ab5fSopenharmony_ci        }
1243af6ab5fSopenharmony_ci        return Property()->Variable() != nullptr ? Property()->Variable()->AsLocalVariable() : nullptr;
1253af6ab5fSopenharmony_ci    }
1263af6ab5fSopenharmony_ci
1273af6ab5fSopenharmony_ci    [[nodiscard]] bool IsComputed() const noexcept
1283af6ab5fSopenharmony_ci    {
1293af6ab5fSopenharmony_ci        return computed_;
1303af6ab5fSopenharmony_ci    }
1313af6ab5fSopenharmony_ci
1323af6ab5fSopenharmony_ci    [[nodiscard]] MemberExpressionKind Kind() const noexcept
1333af6ab5fSopenharmony_ci    {
1343af6ab5fSopenharmony_ci        return kind_;
1353af6ab5fSopenharmony_ci    }
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    void AddMemberKind(MemberExpressionKind kind) noexcept
1383af6ab5fSopenharmony_ci    {
1393af6ab5fSopenharmony_ci        kind_ |= kind;
1403af6ab5fSopenharmony_ci    }
1413af6ab5fSopenharmony_ci
1423af6ab5fSopenharmony_ci    [[nodiscard]] bool HasMemberKind(MemberExpressionKind kind) const noexcept
1433af6ab5fSopenharmony_ci    {
1443af6ab5fSopenharmony_ci        return (kind_ & kind) != 0;
1453af6ab5fSopenharmony_ci    }
1463af6ab5fSopenharmony_ci
1473af6ab5fSopenharmony_ci    void RemoveMemberKind(MemberExpressionKind const kind) noexcept
1483af6ab5fSopenharmony_ci    {
1493af6ab5fSopenharmony_ci        kind_ &= ~kind;
1503af6ab5fSopenharmony_ci    }
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_ci    [[nodiscard]] checker::ETSObjectType *ObjType() const noexcept
1533af6ab5fSopenharmony_ci    {
1543af6ab5fSopenharmony_ci        return objType_;
1553af6ab5fSopenharmony_ci    }
1563af6ab5fSopenharmony_ci
1573af6ab5fSopenharmony_ci    void SetPropVar(varbinder::LocalVariable *propVar) noexcept
1583af6ab5fSopenharmony_ci    {
1593af6ab5fSopenharmony_ci        ASSERT(Property());
1603af6ab5fSopenharmony_ci        Property()->SetVariable(propVar);
1613af6ab5fSopenharmony_ci    }
1623af6ab5fSopenharmony_ci
1633af6ab5fSopenharmony_ci    void SetObjectType(checker::ETSObjectType *objType) noexcept
1643af6ab5fSopenharmony_ci    {
1653af6ab5fSopenharmony_ci        objType_ = objType;
1663af6ab5fSopenharmony_ci    }
1673af6ab5fSopenharmony_ci
1683af6ab5fSopenharmony_ci    [[nodiscard]] bool IsIgnoreBox() const noexcept
1693af6ab5fSopenharmony_ci    {
1703af6ab5fSopenharmony_ci        return ignoreBox_;
1713af6ab5fSopenharmony_ci    }
1723af6ab5fSopenharmony_ci
1733af6ab5fSopenharmony_ci    void SetIgnoreBox() noexcept
1743af6ab5fSopenharmony_ci    {
1753af6ab5fSopenharmony_ci        ignoreBox_ = true;
1763af6ab5fSopenharmony_ci    }
1773af6ab5fSopenharmony_ci
1783af6ab5fSopenharmony_ci    [[nodiscard]] checker::Type *UncheckedType() const noexcept
1793af6ab5fSopenharmony_ci    {
1803af6ab5fSopenharmony_ci        return uncheckedType_;
1813af6ab5fSopenharmony_ci    }
1823af6ab5fSopenharmony_ci
1833af6ab5fSopenharmony_ci    [[nodiscard]] bool IsPrivateReference() const noexcept;
1843af6ab5fSopenharmony_ci
1853af6ab5fSopenharmony_ci    [[nodiscard]] MemberExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override;
1863af6ab5fSopenharmony_ci
1873af6ab5fSopenharmony_ci    void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override;
1883af6ab5fSopenharmony_ci    void Iterate(const NodeTraverser &cb) const override;
1893af6ab5fSopenharmony_ci    void Dump(ir::AstDumper *dumper) const override;
1903af6ab5fSopenharmony_ci    void Dump(ir::SrcDumper *dumper) const override;
1913af6ab5fSopenharmony_ci    bool CompileComputed(compiler::ETSGen *etsg) const;
1923af6ab5fSopenharmony_ci    void Compile(compiler::PandaGen *pg) const override;
1933af6ab5fSopenharmony_ci    void Compile(compiler::ETSGen *etsg) const override;
1943af6ab5fSopenharmony_ci    void CompileToReg(compiler::PandaGen *pg, compiler::VReg objReg) const;
1953af6ab5fSopenharmony_ci    void CompileToRegs(compiler::PandaGen *pg, compiler::VReg object, compiler::VReg property) const;
1963af6ab5fSopenharmony_ci    checker::Type *Check(checker::TSChecker *checker) override;
1973af6ab5fSopenharmony_ci    checker::Type *Check(checker::ETSChecker *checker) override;
1983af6ab5fSopenharmony_ci
1993af6ab5fSopenharmony_ci    void Accept(ASTVisitorT *v) override
2003af6ab5fSopenharmony_ci    {
2013af6ab5fSopenharmony_ci        v->Accept(this);
2023af6ab5fSopenharmony_ci    }
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ciprotected:
2053af6ab5fSopenharmony_ci    MemberExpression(MemberExpression const &other) : MaybeOptionalExpression(other)
2063af6ab5fSopenharmony_ci    {
2073af6ab5fSopenharmony_ci        kind_ = other.kind_;
2083af6ab5fSopenharmony_ci        computed_ = other.computed_;
2093af6ab5fSopenharmony_ci        ignoreBox_ = other.ignoreBox_;
2103af6ab5fSopenharmony_ci        // Note! Probably, we need to do 'Instantiate(...)' but we haven't access to 'Relation()' here...
2113af6ab5fSopenharmony_ci        uncheckedType_ = other.uncheckedType_;
2123af6ab5fSopenharmony_ci        objType_ = other.objType_;
2133af6ab5fSopenharmony_ci    }
2143af6ab5fSopenharmony_ci
2153af6ab5fSopenharmony_ciprivate:
2163af6ab5fSopenharmony_ci    std::pair<checker::Type *, varbinder::LocalVariable *> ResolveEnumMember(checker::ETSChecker *checker,
2173af6ab5fSopenharmony_ci                                                                             checker::Type *type) const;
2183af6ab5fSopenharmony_ci    std::pair<checker::Type *, varbinder::LocalVariable *> ResolveObjectMember(checker::ETSChecker *checker) const;
2193af6ab5fSopenharmony_ci
2203af6ab5fSopenharmony_ci    checker::Type *AdjustType(checker::ETSChecker *checker, checker::Type *type);
2213af6ab5fSopenharmony_ci    checker::Type *SetAndAdjustType(checker::ETSChecker *checker, checker::ETSObjectType *objectType);
2223af6ab5fSopenharmony_ci    checker::Type *CheckComputed(checker::ETSChecker *checker, checker::Type *baseType);
2233af6ab5fSopenharmony_ci    checker::Type *CheckUnionMember(checker::ETSChecker *checker, checker::Type *baseType);
2243af6ab5fSopenharmony_ci    checker::Type *TraverseUnionMember(checker::ETSChecker *checker, checker::ETSUnionType *unionType,
2253af6ab5fSopenharmony_ci                                       checker::Type *commonPropType);
2263af6ab5fSopenharmony_ci
2273af6ab5fSopenharmony_ci    bool CheckArrayIndexValue(checker::ETSChecker *checker) const;
2283af6ab5fSopenharmony_ci    checker::Type *CheckIndexAccessMethod(checker::ETSChecker *checker);
2293af6ab5fSopenharmony_ci    checker::Type *CheckTupleAccessMethod(checker::ETSChecker *checker, checker::Type *baseType);
2303af6ab5fSopenharmony_ci
2313af6ab5fSopenharmony_ci    void LoadRhs(compiler::PandaGen *pg) const;
2323af6ab5fSopenharmony_ci
2333af6ab5fSopenharmony_ci    Expression *object_ = nullptr;
2343af6ab5fSopenharmony_ci    Expression *property_ = nullptr;
2353af6ab5fSopenharmony_ci    MemberExpressionKind kind_;
2363af6ab5fSopenharmony_ci    bool computed_;
2373af6ab5fSopenharmony_ci    bool ignoreBox_ {false};
2383af6ab5fSopenharmony_ci    checker::Type *uncheckedType_ {};
2393af6ab5fSopenharmony_ci    checker::ETSObjectType *objType_ {};
2403af6ab5fSopenharmony_ci};
2413af6ab5fSopenharmony_ci}  // namespace ark::es2panda::ir
2423af6ab5fSopenharmony_ci
2433af6ab5fSopenharmony_ci#endif
244