static constexpr auto extension{".mod"};
// The initial characters of a file that identify it as a .mod file.
static constexpr auto magic{"!mod$"};
-// Construct the path to a module file.
-static std::string ModFilePath(const std::string &, const std::string &);
+
// Helpers for creating error messages.
static parser::Message Error(
const SourceName &, parser::MessageFixedText, const std::string &);
static parser::Message Error(const SourceName &, parser::MessageFixedText,
const std::string &, const std::string &);
+static const SourceName *GetSubmoduleParent(const parser::Program &);
+static std::string ModFilePath(
+ const std::string &, const SourceName &, const std::string &);
static void PutEntity(std::ostream &, const Symbol &);
static void PutObjectEntity(std::ostream &, const Symbol &);
static void PutProcEntity(std::ostream &, const Symbol &);
static std::string CheckSum(const std::string &);
bool ModFileWriter::WriteAll() {
- for (const auto &scope : Scope::globalScope.children()) {
- if (scope.kind() == Scope::Kind::Module) {
- auto &symbol{*scope.symbol()}; // symbol must be present for module
- if (!symbol.test(Symbol::Flag::ModFile)) {
- WriteOne(symbol);
- }
- }
- }
+ WriteChildren(Scope::globalScope);
return errors_.empty();
}
-bool ModFileWriter::WriteOne(const Symbol &modSymbol) {
- CHECK(modSymbol.has<ModuleDetails>());
- auto name{parser::ToLowerCaseLetters(modSymbol.name().ToString())};
- std::string path{ModFilePath(dir_, name)};
- std::ofstream os{path};
- PutSymbols(*modSymbol.scope());
- std::string all{GetAsString(name)};
- auto header{GetHeader(all)};
- os << header << all;
- os.close();
- if (!os) {
- errors_.emplace_back(
- "Error writing %s: %s"_err_en_US, path.c_str(), std::strerror(errno));
- return false;
+void ModFileWriter::WriteChildren(const Scope &scope) {
+ for (const auto &child : scope.children()) {
+ WriteOne(child);
}
- return true;
+}
+
+void ModFileWriter::WriteOne(const Scope &scope) {
+ auto *symbol{scope.symbol()};
+ if (scope.kind() != Scope::Kind::Module) {
+ return;
+ }
+ if (!symbol->test(Symbol::Flag::ModFile)) {
+ auto *ancestor{symbol->get<ModuleDetails>().ancestor()};
+ auto ancestorName{ancestor ? ancestor->name().ToString() : ""s};
+ auto path{ModFilePath(dir_, symbol->name(), ancestorName)};
+ std::ofstream os{path};
+ PutSymbols(scope);
+ std::string all{GetAsString(*symbol)};
+ auto header{GetHeader(all)};
+ os << header << all;
+ os.close();
+ if (!os) {
+ errors_.emplace_back(
+ "Error writing %s: %s"_err_en_US, path.c_str(), std::strerror(errno));
+ return;
+ }
+ }
+ WriteChildren(scope); // write out submodules
}
// Return the entire body of the module file
// and clear saved uses, decls, and contains.
-std::string ModFileWriter::GetAsString(const std::string &name) {
+std::string ModFileWriter::GetAsString(const Symbol &symbol) {
std::stringstream all;
- all << "module " << name << '\n';
- all << uses_.str();
+ auto &details{symbol.get<ModuleDetails>()};
+ if (!details.isSubmodule()) {
+ PutLower(all << "module ", symbol);
+ } else {
+ auto *parent{details.parent()->symbol()};
+ auto *ancestor{details.ancestor()->symbol()};
+ PutLower(all << "submodule(", *ancestor);
+ if (parent != ancestor) {
+ PutLower(all << ':', *parent);
+ }
+ PutLower(all << ") ", symbol);
+ }
+ all << '\n' << uses_.str();
uses_.str(""s);
all << useExtraAttrs_.str();
useExtraAttrs_.str(""s);
return result;
}
-bool ModFileReader::Read(const SourceName &modName) {
- auto path{FindModFile(modName)};
+Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
+ std::string ancestorName; // empty for module
+ if (ancestor) {
+ if (auto *scope{ancestor->FindSubmodule(name)}) {
+ return scope;
+ }
+ ancestorName = ancestor->name().ToString();
+ } else {
+ auto it{Scope::globalScope.find(name)};
+ if (it != Scope::globalScope.end()) {
+ return it->second->scope();
+ }
+ }
+ auto path{FindModFile(name, ancestorName)};
if (!path.has_value()) {
- return false;
+ return nullptr;
}
// TODO: Construct parsing with an AllSources reference to share provenance
parser::Parsing parsing;
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;
+ Error(name, "Module file for '%s' is corrupt: %s"_err_en_US,
+ name.ToString(), *path));
+ return nullptr;
}
- ResolveNames(*parseTree, parsing.cooked(), directories_);
-
- const auto &it{Scope::globalScope.find(modName)};
- if (it == Scope::globalScope.end()) {
- return false;
+ Scope *parentScope;
+ if (!ancestor) {
+ // module: goes into global scope
+ parentScope = &Scope::globalScope;
+ } else {
+ // submodule: goes into parent module/submodule
+ auto *parent{GetSubmoduleParent(*parseTree)};
+ parentScope = parent ? Read(*parent, ancestor) : ancestor;
+ }
+ ResolveNames(*parentScope, *parseTree, parsing.cooked(), directories_);
+ const auto &it{parentScope->find(name)};
+ if (it == parentScope->end()) {
+ return nullptr;
}
auto &modSymbol{*it->second};
// TODO: Preserve the CookedSource rather than acquiring its string.
modSymbol.scope()->set_chars(std::string{parsing.cooked().AcquireData()});
modSymbol.set(Symbol::Flag::ModFile);
- return true;
+ return modSymbol.scope();
}
-// Look for the .mod file for this module in the search directories.
-// Add to errors_ if not found.
std::optional<std::string> ModFileReader::FindModFile(
- const SourceName &modName) {
- auto error{Error(modName, "Cannot find module file for '%s'"_err_en_US,
- modName.ToString())};
+ const SourceName &name, const std::string &ancestor) {
+ std::vector<parser::Message> errors;
for (auto &dir : directories_) {
- std::string path{ModFilePath(dir, modName.ToString())};
+ std::string path{ModFilePath(dir, name, ancestor)};
std::ifstream ifstream{path};
if (!ifstream.good()) {
- error.Attach(Error(
- modName, "%s: %s"_en_US, path, std::string{std::strerror(errno)}));
+ errors.push_back(
+ Error(name, "%s: %s"_en_US, path, std::string{std::strerror(errno)}));
} else {
std::string line;
ifstream >> line;
if (std::equal(line.begin(), line.end(), std::string{magic}.begin())) {
- // TODO: verify reset of header line: version, checksum, etc.
- return path; // success
+ // TODO: verify rest of header line: version, checksum, etc.
+ return path;
}
- error.Attach(Error(modName, "%s: Not a valid module file"_en_US, path));
+ errors.push_back(Error(name, "%s: Not a valid module file"_en_US, path));
}
}
+ auto error{Error(name,
+ ancestor.empty()
+ ? "Cannot find module file for '%s'"_err_en_US
+ : "Cannot find module file for submodule '%s' of module '%s'"_err_en_US,
+ name.ToString(), ancestor)};
+ for (auto &e : errors) {
+ error.Attach(e);
+ }
errors_.push_back(error);
return std::nullopt;
}
-static std::string ModFilePath(
- const std::string &dir, const std::string &modName) {
- if (dir == "."s) {
- return modName + extension;
+// program was read from a .mod file for a submodule; return the name of the
+// submodule's parent submodule, nullptr if none.
+static const SourceName *GetSubmoduleParent(const parser::Program &program) {
+ CHECK(program.v.size() == 1);
+ auto &unit{program.v.front()};
+ auto &submod{std::get<common::Indirection<parser::Submodule>>(unit.u)};
+ auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(submod->t)};
+ auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)};
+ if (auto &parent{std::get<std::optional<parser::Name>>(parentId.t)}) {
+ return &parent->source;
} else {
- return dir + '/' + modName + extension;
+ return nullptr;
+ }
+}
+
+// Construct the path to a module file. ancestorName not empty means submodule.
+static std::string ModFilePath(const std::string &dir, const SourceName &name,
+ const std::string &ancestorName) {
+ std::stringstream path;
+ if (dir != "."s) {
+ path << dir << '/';
+ }
+ if (!ancestorName.empty()) {
+ PutLower(path, ancestorName) << '-';
}
+ PutLower(path, name.ToString()) << extension;
+ return path.str();
}
static parser::Message Error(const SourceName &location,
// Write out all .mod files; if error return false.
bool WriteAll();
- // Write out .mod file for one module; if error return false.
- bool WriteOne(const Symbol &);
private:
using symbolSet = std::set<const Symbol *>;
// Any errors encountered during writing:
std::vector<parser::MessageFormattedText> errors_;
- std::string GetAsString(const std::string &);
+ void WriteChildren(const Scope &);
+ void WriteOne(const Scope &);
+ std::string GetAsString(const Symbol &);
std::string GetHeader(const std::string &);
void PutSymbols(const Scope &);
symbolVector SortSymbols(const symbolSet);
// directories specifies where to search for module files
ModFileReader(const std::vector<std::string> &directories)
: directories_{directories} {}
-
- // Find and read the module file for modName.
- // Return true on success; otherwise errors() reports the problems.
- bool Read(const SourceName &modName);
+ // Find and read the module file for a module or submodule.
+ // If ancestor is specified, look for a submodule of that module.
+ // Return the Scope for that module/submodule or nullptr on error.
+ Scope *Read(const SourceName &, Scope *ancestor = nullptr);
+ // Errors that occurred when Read returns nullptr.
std::vector<parser::Message> &errors() { return errors_; }
private:
std::vector<std::string> directories_;
std::vector<parser::Message> errors_;
- std::optional<std::string> FindModFile(const SourceName &);
- bool Prescan(const SourceName &, const std::string &);
+ std::optional<std::string> FindModFile(
+ const SourceName &, const std::string &);
};
} // namespace Fortran::semantics
// Manage a stack of Scopes
class ScopeHandler : public virtual ImplicitRulesVisitor {
public:
- ScopeHandler() { PushScope(Scope::globalScope); }
+ void set_rootScope(Scope &scope) { PushScope(scope); }
Scope &CurrScope() { return *scopes_.top(); }
// Return the enclosing scope not corresponding to a derived type:
Scope &CurrNonTypeScope();
// Create a new scope and push it on the scope stack.
Scope &PushScope(Scope::Kind kind, Symbol *symbol);
+ void PushScope(Scope &scope);
void PopScope();
Symbol *FindSymbol(const SourceName &name);
private:
// Stack of containing scopes; memory referenced is owned by parent scopes
std::stack<Scope *, std::list<Scope *>> scopes_;
-
- void PushScope(Scope &scope);
};
class ModuleVisitor : public virtual ScopeHandler {
public:
bool Pre(const parser::Module &);
void Post(const parser::Module &);
+ bool Pre(const parser::Submodule &);
+ void Post(const parser::Submodule &);
bool Pre(const parser::AccessStmt &);
bool Pre(const parser::Only &);
bool Pre(const parser::Rename::Names &);
void SetAccess(const parser::Name &, Attr);
void ApplyDefaultAccess();
- const Scope *FindModule(const SourceName &);
void AddUse(const parser::Rename::Names &);
void AddUse(const parser::Name &);
// Record a use from useModuleScope_ of useName as localName. location is
// where it occurred (either the module or the rename) for error reporting.
void AddUse(const SourceName &location, const SourceName &localName,
const SourceName &useName);
+ Symbol &BeginModule(const SourceName &, bool isSubmodule,
+ const std::optional<parser::ModuleSubprogramPart> &);
+ Scope *FindModule(const SourceName &, Scope * = nullptr);
};
class InterfaceVisitor : public virtual ScopeHandler {
useModuleScope_ = nullptr;
}
-// Find the module with this name and return its scope.
-// May have to read a .mod file to find it.
-// Return nullptr on error, after reporting it.
-const Scope *ModuleVisitor::FindModule(const SourceName &name) {
- auto it{Scope::globalScope.find(name)};
- if (it == Scope::globalScope.end()) {
- ModFileReader reader{searchDirectories_};
- if (!reader.Read(name)) {
- for (auto &error : reader.errors()) {
- Say(std::move(error));
- }
- return nullptr;
- }
- it = Scope::globalScope.find(name);
- CHECK(it != Scope::globalScope.end()); // else would have reported error
- }
- const auto *details{it->second->detailsIf<ModuleDetails>()};
- if (!details) {
- Say(name, "'%s' is not a module"_err_en_US);
- return nullptr;
- }
- return details->scope();
-}
-
void ModuleVisitor::AddUse(const parser::Rename::Names &names) {
const SourceName &useName{std::get<0>(names.t).source};
const SourceName &localName{std::get<1>(names.t).source};
}
}
+bool ModuleVisitor::Pre(const parser::Submodule &x) {
+ auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
+ auto &name{std::get<parser::Name>(stmt.statement.t).source};
+ auto &subpPart{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
+ auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)};
+ auto &ancestorName{std::get<parser::Name>(parentId.t).source};
+ auto &parentName{std::get<std::optional<parser::Name>>(parentId.t)};
+ Scope *ancestor{FindModule(ancestorName)};
+ if (!ancestor) {
+ return false;
+ }
+ Scope *parentScope{
+ parentName ? FindModule(parentName->source, ancestor) : ancestor};
+ if (!parentScope) {
+ return false;
+ }
+ PushScope(*parentScope); // submodule is hosted in parent
+ auto &symbol{BeginModule(name, true, subpPart)};
+ if (ancestor->AddSubmodule(name, &CurrScope())) {
+ Say(name, "Module '%s' already has a submodule named '%s'"_err_en_US,
+ ancestorName, name);
+ }
+ MakeSymbol(name, symbol.get<ModuleDetails>());
+ return true;
+}
+void ModuleVisitor::Post(const parser::Submodule &) {
+ PopScope(); // submodule's scope
+ PopScope(); // parent's scope
+}
+
bool ModuleVisitor::Pre(const parser::Module &x) {
// Make a symbol and push a scope for this module
const auto &name{
- std::get<parser::Statement<parser::ModuleStmt>>(x.t).statement.v};
- auto &symbol{MakeSymbol(name, ModuleDetails{})};
- ModuleDetails &details{symbol.get<ModuleDetails>()};
- Scope &modScope{PushScope(Scope::Kind::Module, &symbol)};
- details.set_scope(&modScope);
- MakeSymbol(name, ModuleDetails{details});
- // collect module subprogram names
- if (const auto &subpPart{
- std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)}) {
- subpNamesOnly_ = SubprogramKind::Module;
- parser::Walk(*subpPart, *static_cast<ResolveNamesVisitor *>(this));
- subpNamesOnly_ = std::nullopt;
- }
+ std::get<parser::Statement<parser::ModuleStmt>>(x.t).statement.v.source};
+ auto &subpPart{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
+ auto &symbol{BeginModule(name, false, subpPart)};
+ MakeSymbol(name, symbol.details());
return true;
}
prevAccessStmt_ = nullptr;
}
+Symbol &ModuleVisitor::BeginModule(const SourceName &name, bool isSubmodule,
+ const std::optional<parser::ModuleSubprogramPart> &subpPart) {
+ auto &symbol{MakeSymbol(name, ModuleDetails{isSubmodule})};
+ auto &details{symbol.get<ModuleDetails>()};
+ auto &modScope{PushScope(Scope::Kind::Module, &symbol)};
+ details.set_scope(&modScope);
+ if (subpPart) {
+ subpNamesOnly_ = SubprogramKind::Module;
+ parser::Walk(*subpPart, *static_cast<ResolveNamesVisitor *>(this));
+ subpNamesOnly_ = std::nullopt;
+ }
+ return symbol;
+}
+
+// Find a module or submodule by name and return its scope.
+// If ancestor is present, look for a submodule of that ancestor module.
+// May have to read a .mod file to find it.
+// If an error occurs, report it and return nullptr.
+Scope *ModuleVisitor::FindModule(const SourceName &name, Scope *ancestor) {
+ ModFileReader reader{searchDirectories_};
+ auto *scope{reader.Read(name, ancestor)};
+ if (!scope) {
+ for (auto &error : reader.errors()) {
+ Say(std::move(error));
+ }
+ return nullptr;
+ }
+ if (scope->kind() != Scope::Kind::Module) {
+ Say(name, "'%s' is not a module"_err_en_US);
+ return nullptr;
+ }
+ return scope;
+}
+
void ModuleVisitor::ApplyDefaultAccess() {
for (auto &pair : CurrScope()) {
Symbol &symbol = *pair.second;
CHECK(!GetDeclTypeSpec());
}
-void ResolveNames(parser::Program &program,
+void ResolveNames(Scope &rootScope, parser::Program &program,
const parser::CookedSource &cookedSource,
const std::vector<std::string> &searchDirectories) {
ResolveNamesVisitor visitor;
+ visitor.set_rootScope(rootScope);
for (auto &dir : searchDirectories) {
visitor.add_searchDirectory(dir);
}
namespace Fortran::semantics {
-void ResolveNames(parser::Program &, const parser::CookedSource &,
- const std::vector<std::string> &);
+class Scope;
+
+void ResolveNames(Scope &rootScope, parser::Program &,
+ const parser::CookedSource &, const std::vector<std::string> &);
void DumpSymbols(std::ostream &);
} // namespace Fortran::semantics
return 0;
}
}
+Scope *Scope::FindSubmodule(const SourceName &name) const {
+ auto it{submodules_.find(name)};
+ if (it == submodules_.end()) {
+ return nullptr;
+ } else {
+ return it->second;
+ }
+}
+Scope *Scope::AddSubmodule(const SourceName &name, Scope *submodule) {
+ auto pair{submodules_.emplace(name, submodule)};
+ return !pair.second ? pair.first->second : nullptr;
+}
DerivedTypeSpec &Scope::MakeDerivedTypeSpec(const SourceName &name) {
derivedTypeSpecs_.emplace_back(name);
return derivedTypeSpecs_.back();
std::pair<iterator, bool> try_emplace(
const SourceName &name, Attrs attrs, D &&details) {
Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
- return symbols_.insert(std::make_pair(name, &symbol));
+ return symbols_.emplace(name, &symbol);
}
/// Make a Symbol but don't add it to the scope.
std::list<Scope> &children() { return children_; }
const std::list<Scope> &children() const { return children_; }
+ // For Module scope, maintain a mapping of all submodule scopes with this
+ // module as its ancestor module.
+ Scope *FindSubmodule(const SourceName &) const;
+ Scope *AddSubmodule(const SourceName &, Scope *);
+
DerivedTypeSpec &MakeDerivedTypeSpec(const SourceName &);
// For modules read from module files, this is the stream of characters
// that are referenced by SourceName objects.
- void set_chars(std::string &&chars) {
- chars_ = std::move(chars);
- }
+ void set_chars(std::string &&chars) { chars_ = std::move(chars); }
private:
Scope &parent_;
Symbol *const symbol_;
std::list<Scope> children_;
mapType symbols_;
+ std::map<SourceName, Scope *> submodules_;
std::list<DerivedTypeSpec> derivedTypeSpecs_;
std::string chars_;
return os << name.ToString();
}
+const Scope *ModuleDetails::parent() const {
+ return isSubmodule_ ? &scope_->parent() : nullptr;
+}
+const Scope *ModuleDetails::ancestor() const {
+ if (!isSubmodule_) {
+ return nullptr;
+ }
+ for (auto *scope{scope_};;) {
+ auto *parent{&scope->parent()};
+ if (parent->kind() != Scope::Kind::Module) {
+ return scope;
+ }
+ scope = parent;
+ }
+}
+void ModuleDetails::set_scope(const Scope *scope) {
+ CHECK(!scope_);
+ bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
+ CHECK(isSubmodule_ == scopeIsSubmodule);
+ scope_ = scope;
+}
+
void EntityDetails::set_type(const DeclTypeSpec &type) {
CHECK(!type_);
type_ = type;
common::visitors{
[&](const UnknownDetails &x) {},
[&](const MainProgramDetails &x) {},
- [&](const ModuleDetails &x) {},
+ [&](const ModuleDetails &x) {
+ if (x.isSubmodule()) {
+ auto &ancestor{x.ancestor()->name()};
+ auto &parent{x.parent()->name()};
+ os << " (" << ancestor.ToString();
+ if (parent != ancestor) {
+ os << ':' << parent.ToString();
+ }
+ os << ")";
+ }
+ },
[&](const SubprogramDetails &x) {
os << " (";
int n = 0;
class Scope;
class Symbol;
+// A module or submodule.
class ModuleDetails {
public:
+ ModuleDetails(bool isSubmodule = false) : isSubmodule_{isSubmodule} {}
+ bool isSubmodule() const { return isSubmodule_; }
const Scope *scope() const { return scope_; }
- void set_scope(const Scope *scope) {
- CHECK(!scope_);
- scope_ = scope;
- }
+ const Scope *ancestor() const; // for submodule; nullptr for module
+ const Scope *parent() const; // for submodule; nullptr for module
+ void set_scope(const Scope *);
private:
+ bool isSubmodule_;
const Scope *scope_{nullptr};
};
resolve23.f90
resolve24.f90
resolve25.f90
+ resolve26.f90
+ resolve27.f90
)
# These test files have expected symbols in the source
modfile06.f90
modfile07.f90
modfile08.f90
+ modfile09-*.f90
)
foreach(test ${ERROR_TESTS})
--- /dev/null
+module m
+ integer :: m1_x
+ interface
+ module subroutine s()
+ end subroutine
+ end interface
+end
+
+!Expect: m.mod
+!module m
+!integer::m1_x
+!interface
+!module subroutine s()
+!end
+!end interface
+!end
--- /dev/null
+submodule(m) s1
+ integer s1_x
+end
+
+!Expect: m-s1.mod
+!submodule(m) s1
+!integer::s1_x
+!end
--- /dev/null
+submodule(m:s1) s2
+ integer s2_x
+end
+
+!Expect: m-s2.mod
+!submodule(m:s1) s2
+!integer::s2_x
+!end
--- /dev/null
+submodule(m:s2) s3
+ integer s3_x
+end
+
+!Expect: m-s3.mod
+!submodule(m:s2) s3
+!integer::s3_x
+!end
--- /dev/null
+module m1
+ interface
+ module subroutine s()
+ end subroutine
+ end interface
+end
+
+module m2
+ interface
+ module subroutine s()
+ end subroutine
+ end interface
+end
+
+submodule(m1) s1
+end
+
+!ERROR: Cannot find module file for submodule 's1' of module 'm2'
+submodule(m2:s1) s2
+end
+
+!ERROR: Cannot find module file for 'm3'
+submodule(m3:s1) s3
+end
--- /dev/null
+module m
+ interface
+ module subroutine s()
+ end subroutine
+ end interface
+end
+
+submodule(m) s1
+end
+
+submodule(m) s2
+end
+
+submodule(m:s1) s3
+ integer x
+end
+
+!ERROR: Module 'm' already has a submodule named 's3'
+submodule(m:s2) s3
+ integer y
+end
PATH=/usr/bin:/bin
srcdir=$(dirname $0)
CMD="${F18:-../../../tools/f18/f18} -fdebug-resolve-names -fparse-only"
-
if [[ $# != 1 ]]; then
echo "Usage: $0 <fortran-source>"
exit 1
fi
src=$srcdir/$1
-[[ ! -f $src ]] && echo "File not found: $src" && exit 1
temp=temp-$1
rm -rf $temp
mkdir $temp
[[ $KEEP ]] || trap "rm -rf $temp" EXIT
-
-( cd $temp && $CMD $src )
-
actual=$temp/actual.mod
expect=$temp/expect.mod
actual_files=$temp/actual_files
+prev_files=$temp/prev_files
diffs=$temp/diffs
-( cd $temp && ls -1 *.mod ) > $actual_files
-expected_files=$(sed -n 's/^!Expect: \(.*\)/\1/p' $src)
-extra_files=$(echo "$expected_files" | comm -23 $actual_files -)
-if [[ ! -z "$extra_files" ]]; then
- echo "Unexpected .mod files produced:" $extra_files
- echo FAIL
- exit 1
-fi
-for mod in $expected_files; do
- if [[ ! -f $temp/$mod ]]; then
- echo "Compilation did not produce expected mod file: $mod"
- echo FAIL
- exit 1
- fi
- sed '/^!mod\$/d' $temp/$mod > $actual
- sed '1,/^!Expect: '"$mod"'/d' $src | sed -e '/^$/,$d' -e 's/^! *//' > $expect
- if ! diff -U999999 $actual $expect > $diffs; then
- echo "Module file $mod differs from expected:"
- sed '1,2d' $diffs
+set $src
+
+touch $actual
+for src in "$@"; do
+ [[ ! -f $src ]] && echo "File not found: $src" && exit 1
+ (
+ cd $temp
+ ls -1 *.mod > prev_files
+ $CMD $src
+ ls -1 *.mod | comm -13 prev_files -
+ ) > $actual_files
+ expected_files=$(sed -n 's/^!Expect: \(.*\)/\1/p' $src)
+ extra_files=$(echo "$expected_files" | comm -23 $actual_files -)
+ if [[ ! -z "$extra_files" ]]; then
+ echo "Unexpected .mod files produced:" $extra_files
echo FAIL
exit 1
fi
+ for mod in $expected_files; do
+ if [[ ! -f $temp/$mod ]]; then
+ echo "Compilation did not produce expected mod file: $mod"
+ echo FAIL
+ exit 1
+ fi
+ sed '/^!mod\$/d' $temp/$mod > $actual
+ sed '1,/^!Expect: '"$mod"'/d' $src | sed -e '/^$/,$d' -e 's/^! *//' > $expect
+ if ! diff -U999999 $actual $expect > $diffs; then
+ echo "Module file $mod differs from expected:"
+ sed '1,2d' $diffs
+ echo FAIL
+ exit 1
+ fi
+ done
+ rm -f $actual $expect
done
echo PASS
#include "../../lib/semantics/dump-parse-tree.h"
#include "../../lib/semantics/mod-file.h"
#include "../../lib/semantics/resolve-names.h"
+#include "../../lib/semantics/scope.h"
#include "../../lib/semantics/unparse-with-symbols.h"
#include <cerrno>
#include <cstdio>
if (driver.moduleDirectory != "."s) {
directories.insert(directories.begin(), driver.moduleDirectory);
}
- Fortran::semantics::ResolveNames(parseTree, parsing.cooked(), directories);
+ Fortran::semantics::ResolveNames(Fortran::semantics::Scope::globalScope,
+ parseTree, parsing.cooked(), directories);
Fortran::semantics::ModFileWriter writer;
writer.set_directory(driver.moduleDirectory);
if (!writer.WriteAll()) {