150 lines · cpp
1//===--- ParserActions.cpp ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12 13#include "flang/Frontend/ParserActions.h"14#include "flang/Frontend/CompilerInstance.h"15#include "flang/Lower/Bridge.h"16#include "flang/Lower/PFTBuilder.h"17#include "flang/Parser/dump-parse-tree.h"18#include "flang/Parser/parsing.h"19#include "flang/Parser/provenance.h"20#include "flang/Parser/source.h"21#include "flang/Parser/unparse.h"22#include "flang/Semantics/unparse-with-symbols.h"23#include "llvm/Support/raw_ostream.h"24 25namespace Fortran::frontend {26 27parser::AllCookedSources &getAllCooked(CompilerInstance &ci) {28 return ci.getParsing().allCooked();29}30 31void parseAndLowerTree(CompilerInstance &ci, lower::LoweringBridge &lb) {32 parser::Program &parseTree{*ci.getParsing().parseTree()};33 lb.lower(parseTree, ci.getSemanticsContext());34}35 36void dumpTree(CompilerInstance &ci) {37 auto &parseTree{ci.getParsing().parseTree()};38 llvm::outs() << "========================";39 llvm::outs() << " Flang: parse tree dump ";40 llvm::outs() << "========================\n";41 parser::DumpTree(llvm::outs(), parseTree, &ci.getInvocation().getAsFortran());42}43 44void dumpProvenance(CompilerInstance &ci) {45 ci.getParsing().DumpProvenance(llvm::outs());46}47 48void dumpPreFIRTree(CompilerInstance &ci) {49 auto &parseTree{*ci.getParsing().parseTree()};50 51 if (auto ast{lower::createPFT(parseTree, ci.getSemanticsContext())}) {52 lower::dumpPFT(llvm::outs(), *ast);53 } else {54 unsigned diagID = ci.getDiagnostics().getCustomDiagID(55 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");56 ci.getDiagnostics().Report(diagID);57 }58}59 60void formatOrDumpPrescanner(std::string &buf,61 llvm::raw_string_ostream &outForPP,62 CompilerInstance &ci) {63 if (ci.getInvocation().getPreprocessorOpts().showMacros) {64 ci.getParsing().EmitPreprocessorMacros(outForPP);65 } else if (ci.getInvocation().getPreprocessorOpts().noReformat) {66 ci.getParsing().DumpCookedChars(outForPP);67 } else {68 ci.getParsing().EmitPreprocessedSource(69 outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives);70 }71 72 // Print getDiagnostics from the prescanner73 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());74}75 76struct MeasurementVisitor {77 template <typename A>78 bool Pre(const A &) {79 return true;80 }81 template <typename A>82 void Post(const A &) {83 ++objects;84 bytes += sizeof(A);85 }86 size_t objects{0}, bytes{0};87};88 89void debugMeasureParseTree(CompilerInstance &ci, llvm::StringRef filename) {90 // Parse. In case of failure, report and return.91 ci.getParsing().Parse(llvm::outs());92 93 if ((ci.getParsing().parseTree().has_value() &&94 !ci.getParsing().consumedWholeFile()) ||95 (!ci.getParsing().messages().empty() &&96 (ci.getInvocation().getWarnAsErr() ||97 ci.getParsing().messages().AnyFatalError()))) {98 unsigned diagID = ci.getDiagnostics().getCustomDiagID(99 clang::DiagnosticsEngine::Error, "Could not parse %0");100 ci.getDiagnostics().Report(diagID) << filename;101 102 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());103 return;104 }105 106 // Report the getDiagnostics from parsing107 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());108 109 auto &parseTree{ci.getParsing().parseTree()};110 MeasurementVisitor visitor;111 parser::Walk(parseTree, visitor);112 llvm::outs() << "Parse tree comprises " << visitor.objects113 << " objects and occupies " << visitor.bytes114 << " total bytes.\n";115}116 117void debugUnparseNoSema(CompilerInstance &ci, llvm::raw_ostream &out) {118 auto &invoc = ci.getInvocation();119 auto &parseTree{ci.getParsing().parseTree()};120 121 // TODO: Options should come from CompilerInvocation122 Unparse(out, *parseTree, ci.getInvocation().getLangOpts(),123 /*encoding=*/parser::Encoding::UTF_8,124 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,125 /*preStatement=*/nullptr,126 invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()127 : nullptr);128}129 130void debugUnparseWithSymbols(CompilerInstance &ci) {131 auto &parseTree{*ci.getParsing().parseTree()};132 133 semantics::UnparseWithSymbols(llvm::outs(), parseTree,134 ci.getInvocation().getLangOpts(),135 /*encoding=*/parser::Encoding::UTF_8);136}137 138void debugUnparseWithModules(CompilerInstance &ci) {139 auto &parseTree{*ci.getParsing().parseTree()};140 semantics::UnparseWithModules(llvm::outs(), ci.getSemantics().context(),141 parseTree,142 /*encoding=*/parser::Encoding::UTF_8);143}144 145void debugDumpParsingLog(CompilerInstance &ci) {146 ci.getParsing().Parse(llvm::errs());147 ci.getParsing().DumpParsingLog(llvm::outs());148}149} // namespace Fortran::frontend150