TypeGraphParser: Throw custom error types

We can catch these exceptions and print clearer failure messages.

Before:
  unknown file: Failure
  C++ exception with description "Invalid type for child" thrown in the test body.

After:
  ../test/type_graph_utils.cpp:44: Failure
  Failed
  Error parsing input graph: Invalid type for child
This commit is contained in:
Alastair Robertson 2023-07-18 04:14:41 -07:00 committed by Alastair Robertson
parent 31f46831c2
commit 4d96848bdb
3 changed files with 35 additions and 20 deletions

View File

@ -49,7 +49,8 @@ Primitive::Kind getKind(std::string_view kindStr) {
return Primitive::Kind::UIntPtr; return Primitive::Kind::UIntPtr;
if (kindStr == "void") if (kindStr == "void")
return Primitive::Kind::Void; return Primitive::Kind::Void;
throw std::runtime_error("Invalid Primitive::Kind: " + std::string{kindStr}); throw TypeGraphParserError{"Invalid Primitive::Kind: " +
std::string{kindStr}};
} }
ContainerInfo getContainerInfo(std::string_view name) { ContainerInfo getContainerInfo(std::string_view name) {
@ -71,14 +72,14 @@ ContainerInfo getContainerInfo(std::string_view name) {
ContainerInfo info{"std::allocator", DUMMY_TYPE, "memory"}; ContainerInfo info{"std::allocator", DUMMY_TYPE, "memory"};
return info; return info;
} }
throw std::runtime_error("Unsupported container: " + std::string{name}); throw TypeGraphParserError{"Unsupported container: " + std::string{name}};
} }
Qualifier getQualifier(std::string_view line) { Qualifier getQualifier(std::string_view line) {
if (line == "const") { if (line == "const") {
return Qualifier::Const; return Qualifier::Const;
} }
throw std::runtime_error("Unsupported qualifier: " + std::string{line}); throw TypeGraphParserError{"Unsupported qualifier: " + std::string{line}};
} }
size_t stripIndent(std::string_view& line) { size_t stripIndent(std::string_view& line) {
@ -96,9 +97,9 @@ bool tryRemovePrefix(std::string_view& line, std::string_view prefix) {
void removePrefix(std::string_view& line, std::string_view prefix) { void removePrefix(std::string_view& line, std::string_view prefix) {
if (!tryRemovePrefix(line, prefix)) if (!tryRemovePrefix(line, prefix))
throw std::runtime_error("Unexpected line prefix. Expected '" + throw TypeGraphParserError{"Unexpected line prefix. Expected '" +
std::string{prefix} + "'. Got '" + std::string{prefix} + "'. Got '" +
std::string{line} + "'."); std::string{line} + "'."};
} }
std::optional<uint64_t> tryParseIntAttribute(std::string_view line, std::optional<uint64_t> tryParseIntAttribute(std::string_view line,
@ -120,9 +121,9 @@ uint64_t parseIntAttribute(std::string_view line,
std::string_view marker) { std::string_view marker) {
auto val = tryParseIntAttribute(line, marker); auto val = tryParseIntAttribute(line, marker);
if (!val) if (!val)
throw std::runtime_error(std::string{type} + " must have an attribute: '" + throw TypeGraphParserError{
std::string{marker} + "'. Got: '" + std::string{type} + " must have an attribute: '" + std::string{marker} +
std::string{line} + "'"); "'. Got: '" + std::string{line} + "'"};
return *val; return *val;
} }
@ -186,8 +187,8 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
size_t indent = stripIndent(line) + idLen; size_t indent = stripIndent(line) + idLen;
if (indent != rootIndent) if (indent != rootIndent)
throw std::runtime_error("Unexpected indent for line: " + throw TypeGraphParserError{"Unexpected indent for line: " +
std::string{line}); std::string{line}};
auto nodeEndPos = line.find_first_of(": \n"); auto nodeEndPos = line.find_first_of(": \n");
auto nodeTypeName = line.substr(0, nodeEndPos); auto nodeTypeName = line.substr(0, nodeEndPos);
@ -196,8 +197,8 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
if (NodeId refId = getId(nodeTypeName); refId != -1) { if (NodeId refId = getId(nodeTypeName); refId != -1) {
auto it = nodesById_.find(refId); auto it = nodesById_.find(refId);
if (it == nodesById_.end()) if (it == nodesById_.end())
throw std::runtime_error("Node ID referenced before definition: " + throw TypeGraphParserError{"Node ID referenced before definition: " +
std::to_string(refId)); std::to_string(refId)};
type = &it->second.get(); type = &it->second.get();
} else if (nodeTypeName == "Class" || nodeTypeName == "Struct" || } else if (nodeTypeName == "Class" || nodeTypeName == "Struct" ||
@ -281,8 +282,8 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
type = &typeGraph_.makeType<Pointer>(id, pointeeType); type = &typeGraph_.makeType<Pointer>(id, pointeeType);
nodesById_.insert({id, *type}); nodesById_.insert({id, *type});
} else { } else {
throw std::runtime_error("Unsupported node type: " + throw TypeGraphParserError{"Unsupported node type: " +
std::string{nodeTypeName}); std::string{nodeTypeName}};
} }
return *type; return *type;
@ -413,7 +414,7 @@ void TypeGraphParser::parseChildren(Class& c,
Type& type = parseType(input, rootIndent + 2); Type& type = parseType(input, rootIndent + 2);
auto* childClass = dynamic_cast<Class*>(&type); auto* childClass = dynamic_cast<Class*>(&type);
if (!childClass) if (!childClass)
throw std::runtime_error("Invalid type for child"); throw TypeGraphParserError{"Invalid type for child"};
c.children.push_back(*childClass); c.children.push_back(*childClass);
} }

View File

@ -35,3 +35,9 @@ class TypeGraphParser {
void parseFunctions(Class& c, std::string_view& input, size_t rootIndent); void parseFunctions(Class& c, std::string_view& input, size_t rootIndent);
void parseChildren(Class& c, std::string_view& input, size_t rootIndent); void parseChildren(Class& c, std::string_view& input, size_t rootIndent);
}; };
class TypeGraphParserError : public std::runtime_error {
public:
TypeGraphParserError(const std::string& msg) : std::runtime_error{msg} {
}
};

View File

@ -38,10 +38,14 @@ void test(type_graph::Pass pass,
input.remove_prefix(1); // Remove initial '\n' input.remove_prefix(1); // Remove initial '\n'
TypeGraph typeGraph; TypeGraph typeGraph;
TypeGraphParser parser{typeGraph}; TypeGraphParser parser{typeGraph};
parser.parse(input); try {
parser.parse(input);
} catch (const TypeGraphParserError& err) {
FAIL() << "Error parsing input graph: " << err.what();
}
// Validate input formatting // Validate input formatting
check(typeGraph.rootTypes(), input, " parsing input graph"); check(typeGraph.rootTypes(), input, "parsing input graph");
// Run pass and check results // Run pass and check results
test(pass, typeGraph.rootTypes(), expectedAfter); test(pass, typeGraph.rootTypes(), expectedAfter);
@ -51,10 +55,14 @@ void testNoChange(type_graph::Pass pass, std::string_view input) {
input.remove_prefix(1); // Remove initial '\n' input.remove_prefix(1); // Remove initial '\n'
TypeGraph typeGraph; TypeGraph typeGraph;
TypeGraphParser parser{typeGraph}; TypeGraphParser parser{typeGraph};
parser.parse(input); try {
parser.parse(input);
} catch (const TypeGraphParserError& err) {
FAIL() << "Error parsing input graph: " << err.what();
}
// Validate input formatting // Validate input formatting
check(typeGraph.rootTypes(), input, " parsing input graph"); check(typeGraph.rootTypes(), input, "parsing input graph");
// Run pass and check results // Run pass and check results
test(pass, typeGraph.rootTypes(), input); test(pass, typeGraph.rootTypes(), input);