/
FrontendActions.cpp
152 lines (122 loc) · 5.09 KB
/
FrontendActions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//===--- FrontendActions.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
//
//===----------------------------------------------------------------------===//
#include "flang/Frontend/FrontendActions.h"
#include "flang/Common/default-kinds.h"
#include "flang/Frontend/CompilerInstance.h"
#include "flang/Parser/parsing.h"
#include "flang/Parser/provenance.h"
#include "flang/Parser/source.h"
#include "flang/Semantics/semantics.h"
using namespace Fortran::frontend;
bool PrescanAction::BeginSourceFileAction(CompilerInstance &c1) {
CompilerInstance &ci = this->instance();
std::string currentInputPath{GetCurrentFileOrBufferName()};
Fortran::parser::Options parserOptions = ci.invocation().fortranOpts();
if (ci.invocation().frontendOpts().fortranForm_ == FortranForm::Unknown) {
// Switch between fixed and free form format based on the input file
// extension.
//
// Ideally we should have all Fortran options set before entering this
// method (i.e. before processing any specific input files). However, we
// can't decide between fixed and free form based on the file extension
// earlier than this.
parserOptions.isFixedForm = currentInput().IsFixedForm();
}
// Prescan. In case of failure, report and return.
ci.parsing().Prescan(currentInputPath, parserOptions);
if (ci.parsing().messages().AnyFatalError()) {
const unsigned diagID = ci.diagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, "Could not scan %0");
ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
return false;
}
return true;
}
void InputOutputTestAction::ExecuteAction() {
// Get the name of the file from FrontendInputFile current.
std::string path{GetCurrentFileOrBufferName()};
std::string buf;
llvm::raw_string_ostream error_stream{buf};
bool binaryMode = true;
// Set/store input file info into CompilerInstance.
CompilerInstance &ci = instance();
Fortran::parser::AllSources &allSources{ci.allSources()};
const Fortran::parser::SourceFile *sf;
sf = allSources.Open(path, error_stream, std::optional<std::string>{"."s});
llvm::ArrayRef<char> fileContent = sf->content();
// Output file descriptor to receive the content of input file.
std::unique_ptr<llvm::raw_ostream> os;
// Do not write on the output file if using outputStream_.
if (ci.IsOutputStreamNull()) {
os = ci.CreateDefaultOutputFile(
binaryMode, GetCurrentFileOrBufferName(), "txt");
if (!os)
return;
(*os) << fileContent.data();
} else {
ci.WriteOutputStream(fileContent.data());
}
}
void PrintPreprocessedAction::ExecuteAction() {
std::string buf;
llvm::raw_string_ostream outForPP{buf};
// Run the preprocessor
CompilerInstance &ci = this->instance();
ci.parsing().DumpCookedChars(outForPP);
// If a pre-defined output stream exists, dump the preprocessed content there
if (!ci.IsOutputStreamNull()) {
// Send the output to the pre-defined output buffer.
ci.WriteOutputStream(outForPP.str());
return;
}
// Print diagnostics from the preprocessor
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
// Create a file and save the preprocessed output there
if (auto os{ci.CreateDefaultOutputFile(
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName())}) {
(*os) << outForPP.str();
} else {
llvm::errs() << "Unable to create the output file\n";
return;
}
}
void ParseSyntaxOnlyAction::ExecuteAction() {
CompilerInstance &ci = this->instance();
// Parse. In case of failure, report and return.
ci.parsing().Parse(llvm::outs());
if (ci.parsing().messages().AnyFatalError()) {
unsigned diagID = ci.diagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, "Could not parse %0");
ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
ci.parsing().messages().Emit(
llvm::errs(), this->instance().allCookedSources());
return;
}
// Report the diagnostics from parsing
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
auto &parseTree{*ci.parsing().parseTree()};
// Prepare semantics
Fortran::semantics::Semantics semantics{
ci.semanticsContext(), parseTree, ci.parsing().cooked().AsCharBlock()};
// Run semantic checks
semantics.Perform();
// Report the diagnostics from the semantic checks
semantics.EmitMessages(ci.semaOutputStream());
if (semantics.AnyFatalError()) {
unsigned DiagID = ci.diagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, "Semantic errors in %0");
ci.diagnostics().Report(DiagID) << GetCurrentFileOrBufferName();
}
}
void EmitObjAction::ExecuteAction() {
CompilerInstance &ci = this->instance();
unsigned DiagID = ci.diagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, "code-generation is not available yet");
ci.diagnostics().Report(DiagID);
}