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_)