Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(verifier): add a relation for anchors #5667

Merged
merged 2 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions kythe/cxx/verifier/assertion_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
#include "glog/logging.h"
#include "kythe/cxx/verifier/location.hh"
#include "pretty_printer.h"
Expand All @@ -42,6 +43,20 @@ class SymbolTable {
public:
explicit SymbolTable() : id_regex_("[%#]?[_a-zA-Z/][a-zA-Z_0-9/]*") {}

/// \brief Returns the `Symbol` associated with `string` or `nullopt`.
absl::optional<Symbol> FindInterned(absl::string_view string) const {
const auto old = symbols_.find(std::string(string));
if (old == symbols_.end()) return absl::nullopt;
return old->second;
}

/// \brief Returns the `Symbol` associated with `string`, or aborts.
Symbol MustIntern(absl::string_view string) const {
auto sym = FindInterned(string);
CHECK(sym) << "no symbol for " << string;
return *sym;
}

/// \brief Returns the `Symbol` associated with `string`, or makes a new one.
Symbol intern(const std::string& string) {
const auto old = symbols_.find(string);
Expand Down
40 changes: 29 additions & 11 deletions kythe/cxx/verifier/assertions_to_souffle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "kythe/cxx/verifier/assertions_to_souffle.h"

#include "absl/strings/substitute.h"

namespace kythe::verifier {
namespace {
constexpr absl::string_view kGlobalDecls = R"(
Expand All @@ -30,6 +32,10 @@ constexpr absl::string_view kGlobalDecls = R"(
.input entry(IO=kythe)
.decl anchor(begin:number, end:number, vname:vname)
.input anchor(IO=kythe, anchors=1)
.decl at(startsym:number, endsym:number, vname:vname)
at(s, e, v) :- entry(v, $0, nil, $1, $2),
entry(v, $0, nil, $3, s),
entry(v, $0, nil, $4, e).
.decl result()
result() :- true
)";
Expand Down Expand Up @@ -66,8 +72,8 @@ bool SouffleProgram::LowerSubexpression(AstNode* node) {

bool SouffleProgram::LowerGoalGroup(const SymbolTable& symbol_table,
const GoalGroup& group) {
auto eq_sym = const_cast<SymbolTable&>(symbol_table).intern("=");
auto empty_sym = const_cast<SymbolTable&>(symbol_table).intern("");
auto eq_sym = symbol_table.MustIntern("=");
auto empty_sym = symbol_table.MustIntern("");
#ifdef DEBUG_LOWERING
FileHandlePrettyPrinter dprinter(stderr);
#endif
Expand All @@ -87,14 +93,19 @@ bool SouffleProgram::LowerGoalGroup(const SymbolTable& symbol_table,
return false;
}
if (auto* range = tup->element(0)->AsRange()) {
absl::StrAppend(&code_, ", v", FindEVar(evar), "=[_, ", range->corpus(),
", ", range->path(), ", ", range->root(), ", _]");
// TODO(zarko): derive an anchor relation (will need to convert
// range->begin, end to symbols; also need to get the relevant symbols
// included in the prelude) or populate the anchor map (would require
// sorting input, which is a huge time sink).
absl::StrAppend(&code_, ", anchor(", range->begin(), ", ", range->end(),
", v", FindEVar(evar), ")");
auto beginsym =
symbol_table.FindInterned(std::to_string(range->begin()));
auto endsym = symbol_table.FindInterned(std::to_string(range->end()));
if (!beginsym || !endsym) {
// TODO(zarko): emit a warning here (if we're in a positive goal)?
absl::StrAppend(&code_, ", false");
} else {
absl::StrAppend(&code_, ", v", FindEVar(evar), "=[_, ",
range->corpus(), ", ", range->path(), ", ",
range->root(), ", _]");
absl::StrAppend(&code_, ", at(", *beginsym, ", ", *endsym, ", v",
FindEVar(evar), ")");
}
} else {
auto* oevar = tup->element(0)->AsEVar();
if (oevar == nullptr) {
Expand Down Expand Up @@ -134,7 +145,14 @@ bool SouffleProgram::LowerGoalGroup(const SymbolTable& symbol_table,

bool SouffleProgram::Lower(const SymbolTable& symbol_table,
const std::vector<GoalGroup>& goal_groups) {
code_ = emit_prelude_ ? std::string(kGlobalDecls) : "";
code_.clear();
if (emit_prelude_) {
code_ = absl::Substitute(kGlobalDecls, symbol_table.MustIntern(""),
symbol_table.MustIntern("/kythe/node/kind"),
symbol_table.MustIntern("anchor"),
symbol_table.MustIntern("/kythe/loc/start"),
symbol_table.MustIntern("/kythe/loc/end"));
}
CHECK_LE(goal_groups.size(), 1) << "(unimplemented)";
if (goal_groups.size() == 0) {
absl::StrAppend(&code_, ".\n");
Expand Down
6 changes: 6 additions & 0 deletions kythe/cxx/verifier/souffle_interpreter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
namespace kythe::verifier {
TEST(SouffleInterpreterTest, SmokeTest) {
SymbolTable symbols;
// Intern the symbols required by the prelude.
symbols.intern("");
symbols.intern("/kythe/node/kind");
symbols.intern("anchor");
symbols.intern("/kythe/loc/start");
symbols.intern("/kythe/loc/end");
Database db;
AnchorMap anchors;
std::vector<GoalGroup> groups;
Expand Down
11 changes: 8 additions & 3 deletions kythe/cxx/verifier/verifier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,10 @@ bool Verifier::SetGoalCommentRegex(const std::string& regex,
return true;
}

bool Verifier::LoadInlineProtoFile(const std::string& file_data) {
bool Verifier::LoadInlineProtoFile(const std::string& file_data,
absl::string_view path,
absl::string_view root,
absl::string_view corpus) {
kythe::proto::Entries entries;
bool ok = google::protobuf::TextFormat::ParseFromString(file_data, &entries);
if (!ok) {
Expand All @@ -730,8 +733,10 @@ bool Verifier::LoadInlineProtoFile(const std::string& file_data) {
}
}
Symbol empty = symbol_table_.intern("");
return parser_.ParseInlineRuleString(file_data, *kStandardIn, empty, empty,
empty, "\\s*\\#\\-(.*)");
return parser_.ParseInlineRuleString(
file_data, *kStandardIn, symbol_table_.intern(std::string(path)),
symbol_table_.intern(std::string(root)),
symbol_table_.intern(std::string(corpus)), "\\s*\\#\\-(.*)");
}

bool Verifier::LoadInlineRuleFile(const std::string& filename) {
Expand Down
8 changes: 7 additions & 1 deletion kythe/cxx/verifier/verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,14 @@ class Verifier {
/// \brief Loads a text proto with goal comments indicating rules and data.
/// The VName for the source file will be blank.
/// \param file_data The data to load
/// \param path the path to use for anchors
/// \param root the root to use for anchors
/// \param corpus the corpus to use for anchors
/// \return false if we failed
bool LoadInlineProtoFile(const std::string& file_data);
bool LoadInlineProtoFile(const std::string& file_data,
absl::string_view path = "",
absl::string_view root = "",
absl::string_view corpus = "");

/// \brief During verification, ignore duplicate facts.
void IgnoreDuplicateFacts();
Expand Down
6 changes: 3 additions & 3 deletions kythe/cxx/verifier/verifier_unit_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,7 @@ fact_value: ""
}

// TODO(zarko): See comments in souffle_interpreter re: the anchor() relation.
TEST(VerifierUnitTest, GenerateAnchorEvar) {
Verifier v;
TEST_P(VerifierTest, GenerateAnchorEvar) {
ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries {
#- @text defines SomeNode
##text (line 3 column 2 offset 38-42)
Expand All @@ -541,7 +540,8 @@ edge_kind: "/kythe/edge/defines"
target { root:"2" }
fact_name: "/"
fact_value: ""
})"));
})",
"", "1"));
ASSERT_TRUE(v.PrepareDatabase());
ASSERT_TRUE(v.VerifyAllGoals());
}
Expand Down