[flang] Refactor ModFileReader to use parser::Parsing

parser::Parsing does most of the work needed to prescan and parse a file.
The only problem is that for module files we need to take ownership of
the cooked character stream so that it lives as long as the module scope
does.

To achieve this, change Parsing::cooked_ to be a unique_ptr and add a
member function to allow the caller to take ownership of it.

Original-commit: flang-compiler/f18@9088891ab2
Reviewed-on: https://github.com/flang-compiler/f18/pull/149
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2018-07-26 10:57:51 -07:00
parent fb8950ee93
commit 9e48304374
3 changed files with 27 additions and 54 deletions

View File

@ -63,7 +63,7 @@ void Parsing::Prescan(const std::string &path, Options options) {
preprocessor.Undefine(predef.first);
}
}
Prescanner prescanner{messages_, cooked_, preprocessor, options.features};
Prescanner prescanner{messages_, *cooked_, preprocessor, options.features};
prescanner.set_fixedForm(options.isFixedForm)
.set_fixedFormColumnLimit(options.fixedFormColumns)
.set_encoding(options.encoding)
@ -75,30 +75,30 @@ void Parsing::Prescan(const std::string &path, Options options) {
ProvenanceRange range{
allSources_.AddIncludedFile(*sourceFile, ProvenanceRange{})};
prescanner.Prescan(range);
cooked_.Marshal();
cooked_->Marshal();
}
void Parsing::DumpCookedChars(std::ostream &out) const {
UserState userState{cooked_, LanguageFeatureControl{}};
ParseState parseState{cooked_};
UserState userState{*cooked_, LanguageFeatureControl{}};
ParseState parseState{*cooked_};
parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
while (std::optional<const char *> p{parseState.GetNextChar()}) {
out << **p;
}
}
void Parsing::DumpProvenance(std::ostream &out) const { cooked_.Dump(out); }
void Parsing::DumpProvenance(std::ostream &out) const { cooked_->Dump(out); }
void Parsing::DumpParsingLog(std::ostream &out) const {
log_.Dump(out, cooked_);
log_.Dump(out, *cooked_);
}
void Parsing::Parse(std::ostream *out) {
UserState userState{cooked_, options_.features};
UserState userState{*cooked_, options_.features};
userState.set_debugOutput(out)
.set_instrumentedParse(options_.instrumentedParse)
.set_log(&log_);
ParseState parseState{cooked_};
ParseState parseState{*cooked_};
parseState.set_inFixedForm(options_.isFixedForm)
.set_encoding(options_.encoding)
.set_userState(&userState);
@ -115,12 +115,12 @@ void Parsing::ClearLog() { log_.clear(); }
bool Parsing::ForTesting(std::string path, std::ostream &err) {
Prescan(path, Options{});
if (messages_.AnyFatalError()) {
messages_.Emit(err, cooked_);
messages_.Emit(err, *cooked_);
err << "could not scan " << path << '\n';
return false;
}
Parse();
messages_.Emit(err, cooked_);
messages_.Emit(err, *cooked_);
if (!consumedWholeFile_) {
EmitMessage(err, finalRestingPlace_, "parser FAIL; final position");
return false;

View File

@ -50,7 +50,8 @@ public:
bool consumedWholeFile() const { return consumedWholeFile_; }
const char *finalRestingPlace() const { return finalRestingPlace_; }
CookedSource &cooked() { return cooked_; }
CookedSource &cooked() { return *cooked_; }
std::unique_ptr<CookedSource> MoveCooked() { return std::move(cooked_); }
Messages &messages() { return messages_; }
std::optional<Program> &parseTree() { return parseTree_; }
@ -64,7 +65,7 @@ public:
void EmitMessage(std::ostream &o, const char *at, const std::string &message,
bool echoSourceLine = false) const {
allSources_.EmitMessage(
o, cooked_.GetProvenanceRange(at).start(), message, echoSourceLine);
o, cooked_->GetProvenanceRange(at).start(), message, echoSourceLine);
}
bool ForTesting(std::string path, std::ostream &);
@ -72,7 +73,8 @@ public:
private:
Options options_;
AllSources allSources_;
CookedSource cooked_{allSources_};
std::unique_ptr<parser::CookedSource> cooked_{
std::make_unique<parser::CookedSource>(allSources_)};
Messages messages_;
bool consumedWholeFile_{false};
const char *finalRestingPlace_{nullptr};

View File

@ -15,11 +15,8 @@
#include "mod-file.h"
#include "scope.h"
#include "symbol.h"
#include "../parser/grammar.h"
#include "../parser/message.h"
#include "../parser/openmp-grammar.h"
#include "../parser/preprocessor.h"
#include "../parser/prescan.h"
#include "../parser/parsing.h"
#include <algorithm>
#include <cerrno>
#include <fstream>
@ -27,8 +24,6 @@
#include <ostream>
#include <set>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
namespace Fortran::semantics {
@ -358,19 +353,20 @@ bool ModFileReader::Read(const SourceName &modName) {
if (!path.has_value()) {
return false;
}
if (!Prescan(modName, *path)) {
return false;
}
parser::ParseState parseState{*cooked_};
auto parseTree{parser::program.Parse(parseState)};
if (!parseState.messages().empty()) {
errors_.emplace_back(modName,
parser::MessageFormattedText{
"Module file for '%s' is corrupt: %s"_err_en_US,
modName.ToString().data(), path->data()});
parser::Parsing parsing;
parsing.Prescan(*path, {});
parsing.Parse(&std::cout);
auto &parseTree{parsing.parseTree()};
if (!parsing.messages().empty() || !parsing.consumedWholeFile() ||
!parseTree.has_value()) {
errors_.push_back(
Error(modName, "Module file for '%s' is corrupt: %s"_err_en_US,
modName.ToString(), *path));
return false;
}
std::unique_ptr<parser::CookedSource> cooked_{parsing.MoveCooked()};
ResolveNames(*parseTree, *cooked_, directories_);
const auto &it{Scope::globalScope.find(modName)};
if (it == Scope::globalScope.end()) {
return false;
@ -407,31 +403,6 @@ std::optional<std::string> ModFileReader::FindModFile(
return std::nullopt;
}
bool ModFileReader::Prescan(
const SourceName &modName, const std::string &path) {
std::stringstream fileError;
const auto *sourceFile{allSources_.Open(path, &fileError)};
if (sourceFile == nullptr) {
errors_.push_back(
Error(modName, "Cannot read %s: %s"_err_en_US, path, fileError.str()));
return false;
}
parser::Preprocessor preprocessor{allSources_};
parser::Messages messages;
parser::Prescanner prescanner{messages, *cooked_, preprocessor, {}};
parser::ProvenanceRange range{
allSources_.AddIncludedFile(*sourceFile, parser::ProvenanceRange{})};
prescanner.Prescan(range);
if (!messages.empty()) {
errors_.push_back(
Error(modName, "Module file for '%s' is corrupt: %s"_err_en_US,
modName.ToString(), path));
return false;
}
cooked_->Marshal();
return true;
}
static std::string ModFilePath(
const std::string &dir, const std::string &modName) {
if (dir == "."s) {