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