mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
169 lines
4.8 KiB
C++
169 lines
4.8 KiB
C++
/// \file Runner.cpp
|
|
/// A target is a object that is associated to the content of a container to
|
|
/// describe it without knowing what is the real type of the content itself.
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
#include "revng/Pipeline/Container.h"
|
|
#include "revng/Pipeline/Context.h"
|
|
#include "revng/Pipeline/Kind.h"
|
|
#include "revng/Pipeline/KindsRegistry.h"
|
|
#include "revng/Pipeline/Target.h"
|
|
#include "revng/Support/Assert.h"
|
|
|
|
using namespace pipeline;
|
|
using namespace std;
|
|
using namespace llvm;
|
|
|
|
bool TargetsList::contains(const Target &Target) const {
|
|
return find(*this, Target) != end();
|
|
}
|
|
|
|
void TargetsList::merge(const TargetsList &Source) {
|
|
copy(Source, back_inserter(Contained));
|
|
llvm::sort(Contained);
|
|
Contained.erase(unique(Contained.begin(), Contained.end()), Contained.end());
|
|
}
|
|
|
|
void ContainerToTargetsMap::erase(const ContainerToTargetsMap &Other) {
|
|
for (const auto &Container : Other.Status) {
|
|
const auto &ContainerName = Container.first();
|
|
const auto &ContainerSymbols = Container.second;
|
|
if (Status.find(ContainerName) == Status.end())
|
|
continue;
|
|
auto &ToRemoveFrom = Status[ContainerName];
|
|
|
|
for (auto &Symbol : ContainerSymbols)
|
|
ToRemoveFrom.erase(Symbol);
|
|
}
|
|
}
|
|
|
|
void ContainerToTargetsMap::merge(const ContainerToTargetsMap &Other) {
|
|
for (const auto &Container : Other.Status) {
|
|
const auto &ContainerName = Container.first();
|
|
const auto &ContainerSymbols = Container.second;
|
|
auto &ToMergeIn = Status[ContainerName];
|
|
|
|
ToMergeIn.merge(ContainerSymbols);
|
|
}
|
|
}
|
|
|
|
// NOTE: this operator needs to be stable w.r.t. library load order and memory
|
|
// layout
|
|
int Target::operator<=>(const Target &Other) const {
|
|
if (K->id() < Other.K->id())
|
|
return -1;
|
|
if (K->id() > Other.K->id())
|
|
return 1;
|
|
|
|
if (Components.size() != Other.Components.size()) {
|
|
if (Components.size() > Other.Components.size())
|
|
return -1;
|
|
if (Components.size() < Other.Components.size())
|
|
return 1;
|
|
}
|
|
|
|
for (const auto &[l, r] : zip(Components, Other.Components)) {
|
|
if (l < r)
|
|
return -1;
|
|
if (l > r)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
std::string Target::toString() const {
|
|
std::string ToReturn;
|
|
|
|
if (Components.size() == 0) {
|
|
return ":" + K->name().str();
|
|
}
|
|
|
|
for (size_t I = 0; I < Components.size() - 1; I++)
|
|
ToReturn += Components[I] + "/";
|
|
|
|
ToReturn += Components.back();
|
|
ToReturn += ":";
|
|
ToReturn += K->name();
|
|
|
|
return ToReturn;
|
|
}
|
|
|
|
llvm::Expected<Target> Target::deserialize(Context &Context,
|
|
llvm::StringRef String) {
|
|
if (String.contains('*'))
|
|
return revng::createError("String cannot contain *");
|
|
|
|
TargetsList Out;
|
|
if (auto Error = parseTarget(Context,
|
|
String,
|
|
Context.getKindsRegistry(),
|
|
Out);
|
|
Error) {
|
|
return std::move(Error);
|
|
}
|
|
|
|
revng_assert(Out.size() == 1);
|
|
return Out.front();
|
|
}
|
|
|
|
llvm::Error pipeline::parseTarget(const Context &Context,
|
|
llvm::StringRef AsString,
|
|
const KindsRegistry &Dict,
|
|
TargetsList &Out) {
|
|
|
|
size_t Pos = AsString.rfind(':');
|
|
|
|
if (Pos == llvm::StringRef::npos) {
|
|
auto *Message = "String '%s' was not in expected form <path:kind>";
|
|
return revng::createError(Message, AsString.str().c_str());
|
|
}
|
|
|
|
llvm::StringRef Name(AsString.data(), Pos);
|
|
llvm::StringRef KindName = AsString.drop_front(Pos + 1);
|
|
llvm::SmallVector<llvm::StringRef, 4> Path;
|
|
Name.split(Path, '/');
|
|
|
|
auto It = llvm::find_if(Dict, [&](Kind &K) { return KindName == K.name(); });
|
|
if (It == Dict.end())
|
|
return revng::createError("No known Kind '%s' in dictionary",
|
|
KindName.str().c_str());
|
|
|
|
if (AsString[0] == ':') {
|
|
Out.push_back(Target({}, *It));
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
if (find(AsString, '*') != AsString.end()) {
|
|
It->appendAllTargets(Context, Out);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
Out.push_back(Target(std::move(Path), *It));
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error pipeline::parseTarget(const Context &Context,
|
|
ContainerToTargetsMap &CurrentStatus,
|
|
llvm::StringRef AsString,
|
|
const KindsRegistry &Dict) {
|
|
if (AsString.empty())
|
|
return llvm::Error::success();
|
|
|
|
llvm::SmallVector<llvm::StringRef, 2> Parts;
|
|
AsString.split(Parts, '/', 1);
|
|
|
|
if (Parts.size() != 2) {
|
|
auto *Text = "string '%s' was not in expected form <ContainerName/Target>";
|
|
return revng::createError(Text, AsString.str().c_str());
|
|
}
|
|
|
|
return parseTarget(Context, Parts[1], Dict, CurrentStatus[Parts[0]]);
|
|
}
|