• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 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_CORE_AST_VERIFIER_INVARIANTBASE_H
17 #define ES2PANDA_COMPILER_CORE_AST_VERIFIER_INVARIANTBASE_H
18 
19 #include "generated/options.h"
20 #include "ir/astNode.h"
21 #include "utils/json_builder.h"
22 
23 namespace ark::es2panda::compiler::ast_verifier {
24 
25 enum class CheckDecision { CORRECT, INCORRECT };
26 enum class CheckAction { CONTINUE, SKIP_SUBTREE };
27 
28 using CheckResult = std::tuple<CheckDecision, CheckAction>;
29 using VerifierInvariants = util::gen::ast_verifier::Enum;
30 using Enum = VerifierInvariants;
31 
32 template <typename... Invs>
33 class InvariantsRegistryImpl {
34 public:
InvariantsRegistryImpl()35     InvariantsRegistryImpl() : invariants_ {Invs(this)...} {}
36 
37     using Invariants = std::tuple<Invs...>;
38     template <VerifierInvariants ID>
39     using InvariantClass = std::tuple_element_t<ID, Invariants>;
40     template <typename T>
41     using InvArray = std::array<T, VerifierInvariants::COUNT>;
42 
43     template <VerifierInvariants ID>
Get()44     constexpr auto *Get()
45     {
46         return Get<InvariantClass<ID>>();
47     }
48 
49     template <typename Inv>
Get()50     constexpr auto *Get()
51     {
52         return &std::get<Inv>(invariants_);
53     }
54 
55     template <typename Func>
Apply(Func && f)56     auto Apply(Func &&f)
57     {
58         return std::apply(std::forward<Func>(f), invariants_);
59     }
60 
61 private:
62     Invariants invariants_;
63 
64     template <typename T, T... INTS>
CheckRegistry(std::integer_sequence<T,INTS...>)65     static constexpr bool CheckRegistry(std::integer_sequence<T, INTS...> /*unused*/)
66     {
67         return ((CheckRegistry<VerifierInvariants(INTS), Invs::ID>()) && ...);
68     }
69 
70     template <VerifierInvariants ORDER_IN_PARAMETER_LIST, VerifierInvariants DEFINED_ENUM>
CheckRegistry()71     static constexpr bool CheckRegistry()
72     {
73         static_assert(ORDER_IN_PARAMETER_LIST == DEFINED_ENUM,
74                       "Invariant's `ID` must be equal to"
75                       "index of the invariant in `InvariantsRegistryImpl` parameter-list");
76         return true;
77     }
78 
79     static_assert(sizeof...(Invs) == VerifierInvariants::COUNT,
80                   "Parameter-list is inconsistent with invaraints' declararation in 'options.yaml'");
81     static_assert(CheckRegistry(std::make_index_sequence<sizeof...(Invs)> {}));
82 };
83 
84 class CheckMessage {
85 public:
CheckMessage(util::StringView cause,const ir::AstNode * node)86     explicit CheckMessage(util::StringView cause, const ir::AstNode *node) : cause_ {cause}, node_ {node} {}
87 
DumpJSON()88     std::function<void(JsonObjectBuilder &)> DumpJSON() const
89     {
90         return [this](JsonObjectBuilder &body) {
91             body.AddProperty("cause", cause_);
92             body.AddProperty("ast", node_->DumpJSON());
93             body.AddProperty("line", node_->Start().line + 1);
94         };
95     }
96 
ToString()97     std::string ToString() const
98     {
99         auto nodeLocation = std::string(ir::ToString(node_->Type()));
100         auto parent = node_->Parent();
101         while (parent != nullptr) {
102             nodeLocation = std::string(ir::ToString(parent->Type())).append("->").append(nodeLocation);
103             parent = parent->Parent();
104         }
105 
106         return cause_ + "(" + nodeLocation + ", line " + std::to_string(node_->Start().line + 1) + ')';
107     }
108 
Cause()109     const auto &Cause() const
110     {
111         return cause_;
112     }
113 
114 private:
115     std::string cause_;
116     const ir::AstNode *node_;
117 };
118 
119 using Messages = std::vector<CheckMessage>;
120 
121 class InvariantMessages {
122 public:
Init()123     void Init()
124     {
125         messages_.clear();
126     }
127 
128     void AddCheckMessage(const std::string &cause, const ir::AstNode &node);
129 
MoveMessages()130     auto &&MoveMessages() &&
131     {
132         return std::move(messages_);
133     }
134 
ViewMessages()135     const auto &ViewMessages() const
136     {
137         return messages_;
138     }
139 
HasMessages()140     bool HasMessages() const
141     {
142         return !messages_.empty();
143     }
144 
145 private:
146     Messages messages_;
147 };
148 
149 template <VerifierInvariants ENUM, typename... RequiredInvs>
150 class RequiredInvariants {
151 public:
152     template <typename InvariantsReg>
RequiredInvariants(InvariantsReg * reg)153     explicit constexpr RequiredInvariants([[maybe_unused]] InvariantsReg *reg)
154         : required_ {*reg->template Get<RequiredInvs>()...}
155     {
156     }
157 
GetRequired()158     const auto &GetRequired() const
159     {
160         return required_;
161     }
162 
163 protected:
164     template <typename Inv>
Get()165     const auto &Get()
166     {
167         return std::get<Inv &>(required_);
168     }
169 
170 private:
171     static_assert(((RequiredInvs::ID < ENUM) && ...), "'Required' invariants should precede the related invariant");
172     std::tuple<RequiredInvs &...> required_;
173 };
174 
175 template <VerifierInvariants ENUM, typename... RequiredInvs>
176 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
177 class InvariantBase : public RequiredInvariants<ENUM, RequiredInvs...>, public InvariantMessages {
178 public:
179     using RequiredInvariants<ENUM, RequiredInvs...>::RequiredInvariants;
180     using Base = InvariantBase<ENUM, RequiredInvs...>;
181     constexpr static VerifierInvariants ID = ENUM;
182     constexpr static std::string_view NAME = util::gen::ast_verifier::ToString(ID);
183 };
184 
185 }  // namespace ark::es2panda::compiler::ast_verifier
186 
187 #endif  // ES2PANDA_COMPILER_CORE_AST_VERIFIER_INVARIANTBASE_H
188