10 #include "llvm/ADT/Optional.h"
11 #include "llvm/ADT/SmallSet.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/MemoryBuffer.h"
14 #include "llvm/Support/SourceMgr.h"
15 #include "llvm/Support/YAMLParser.h"
16 #include <system_error>
22 using llvm::yaml::BlockScalarNode;
23 using llvm::yaml::MappingNode;
24 using llvm::yaml::Node;
25 using llvm::yaml::ScalarNode;
26 using llvm::yaml::SequenceNode;
30 bool HadError =
false;
37 bool parse(Fragment &F, Node &N) {
38 DictParser Dict(
"Config",
this);
39 Dict.handle(
"If", [&](Node &N) { parse(F.If, N); });
40 Dict.handle(
"CompileFlags", [&](Node &N) { parse(F.CompileFlags, N); });
42 return !(N.failed() || HadError);
46 void parse(Fragment::IfBlock &F, Node &N) {
47 DictParser Dict(
"If",
this);
49 [&](llvm::StringRef) { F.HasUnrecognizedCondition =
true; });
50 Dict.handle(
"PathMatch", [&](Node &N) {
51 if (
auto Values = scalarValues(N))
52 F.PathMatch = std::move(*Values);
54 Dict.handle(
"PathExclude", [&](Node &N) {
55 if (
auto Values = scalarValues(N))
56 F.PathExclude = std::move(*Values);
61 void parse(Fragment::CompileFlagsBlock &F, Node &N) {
62 DictParser Dict(
"CompileFlags",
this);
63 Dict.handle(
"Add", [&](Node &N) {
64 if (
auto Values = scalarValues(N))
65 F.Add = std::move(*Values);
67 Dict.handle(
"Remove", [&](Node &N) {
68 if (
auto Values = scalarValues(N))
69 F.Remove = std::move(*Values);
74 void parse(Fragment::IndexBlock &F, Node &N) {
75 DictParser Dict(
"Index",
this);
76 Dict.handle(
"Background",
77 [&](Node &N) { F.Background = scalarValue(N,
"Background"); });
85 std::vector<std::pair<llvm::StringRef, std::function<void(Node &)>>> Keys;
86 std::function<void(llvm::StringRef)> Unknown;
96 void handle(llvm::StringLiteral Key, std::function<
void(Node &)> Parse) {
97 for (
const auto &
Entry : Keys) {
99 assert(
Entry.first != Key &&
"duplicate key handler");
101 Keys.emplace_back(Key, std::move(Parse));
106 void unrecognized(std::function<
void(llvm::StringRef)> Fallback) {
107 Unknown = std::move(Fallback);
111 void parse(Node &N)
const {
112 if (N.getType() != Node::NK_Mapping) {
116 llvm::SmallSet<std::string, 8> Seen;
118 for (
auto &KV : llvm::cast<MappingNode>(N)) {
119 auto *K = KV.getKey();
122 auto Key =
Outer->scalarValue(*K,
"Dictionary key");
125 if (!Seen.insert(**Key).second) {
126 Outer->warning(
"Duplicate key " + **Key +
" is ignored", *K);
129 auto *Value = KV.getValue();
132 bool Matched =
false;
133 for (
const auto &Handler : Keys) {
134 if (Handler.first == **Key) {
136 Handler.second(*Value);
150 llvm::Optional<Located<std::string>> scalarValue(Node &N,
151 llvm::StringRef Desc) {
152 llvm::SmallString<256> Buf;
153 if (
auto *S = llvm::dyn_cast<ScalarNode>(&N))
154 return Located<std::string>(S->getValue(Buf).str(), N.getSourceRange());
155 if (
auto *BS = llvm::dyn_cast<BlockScalarNode>(&N))
156 return Located<std::string>(BS->getValue().str(), N.getSourceRange());
157 warning(Desc +
" should be scalar", N);
162 llvm::Optional<std::vector<Located<std::string>>> scalarValues(Node &N) {
163 std::vector<Located<std::string>> Result;
164 if (
auto *S = llvm::dyn_cast<ScalarNode>(&N)) {
165 llvm::SmallString<256> Buf;
166 Result.emplace_back(S->getValue(Buf).str(), N.getSourceRange());
167 }
else if (
auto *S = llvm::dyn_cast<BlockScalarNode>(&N)) {
168 Result.emplace_back(S->getValue().str(), N.getSourceRange());
169 }
else if (
auto *S = llvm::dyn_cast<SequenceNode>(&N)) {
171 for (
auto &Child : *S) {
172 if (
auto Value = scalarValue(Child,
"List item"))
173 Result.push_back(std::move(*Value));
176 warning(
"Expected scalar or list of scalars", N);
183 void error(
const llvm::Twine &Msg,
const Node &N) {
185 SM.PrintMessage(N.getSourceRange().Start, llvm::SourceMgr::DK_Error, Msg,
190 void warning(
const llvm::Twine &Msg,
const Node &N) {
191 SM.PrintMessage(N.getSourceRange().Start, llvm::SourceMgr::DK_Warning, Msg,
199 llvm::StringRef BufferName,
203 auto SM = std::make_shared<llvm::SourceMgr>();
204 auto Buf = llvm::MemoryBuffer::getMemBufferCopy(
YAML, BufferName);
208 [](
const llvm::SMDiagnostic &
Diag,
void *
Ctx) {
209 (*reinterpret_cast<DiagnosticCallback *>(
Ctx))(
Diag);
212 std::vector<Fragment> Result;
213 for (
auto &Doc : llvm::yaml::Stream(*Buf, *SM)) {
214 if (Node *N = Doc.getRoot()) {
218 if (Parser(*SM).parse(
Fragment, *N))
219 Result.push_back(std::move(
Fragment));
224 SM->AddNewSourceBuffer(std::move(Buf), llvm::SMLoc());