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 
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 
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   // Create a file and save the preprocessed output there
65   if (auto os{ci.CreateDefaultOutputFile(
66           /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName())}) {
67     (*os) << outForPP.str();
68   } else {
69     llvm::errs() << "Unable to create the output file\n";
70     return;
71   }
72 }
73 
74 void ParseSyntaxOnlyAction::ExecuteAction() {
75   CompilerInstance &ci = this->instance();
76 
77   // TODO: These should be specifiable by users. For now just use the defaults.
78   common::LanguageFeatureControl features;
79   Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
80 
81   // Parse. In case of failure, report and return.
82   ci.parsing().Parse(llvm::outs());
83 
84   if (ci.parsing().messages().AnyFatalError()) {
85     unsigned diagID = ci.diagnostics().getCustomDiagID(
86         clang::DiagnosticsEngine::Error, "Could not parse %0");
87     ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
88 
89     ci.parsing().messages().Emit(
90         llvm::errs(), this->instance().allCookedSources());
91     return;
92   }
93 
94   auto &parseTree{*ci.parsing().parseTree()};
95 
96   // Prepare semantics
97   Fortran::semantics::SemanticsContext semanticsContext{
98       defaultKinds, features, ci.allCookedSources()};
99   Fortran::semantics::Semantics semantics{
100       semanticsContext, parseTree, ci.parsing().cooked().AsCharBlock()};
101 
102   // Run semantic checks
103   semantics.Perform();
104 
105   // Report the diagnostics from the semantic checks
106   semantics.EmitMessages(ci.semaOutputStream());
107 
108   if (semantics.AnyFatalError()) {
109     unsigned DiagID = ci.diagnostics().getCustomDiagID(
110         clang::DiagnosticsEngine::Error, "Semantic errors in %0");
111     ci.diagnostics().Report(DiagID) << GetCurrentFileOrBufferName();
112   }
113 }
114 
115 void EmitObjAction::ExecuteAction() {
116   CompilerInstance &ci = this->instance();
117   unsigned DiagID = ci.diagnostics().getCustomDiagID(
118       clang::DiagnosticsEngine::Error, "code-generation is not available yet");
119   ci.diagnostics().Report(DiagID);
120 }
121