[toolchain] Add dump-parse-tree command to driver. (#584)

Also stop producing a redundant additional error message if lexing fails in dump-tokens. The lexer will have produced a diagnostic already.
This commit is contained in:
Richard Smith
2021-06-17 19:07:14 -07:00
committed by GitHub
parent 6a4c8a5186
commit d6b47ba10f
5 changed files with 102 additions and 5 deletions
+1
View File
@@ -15,6 +15,7 @@ cc_library(
deps = [
"//toolchain/diagnostics:diagnostic_emitter",
"//toolchain/lexer:tokenized_buffer",
"//toolchain/parser:parse_tree",
"//toolchain/source:source_buffer",
"@llvm-project//llvm:Support",
],
+33 -5
View File
@@ -13,6 +13,7 @@
#include "llvm/Support/Format.h"
#include "toolchain/diagnostics/diagnostic_emitter.h"
#include "toolchain/lexer/tokenized_buffer.h"
#include "toolchain/parser/parse_tree.h"
#include "toolchain/source/source_buffer.h"
namespace Carbon {
@@ -118,13 +119,40 @@ auto Driver::RunDumpTokensSubcommand(llvm::ArrayRef<llvm::StringRef> args)
}
auto tokenized_source =
TokenizedBuffer::Lex(*source, ConsoleDiagnosticConsumer());
if (tokenized_source.HasErrors()) {
error_stream << "ERROR: Unable to tokenize source file '" << input_file_name
<< "'!\n";
tokenized_source.Print(output_stream);
return !tokenized_source.HasErrors();
}
auto Driver::RunDumpParseTreeSubcommand(llvm::ArrayRef<llvm::StringRef> args)
-> bool {
if (args.empty()) {
error_stream << "ERROR: No input file specified.\n";
return false;
}
tokenized_source.Print(output_stream);
return true;
llvm::StringRef input_file_name = args.front();
args = args.drop_front();
if (!args.empty()) {
ReportExtraArgs("dump-parse-tree", args);
return false;
}
auto source = SourceBuffer::CreateFromFile(input_file_name);
if (!source) {
error_stream << "ERROR: Unable to open input source file: ";
llvm::handleAllErrors(source.takeError(),
[&](const llvm::ErrorInfoBase& ei) {
ei.log(error_stream);
error_stream << "\n";
});
return false;
}
auto tokenized_source =
TokenizedBuffer::Lex(*source, ConsoleDiagnosticConsumer());
auto parse_tree =
ParseTree::Parse(tokenized_source, ConsoleDiagnosticConsumer());
parse_tree.Print(output_stream);
return !tokenized_source.HasErrors() && !parse_tree.HasErrors();
}
auto Driver::ReportExtraArgs(llvm::StringRef subcommand_text,
+10
View File
@@ -57,6 +57,16 @@ class Driver {
// registered error stream (stderr by default).
auto RunDumpTokensSubcommand(llvm::ArrayRef<llvm::StringRef> args) -> bool;
// Subcommand that dumps the parse tree for the provided source file.
//
// Requires exactly one positional parameter to designate the source file to
// read. May be `-` to read from stdin.
//
// Returns true if the operation succeeds. If the operation fails, this
// returns false and any information about the failure is printed to the
// registered error stream (stderr by default).
auto RunDumpParseTreeSubcommand(llvm::ArrayRef<llvm::StringRef> args) -> bool;
private:
auto ReportExtraArgs(llvm::StringRef subcommand_text,
llvm::ArrayRef<llvm::StringRef> args) -> void;
+55
View File
@@ -179,5 +179,60 @@ TEST(DriverTest, DumpTokenErrors) {
EXPECT_THAT(test_error_stream.TakeStr(), HasSubstr("ERROR"));
}
TEST(DriverTest, DumpParseTree) {
RawTestOstream test_output_stream;
RawTestOstream test_error_stream;
Driver driver = Driver(test_output_stream, test_error_stream);
auto test_file_path = CreateTestFile("var v: Int = 42;");
EXPECT_TRUE(driver.RunDumpParseTreeSubcommand({test_file_path}));
EXPECT_THAT(test_error_stream.TakeStr(), StrEq(""));
auto tokenized_text = test_output_stream.TakeStr();
EXPECT_THAT(
Yaml::Value::FromText(tokenized_text),
ElementsAre(Yaml::SequenceValue{
Yaml::MappingValue{
{"node_index", "6"},
{"kind", "VariableDeclaration"},
{"text", "var"},
{"subtree_size", "7"},
{"children",
Yaml::SequenceValue{
Yaml::MappingValue{
{"node_index", "2"},
{"kind", "PatternBinding"},
{"text", ":"},
{"subtree_size", "3"},
{"children",
Yaml::SequenceValue{
Yaml::MappingValue{{"node_index", "0"},
{"kind", "DeclaredName"},
{"text", "v"}},
Yaml::MappingValue{{"node_index", "1"},
{"kind", "NameReference"},
{"text", "Int"}}}}},
Yaml::MappingValue{{"node_index", "4"},
{"kind", "VariableInitializer"},
{"text", "="},
{"subtree_size", "2"},
{"children", //
Yaml::SequenceValue{Yaml::MappingValue{
{"node_index", "3"},
{"kind", "Literal"},
{"text", "42"}}}}},
Yaml::MappingValue{{"node_index", "5"},
{"kind", "DeclarationEnd"},
{"text", ";"}}}}},
Yaml::MappingValue{{"node_index", "7"}, //
{"kind", "FileEnd"},
{"text", ""}}}));
// Check that the subcommand dispatch works.
EXPECT_TRUE(driver.RunFullCommand({"dump-parse-tree", test_file_path}));
EXPECT_THAT(test_error_stream.TakeStr(), StrEq(""));
EXPECT_THAT(test_output_stream.TakeStr(), StrEq(tokenized_text));
}
} // namespace
} // namespace Carbon
+3
View File
@@ -15,5 +15,8 @@ CARBON_SUBCOMMAND(Help, "help",
CARBON_SUBCOMMAND(
DumpTokens, "dump-tokens",
"Dumps the sequence of tokens lexed out of the input source file.")
CARBON_SUBCOMMAND(
DumpParseTree, "dump-parse-tree",
"Dumps the parse tree for the input source file.")
#undef CARBON_SUBCOMMAND