diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h index 509c9f4b9e91a..e37ef5e236871 100644 --- a/flang/include/flang/Frontend/CompilerInstance.h +++ b/flang/include/flang/Frontend/CompilerInstance.h @@ -15,9 +15,8 @@ #include "flang/Frontend/CompilerInvocation.h" #include "flang/Frontend/FrontendAction.h" +#include "flang/Frontend/ParserActions.h" #include "flang/Frontend/PreprocessorOptions.h" -#include "flang/Parser/parsing.h" -#include "flang/Parser/provenance.h" #include "flang/Semantics/runtime-type-info.h" #include "flang/Semantics/semantics.h" #include "flang/Support/StringOstream.h" diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h index 9e6724be33033..d6ee1511cdb4b 100644 --- a/flang/include/flang/Frontend/CompilerInvocation.h +++ b/flang/include/flang/Frontend/CompilerInvocation.h @@ -18,7 +18,7 @@ #include "flang/Frontend/PreprocessorOptions.h" #include "flang/Frontend/TargetOptions.h" #include "flang/Lower/LoweringOptions.h" -#include "flang/Parser/parsing.h" +#include "flang/Parser/options.h" #include "flang/Semantics/semantics.h" #include "flang/Support/LangOptions.h" #include "mlir/Support/Timing.h" @@ -29,7 +29,7 @@ namespace llvm { class TargetMachine; -} +} // namespace llvm namespace Fortran::frontend { diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h index 4e3d3cb2657db..f9a45bd6c0a56 100644 --- a/flang/include/flang/Frontend/FrontendActions.h +++ b/flang/include/flang/Frontend/FrontendActions.h @@ -13,10 +13,8 @@ #ifndef FORTRAN_FRONTEND_FRONTENDACTIONS_H #define FORTRAN_FRONTEND_FRONTENDACTIONS_H -#include "flang/Frontend/CodeGenOptions.h" #include "flang/Frontend/FrontendAction.h" -#include "flang/Parser/parsing.h" -#include "flang/Semantics/semantics.h" +#include "flang/Frontend/ParserActions.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/OwningOpRef.h" @@ -26,21 +24,6 @@ namespace Fortran::frontend { -// TODO: This is a copy from f18.cpp. It doesn't really belong here and should -// be moved to a more suitable place in future. -struct MeasurementVisitor { - template - bool Pre(const A &) { - return true; - } - template - void Post(const A &) { - ++objects; - bytes += sizeof(A); - } - size_t objects{0}, bytes{0}; -}; - //===----------------------------------------------------------------------===// // Custom Consumer Actions //===----------------------------------------------------------------------===// diff --git a/flang/include/flang/Frontend/ParserActions.h b/flang/include/flang/Frontend/ParserActions.h new file mode 100644 index 0000000000000..8e7d1f71ec105 --- /dev/null +++ b/flang/include/flang/Frontend/ParserActions.h @@ -0,0 +1,67 @@ +//===- ParserActions.h -------------------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_PARSER_ACTIONS_H_ +#define FORTRAN_PARSER_ACTIONS_H_ + +#include + +namespace llvm { +class raw_string_ostream; +class raw_ostream; +class StringRef; +} // namespace llvm + +namespace Fortran::lower { +class LoweringBridge; +} // namespace Fortran::lower + +namespace Fortran::parser { +class Parsing; +class AllCookedSources; +} // namespace Fortran::parser + +namespace lower::pft { +class Program; +} // namespace lower::pft + +//=== Frontend Parser helpers === + +namespace Fortran::frontend { +class CompilerInstance; + +parser::AllCookedSources &getAllCooked(CompilerInstance &ci); + +void parseAndLowerTree(CompilerInstance &ci, lower::LoweringBridge &lb); + +void dumpTree(CompilerInstance &ci); + +void dumpProvenance(CompilerInstance &ci); + +void dumpPreFIRTree(CompilerInstance &ci); + +void formatOrDumpPrescanner(std::string &buf, + llvm::raw_string_ostream &outForPP, + CompilerInstance &ci); + +void debugMeasureParseTree(CompilerInstance &ci, llvm::StringRef filename); + +void debugUnparseNoSema(CompilerInstance &ci, llvm::raw_ostream &out); + +void debugUnparseWithSymbols(CompilerInstance &ci); + +void debugUnparseWithModules(CompilerInstance &ci); + +void debugDumpParsingLog(CompilerInstance &ci); +} // namespace Fortran::frontend + +#endif // FORTRAN_PARSER_ACTIONS_H_ diff --git a/flang/include/flang/Parser/options.h b/flang/include/flang/Parser/options.h new file mode 100644 index 0000000000000..dc363acb7c28a --- /dev/null +++ b/flang/include/flang/Parser/options.h @@ -0,0 +1,43 @@ +//===-- include/flang/Parser/options.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_PARSER_OPTIONS_H_ +#define FORTRAN_PARSER_OPTIONS_H_ + +#include "characters.h" +#include "flang/Support/Fortran-features.h" + +#include +#include +#include + +namespace Fortran::parser { + +struct Options { + Options() {} + + using Predefinition = std::pair>; + + bool isFixedForm{false}; + int fixedFormColumns{72}; + common::LanguageFeatureControl features; + std::vector searchDirectories; + std::vector intrinsicModuleDirectories; + std::vector predefinitions; + bool instrumentedParse{false}; + bool isModuleFile{false}; + bool needProvenanceRangeToCharBlockMappings{false}; + Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8}; + bool prescanAndReformat{false}; // -E + bool expandIncludeLinesInPreprocessedOutput{true}; + bool showColors{false}; +}; + +} // namespace Fortran::parser + +#endif // FORTRAN_PARSER_OPTIONS_H_ diff --git a/flang/include/flang/Parser/parsing.h b/flang/include/flang/Parser/parsing.h index 116b6bd6f191f..3365628dc4e0c 100644 --- a/flang/include/flang/Parser/parsing.h +++ b/flang/include/flang/Parser/parsing.h @@ -9,41 +9,18 @@ #ifndef FORTRAN_PARSER_PARSING_H_ #define FORTRAN_PARSER_PARSING_H_ -#include "characters.h" #include "instrumented-parser.h" #include "message.h" +#include "options.h" #include "parse-tree.h" #include "provenance.h" #include "flang/Parser/preprocessor.h" -#include "flang/Support/Fortran-features.h" #include "llvm/Support/raw_ostream.h" #include #include -#include -#include namespace Fortran::parser { -struct Options { - Options() {} - - using Predefinition = std::pair>; - - bool isFixedForm{false}; - int fixedFormColumns{72}; - common::LanguageFeatureControl features; - std::vector searchDirectories; - std::vector intrinsicModuleDirectories; - std::vector predefinitions; - bool instrumentedParse{false}; - bool isModuleFile{false}; - bool needProvenanceRangeToCharBlockMappings{false}; - Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8}; - bool prescanAndReformat{false}; // -E - bool expandIncludeLinesInPreprocessedOutput{true}; - bool showColors{false}; -}; - class Parsing { public: explicit Parsing(AllCookedSources &); diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index 80d63fca6fb76..c80373799b015 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -5,6 +5,7 @@ add_flang_library(flangFrontend CompilerInstance.cpp CompilerInvocation.cpp CodeGenOptions.cpp + ParserActions.cpp FrontendAction.cpp FrontendActions.cpp FrontendOptions.cpp diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp index 9a555bc7cd23b..ab77d143fa4b6 100644 --- a/flang/lib/Frontend/FrontendAction.cpp +++ b/flang/lib/Frontend/FrontendAction.cpp @@ -15,6 +15,7 @@ #include "flang/Frontend/FrontendActions.h" #include "flang/Frontend/FrontendOptions.h" #include "flang/Frontend/FrontendPluginRegistry.h" +#include "flang/Parser/parsing.h" #include "clang/Basic/DiagnosticFrontend.h" #include "llvm/Support/Errc.h" #include "llvm/Support/VirtualFileSystem.h" diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 76d329d043731..271ecff5758b6 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -14,9 +14,8 @@ #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/CompilerInvocation.h" #include "flang/Frontend/FrontendOptions.h" -#include "flang/Frontend/PreprocessorOptions.h" +#include "flang/Frontend/ParserActions.h" #include "flang/Lower/Bridge.h" -#include "flang/Lower/PFTBuilder.h" #include "flang/Lower/Support/Verifier.h" #include "flang/Optimizer/Dialect/Support/FIRContext.h" #include "flang/Optimizer/Dialect/Support/KindMapping.h" @@ -25,13 +24,7 @@ #include "flang/Optimizer/Support/InitFIR.h" #include "flang/Optimizer/Support/Utils.h" #include "flang/Optimizer/Transforms/Passes.h" -#include "flang/Parser/dump-parse-tree.h" -#include "flang/Parser/parsing.h" -#include "flang/Parser/provenance.h" -#include "flang/Parser/source.h" -#include "flang/Parser/unparse.h" #include "flang/Semantics/runtime-type-info.h" -#include "flang/Semantics/semantics.h" #include "flang/Semantics/unparse-with-symbols.h" #include "flang/Support/default-kinds.h" #include "flang/Tools/CrossToolHelpers.h" @@ -317,9 +310,9 @@ bool CodeGenAction::beginSourceFileAction() { lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create( *mlirCtx, ci.getSemanticsContext(), defKinds, ci.getSemanticsContext().intrinsics(), - ci.getSemanticsContext().targetCharacteristics(), - ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple, - kindMap, ci.getInvocation().getLoweringOpts(), + ci.getSemanticsContext().targetCharacteristics(), getAllCooked(ci), + ci.getInvocation().getTargetOpts().triple, kindMap, + ci.getInvocation().getLoweringOpts(), ci.getInvocation().getFrontendOpts().envDefaults, ci.getInvocation().getFrontendOpts().features, targetMachine, ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts()); @@ -333,8 +326,7 @@ bool CodeGenAction::beginSourceFileAction() { } // Create a parse tree and lower it to FIR - Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()}; - lb.lower(parseTree, ci.getSemanticsContext()); + parseAndLowerTree(ci, lb); // Fetch module from lb, so we can set mlirModule = lb.getModuleAndRelease(); @@ -431,19 +423,8 @@ void PrintPreprocessedAction::executeAction() { std::string buf; llvm::raw_string_ostream outForPP{buf}; - // Format or dump the prescanner's output CompilerInstance &ci = this->getInstance(); - if (ci.getInvocation().getPreprocessorOpts().showMacros) { - ci.getParsing().EmitPreprocessorMacros(outForPP); - } else if (ci.getInvocation().getPreprocessorOpts().noReformat) { - ci.getParsing().DumpCookedChars(outForPP); - } else { - ci.getParsing().EmitPreprocessedSource( - outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives); - } - - // Print getDiagnostics from the prescanner - ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); + formatOrDumpPrescanner(buf, outForPP, ci); // If a pre-defined output stream exists, dump the preprocessed content there if (!ci.isOutputStreamNull()) { @@ -463,60 +444,31 @@ void PrintPreprocessedAction::executeAction() { } void DebugDumpProvenanceAction::executeAction() { - this->getInstance().getParsing().DumpProvenance(llvm::outs()); + dumpProvenance(this->getInstance()); } void ParseSyntaxOnlyAction::executeAction() {} void DebugUnparseNoSemaAction::executeAction() { - auto &invoc = this->getInstance().getInvocation(); - auto &parseTree{getInstance().getParsing().parseTree()}; - - // TODO: Options should come from CompilerInvocation - Unparse(llvm::outs(), *parseTree, - /*encoding=*/Fortran::parser::Encoding::UTF_8, - /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, - /*preStatement=*/nullptr, - invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() - : nullptr); + debugUnparseNoSema(this->getInstance(), llvm::outs()); } void DebugUnparseAction::executeAction() { - auto &invoc = this->getInstance().getInvocation(); - auto &parseTree{getInstance().getParsing().parseTree()}; - CompilerInstance &ci = this->getInstance(); auto os{ci.createDefaultOutputFile( /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())}; - // TODO: Options should come from CompilerInvocation - Unparse(*os, *parseTree, - /*encoding=*/Fortran::parser::Encoding::UTF_8, - /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, - /*preStatement=*/nullptr, - invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() - : nullptr); - - // Report fatal semantic errors + debugUnparseNoSema(ci, *os); reportFatalSemanticErrors(); } void DebugUnparseWithSymbolsAction::executeAction() { - auto &parseTree{*getInstance().getParsing().parseTree()}; - - Fortran::semantics::UnparseWithSymbols( - llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8); - - // Report fatal semantic errors + debugUnparseWithSymbols(this->getInstance()); reportFatalSemanticErrors(); } void DebugUnparseWithModulesAction::executeAction() { - auto &parseTree{*getInstance().getParsing().parseTree()}; - CompilerInstance &ci{getInstance()}; - Fortran::semantics::UnparseWithModules( - llvm::outs(), ci.getSemantics().context(), parseTree, - /*encoding=*/Fortran::parser::Encoding::UTF_8); + debugUnparseWithModules(this->getInstance()); reportFatalSemanticErrors(); } @@ -540,12 +492,7 @@ void DebugDumpAllAction::executeAction() { CompilerInstance &ci = this->getInstance(); // Dump parse tree - auto &parseTree{getInstance().getParsing().parseTree()}; - llvm::outs() << "========================"; - llvm::outs() << " Flang: parse tree dump "; - llvm::outs() << "========================\n"; - Fortran::parser::DumpTree(llvm::outs(), parseTree, - &ci.getInvocation().getAsFortran()); + dumpTree(ci); if (!ci.getRtTyTables().schemata) { unsigned diagID = ci.getDiagnostics().getCustomDiagID( @@ -564,21 +511,11 @@ void DebugDumpAllAction::executeAction() { } void DebugDumpParseTreeNoSemaAction::executeAction() { - auto &parseTree{getInstance().getParsing().parseTree()}; - - // Dump parse tree - Fortran::parser::DumpTree( - llvm::outs(), parseTree, - &this->getInstance().getInvocation().getAsFortran()); + dumpTree(this->getInstance()); } void DebugDumpParseTreeAction::executeAction() { - auto &parseTree{getInstance().getParsing().parseTree()}; - - // Dump parse tree - Fortran::parser::DumpTree( - llvm::outs(), parseTree, - &this->getInstance().getInvocation().getAsFortran()); + dumpTree(this->getInstance()); // Report fatal semantic errors reportFatalSemanticErrors(); @@ -586,62 +523,20 @@ void DebugDumpParseTreeAction::executeAction() { void DebugMeasureParseTreeAction::executeAction() { CompilerInstance &ci = this->getInstance(); - - // Parse. In case of failure, report and return. - ci.getParsing().Parse(llvm::outs()); - - if ((ci.getParsing().parseTree().has_value() && - !ci.getParsing().consumedWholeFile()) || - (!ci.getParsing().messages().empty() && - (ci.getInvocation().getWarnAsErr() || - ci.getParsing().messages().AnyFatalError()))) { - unsigned diagID = ci.getDiagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Error, "Could not parse %0"); - ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); - - ci.getParsing().messages().Emit(llvm::errs(), - this->getInstance().getAllCookedSources()); - return; - } - - // Report the getDiagnostics from parsing - ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); - - auto &parseTree{*ci.getParsing().parseTree()}; - - // Measure the parse tree - MeasurementVisitor visitor; - Fortran::parser::Walk(parseTree, visitor); - llvm::outs() << "Parse tree comprises " << visitor.objects - << " objects and occupies " << visitor.bytes - << " total bytes.\n"; + debugMeasureParseTree(ci, getCurrentFileOrBufferName()); } void DebugPreFIRTreeAction::executeAction() { - CompilerInstance &ci = this->getInstance(); // Report and exit if fatal semantic errors are present if (reportFatalSemanticErrors()) { return; } - auto &parseTree{*ci.getParsing().parseTree()}; - - // Dump pre-FIR tree - if (auto ast{ - Fortran::lower::createPFT(parseTree, ci.getSemanticsContext())}) { - Fortran::lower::dumpPFT(llvm::outs(), *ast); - } else { - unsigned diagID = ci.getDiagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); - ci.getDiagnostics().Report(diagID); - } + dumpPreFIRTree(this->getInstance()); } void DebugDumpParsingLogAction::executeAction() { - CompilerInstance &ci = this->getInstance(); - - ci.getParsing().Parse(llvm::errs()); - ci.getParsing().DumpParsingLog(llvm::outs()); + debugDumpParsingLog(this->getInstance()); } void GetDefinitionAction::executeAction() { @@ -1473,17 +1368,7 @@ void InitOnlyAction::executeAction() { void PluginParseTreeAction::executeAction() {} void DebugDumpPFTAction::executeAction() { - CompilerInstance &ci = this->getInstance(); - - if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(), - ci.getSemantics().context())) { - Fortran::lower::dumpPFT(llvm::outs(), *ast); - return; - } - - unsigned diagID = ci.getDiagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); - ci.getDiagnostics().Report(diagID); + dumpPreFIRTree(this->getInstance()); } Fortran::parser::Parsing &PluginParseTreeAction::getParsing() { diff --git a/flang/lib/Frontend/ParserActions.cpp b/flang/lib/Frontend/ParserActions.cpp new file mode 100644 index 0000000000000..cc7e72f696f96 --- /dev/null +++ b/flang/lib/Frontend/ParserActions.cpp @@ -0,0 +1,148 @@ +//===--- ParserActions.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Frontend/ParserActions.h" +#include "flang/Frontend/CompilerInstance.h" +#include "flang/Lower/Bridge.h" +#include "flang/Lower/PFTBuilder.h" +#include "flang/Parser/dump-parse-tree.h" +#include "flang/Parser/parsing.h" +#include "flang/Parser/provenance.h" +#include "flang/Parser/source.h" +#include "flang/Parser/unparse.h" +#include "flang/Semantics/unparse-with-symbols.h" +#include "llvm/Support/raw_ostream.h" + +namespace Fortran::frontend { + +parser::AllCookedSources &getAllCooked(CompilerInstance &ci) { + return ci.getParsing().allCooked(); +} + +void parseAndLowerTree(CompilerInstance &ci, lower::LoweringBridge &lb) { + parser::Program &parseTree{*ci.getParsing().parseTree()}; + lb.lower(parseTree, ci.getSemanticsContext()); +} + +void dumpTree(CompilerInstance &ci) { + auto &parseTree{ci.getParsing().parseTree()}; + llvm::outs() << "========================"; + llvm::outs() << " Flang: parse tree dump "; + llvm::outs() << "========================\n"; + parser::DumpTree(llvm::outs(), parseTree, &ci.getInvocation().getAsFortran()); +} + +void dumpProvenance(CompilerInstance &ci) { + ci.getParsing().DumpProvenance(llvm::outs()); +} + +void dumpPreFIRTree(CompilerInstance &ci) { + auto &parseTree{*ci.getParsing().parseTree()}; + + if (auto ast{lower::createPFT(parseTree, ci.getSemanticsContext())}) { + lower::dumpPFT(llvm::outs(), *ast); + } else { + unsigned diagID = ci.getDiagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); + ci.getDiagnostics().Report(diagID); + } +} + +void formatOrDumpPrescanner(std::string &buf, + llvm::raw_string_ostream &outForPP, + CompilerInstance &ci) { + if (ci.getInvocation().getPreprocessorOpts().showMacros) { + ci.getParsing().EmitPreprocessorMacros(outForPP); + } else if (ci.getInvocation().getPreprocessorOpts().noReformat) { + ci.getParsing().DumpCookedChars(outForPP); + } else { + ci.getParsing().EmitPreprocessedSource( + outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives); + } + + // Print getDiagnostics from the prescanner + ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); +} + +struct MeasurementVisitor { + template + bool Pre(const A &) { + return true; + } + template + void Post(const A &) { + ++objects; + bytes += sizeof(A); + } + size_t objects{0}, bytes{0}; +}; + +void debugMeasureParseTree(CompilerInstance &ci, llvm::StringRef filename) { + // Parse. In case of failure, report and return. + ci.getParsing().Parse(llvm::outs()); + + if ((ci.getParsing().parseTree().has_value() && + !ci.getParsing().consumedWholeFile()) || + (!ci.getParsing().messages().empty() && + (ci.getInvocation().getWarnAsErr() || + ci.getParsing().messages().AnyFatalError()))) { + unsigned diagID = ci.getDiagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "Could not parse %0"); + ci.getDiagnostics().Report(diagID) << filename; + + ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); + return; + } + + // Report the getDiagnostics from parsing + ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); + + auto &parseTree{ci.getParsing().parseTree()}; + MeasurementVisitor visitor; + parser::Walk(parseTree, visitor); + llvm::outs() << "Parse tree comprises " << visitor.objects + << " objects and occupies " << visitor.bytes + << " total bytes.\n"; +} + +void debugUnparseNoSema(CompilerInstance &ci, llvm::raw_ostream &out) { + auto &invoc = ci.getInvocation(); + auto &parseTree{ci.getParsing().parseTree()}; + + // TODO: Options should come from CompilerInvocation + Unparse(out, *parseTree, + /*encoding=*/parser::Encoding::UTF_8, + /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, + /*preStatement=*/nullptr, + invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() + : nullptr); +} + +void debugUnparseWithSymbols(CompilerInstance &ci) { + auto &parseTree{*ci.getParsing().parseTree()}; + + semantics::UnparseWithSymbols(llvm::outs(), parseTree, + /*encoding=*/parser::Encoding::UTF_8); +} + +void debugUnparseWithModules(CompilerInstance &ci) { + auto &parseTree{*ci.getParsing().parseTree()}; + semantics::UnparseWithModules(llvm::outs(), ci.getSemantics().context(), + parseTree, + /*encoding=*/parser::Encoding::UTF_8); +} + +void debugDumpParsingLog(CompilerInstance &ci) { + ci.getParsing().Parse(llvm::errs()); + ci.getParsing().DumpParsingLog(llvm::outs()); +} +} // namespace Fortran::frontend