1 //===- FrontendOptions.h ----------------------------------------*- C++ -*-===//
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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef FORTRAN_FRONTEND_FRONTENDOPTIONS_H
14 #define FORTRAN_FRONTEND_FRONTENDOPTIONS_H
15 
16 #include "flang/Common/Fortran-features.h"
17 #include "flang/Parser/characters.h"
18 #include "flang/Parser/unparse.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include <cstdint>
22 #include <string>
23 
24 namespace Fortran::frontend {
25 
26 enum ActionKind {
27   /// -test-io mode
28   InputOutputTest,
29 
30   /// -E mode
31   PrintPreprocessedInput,
32 
33   /// -fsyntax-only
34   ParseSyntaxOnly,
35 
36   /// Emit a .mlir file
37   EmitMLIR,
38 
39   /// Emit an .ll file
40   EmitLLVM,
41 
42   /// Emit a .bc file
43   EmitLLVMBitcode,
44 
45   /// Emit a .o file.
46   EmitObj,
47 
48   /// Emit a .s file.
49   EmitAssembly,
50 
51   /// Parse, unparse the parse-tree and output a Fortran source file
52   DebugUnparse,
53 
54   /// Parse, unparse the parse-tree and output a Fortran source file, skip the
55   /// semantic checks
56   DebugUnparseNoSema,
57 
58   /// Parse, resolve the sybmols, unparse the parse-tree and then output a
59   /// Fortran source file
60   DebugUnparseWithSymbols,
61 
62   /// Parse, run semantics and then output symbols from semantics
63   DebugDumpSymbols,
64 
65   /// Parse, run semantics and then output the parse tree
66   DebugDumpParseTree,
67 
68   /// Parse, run semantics and then output the pre-fir parse tree
69   DebugDumpPFT,
70 
71   /// Parse, run semantics and then output the parse tree and symbols
72   DebugDumpAll,
73 
74   /// Parse and then output the parse tree, skip the semantic checks
75   DebugDumpParseTreeNoSema,
76 
77   /// Dump provenance
78   DebugDumpProvenance,
79 
80   /// Parse then output the parsing log
81   DebugDumpParsingLog,
82 
83   /// Parse then output the number of objects in the parse tree and the overall
84   /// size
85   DebugMeasureParseTree,
86 
87   /// Parse, run semantics and then output the pre-FIR tree
88   DebugPreFIRTree,
89 
90   /// `-fget-definition`
91   GetDefinition,
92 
93   /// Parse, run semantics and then dump symbol sources map
94   GetSymbolsSources,
95 
96   /// Only execute frontend initialization
97   InitOnly,
98 
99   /// Run a plugin action
100   PluginAction
101 };
102 
103 /// \param suffix The file extension
104 /// \return True if the file extension should be processed as fixed form
105 bool isFixedFormSuffix(llvm::StringRef suffix);
106 
107 /// \param suffix The file extension
108 /// \return True if the file extension should be processed as free form
109 bool isFreeFormSuffix(llvm::StringRef suffix);
110 
111 /// \param suffix The file extension
112 /// \return True if the file should be preprocessed
113 bool isToBePreprocessed(llvm::StringRef suffix);
114 
115 enum class Language : uint8_t {
116   Unknown,
117 
118   /// MLIR: we accept this so that we can run the optimizer on it, and compile
119   /// it to LLVM IR, assembly or object code.
120   MLIR,
121 
122   /// LLVM IR: we accept this so that we can run the optimizer on it,
123   /// and compile it to assembly or object code.
124   LLVM_IR,
125 
126   /// @{ Languages that the frontend can parse and compile.
127   Fortran,
128   /// @}
129 };
130 
131 // Source file layout
132 enum class FortranForm {
133   /// The user has not specified a form. Base the form off the file extension.
134   Unknown,
135 
136   /// -ffree-form
137   FixedForm,
138 
139   /// -ffixed-form
140   FreeForm
141 };
142 
143 /// The kind of a file that we've been handed as an input.
144 class InputKind {
145 private:
146   Language lang;
147 
148 public:
149   /// The input file format.
150   enum Format { Source, ModuleMap, Precompiled };
151 
lang(l)152   constexpr InputKind(Language l = Language::Unknown) : lang(l) {}
153 
getLanguage()154   Language getLanguage() const { return static_cast<Language>(lang); }
155 
156   /// Is the input kind fully-unknown?
isUnknown()157   bool isUnknown() const { return lang == Language::Unknown; }
158 };
159 
160 /// An input file for the front end.
161 class FrontendInputFile {
162   /// The file name, or "-" to read from standard input.
163   std::string file;
164 
165   /// The input, if it comes from a buffer rather than a file. This object
166   /// does not own the buffer, and the caller is responsible for ensuring
167   /// that it outlives any users.
168   const llvm::MemoryBuffer *buffer = nullptr;
169 
170   /// The kind of input, atm it contains language
171   InputKind kind;
172 
173   /// Is this input file in fixed-form format? This is simply derived from the
174   /// file extension and should not be altered by consumers. For input from
175   /// stdin this is never modified.
176   bool isFixedForm = false;
177 
178   /// Must this file be preprocessed? Note that in Flang the preprocessor is
179   /// always run. This flag is used to control whether predefined and command
180   /// line preprocessor macros are enabled or not. In practice, this is
181   /// sufficient to implement gfortran`s logic controlled with `-cpp/-nocpp`.
182   unsigned mustBePreprocessed : 1;
183 
184 public:
185   FrontendInputFile() = default;
FrontendInputFile(llvm::StringRef file,InputKind inKind)186   FrontendInputFile(llvm::StringRef file, InputKind inKind)
187       : file(file.str()), kind(inKind) {
188 
189     // Based on the extension, decide whether this is a fixed or free form
190     // file.
191     auto pathDotIndex{file.rfind(".")};
192     std::string pathSuffix{file.substr(pathDotIndex + 1)};
193     isFixedForm = isFixedFormSuffix(pathSuffix);
194     mustBePreprocessed = isToBePreprocessed(pathSuffix);
195   }
196 
FrontendInputFile(const llvm::MemoryBuffer * memBuf,InputKind inKind)197   FrontendInputFile(const llvm::MemoryBuffer *memBuf, InputKind inKind)
198       : buffer(memBuf), kind(inKind) {}
199 
getKind()200   InputKind getKind() const { return kind; }
201 
isEmpty()202   bool isEmpty() const { return file.empty() && buffer == nullptr; }
isFile()203   bool isFile() const { return (buffer == nullptr); }
getIsFixedForm()204   bool getIsFixedForm() const { return isFixedForm; }
getMustBePreprocessed()205   bool getMustBePreprocessed() const { return mustBePreprocessed; }
206 
getFile()207   llvm::StringRef getFile() const {
208     assert(isFile());
209     return file;
210   }
211 
getBuffer()212   const llvm::MemoryBuffer *getBuffer() const {
213     assert(buffer && "Requested buffer, but it is empty!");
214     return buffer;
215   }
216 };
217 
218 /// FrontendOptions - Options for controlling the behavior of the frontend.
219 struct FrontendOptions {
FrontendOptionsFrontendOptions220   FrontendOptions()
221       : showHelp(false), showVersion(false), instrumentedParse(false),
222         showColors(false), needProvenanceRangeToCharBlockMappings(false) {}
223 
224   /// Show the -help text.
225   unsigned showHelp : 1;
226 
227   /// Show the -version text.
228   unsigned showVersion : 1;
229 
230   /// Instrument the parse to get a more verbose log
231   unsigned instrumentedParse : 1;
232 
233   /// Enable color diagnostics.
234   unsigned showColors : 1;
235 
236   /// Enable Provenance to character-stream mapping. Allows e.g. IDEs to find
237   /// symbols based on source-code location. This is not needed in regular
238   /// compilation.
239   unsigned needProvenanceRangeToCharBlockMappings : 1;
240 
241   /// Input values from `-fget-definition`
242   struct GetDefinitionVals {
243     unsigned line;
244     unsigned startColumn;
245     unsigned endColumn;
246   };
247   GetDefinitionVals getDefVals;
248 
249   /// The input files and their types.
250   std::vector<FrontendInputFile> inputs;
251 
252   /// The output file, if any.
253   std::string outputFile;
254 
255   /// The frontend action to perform.
256   frontend::ActionKind programAction = ParseSyntaxOnly;
257 
258   // The form to process files in, if specified.
259   FortranForm fortranForm = FortranForm::Unknown;
260 
261   // The column after which characters are ignored in fixed form lines in the
262   // source file.
263   int fixedFormColumns = 72;
264 
265   /// The input kind, either specified via -x argument or deduced from the input
266   /// file name.
267   InputKind dashX;
268 
269   // Language features
270   common::LanguageFeatureControl features;
271 
272   // Source file encoding
273   Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
274 
275   /// The list of plugins to load.
276   std::vector<std::string> plugins;
277 
278   /// The name of the action to run when using a plugin action.
279   std::string actionName;
280 
281   /// A list of arguments to forward to LLVM's option processing; this
282   /// should only be used for debugging and experimental features.
283   std::vector<std::string> llvmArgs;
284 
285   /// A list of arguments to forward to MLIR's option processing; this
286   /// should only be used for debugging and experimental features.
287   std::vector<std::string> mlirArgs;
288 
289   // Return the appropriate input kind for a file extension. For example,
290   /// "*.f" would return Language::Fortran.
291   ///
292   /// \return The input kind for the extension, or Language::Unknown if the
293   /// extension is not recognized.
294   static InputKind getInputKindForExtension(llvm::StringRef extension);
295 };
296 } // namespace Fortran::frontend
297 
298 #endif // FORTRAN_FRONTEND_FRONTENDOPTIONS_H
299