llvm/flang/lib/semantics/symbol.h
Tim Keith a3de9d789c [flang] Partial implementation of Symbols and Scopes.
A Symbol consists of a common part (in class Symbol) containing name,
owner, attributes. Information for a specific kind of symbol is in a
variant containing one of the *Details classes. So the kind of symbol is
determined by the type of details class stored in the details_ variant.

For scopes there is a single Scope class with an enum indicating the
kind. So far there isn't a need for extra kind-specific details as with
Symbols but that could change. Symbols defined in a Scope are stored
there in a simple map.

resolve-names.cc is a partial implementation of a parse-tree walker that
resolves names to Symbols. Currently is only handles functions (which
introduce a new Scope) and entity-decls. The test-type executable was
reused as a driver for this to avoid the need for a new one.

Sample output is below. When each "end function" is encountered the
scope is dumped, which shows the symbols defined in it.

$ cat a.f90
pure integer(8) function foo(arg1, arg2) result(res)
  integer :: arg1
  real :: arg2
contains
  function bar(arg1)
    real :: bar
    real :: arg1
  end function
end function

$ Debug/tools/f18/test-type a.f90
Subprogram scope: 0 children
  arg1:  Entity type: REAL
  bar:  Entity type: REAL
Subprogram scope: 1 children
  arg1:  Entity type: INTEGER
  arg2:  Entity type: REAL
  bar:  Subprogram (arg1)
  foo:  Subprogram (arg1, arg2) result(res)
  res:  Entity type: INTEGER(8)

Original-commit: flang-compiler/f18@1cd2fbc04d
Reviewed-on: https://github.com/flang-compiler/f18/pull/30
Tree-same-pre-rewrite: false
2018-03-22 17:25:34 -07:00

112 lines
3 KiB
C++

#ifndef FORTRAN_SEMANTICS_SYMBOL_H_
#define FORTRAN_SEMANTICS_SYMBOL_H_
#include "type.h"
#include <memory>
#include <functional>
namespace Fortran {
namespace semantics {
/// A Symbol consists of common information (name, owner, and attributes)
/// and details information specific to the kind of symbol, represented by the
/// *Details classes.
class Scope;
class ModuleDetails {
public:
private:
};
class MainProgramDetails {
public:
private:
};
class SubprogramDetails {
public:
SubprogramDetails(const std::list<Name> &dummyNames)
: isFunction_{false}, dummyNames_{dummyNames} {}
SubprogramDetails(const std::list<Name> &dummyNames, const std::optional<Name> &resultName)
: isFunction_{true}, dummyNames_{dummyNames}, resultName_{resultName} {}
bool isFunction() const { return isFunction_; }
const std::list<Name> &dummyNames() const { return dummyNames_; }
const std::optional<Name> &resultName() const { return resultName_; }
private:
bool isFunction_;
std::list<Name> dummyNames_;
std::optional<Name> resultName_;
friend std::ostream &operator<<(std::ostream &, const SubprogramDetails &);
};
class EntityDetails {
public:
EntityDetails(bool isDummy = false) : isDummy_{isDummy} {}
const std::optional<DeclTypeSpec> &type() const { return type_; }
void set_type(const DeclTypeSpec &type) { type_ = type; };
bool isDummy() const { return isDummy_; }
private:
bool isDummy_;
std::optional<DeclTypeSpec> type_;
friend std::ostream &operator<<(std::ostream &, const EntityDetails &);
};
class UnknownDetails {
};
class Symbol {
public:
//TODO: more kinds of details
using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
SubprogramDetails, EntityDetails>;
Symbol(
const Scope &owner, const Name &name, const Attrs &attrs, Details &&details)
: owner_{owner}, name_{name}, attrs_{attrs}, details_{std::move(details)} {}
const Scope &owner() const { return owner_; }
const Name &name() const { return name_; }
const Attrs &attrs() const { return attrs_; }
// Does symbol have this type of details?
template<typename D> bool has() const {
return std::holds_alternative<D>(details_);
}
// Return a non-owning pointer to details if it is type D, else nullptr.
template<typename D> D *detailsIf() { return std::get_if<D>(&details_); }
// Return a reference to the details which must be of type D.
template<typename D> D &details() {
auto p = detailsIf<D>();
CHECK(p && "unexpected type");
return *p;
}
template<typename D> const D &details() const {
const auto p = detailsIf<D>();
CHECK(p && "unexpected type");
return *p;
}
// Assign the details of the symbol from one of the variants.
// Only allowed if unknown.
void set_details(const Details &details) {
CHECK(has<UnknownDetails>());
details_ = details;
};
private:
const Scope &owner_;
const Name name_;
const Attrs attrs_;
Details details_;
friend std::ostream &operator<<(std::ostream &, const Symbol &);
};
}
}
#endif // FORTRAN_SEMANTICS_SYMBOL_H_