in lib/BuildSystem/BuildFile.cpp [610:822]
bool parseCommandsMapping(llvm::yaml::MappingNode* map) {
for (auto& entry: *map) {
// Every key must be scalar.
if (entry.getKey()->getType() != llvm::yaml::Node::NK_Scalar) {
error(entry.getKey(), "invalid key type in 'commands' map");
continue;
}
// Every value must be a mapping.
if (entry.getValue()->getType() != llvm::yaml::Node::NK_Mapping) {
error(entry.getValue(), "invalid value type in 'commands' map");
continue;
}
std::string name = stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(entry.getKey()));
llvm::yaml::MappingNode* attrs = static_cast<llvm::yaml::MappingNode*>(
entry.getValue());
// Check that the command is not a duplicate.
if (commands.count(name) != 0) {
error(entry.getKey(), "duplicate command in 'commands' map");
continue;
}
// Get the initial attribute, which must be the tool name.
auto it = attrs->begin();
if (it == attrs->end()) {
error(entry.getKey(),
"missing 'tool' key for command in 'command' map");
continue;
}
if (!nodeIsScalarString(it->getKey(), "tool")) {
error(it->getKey(),
"expected 'tool' initial key for command in 'commands' map");
// Skip to the end.
while (it != attrs->end()) ++it;
continue;
}
if (it->getValue()->getType() != llvm::yaml::Node::NK_Scalar) {
error(it->getValue(),
"invalid 'tool' value type for command in 'commands' map");
// Skip to the end.
while (it != attrs->end()) ++it;
continue;
}
// Lookup the tool for this command.
auto tool = getOrCreateTool(
stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(
it->getValue())),
it->getValue());
if (!tool) {
return false;
}
// Create the command.
auto command = tool->createCommand(name);
if (!command) {
error(it->getValue(), "tool failed to create a command");
return false;
}
// Parse the remaining command attributes.
++it;
for (; it != attrs->end(); ++it) {
auto key = it->getKey();
auto value = it->getValue();
// If this is a known key, parse it.
if (nodeIsScalarString(key, "inputs")) {
if (value->getType() != llvm::yaml::Node::NK_Sequence) {
error(value, "invalid value type for 'inputs' command key");
continue;
}
llvm::yaml::SequenceNode* nodeNames =
static_cast<llvm::yaml::SequenceNode*>(value);
std::vector<Node*> nodes;
for (auto& nodeName: *nodeNames) {
if (nodeName.getType() != llvm::yaml::Node::NK_Scalar) {
error(&nodeName, "invalid node type in 'inputs' command key");
continue;
}
nodes.push_back(
getOrCreateNode(
stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(&nodeName)),
/*isImplicit=*/true));
}
command->configureInputs(getContext(key), nodes);
} else if (nodeIsScalarString(key, "outputs")) {
if (value->getType() != llvm::yaml::Node::NK_Sequence) {
error(value, "invalid value type for 'outputs' command key");
continue;
}
llvm::yaml::SequenceNode* nodeNames =
static_cast<llvm::yaml::SequenceNode*>(value);
std::vector<Node*> nodes;
for (auto& nodeName: *nodeNames) {
if (nodeName.getType() != llvm::yaml::Node::NK_Scalar) {
error(&nodeName, "invalid node type in 'outputs' command key");
continue;
}
auto node = getOrCreateNode(
stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(&nodeName)),
/*isImplicit=*/true);
nodes.push_back(node);
// Add this command to the node producer list.
node->getProducers().push_back(command.get());
}
command->configureOutputs(getContext(key), nodes);
} else if (nodeIsScalarString(key, "description")) {
if (value->getType() != llvm::yaml::Node::NK_Scalar) {
error(value, "invalid value type for 'description' command key");
continue;
}
command->configureDescription(
getContext(key), stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(value)));
} else {
// Otherwise, it should be an attribute assignment.
// All keys must be scalar.
if (key->getType() != llvm::yaml::Node::NK_Scalar) {
error(key, "invalid key type in 'commands' map");
continue;
}
auto attribute = stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(key));
if (value->getType() == llvm::yaml::Node::NK_Mapping) {
std::vector<std::pair<std::string, std::string>> values;
for (auto& entry: *static_cast<llvm::yaml::MappingNode*>(value)) {
// Every key must be scalar.
if (entry.getKey()->getType() != llvm::yaml::Node::NK_Scalar) {
error(entry.getKey(), ("invalid key type for '" + attribute +
"' in 'commands' map"));
continue;
}
// Every value must be scalar.
if (entry.getValue()->getType() != llvm::yaml::Node::NK_Scalar) {
error(entry.getKey(), ("invalid value type for '" + attribute +
"' in 'commands' map"));
continue;
}
std::string key = stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(entry.getKey()));
std::string value = stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(entry.getValue()));
values.push_back(std::make_pair(key, value));
}
if (!command->configureAttribute(
getContext(key), attribute,
std::vector<std::pair<StringRef, StringRef>>(
values.begin(), values.end()))) {
return false;
}
} else if (value->getType() == llvm::yaml::Node::NK_Sequence) {
std::vector<std::string> values;
for (auto& node: *static_cast<llvm::yaml::SequenceNode*>(value)) {
if (node.getType() != llvm::yaml::Node::NK_Scalar) {
error(&node, "invalid value type for command in 'commands' map");
continue;
}
values.push_back(
stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(&node)));
}
if (!command->configureAttribute(
getContext(key), attribute,
std::vector<StringRef>(values.begin(), values.end()))) {
return false;
}
} else {
if (value->getType() != llvm::yaml::Node::NK_Scalar) {
error(value, "invalid value type for command in 'commands' map");
continue;
}
if (!command->configureAttribute(
getContext(key), attribute,
stringFromScalarNode(
static_cast<llvm::yaml::ScalarNode*>(value)))) {
return false;
}
}
}
}
// Let the delegate know we loaded a command.
delegate.loadedCommand(name, *command);
// Add the command to the commands map.
commands[name] = std::move(command);
}
return true;
}