kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/verifier/assertions_to_souffle.h (about) 1 /* 2 * Copyright 2021 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef KYTHE_CXX_VERIFIER_ASSERTIONS_TO_SOUFFLE_ 18 #define KYTHE_CXX_VERIFIER_ASSERTIONS_TO_SOUFFLE_ 19 20 #include <cstddef> 21 #include <optional> 22 #include <string> 23 24 #include "absl/base/attributes.h" 25 #include "absl/container/flat_hash_map.h" 26 #include "absl/container/flat_hash_set.h" 27 #include "absl/strings/string_view.h" 28 #include "kythe/cxx/verifier/assertion_ast.h" 29 30 namespace kythe::verifier { 31 /// \brief Inferred type for an EVar. 32 enum class EVarType { kVName, kSymbol, kUnknown }; 33 34 /// The error recovery state for a particular list of goal groups. 35 class SouffleErrorState { 36 public: 37 /// Creates a new error state for `goal_groups`. `goal_groups` should equal or 38 /// exceed the lifetime of any bound `SouffleErrorState`. 39 explicit SouffleErrorState( 40 const std::vector<GoalGroup>* goal_groups ABSL_ATTRIBUTE_LIFETIME_BOUND) 41 : goal_groups_(goal_groups) {} 42 SouffleErrorState(const SouffleErrorState&) = delete; 43 SouffleErrorState& operator=(const SouffleErrorState&) = delete; 44 /// Advances the error state by one step. 45 /// \return true if the solver should continue to run. 46 bool NextStep(); 47 /// \return the current highest group to solve (or -1 if uninitialized). 48 int target_group() const { return target_group_; } 49 /// \return the current highest goal to solve (ignored if target_group is 50 /// invalid). 51 int target_goal() const { return target_goal_; } 52 /// \return whether `group` (and subsequent groups) have already been 53 /// explored during error recovery. 54 bool IsFinished(int group) const { 55 return target_group_ >= 0 && group > target_group_; 56 } 57 /// \return the target goal for `group`, or -1 if all goals should be 58 /// explored given a valid `group`. 59 int GoalForGroup(int group) const { 60 return group == target_group_ ? target_goal_ : -1; 61 } 62 /// \return whether we're performing error recovery. 63 bool IsDoingErrorRecovery() const { return recovering_; } 64 65 private: 66 /// The goal groups being solved. Not owned. 67 const std::vector<GoalGroup>* goal_groups_; 68 /// The current highest group to solve (or -1 if uninitialized). 69 int target_group_ = -1; 70 /// The current highest goal to solve (ignored if target_group_ is invalid). 71 int target_goal_ = -1; 72 /// Whether we know that we're doing recovery. 73 bool recovering_ = false; 74 }; 75 76 /// \brief Packages together for a possibly multistage Souffle program. 77 class SouffleProgram { 78 public: 79 /// \brief Turns `goal_groups` into a Souffle program. 80 /// \param symbol_table the symbol table used by `goal_groups`. 81 /// \param goal_groups the goal groups to lower. 82 /// \param inspections inspections to perform. 83 bool Lower(const SymbolTable& symbol_table, 84 const std::vector<GoalGroup>& goal_groups, 85 const std::vector<Inspection>& inspections, 86 const SouffleErrorState& error_state); 87 88 /// \return the lowered Souffle code. 89 absl::string_view code() { return code_; } 90 91 /// \brief Configures whether to emit initial definitions. 92 void set_emit_prelude(bool emit_prelude) { emit_prelude_ = emit_prelude; } 93 94 std::optional<EVarType> EVarTypeFor(EVar* e) const { 95 const auto i = evar_types_.find(e); 96 return i == evar_types_.end() ? std::nullopt 97 : std::make_optional(i->second); 98 } 99 100 const std::vector<EVar*>& inspections() const { return inspections_; } 101 102 private: 103 /// \brief Lowers `node`. 104 /// \param positive_cxt whether we are in a positive goal context. 105 bool LowerSubexpression(AstNode* node, EVarType type, bool positive_cxt); 106 107 /// \brief Lowers a goal from `goal`. 108 /// \param positive_cxt whether we are in a positive goal context. 109 bool LowerGoal(const SymbolTable& symbol_table, AstNode* goal, 110 bool positive_cxt); 111 112 /// \brief Lowers `group`. 113 bool LowerGoalGroup(const SymbolTable& symbol_table, const GoalGroup& group, 114 int target_goal); 115 116 /// \brief Assigns or checks `evar`'s type against `type`. 117 bool AssignEVarType(EVar* evar, EVarType type); 118 119 /// \brief Assigns or checks `evar`'s type against `oevar`'s type. 120 bool AssignEVarType(EVar* evar, EVar* oevar); 121 122 /// The current finished code buffer. 123 std::string code_; 124 125 /// Whether to emit the prelude. 126 bool emit_prelude_ = true; 127 128 /// \return a stable short name for `evar`. 129 size_t FindEVar(EVar* evar) { 130 return evars_.try_emplace(evar, evars_.size()).first->second; 131 } 132 133 /// An association between an EVar and a Datalog variable. 134 struct FoundEVar { 135 /// The Datalog id of the EVar. 136 size_t id = 0; 137 /// Whether this was the first time this EVar was seen. 138 bool is_fresh = false; 139 }; 140 141 /// \return a stable short name for `evar` and whether this was the first time 142 /// it was seen. 143 FoundEVar FindFreshEVar(EVar* evar) { 144 auto id = FindEVar(evar); 145 return {.id = id, .is_fresh = id == evars_.size() - 1}; 146 } 147 148 /// Known evars. 149 absl::flat_hash_map<EVar*, size_t> evars_; 150 151 /// Evars that first appear in a negated context. 152 absl::flat_hash_set<EVar*> negated_evars_; 153 154 /// EVars appearing in output positions (as inspections). 155 std::vector<EVar*> inspections_; 156 157 /// Known EVar typings. 158 absl::flat_hash_map<EVar*, EVarType> evar_types_; 159 }; 160 161 } // namespace kythe::verifier 162 163 #endif // defined(KYTHE_CXX_VERIFIER_ASSERTIONS_TO_SOUFFLE_)