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