xref: /llvm-project/flang/lib/Parser/parsing.cpp (revision 8670e49901d116b2094aeb0a5117edef9e69cdcf)
164ab3302SCarolineConcatto //===-- lib/Parser/parsing.cpp --------------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Parser/parsing.h"
1064ab3302SCarolineConcatto #include "preprocessor.h"
1164ab3302SCarolineConcatto #include "prescan.h"
1264ab3302SCarolineConcatto #include "type-parsers.h"
1364ab3302SCarolineConcatto #include "flang/Parser/message.h"
1464ab3302SCarolineConcatto #include "flang/Parser/provenance.h"
1564ab3302SCarolineConcatto #include "flang/Parser/source.h"
16*8670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
1764ab3302SCarolineConcatto 
1864ab3302SCarolineConcatto namespace Fortran::parser {
1964ab3302SCarolineConcatto 
2064ab3302SCarolineConcatto Parsing::Parsing(AllSources &s) : cooked_{s} {}
2164ab3302SCarolineConcatto Parsing::~Parsing() {}
2264ab3302SCarolineConcatto 
2364ab3302SCarolineConcatto const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
2464ab3302SCarolineConcatto   options_ = options;
2564ab3302SCarolineConcatto   AllSources &allSources{cooked_.allSources()};
2664ab3302SCarolineConcatto   if (options.isModuleFile) {
2764ab3302SCarolineConcatto     for (const auto &path : options.searchDirectories) {
2864ab3302SCarolineConcatto       allSources.PushSearchPathDirectory(path);
2964ab3302SCarolineConcatto     }
3064ab3302SCarolineConcatto   }
3164ab3302SCarolineConcatto 
32*8670e499SCaroline Concatto   std::string buf;
33*8670e499SCaroline Concatto   llvm::raw_string_ostream fileError{buf};
3464ab3302SCarolineConcatto   const SourceFile *sourceFile;
3564ab3302SCarolineConcatto   if (path == "-") {
36*8670e499SCaroline Concatto     sourceFile = allSources.ReadStandardInput(fileError);
3764ab3302SCarolineConcatto   } else {
38*8670e499SCaroline Concatto     sourceFile = allSources.Open(path, fileError);
3964ab3302SCarolineConcatto   }
4064ab3302SCarolineConcatto   if (!fileError.str().empty()) {
4164ab3302SCarolineConcatto     ProvenanceRange range{allSources.AddCompilerInsertion(path)};
4264ab3302SCarolineConcatto     messages_.Say(range, "%s"_err_en_US, fileError.str());
4364ab3302SCarolineConcatto     return sourceFile;
4464ab3302SCarolineConcatto   }
4564ab3302SCarolineConcatto   CHECK(sourceFile);
4664ab3302SCarolineConcatto 
4764ab3302SCarolineConcatto   if (!options.isModuleFile) {
4864ab3302SCarolineConcatto     // For .mod files we always want to look in the search directories.
4964ab3302SCarolineConcatto     // For normal source files we don't push them until after the primary
5064ab3302SCarolineConcatto     // source file has been opened.  If foo.f is missing from the current
5164ab3302SCarolineConcatto     // working directory, we don't want to accidentally read another foo.f
5264ab3302SCarolineConcatto     // from another directory that's on the search path.
5364ab3302SCarolineConcatto     for (const auto &path : options.searchDirectories) {
5464ab3302SCarolineConcatto       allSources.PushSearchPathDirectory(path);
5564ab3302SCarolineConcatto     }
5664ab3302SCarolineConcatto   }
5764ab3302SCarolineConcatto 
5864ab3302SCarolineConcatto   Preprocessor preprocessor{allSources};
5964ab3302SCarolineConcatto   for (const auto &predef : options.predefinitions) {
6064ab3302SCarolineConcatto     if (predef.second) {
6164ab3302SCarolineConcatto       preprocessor.Define(predef.first, *predef.second);
6264ab3302SCarolineConcatto     } else {
6364ab3302SCarolineConcatto       preprocessor.Undefine(predef.first);
6464ab3302SCarolineConcatto     }
6564ab3302SCarolineConcatto   }
6664ab3302SCarolineConcatto   Prescanner prescanner{messages_, cooked_, preprocessor, options.features};
6764ab3302SCarolineConcatto   prescanner.set_fixedForm(options.isFixedForm)
6864ab3302SCarolineConcatto       .set_fixedFormColumnLimit(options.fixedFormColumns)
6964ab3302SCarolineConcatto       .AddCompilerDirectiveSentinel("dir$");
7064ab3302SCarolineConcatto   if (options.features.IsEnabled(LanguageFeature::OpenMP)) {
7164ab3302SCarolineConcatto     prescanner.AddCompilerDirectiveSentinel("$omp");
7264ab3302SCarolineConcatto     prescanner.AddCompilerDirectiveSentinel("$");  // OMP conditional line
7364ab3302SCarolineConcatto   }
7464ab3302SCarolineConcatto   ProvenanceRange range{allSources.AddIncludedFile(
7564ab3302SCarolineConcatto       *sourceFile, ProvenanceRange{}, options.isModuleFile)};
7664ab3302SCarolineConcatto   prescanner.Prescan(range);
7764ab3302SCarolineConcatto   if (cooked_.BufferedBytes() == 0 && !options.isModuleFile) {
7864ab3302SCarolineConcatto     // Input is empty.  Append a newline so that any warning
7964ab3302SCarolineConcatto     // message about nonstandard usage will have provenance.
8064ab3302SCarolineConcatto     cooked_.Put('\n', range.start());
8164ab3302SCarolineConcatto   }
8264ab3302SCarolineConcatto   cooked_.Marshal();
8364ab3302SCarolineConcatto   if (options.needProvenanceRangeToCharBlockMappings) {
8464ab3302SCarolineConcatto     cooked_.CompileProvenanceRangeToOffsetMappings();
8564ab3302SCarolineConcatto   }
8664ab3302SCarolineConcatto   return sourceFile;
8764ab3302SCarolineConcatto }
8864ab3302SCarolineConcatto 
89*8670e499SCaroline Concatto void Parsing::DumpCookedChars(llvm::raw_ostream &out) const {
9064ab3302SCarolineConcatto   UserState userState{cooked_, common::LanguageFeatureControl{}};
9164ab3302SCarolineConcatto   ParseState parseState{cooked_};
9264ab3302SCarolineConcatto   parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
9364ab3302SCarolineConcatto   while (std::optional<const char *> p{parseState.GetNextChar()}) {
9464ab3302SCarolineConcatto     out << **p;
9564ab3302SCarolineConcatto   }
9664ab3302SCarolineConcatto }
9764ab3302SCarolineConcatto 
98*8670e499SCaroline Concatto void Parsing::DumpProvenance(llvm::raw_ostream &out) const {
99*8670e499SCaroline Concatto   cooked_.Dump(out);
100*8670e499SCaroline Concatto }
10164ab3302SCarolineConcatto 
102*8670e499SCaroline Concatto void Parsing::DumpParsingLog(llvm::raw_ostream &out) const {
10364ab3302SCarolineConcatto   log_.Dump(out, cooked_);
10464ab3302SCarolineConcatto }
10564ab3302SCarolineConcatto 
106*8670e499SCaroline Concatto void Parsing::Parse(llvm::raw_ostream &out) {
10764ab3302SCarolineConcatto   UserState userState{cooked_, options_.features};
10864ab3302SCarolineConcatto   userState.set_debugOutput(out)
10964ab3302SCarolineConcatto       .set_instrumentedParse(options_.instrumentedParse)
11064ab3302SCarolineConcatto       .set_log(&log_);
11164ab3302SCarolineConcatto   ParseState parseState{cooked_};
11264ab3302SCarolineConcatto   parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
11364ab3302SCarolineConcatto   parseTree_ = program.Parse(parseState);
11464ab3302SCarolineConcatto   CHECK(
11564ab3302SCarolineConcatto       !parseState.anyErrorRecovery() || parseState.messages().AnyFatalError());
11664ab3302SCarolineConcatto   consumedWholeFile_ = parseState.IsAtEnd();
11764ab3302SCarolineConcatto   messages_.Annex(std::move(parseState.messages()));
11864ab3302SCarolineConcatto   finalRestingPlace_ = parseState.GetLocation();
11964ab3302SCarolineConcatto }
12064ab3302SCarolineConcatto 
12164ab3302SCarolineConcatto void Parsing::ClearLog() { log_.clear(); }
12264ab3302SCarolineConcatto 
123*8670e499SCaroline Concatto bool Parsing::ForTesting(std::string path, llvm::raw_ostream &err) {
124*8670e499SCaroline Concatto   llvm::raw_null_ostream NullStream;
12564ab3302SCarolineConcatto   Prescan(path, Options{});
12664ab3302SCarolineConcatto   if (messages_.AnyFatalError()) {
12764ab3302SCarolineConcatto     messages_.Emit(err, cooked_);
12864ab3302SCarolineConcatto     err << "could not scan " << path << '\n';
12964ab3302SCarolineConcatto     return false;
13064ab3302SCarolineConcatto   }
131*8670e499SCaroline Concatto   Parse(NullStream);
13264ab3302SCarolineConcatto   messages_.Emit(err, cooked_);
13364ab3302SCarolineConcatto   if (!consumedWholeFile_) {
13464ab3302SCarolineConcatto     EmitMessage(err, finalRestingPlace_, "parser FAIL; final position");
13564ab3302SCarolineConcatto     return false;
13664ab3302SCarolineConcatto   }
13764ab3302SCarolineConcatto   if (messages_.AnyFatalError() || !parseTree_.has_value()) {
13864ab3302SCarolineConcatto     err << "could not parse " << path << '\n';
13964ab3302SCarolineConcatto     return false;
14064ab3302SCarolineConcatto   }
14164ab3302SCarolineConcatto   return true;
14264ab3302SCarolineConcatto }
14364ab3302SCarolineConcatto }
144