mirror-llvm-project/flang/lib/Frontend/ParserActions.cpp
Krzysztof Parzyszek cf5e8828dc [flang] Pass LangOptions to parser via UserState
This will help deal with syntax changes across different versions of
OpenMP. There are certain cases where being able to generate different
AST for the same source code depending on the version of the OpenMP
spec makes semantic analysis easier.
2026-08-01 12:33:13 -05:00

154 lines
5.5 KiB
C++

//===--- 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()};
// Use default lowering options for PFT dump
lower::LoweringOptions loweringOptions{};
if (auto ast{lower::createPFT(parseTree, ci.getSemanticsContext(),
loweringOptions)}) {
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 <typename A>
bool Pre(const A &) {
return true;
}
template <typename A>
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.
const common::LangOptions &langOptions = ci.getInvocation().getLangOpts();
ci.getParsing().Parse(llvm::outs(), langOptions);
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, ci.getInvocation().getLangOpts(),
/*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,
ci.getInvocation().getLangOpts(),
/*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) {
const common::LangOptions &langOptions = ci.getInvocation().getLangOpts();
ci.getParsing().Parse(llvm::errs(), langOptions);
ci.getParsing().DumpParsingLog(llvm::outs());
}
} // namespace Fortran::frontend