constexpr Parser<ImplicitPart> implicitPart; // R505
constexpr Parser<DeclarationConstruct> declarationConstruct; // R507
constexpr Parser<SpecificationConstruct> specificationConstruct; // R508
+constexpr Parser<ExecutionPart> executionPart; // R509
constexpr Parser<ExecutionPartConstruct> executionPartConstruct; // R510
constexpr Parser<InternalSubprogramPart> internalSubprogramPart; // R511
constexpr Parser<ActionStmt> actionStmt; // R515
construct<ExecutionPartConstruct>{}(executionPartErrorRecovery)))
// R509 execution-part -> executable-construct [execution-part-construct]...
-constexpr auto executionPart =
- inContext("execution part"_en_US, many(executionPartConstruct));
+TYPE_CONTEXT_PARSER("execution part"_en_US,
+ construct<ExecutionPart>{}(many(executionPartConstruct)))
// R602 underscore -> _
constexpr auto underscore = "_"_ch;
--- /dev/null
+#ifndef FORTRAN_PARSER_PARSE_TREE_MUTATOR_H_
+#define FORTRAN_PARSER_PARSE_TREE_MUTATOR_H_
+
+#include "parse-tree.h"
+#include <cstddef>
+#include <optional>
+#include <tuple>
+#include <utility>
+#include <variant>
+
+/// Parse tree mutator
+/// Call Walk(x, mutator) to visit x and, by default, each node under x,
+/// optionally rewriting it in place.
+///
+/// mutator.Pre(x) is called before visiting x and its children are not
+/// visited if it returns false.
+///
+/// mutator.Post(x) is called after visiting x.
+
+namespace Fortran {
+namespace parser {
+
+// Default case for visitation of non-class data members and strings
+template<typename A, typename M>
+typename std::enable_if<!std::is_class_v<A> ||
+ std::is_same_v<std::string, A>>::type
+Walk(A &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ mutator.Post(x);
+ }
+}
+
+template<typename M> void Walk(format::ControlEditDesc &, M &);
+template<typename M> void Walk(format::DerivedTypeDataEditDesc &, M &);
+template<typename M> void Walk(format::FormatItem &, M &);
+template<typename M> void Walk(format::FormatSpecification &, M &);
+template<typename M> void Walk(format::IntrinsicTypeDataEditDesc &, M &);
+
+// Traversal of needed STL template classes (optional, list, tuple, variant)
+template<typename T, typename M>
+void Walk(std::optional<T> &x, M &mutator) {
+ if (x) {
+ Walk(*x, mutator);
+ }
+}
+template<typename T, typename M> void Walk(std::list<T> &x, M &mutator) {
+ for (auto &elem : x) {
+ Walk(elem, mutator);
+ }
+}
+template<std::size_t I = 0, typename Func, typename T>
+void ForEachInTuple(T &tuple, Func func) {
+ if constexpr (I < std::tuple_size_v<T>) {
+ func(std::get<I>(tuple));
+ ForEachInTuple<I + 1>(tuple, func);
+ }
+}
+template<typename M, typename... A>
+void Walk(std::tuple<A...> &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ ForEachInTuple(x, [&](auto &y) { Walk(y, mutator); });
+ mutator.Post(x);
+ }
+}
+template<typename M, typename... A>
+void Walk(std::variant<A...> &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ std::visit([&](auto &y) { Walk(y, mutator); }, x);
+ mutator.Post(x);
+ }
+}
+template<typename A, typename B, typename M>
+void Walk(std::pair<A, B> &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.first, mutator);
+ Walk(x.second, mutator);
+ }
+}
+
+// Trait-determined traversal of empty, tuple, union, and wrapper classes.
+template<typename A, typename M>
+typename std::enable_if<EmptyTrait<A>>::type Walk(A &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ mutator.Post(x);
+ }
+}
+
+template<typename A, typename M>
+typename std::enable_if<TupleTrait<A>>::type Walk(A &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.t, mutator);
+ mutator.Post(x);
+ }
+}
+
+template<typename A, typename M>
+typename std::enable_if<UnionTrait<A>>::type Walk(A &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.u, mutator);
+ mutator.Post(x);
+ }
+}
+
+template<typename A, typename M>
+typename std::enable_if<WrapperTrait<A>>::type Walk(A &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.v, mutator);
+ mutator.Post(x);
+ }
+}
+
+template<typename T, typename M>
+void Walk(Indirection<T> &x, M &mutator) {
+ Walk(*x, mutator);
+}
+
+// Walk a class with a single field 'thing'.
+template<typename T, typename M> void Walk(Scalar<T> &x, M &mutator) {
+ Walk(x.thing, mutator);
+}
+template<typename T, typename M> void Walk(Constant<T> &x, M &mutator) {
+ Walk(x.thing, mutator);
+}
+template<typename T, typename M> void Walk(Integer<T> &x, M &mutator) {
+ Walk(x.thing, mutator);
+}
+template<typename T, typename M> void Walk(Logical<T> &x, M &mutator) {
+ Walk(x.thing, mutator);
+}
+template<typename T, typename M>
+void Walk(DefaultChar<T> &x, M &mutator) {
+ Walk(x.thing, mutator);
+}
+
+template<typename T, typename M> void Walk(Statement<T> &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ // N.B. the label is not traversed
+ Walk(x.statement, mutator);
+ mutator.Post(x);
+ }
+}
+
+template<typename M> void Walk(Name &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ mutator.Post(x);
+ }
+}
+
+template<typename M> void Walk(AcSpec &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.type, mutator);
+ Walk(x.values, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(ArrayElement &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.base, mutator);
+ Walk(x.subscripts, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(CharSelector::LengthAndKind &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.length, mutator);
+ Walk(x.kind, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(CaseValueRange::Range &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.lower, mutator);
+ Walk(x.upper, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(CoindexedNamedObject &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.base, mutator);
+ Walk(x.imageSelector, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(DeclarationTypeSpec::Class &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.derived, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(DeclarationTypeSpec::Type &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.derived, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(ImportStmt &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.names, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(IntrinsicTypeSpec::Character &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.selector, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(IntrinsicTypeSpec::Complex &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.kind, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(IntrinsicTypeSpec::Logical &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.kind, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(IntrinsicTypeSpec::Real &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.kind, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename T, typename M> void Walk(LoopBounds<T> &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.name, mutator);
+ Walk(x.lower, mutator);
+ Walk(x.upper, mutator);
+ Walk(x.step, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(PartRef &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.name, mutator);
+ Walk(x.subscripts, mutator);
+ Walk(x.imageSelector, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(ReadStmt &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.iounit, mutator);
+ Walk(x.format, mutator);
+ Walk(x.controls, mutator);
+ Walk(x.items, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(RealLiteralConstant &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.real, mutator);
+ Walk(x.kind, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(RealLiteralConstant::Real &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(StructureComponent &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.base, mutator);
+ Walk(x.component, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(Suffix &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.binding, mutator);
+ Walk(x.resultName, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(TypeBoundProcedureStmt::WithInterface &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.interfaceName, mutator);
+ Walk(x.attributes, mutator);
+ Walk(x.bindingNames, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(TypeBoundProcedureStmt::WithoutInterface &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.attributes, mutator);
+ Walk(x.declarations, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(UseStmt &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.nature, mutator);
+ Walk(x.moduleName, mutator);
+ Walk(x.u, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(WriteStmt &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.iounit, mutator);
+ Walk(x.format, mutator);
+ Walk(x.controls, mutator);
+ Walk(x.items, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(format::ControlEditDesc &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.kind, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(format::DerivedTypeDataEditDesc &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.type, mutator);
+ Walk(x.parameters, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M> void Walk(format::FormatItem &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.repeatCount, mutator);
+ Walk(x.u, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(format::FormatSpecification &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.items, mutator);
+ Walk(x.unlimitedItems, mutator);
+ mutator.Post(x);
+ }
+}
+template<typename M>
+void Walk(format::IntrinsicTypeDataEditDesc &x, M &mutator) {
+ if (mutator.Pre(x)) {
+ Walk(x.kind, mutator);
+ Walk(x.width, mutator);
+ Walk(x.digits, mutator);
+ Walk(x.exponentWidth, mutator);
+ mutator.Post(x);
+ }
+}
+} // namespace parser
+} // namespace Fortran
+#endif // FORTRAN_PARSER_PARSE_TREE_MUTATOR_H_
namespace Fortran {
namespace semantics {
+class Symbol;
template<typename T> struct Semantic {
Semantic(T *) {}
};
};
// R509 execution-part -> executable-construct [execution-part-construct]...
-using ExecutionPart = std::list<ExecutionPartConstruct>;
+WRAPPER_CLASS(ExecutionPart, std::list<ExecutionPartConstruct>);
// R502 program-unit ->
// main-program | external-subprogram | module | submodule | block-data
COPY_AND_ASSIGN_BOILERPLATE(Name);
std::string ToString() const { return source.ToString(); }
CharBlock source;
- // TODO: pointer to symbol table entity
+ semantics::Symbol *symbol{nullptr};
};
// R516 keyword -> name
attr.cc
make-types.cc
resolve-names.cc
+ rewrite-parse-tree.cc
scope.cc
symbol.cc
type.cc
#ifndef FLANG_SEMA_PARSE_TREE_DUMP_H
#define FLANG_SEMA_PARSE_TREE_DUMP_H
+#include "symbol.h"
#include "../parser/format-specification.h"
#include "../parser/idioms.h"
#include "../parser/indirection.h"
#include "../parser/parse-tree-visitor.h"
#include "../parser/parse-tree.h"
-
#include <cstring>
#include <iomanip>
#include <iostream>
}
}
- bool Pre(const parser::Name &x) { return Pre(x.ToString()); }
+ bool PutName(const std::string &name, const semantics::Symbol *symbol) {
+ if (emptyline) {
+ out_indent();
+ emptyline = false;
+ }
+ if (symbol) {
+ out << "symbol = " << *symbol;
+ } else {
+ out << "Name = '" << name << '\'';
+ }
+ out << '\n';
+ indent++;
+ emptyline = true;
+ return true;
+ }
+
+ bool Pre(const parser::Name &x) {
+ return PutName(x.ToString(), x.symbol);
+ }
+
+ void Post(const parser::Name &) {
+ indent--;
+ }
bool Pre(const std::string &x) {
- if (emptyline ) {
- out_indent();
- emptyline = false ;
- }
- out << "Name = '" << x << "'\n";
- indent++ ;
- emptyline = true ;
- return true ;
+ return PutName(x, nullptr);
}
void Post(const std::string &x) {
#include "resolve-names.h"
+#include "rewrite-parse-tree.h"
#include "attr.h"
#include "scope.h"
#include "symbol.h"
#include "../parser/indirection.h"
#include "../parser/parse-tree-visitor.h"
#include "../parser/parse-tree.h"
-#include <iostream>
+#include <ostream>
#include <list>
#include <memory>
#include <stack>
const parser::Name *funcResultName_{nullptr};
// The attribute corresponding to the statement containing an ObjectDecl
std::optional<Attr> objectDeclAttr_;
+ // Set when we a statement function that is really an array assignment
+ bool badStmtFuncFound_{false};
// Create a subprogram symbol in the current scope and push a new scope.
Symbol &PushSubprogramScope(const parser::Name &);
}
void ResolveNamesVisitor::Post(const parser::SpecificationPart &s) {
+ badStmtFuncFound_ = false;
if (isImplicitNoneType()) {
// Check that every name referenced has an explicit type
for (const auto &pair : CurrScope()) {
void ResolveNamesVisitor::Post(const parser::EndSubroutineStmt &subp) {
ApplyImplicitRules();
- std::cout << "End of subroutine scope\n";
- std::cout << CurrScope();
PopScope();
}
void ResolveNamesVisitor::Post(const parser::EndFunctionStmt &subp) {
ApplyImplicitRules();
- std::cout << "End of function scope\n";
- std::cout << CurrScope();
PopScope();
}
if (details->isArray()) {
// not a stmt-func at all but an array; do nothing
symbol.add_occurrence(name.source);
+ badStmtFuncFound_ = true;
return true;
}
// TODO: check that attrs are compatible with stmt func
CurrScope().erase(symbol.name());
}
}
+ if (badStmtFuncFound_) {
+ Say(name, "'%s' has not been declared as an array"_err_en_US);
+ return true;
+ }
BeginAttrs(); // no attrs to collect, but PushSubprogramScope expects this
auto &symbol = PushSubprogramScope(name);
CopyImplicitRules();
}
void ResolveNamesVisitor::Post(const parser::StmtFunctionStmt &x) {
+ if (badStmtFuncFound_) {
+ return; // This wasn't really a stmt function so no scope was created
+ }
ApplyImplicitRules();
- std::cout << "End of stmt func scope\n";
- std::cout << CurrScope();
PopScope();
}
Symbol &ResolveNamesVisitor::PushSubprogramScope(const parser::Name &name) {
auto &symbol = MakeSymbol(name, EndAttrs(), SubprogramDetails());
- Scope &subpScope = CurrScope().MakeScope(Scope::Kind::Subprogram);
+ Scope &subpScope = CurrScope().MakeScope(Scope::Kind::Subprogram, &symbol);
PushScope(subpScope);
auto &details = symbol.details<SubprogramDetails>();
// can't reuse this name inside subprogram:
void ResolveNamesVisitor::Post(const parser::EndProgramStmt &) {
ApplyImplicitRules();
- std::cout << "End of program scope\n";
- std::cout << CurrScope();
PopScope();
}
}
void ResolveNames(
- const parser::Program &program, const parser::CookedSource &cookedSource) {
+ parser::Program &program, const parser::CookedSource &cookedSource) {
parser::Messages messages{cookedSource};
ResolveNamesVisitor visitor{messages};
parser::Walk(program, visitor);
- messages.Emit(std::cerr);
+ if (!messages.empty()) {
+ messages.Emit(std::cerr);
+ return;
+ }
+ RewriteParseTree(program);
+}
+
+static void PutIndent(std::ostream &os, int indent) {
+ for (int i = 0; i < indent; ++i) {
+ os << " ";
+ }
+}
+
+static void DumpSymbols(std::ostream &os, const Scope &scope, int indent = 0) {
+ PutIndent(os, indent);
+ os << Scope::EnumToString(scope.kind()) << " scope:";
+ if (const auto *symbol = scope.symbol()) {
+ os << ' ' << symbol->name().ToString();
+ }
+ os << '\n';
+ ++indent;
+ for (const auto &symbol : scope) {
+ PutIndent(os, indent);
+ os << symbol.second << "\n";
+ }
+ for (const auto &child : scope.children()) {
+ DumpSymbols(os, child, indent);
+ }
+ --indent;
+}
+
+void DumpSymbols(std::ostream &os) {
+ DumpSymbols(os, Scope::globalScope);
}
} // namespace Fortran::semantics
} // namespace Fortran::parser
namespace Fortran::semantics {
-void ResolveNames(const parser::Program &, const parser::CookedSource &);
+
+void ResolveNames(parser::Program &, const parser::CookedSource &);
+void DumpSymbols(std::ostream &);
+
} // namespace Fortran::semantics
--- /dev/null
+#include "rewrite-parse-tree.h"
+#include "scope.h"
+#include "symbol.h"
+#include "../parser/indirection.h"
+#include "../parser/parse-tree-mutator.h"
+#include "../parser/parse-tree.h"
+#include <list>
+
+namespace Fortran::semantics {
+
+// Symbols collected during name resolution that are added to parse tree.
+using symbolMap = std::map<const SourceName, Symbol *>;
+
+/// Walk the parse tree and add symbols from the symbolMap in Name nodes.
+/// Convert mis-identified statement functions to array assignments.
+class RewriteMutator {
+public:
+ RewriteMutator(const symbolMap &symbols) : symbols_{symbols} {}
+
+ // Default action for a parse tree node is to visit children.
+ template<typename T> bool Pre(T &) { return true; }
+ template<typename T> void Post(T &) {}
+
+ // Fill in name.symbol if there is a corresponding symbol
+ void Post(parser::Name &name) {
+ const auto it = symbols_.find(name.source);
+ if (it != symbols_.end()) {
+ name.symbol = it->second;
+ }
+ }
+
+ using stmtFuncType =
+ parser::Statement<parser::Indirection<parser::StmtFunctionStmt>>;
+
+ // Find mis-parsed statement functions and move to stmtFuncsToConvert list.
+ void Post(parser::SpecificationPart &x) {
+ auto &list = std::get<std::list<parser::DeclarationConstruct>>(x.t);
+ for (auto it = list.begin(); it != list.end();) {
+ if (auto stmt = std::get_if<stmtFuncType>(&it->u)) {
+ Symbol *symbol{std::get<parser::Name>(stmt->statement->t).symbol};
+ if (symbol && symbol->has<EntityDetails>()) {
+ // not a stmt func: remove it here and add to ones to convert
+ stmtFuncsToConvert.push_back(std::move(*stmt));
+ it = list.erase(it);
+ continue;
+ }
+ }
+ ++it;
+ }
+ }
+
+ // Insert converted assignments at start of ExecutionPart.
+ bool Pre(parser::ExecutionPart &x) {
+ auto origFirst = x.v.begin(); // insert each elem before origFirst
+ for (stmtFuncType &sf : stmtFuncsToConvert) {
+ x.v.insert(origFirst, std::move(ConvertToAssignment(sf)));
+ }
+ stmtFuncsToConvert.clear();
+ return true;
+ }
+
+private:
+ const symbolMap &symbols_;
+ std::list<stmtFuncType> stmtFuncsToConvert;
+
+ // Convert a statement function statement to an ExecutionPartConstruct
+ // containing an array assignment statement.
+ static parser::ExecutionPartConstruct ConvertToAssignment(stmtFuncType &x) {
+ parser::StmtFunctionStmt &sf{*x.statement};
+ auto &funcName = std::get<parser::Name>(sf.t);
+ auto &funcArgs = std::get<std::list<parser::Name>>(sf.t);
+ auto &funcExpr = std::get<parser::Scalar<parser::Expr>>(sf.t).thing;
+ parser::ArrayElement arrayElement{
+ funcName, std::list<parser::SectionSubscript>{}};
+ for (parser::Name &arg : funcArgs) {
+ arrayElement.subscripts.push_back(parser::SectionSubscript{
+ parser::Scalar{parser::Integer{parser::Indirection{
+ parser::Expr{parser::Indirection{parser::Designator{arg}}}}}}});
+ }
+ auto &&variable = parser::Variable{parser::Indirection{parser::Designator{
+ parser::DataRef{parser::Indirection{std::move(arrayElement)}}}}};
+ auto &&stmt = parser::Statement{std::nullopt,
+ parser::ActionStmt{parser::Indirection{
+ parser::AssignmentStmt{std::move(variable), std::move(funcExpr)}}}};
+ stmt.source = x.source;
+ return parser::ExecutionPartConstruct{parser::ExecutableConstruct{stmt}};
+ }
+};
+
+static void CollectSymbols(Scope &scope, symbolMap &symbols) {
+ for (auto &pair : scope) {
+ Symbol &symbol{pair.second};
+ for (const auto &name : symbol.occurrences()) {
+ symbols.emplace(name, &symbol);
+ }
+ }
+ for (auto &child : scope.children()) {
+ CollectSymbols(child, symbols);
+ }
+}
+
+void RewriteParseTree(parser::Program &program) {
+ symbolMap symbols;
+ CollectSymbols(Scope::globalScope, symbols);
+ RewriteMutator mutator{symbols};
+ parser::Walk(program, mutator);
+}
+
+} // namespace Fortran::semantics
--- /dev/null
+namespace Fortran::parser {
+
+class Program;
+
+} // namespace Fortran::parser
+
+namespace Fortran::semantics {
+
+void RewriteParseTree(parser::Program &);
+
+} // namespace Fortran::semantics
namespace Fortran::semantics {
-const Scope Scope::systemScope{Scope::systemScope, Scope::Kind::System};
-Scope Scope::globalScope{Scope::systemScope, Scope::Kind::Global};
+const Scope Scope::systemScope{Scope::systemScope, Scope::Kind::System, nullptr};
+Scope Scope::globalScope{Scope::systemScope, Scope::Kind::Global, nullptr};
-Scope &Scope::MakeScope(Kind kind) {
- children_.emplace_back(*this, kind);
+Scope &Scope::MakeScope(Kind kind, const Symbol *symbol) {
+ children_.emplace_back(*this, kind, symbol);
return children_.back();
}
ENUM_CLASS(Kind, System, Global, Module, MainProgram, Subprogram)
- Scope(const Scope &parent, Kind kind) : parent_{parent}, kind_{kind} {}
+ Scope(const Scope &parent, Kind kind, const Symbol *symbol)
+ : parent_{parent}, kind_{kind}, symbol_{symbol} {}
const Scope &parent() const {
CHECK(kind_ != Kind::System);
return parent_;
}
Kind kind() const { return kind_; }
+ const Symbol *symbol() const { return symbol_; }
/// Make a scope nested in this one
- Scope &MakeScope(Kind kind);
+ Scope &MakeScope(Kind kind, const Symbol *symbol = nullptr);
using size_type = mapType::size_type;
using iterator = mapType::iterator;
return symbols_.try_emplace(name, *this, name, attrs, details);
}
+ std::list<Scope> &children() { return children_; }
+ const std::list<Scope> &children() const { return children_; }
+
private:
const Scope &parent_;
const Kind kind_;
+ const Symbol *const symbol_;
std::list<Scope> children_;
mapType symbols_;
}
std::ostream &operator<<(std::ostream &os, const EntityDetails &x) {
- os << "Entity";
if (x.type()) {
os << " type: " << *x.type();
}
if (!sym.attrs().empty()) {
os << ", " << sym.attrs();
}
- os << ": ";
+ os << ": " << sym.GetDetailsName();
std::visit(
parser::visitors{
- [&](const UnknownDetails &x) { os << " Unknown"; },
- [&](const MainProgramDetails &x) { os << " MainProgram"; },
- [&](const ModuleDetails &x) { os << " Module"; },
+ [&](const UnknownDetails &x) {},
+ [&](const MainProgramDetails &x) {},
+ [&](const ModuleDetails &x) {},
[&](const SubprogramDetails &x) {
- os << " Subprogram (";
+ os << " (";
int n = 0;
for (const auto &dummy : x.dummyArgs()) {
if (n++ > 0) os << ", ";
os << x.result().name().ToString() << ')';
}
},
- [&](const EntityDetails &x) { os << ' ' << x; },
+ [&](const EntityDetails &x) { os << x; },
},
sym.details_);
return os;
--- /dev/null
+integer :: g(10)
+f(i) = i + 1 ! statement function
+g(i) = i + 2 ! mis-parsed array assignment
+!ERROR: 'h' has not been declared as an array
+h(i) = i + 3
+end
bool dumpCookedChars{false};
bool dumpUnparse{false};
bool dumpParseTree{false};
+ bool dumpSymbols{false};
bool debugResolveNames{false};
bool measureTree{false};
std::vector<std::string> pgf90Args;
if (driver.measureTree) {
MeasureParseTree(*parsing.parseTree());
}
- if (driver.debugResolveNames) {
+ if (driver.debugResolveNames || driver.dumpSymbols) {
Fortran::semantics::ResolveNames(
*parsing.parseTree(), parsing.messages().cooked());
+ if (driver.dumpSymbols) {
+ Fortran::semantics::DumpSymbols(std::cout);
+ }
}
if (driver.dumpParseTree) {
Fortran::parser::DumpTree(*parsing.parseTree());
driver.dumpProvenance = true;
} else if (arg == "-fdebug-dump-parse-tree") {
driver.dumpParseTree = true;
+ } else if (arg == "-fdebug-dump-symbols") {
+ driver.dumpSymbols = true;
} else if (arg == "-fdebug-resolve-names") {
driver.debugResolveNames = true;
} else if (arg == "-fdebug-measure-parse-tree") {