1 //===--- FrontendActions.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Frontend/FrontendActions.h"
10 #include "flang/Common/default-kinds.h"
11 #include "flang/Frontend/CompilerInstance.h"
12 #include "flang/Parser/parsing.h"
13 #include "flang/Parser/provenance.h"
14 #include "flang/Parser/source.h"
15 #include "flang/Semantics/semantics.h"
16 
17 using namespace Fortran::frontend;
18 
ExecuteAction()19 void InputOutputTestAction::ExecuteAction() {
20 
21   // Get the name of the file from FrontendInputFile current.
22   std::string path{GetCurrentFileOrBufferName()};
23   std::string buf;
24   llvm::raw_string_ostream error_stream{buf};
25   bool binaryMode = true;
26 
27   // Set/store input file info into CompilerInstance.
28   CompilerInstance &ci = instance();
29   Fortran::parser::AllSources &allSources{ci.allSources()};
30   const Fortran::parser::SourceFile *sf;
31   sf = allSources.Open(path, error_stream);
32   llvm::ArrayRef<char> fileContent = sf->content();
33 
34   // Output file descriptor to receive the content of input file.
35   std::unique_ptr<llvm::raw_ostream> os;
36 
37   // Do not write on the output file if using outputStream_.
38   if (ci.IsOutputStreamNull()) {
39     os = ci.CreateDefaultOutputFile(
40         binaryMode, GetCurrentFileOrBufferName(), "txt");
41     if (!os)
42       return;
43     (*os) << fileContent.data();
44   } else {
45     ci.WriteOutputStream(fileContent.data());
46   }
47 }
48 
ExecuteAction()49 void PrintPreprocessedAction::ExecuteAction() {
50   std::string buf;
51   llvm::raw_string_ostream outForPP{buf};
52 
53   // Run the preprocessor
54   CompilerInstance &ci = this->instance();
55   ci.parsing().DumpCookedChars(outForPP);
56 
57   // If a pre-defined output stream exists, dump the preprocessed content there
58   if (!ci.IsOutputStreamNull()) {
59     // Send the output to the pre-defined output buffer.
60     ci.WriteOutputStream(outForPP.str());
61     return;
62   }
63 
64   // Print diagnostics from the preprocessor
65   ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
66 
67   // Create a file and save the preprocessed output there
68   if (auto os{ci.CreateDefaultOutputFile(
69           /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName())}) {
70     (*os) << outForPP.str();
71   } else {
72     llvm::errs() << "Unable to create the output file\n";
73     return;
74   }
75 }
76 
ExecuteAction()77 void ParseSyntaxOnlyAction::ExecuteAction() {
78   CompilerInstance &ci = this->instance();
79 
80   // TODO: These should be specifiable by users. For now just use the defaults.
81   common::LanguageFeatureControl features;
82   Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
83 
84   // Parse. In case of failure, report and return.
85   ci.parsing().Parse(llvm::outs());
86 
87   if (ci.parsing().messages().AnyFatalError()) {
88     unsigned diagID = ci.diagnostics().getCustomDiagID(
89         clang::DiagnosticsEngine::Error, "Could not parse %0");
90     ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
91 
92     ci.parsing().messages().Emit(
93         llvm::errs(), this->instance().allCookedSources());
94     return;
95   }
96 
97   auto &parseTree{*ci.parsing().parseTree()};
98 
99   // Prepare semantics
100   Fortran::semantics::SemanticsContext semanticsContext{
101       defaultKinds, features, ci.allCookedSources()};
102   Fortran::semantics::Semantics semantics{
103       semanticsContext, parseTree, ci.parsing().cooked().AsCharBlock()};
104 
105   // Run semantic checks
106   semantics.Perform();
107 
108   // Report the diagnostics from the semantic checks
109   semantics.EmitMessages(ci.semaOutputStream());
110 
111   if (semantics.AnyFatalError()) {
112     unsigned DiagID = ci.diagnostics().getCustomDiagID(
113         clang::DiagnosticsEngine::Error, "Semantic errors in %0");
114     ci.diagnostics().Report(DiagID) << GetCurrentFileOrBufferName();
115   }
116 }
117 
ExecuteAction()118 void EmitObjAction::ExecuteAction() {
119   CompilerInstance &ci = this->instance();
120   unsigned DiagID = ci.diagnostics().getCustomDiagID(
121       clang::DiagnosticsEngine::Error, "code-generation is not available yet");
122   ci.diagnostics().Report(DiagID);
123 }
124