forked from OSchip/llvm-project
[flang] clean up for review
Original-commit: flang-compiler/f18@d3d81b1e6f Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false
This commit is contained in:
parent
9236fa92ae
commit
6c6234be9e
|
@ -543,7 +543,7 @@ auto ExpressionBase<RESULT>::ScalarValue() const
|
|||
Expr<SomeType>::~Expr() {}
|
||||
|
||||
// Template instantiations to resolve the "extern template" declarations
|
||||
// in expression.h.
|
||||
// that appear in expression.h.
|
||||
|
||||
template class Expr<Type<TypeCategory::Integer, 1>>;
|
||||
template class Expr<Type<TypeCategory::Integer, 2>>;
|
||||
|
@ -605,6 +605,8 @@ template struct ExpressionBase<Type<TypeCategory::Complex, 8>>;
|
|||
template struct ExpressionBase<Type<TypeCategory::Complex, 10>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Complex, 16>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Character, 1>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Character, 2>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Character, 4>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Logical, 1>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Logical, 2>>;
|
||||
template struct ExpressionBase<Type<TypeCategory::Logical, 4>>;
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
|
||||
// Represent Fortran expressions in a type-safe manner.
|
||||
// Expressions are the sole owners of their constituents; i.e., there is no
|
||||
// context-independent hash table or sharing of common subexpressions.
|
||||
// Both deep copy and move semantics are supported for expression construction.
|
||||
// context-independent hash table or sharing of common subexpressions, and
|
||||
// thus these are trees, not DAGs. Both deep copy and move semantics are
|
||||
// supported for expression construction.
|
||||
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
|
@ -721,6 +722,8 @@ extern template struct ExpressionBase<Type<TypeCategory::Complex, 8>>;
|
|||
extern template struct ExpressionBase<Type<TypeCategory::Complex, 10>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Complex, 16>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Character, 1>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Character, 2>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Character, 4>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Logical, 1>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Logical, 2>>;
|
||||
extern template struct ExpressionBase<Type<TypeCategory::Logical, 4>>;
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
// These definitions map Fortran's intrinsic types, characterized by byte
|
||||
// sizes encoded in KIND type parameter values, to their value representation
|
||||
// types in the evaluation library, which are parameterized in terms of
|
||||
// total bit width and real precision.
|
||||
// total bit width and real precision. Instances of these class templates
|
||||
// are suitable for use as template parameters to instantiate other class
|
||||
// templates, like expressions, over the supported types and kinds.
|
||||
|
||||
#include "complex.h"
|
||||
#include "integer.h"
|
||||
|
@ -37,7 +39,7 @@ namespace Fortran::evaluate {
|
|||
using common::TypeCategory;
|
||||
|
||||
// Specific intrinsic types are represented by specializations of
|
||||
// the class template Type<CATEGORY, KIND>.
|
||||
// this class template Type<CATEGORY, KIND>.
|
||||
template<TypeCategory CATEGORY, int KIND> struct Type;
|
||||
|
||||
template<TypeCategory CATEGORY, int KIND> struct TypeBase {
|
||||
|
@ -127,8 +129,8 @@ using SameKind = Type<CATEGORY, std::decay_t<T>::kind>;
|
|||
// Default REAL just simply has to be IEEE-754 single precision today.
|
||||
// It occupies one numeric storage unit by definition. The default INTEGER
|
||||
// and default LOGICAL intrinsic types also have to occupy one numeric
|
||||
// storage unit, so their kinds are also forced. Default COMPLEX occupies
|
||||
// two numeric storage units.
|
||||
// storage unit, so their kinds are also forced. Default COMPLEX must always
|
||||
// comprise two default REAL components.
|
||||
// TODO: Support compile-time options to default reals, ints, or both to KIND=8
|
||||
|
||||
using DefaultReal = Type<TypeCategory::Real, 4>;
|
||||
|
@ -143,8 +145,9 @@ using SubscriptInteger = Type<TypeCategory::Integer, 8>;
|
|||
using LogicalResult = Type<TypeCategory::Logical, 1>;
|
||||
using LargestReal = Type<TypeCategory::Real, 16>;
|
||||
|
||||
// For an intrinsic type category CAT, CategoryTypes<CAT> is an instantiation
|
||||
// of std::tuple<Type<CAT, K>> over each supported kind K in that category.
|
||||
// For each intrinsic type category CAT, CategoryTypes<CAT> is an instantiation
|
||||
// of std::tuple<Type<CAT, K>> that comprises every kind value K in that
|
||||
// category that could possibly be supported on any target.
|
||||
template<TypeCategory CATEGORY, int... KINDS>
|
||||
using CategoryTypesTuple = std::tuple<Type<CATEGORY, KINDS>...>;
|
||||
|
||||
|
|
|
@ -1496,10 +1496,6 @@ constexpr auto complexPartDesignator{construct<ComplexPartDesignator>(dataRef)};
|
|||
// Type parameter inquiries are initially recognized as structure components.
|
||||
TYPE_PARSER(construct<TypeParamInquiry>(structureComponent))
|
||||
|
||||
// R918 array-section ->
|
||||
// data-ref [( substring-range )] | complex-part-designator
|
||||
constexpr auto arraySection{construct<ArraySection>(designator)};
|
||||
|
||||
// R919 subscript -> scalar-int-expr
|
||||
constexpr auto subscript{scalarIntExpr};
|
||||
|
||||
|
@ -3480,6 +3476,9 @@ TYPE_CONTEXT_PARSER("PAUSE statement"_en_US,
|
|||
// is used only via scalar-default-char-variable
|
||||
// R907 int-variable -> variable
|
||||
// is used only via scalar-int-variable
|
||||
// R918 array-section ->
|
||||
// data-ref [( substring-range )] | complex-part-designator
|
||||
// is not used because parsing is not sensitive to rank
|
||||
// R1030 default-char-constant-expr -> default-char-expr
|
||||
// is only used via scalar-default-char-constant-expr
|
||||
} // namespace Fortran::parser
|
||||
|
|
|
@ -1823,13 +1823,6 @@ struct ArrayElement {
|
|||
std::list<SectionSubscript> subscripts;
|
||||
};
|
||||
|
||||
// R918 array-section ->
|
||||
// data-ref [( substring-range )] | complex-part-designator
|
||||
struct ArraySection {
|
||||
WRAPPER_CLASS_BOILERPLATE(ArraySection, Designator);
|
||||
// at least one vector-valued or triplet subscript
|
||||
};
|
||||
|
||||
// R933 allocate-object -> variable-name | structure-component
|
||||
struct AllocateObject {
|
||||
UNION_CLASS_BOILERPLATE(AllocateObject);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "expression.h"
|
||||
#include "dump-parse-tree.h" // TODO pmk temporary
|
||||
#include "dump-parse-tree.h" // TODO temporary
|
||||
#include "symbol.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../evaluate/common.h"
|
||||
|
@ -21,17 +21,22 @@
|
|||
#include "../parser/parse-tree-visitor.h"
|
||||
#include "../parser/parse-tree.h"
|
||||
#include <functional>
|
||||
#include <iostream> // TODO remove soon
|
||||
#include <optional>
|
||||
|
||||
using namespace Fortran::parser::literals;
|
||||
|
||||
// Much of the code that implements semantic analysis of expressions is
|
||||
// tightly coupled with their typed representations in lib/evaluate,
|
||||
// and appears here in namespace Fortran::evaluate for convenience.
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
using common::TypeCategory;
|
||||
|
||||
using MaybeExpr = std::optional<Expr<SomeType>>;
|
||||
|
||||
// A utility subroutine to repackage optional values as MaybeExpr values.
|
||||
// A utility subroutine to repackage optional expressions of various levels
|
||||
// of type specificity as fully general MaybeExpr values.
|
||||
template<typename A> MaybeExpr AsMaybeExpr(std::optional<A> &&x) {
|
||||
if (x.has_value()) {
|
||||
return {AsGenericExpr(AsCategoryExpr(AsExpr(std::move(*x))))};
|
||||
|
@ -55,19 +60,14 @@ MaybeExpr AsMaybeExpr(std::optional<Expr<Type<CAT, KIND>>> &&x) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// This local class wraps some state and a highly overloaded
|
||||
// Analyze() member function that converts parse trees into generic
|
||||
// This local class wraps some state and a highly overloaded Analyze()
|
||||
// member function that converts parse trees into (usually) generic
|
||||
// expressions.
|
||||
struct ExprAnalyzer {
|
||||
using MaybeIntExpr = std::optional<Expr<SomeInteger>>;
|
||||
|
||||
ExprAnalyzer(
|
||||
FoldingContext &ctx, const semantics::IntrinsicTypeDefaultKinds &dfts)
|
||||
: context{ctx}, defaults{dfts} {}
|
||||
|
||||
int Analyze(
|
||||
const std::optional<parser::KindParam> &, int defaultKind, int kanjiKind);
|
||||
|
||||
MaybeExpr Analyze(const parser::Expr &);
|
||||
MaybeExpr Analyze(const parser::CharLiteralConstantSubstring &);
|
||||
MaybeExpr Analyze(const parser::LiteralConstant &);
|
||||
|
@ -78,14 +78,23 @@ struct ExprAnalyzer {
|
|||
MaybeExpr Analyze(const parser::ComplexLiteralConstant &);
|
||||
MaybeExpr Analyze(const parser::CharLiteralConstant &);
|
||||
MaybeExpr Analyze(const parser::LogicalLiteralConstant &);
|
||||
MaybeExpr Analyze(const parser::HollerithLiteralConstant &);
|
||||
MaybeExpr Analyze(const parser::BOZLiteralConstant &);
|
||||
MaybeExpr Analyze(const parser::Name &);
|
||||
MaybeExpr Analyze(const parser::NamedConstant &);
|
||||
MaybeExpr Analyze(const parser::Substring &);
|
||||
MaybeExpr Analyze(const parser::ArrayElement &);
|
||||
MaybeExpr Analyze(const parser::StructureComponent &);
|
||||
MaybeExpr Analyze(const parser::TypeParamInquiry &);
|
||||
MaybeExpr Analyze(const parser::CoindexedNamedObject &);
|
||||
MaybeExpr Analyze(const parser::ComplexPart &);
|
||||
MaybeExpr Analyze(const parser::AcSpec &);
|
||||
MaybeExpr Analyze(const parser::ArrayConstructor &);
|
||||
MaybeExpr Analyze(const parser::StructureConstructor &);
|
||||
MaybeExpr Analyze(const parser::Expr::Parentheses &);
|
||||
MaybeExpr Analyze(const parser::Expr::UnaryPlus &);
|
||||
MaybeExpr Analyze(const parser::Expr::Negate &);
|
||||
MaybeExpr Analyze(const parser::Expr::NOT &);
|
||||
MaybeExpr Analyze(const parser::Expr::PercentLoc &);
|
||||
MaybeExpr Analyze(const parser::Expr::DefinedUnary &);
|
||||
MaybeExpr Analyze(const parser::Expr::Power &);
|
||||
MaybeExpr Analyze(const parser::Expr::Multiply &);
|
||||
|
@ -106,13 +115,18 @@ struct ExprAnalyzer {
|
|||
MaybeExpr Analyze(const parser::Expr::XOR &);
|
||||
MaybeExpr Analyze(const parser::Expr::ComplexConstructor &);
|
||||
MaybeExpr Analyze(const parser::Expr::DefinedBinary &);
|
||||
MaybeExpr Analyze(const parser::Call &);
|
||||
MaybeExpr Analyze(const parser::FunctionReference &);
|
||||
|
||||
// Kind parameter analysis always returns a valid kind value.
|
||||
int Analyze(
|
||||
const std::optional<parser::KindParam> &, int defaultKind, int kanjiKind);
|
||||
|
||||
std::optional<Subscript> Analyze(const parser::SectionSubscript &);
|
||||
std::vector<Subscript> Analyze(const std::list<parser::SectionSubscript> &);
|
||||
|
||||
std::optional<Expr<SubscriptInteger>> AsSubscript(MaybeExpr &&);
|
||||
std::optional<Expr<SubscriptInteger>> TripletPart(
|
||||
const std::optional<parser::Subscript> &);
|
||||
std::optional<Subscript> Analyze(const parser::SectionSubscript &);
|
||||
std::vector<Subscript> Analyze(const std::list<parser::SectionSubscript> &);
|
||||
|
||||
FoldingContext &context;
|
||||
const semantics::IntrinsicTypeDefaultKinds &defaults;
|
||||
|
@ -120,13 +134,11 @@ struct ExprAnalyzer {
|
|||
|
||||
// This helper template function handles the Scalar<>, Integer<>, and
|
||||
// Constant<> wrappers in the parse tree, as well as default behavior
|
||||
// for wrappers and unions.
|
||||
// (C++ doesn't allow template specialization in a class, so this helper
|
||||
// template function must be outside ExprAnalyzer and reflect back into it.)
|
||||
// for unions. (C++ doesn't allow template specialization in
|
||||
// a class, so this helper template function must be outside ExprAnalyzer
|
||||
// and reflect back into it.)
|
||||
template<typename A> MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const A &x) {
|
||||
if constexpr (WrapperTrait<A>) {
|
||||
return AnalyzeHelper(ea, x.v);
|
||||
} else if constexpr (UnionTrait<A>) {
|
||||
if constexpr (UnionTrait<A>) {
|
||||
return AnalyzeHelper(ea, x.u);
|
||||
} else {
|
||||
return ea.Analyze(x);
|
||||
|
@ -171,97 +183,8 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const common::Indirection<A> &x) {
|
|||
return AnalyzeHelper(ea, *x);
|
||||
}
|
||||
|
||||
template<>
|
||||
MaybeExpr AnalyzeHelper(
|
||||
ExprAnalyzer &ea, const parser::HollerithLiteralConstant &x) {
|
||||
return common::SearchDynamicTypes(
|
||||
TypeKindVisitor<TypeCategory::Character, Constant, std::string>{
|
||||
ea.defaults.defaultCharacterKind, x.v});
|
||||
}
|
||||
|
||||
template<>
|
||||
MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::BOZLiteralConstant &x) {
|
||||
const char *p{x.v.data()};
|
||||
std::uint64_t base{16};
|
||||
switch (*p++) {
|
||||
case 'b': base = 2; break;
|
||||
case 'o': base = 8; break;
|
||||
case 'z': break;
|
||||
case 'x': break;
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
CHECK(*p == '"');
|
||||
auto value{BOZLiteralConstant::ReadUnsigned(++p, base)};
|
||||
if (*p != '"') {
|
||||
ea.context.messages.Say(
|
||||
"invalid digit ('%c') in BOZ literal %s"_err_en_US, *p, x.v.data());
|
||||
return std::nullopt;
|
||||
}
|
||||
if (value.overflow) {
|
||||
ea.context.messages.Say("BOZ literal %s too large"_err_en_US, x.v.data());
|
||||
return std::nullopt;
|
||||
}
|
||||
return {AsGenericExpr(value.value)};
|
||||
}
|
||||
|
||||
template<>
|
||||
MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::Parentheses &x) {
|
||||
if (MaybeExpr operand{AnalyzeHelper(ea, *x.v)}) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](BOZLiteralConstant &&boz) {
|
||||
return operand; // ignore parentheses around typeless
|
||||
},
|
||||
[](auto &&catExpr) {
|
||||
return std::visit(
|
||||
[](auto &&expr) -> MaybeExpr {
|
||||
using Ty = ResultType<decltype(expr)>;
|
||||
if constexpr (common::HasMember<Parentheses<Ty>,
|
||||
decltype(expr.u)>) {
|
||||
return {AsGenericExpr(
|
||||
AsExpr(Parentheses<Ty>{std::move(expr)}))};
|
||||
}
|
||||
// TODO: support Parentheses in all Expr specializations
|
||||
return std::nullopt;
|
||||
},
|
||||
std::move(catExpr.u));
|
||||
}},
|
||||
std::move(operand->u));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<>
|
||||
MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::Negate &x) {
|
||||
if (MaybeExpr operand{AnalyzeHelper(ea, *x.v)}) {
|
||||
return Negation(ea.context.messages, std::move(operand->u));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<>
|
||||
MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::NOT &x) {
|
||||
if (MaybeExpr operand{AnalyzeHelper(ea, *x.v)}) {
|
||||
return std::visit(common::visitors{[](Expr<SomeLogical> &&lx) -> MaybeExpr {
|
||||
return {AsGenericExpr(
|
||||
LogicalNegation(std::move(lx)))};
|
||||
},
|
||||
[=](auto &&) -> MaybeExpr {
|
||||
// TODO pmk: INTEGER operand for bitwise extension?
|
||||
ea.context.messages.Say(
|
||||
"Operand of .NOT. must be LOGICAL"_err_en_US);
|
||||
return std::nullopt;
|
||||
}},
|
||||
std::move(operand->u));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<>
|
||||
MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Expr::PercentLoc &) {
|
||||
ea.context.messages.Say("TODO: %LOC unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
// Implementations of ExprAnalyzer::Analyze follow for various parse tree
|
||||
// node types.
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr &x) {
|
||||
return AnalyzeHelper(*this, x);
|
||||
|
@ -311,7 +234,7 @@ MaybeExpr IntLiteralConstant(ExprAnalyzer &ea, const PARSED &x) {
|
|||
TypeKindVisitor<TypeCategory::Integer, Constant, std::int64_t>{
|
||||
kind, static_cast<std::int64_t>(value)})};
|
||||
if (!result.has_value()) {
|
||||
ea.context.messages.Say("unsupported INTEGER(KIND=%u)"_err_en_US, kind);
|
||||
ea.context.messages.Say("unsupported INTEGER(KIND=%d)"_err_en_US, kind);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -393,7 +316,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
|
|||
auto result{common::SearchDynamicTypes(
|
||||
RealTypeVisitor{kind, x.real.source, context})};
|
||||
if (!result.has_value()) {
|
||||
ctxMsgs.Say("unsupported REAL(KIND=%u)"_err_en_US, kind);
|
||||
ctxMsgs.Say("unsupported REAL(KIND=%d)"_err_en_US, kind);
|
||||
}
|
||||
return AsMaybeExpr(std::move(result));
|
||||
}
|
||||
|
@ -426,7 +349,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstant &x) {
|
|||
TypeKindVisitor<TypeCategory::Character, Constant, std::string>{
|
||||
kind, std::move(value)})};
|
||||
if (!result.has_value()) {
|
||||
context.messages.Say("unsupported CHARACTER(KIND=%u)"_err_en_US, kind);
|
||||
context.messages.Say("unsupported CHARACTER(KIND=%d)"_err_en_US, kind);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -439,11 +362,41 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) {
|
|||
TypeKindVisitor<TypeCategory::Logical, Constant, bool>{
|
||||
kind, std::move(value)})};
|
||||
if (!result.has_value()) {
|
||||
context.messages.Say("unsupported LOGICAL(KIND=%u)"_err_en_US, kind);
|
||||
context.messages.Say("unsupported LOGICAL(KIND=%d)"_err_en_US, kind);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::HollerithLiteralConstant &x) {
|
||||
return common::SearchDynamicTypes(
|
||||
TypeKindVisitor<TypeCategory::Character, Constant, std::string>{
|
||||
defaults.defaultCharacterKind, x.v});
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
|
||||
const char *p{x.v.data()};
|
||||
std::uint64_t base{16};
|
||||
switch (*p++) {
|
||||
case 'b': base = 2; break;
|
||||
case 'o': base = 8; break;
|
||||
case 'z': break;
|
||||
case 'x': break;
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
CHECK(*p == '"');
|
||||
auto value{BOZLiteralConstant::ReadUnsigned(++p, base)};
|
||||
if (*p != '"') {
|
||||
context.messages.Say(
|
||||
"invalid digit ('%c') in BOZ literal %s"_err_en_US, *p, x.v.data());
|
||||
return std::nullopt;
|
||||
}
|
||||
if (value.overflow) {
|
||||
context.messages.Say("BOZ literal %s too large"_err_en_US, x.v.data());
|
||||
return std::nullopt;
|
||||
}
|
||||
return {AsGenericExpr(value.value)};
|
||||
}
|
||||
|
||||
template<typename TYPE, TypeCategory CATEGORY>
|
||||
MaybeExpr DataRefIfType(
|
||||
const semantics::Symbol &symbol, int defaultKind, DataRef &&dataRef) {
|
||||
|
@ -511,7 +464,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) {
|
|||
if (n.symbol == nullptr) {
|
||||
// TODO: convert this to a CHECK later
|
||||
context.messages.Say(
|
||||
"TODO: name (%s) is not resolved to an object"_err_en_US,
|
||||
"TODO: name '%s' is not resolved to an object"_err_en_US,
|
||||
n.ToString().data());
|
||||
} else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) {
|
||||
context.messages.Say(
|
||||
|
@ -522,12 +475,23 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) {
|
|||
TypedDataRef(*n.symbol, defaults, DataRef{*n.symbol})}) {
|
||||
return result;
|
||||
}
|
||||
context.messages.Say("%s is not of a supported type and kind"_err_en_US,
|
||||
context.messages.Say("'%s' is not of a supported type and kind"_err_en_US,
|
||||
n.ToString().data());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::NamedConstant &n) {
|
||||
if (MaybeExpr value{Analyze(n.v)}) {
|
||||
if (std::optional<Constant<SomeType>> folded{value->Fold(context)}) {
|
||||
return {AsGenericExpr(std::move(*folded))};
|
||||
}
|
||||
context.messages.Say(
|
||||
"'%s' must be a constant"_err_en_US, n.v.ToString().data());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Substring &ss) {
|
||||
context.messages.Say("TODO: Substring unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
|
@ -604,7 +568,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayElement &ae) {
|
|||
} else if (const auto *component{
|
||||
std::get_if<common::Indirection<parser::StructureComponent>>(
|
||||
&ae.base.u)}) {
|
||||
// pmk continue
|
||||
// pmk continue development here
|
||||
} else {
|
||||
CHECK(!"parser::ArrayRef base DataRef is neither Name nor "
|
||||
"StructureComponent");
|
||||
|
@ -613,38 +577,117 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayElement &ae) {
|
|||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) {
|
||||
context.messages.Say("pmk: StructureComponent unimplemented\n"_err_en_US);
|
||||
context.messages.Say("TODO: StructureComponent unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::TypeParamInquiry &tpi) {
|
||||
context.messages.Say("TODO: TypeParamInquiry unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::CoindexedNamedObject &co) {
|
||||
context.messages.Say("pmk: CoindexedNamedObject unimplemented\n"_err_en_US);
|
||||
context.messages.Say("TODO: CoindexedNamedObject unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstantSubstring &) {
|
||||
context.messages.Say(
|
||||
"pmk: CharLiteralConstantSubstring unimplemented\n"_err_en_US);
|
||||
"TODO: CharLiteralConstantSubstring unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::AcSpec &) {
|
||||
context.messages.Say("pmk: AcSpec unimplemented\n"_err_en_US);
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayConstructor &) {
|
||||
context.messages.Say("TODO: ArrayConstructor unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::StructureConstructor &) {
|
||||
context.messages.Say("pmk: StructureConstructor unimplemented\n"_err_en_US);
|
||||
context.messages.Say("TODO: StructureConstructor unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Call &) {
|
||||
context.messages.Say("pmk: Call unimplemented\n"_err_en_US);
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::FunctionReference &) {
|
||||
context.messages.Say("TODO: FunctionReference unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Parentheses &x) {
|
||||
if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](BOZLiteralConstant &&boz) {
|
||||
return operand; // ignore parentheses around typeless
|
||||
},
|
||||
[](auto &&catExpr) {
|
||||
return std::visit(
|
||||
[](auto &&expr) -> MaybeExpr {
|
||||
using Ty = ResultType<decltype(expr)>;
|
||||
if constexpr (common::HasMember<Parentheses<Ty>,
|
||||
decltype(expr.u)>) {
|
||||
return {AsGenericExpr(
|
||||
AsExpr(Parentheses<Ty>{std::move(expr)}))};
|
||||
}
|
||||
// TODO: support Parentheses in all Expr specializations
|
||||
return std::nullopt;
|
||||
},
|
||||
std::move(catExpr.u));
|
||||
}},
|
||||
std::move(operand->u));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) {
|
||||
MaybeExpr value{AnalyzeHelper(*this, *x.v)};
|
||||
if (value.has_value()) {
|
||||
std::visit(
|
||||
common::visitors{
|
||||
[](const BOZLiteralConstant &) {}, // allow +Z'1', it's harmless
|
||||
[&](const auto &catExpr) {
|
||||
TypeCategory cat{ResultType<decltype(catExpr)>::category};
|
||||
if (cat != TypeCategory::Integer && cat != TypeCategory::Real &&
|
||||
cat != TypeCategory::Complex) {
|
||||
context.messages.Say(
|
||||
"operand of unary + must be of a numeric type"_err_en_US);
|
||||
}
|
||||
}},
|
||||
value->u);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Negate &x) {
|
||||
if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) {
|
||||
return Negation(context.messages, std::move(operand->u));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::NOT &x) {
|
||||
if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) {
|
||||
return std::visit(common::visitors{[](Expr<SomeLogical> &&lx) -> MaybeExpr {
|
||||
return {AsGenericExpr(
|
||||
LogicalNegation(std::move(lx)))};
|
||||
},
|
||||
[=](auto &&) -> MaybeExpr {
|
||||
// TODO: accept INTEGER operand if not overridden
|
||||
context.messages.Say(
|
||||
"Operand of .NOT. must be LOGICAL"_err_en_US);
|
||||
return std::nullopt;
|
||||
}},
|
||||
std::move(operand->u));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::PercentLoc &) {
|
||||
context.messages.Say("TODO: %LOC unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedUnary &) {
|
||||
context.messages.Say("pmk: DefinedUnary unimplemented\n"_err_en_US);
|
||||
context.messages.Say("TODO: DefinedUnary unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -766,7 +809,8 @@ MaybeExpr LogicalHelper(
|
|||
BinaryLogicalOperation(opr, std::move(lx), std::move(ly)))};
|
||||
},
|
||||
[&](auto &&, auto &&) -> MaybeExpr {
|
||||
// TODO pmk: extensions: INTEGER and typeless operands
|
||||
// TODO: extension: INTEGER and typeless operands
|
||||
// ifort and PGI accept them if not overridden
|
||||
ea.context.messages.Say(
|
||||
"operands to LOGICAL operation must be LOGICAL"_err_en_US);
|
||||
return {};
|
||||
|
@ -797,7 +841,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::XOR &x) {
|
|||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedBinary &) {
|
||||
context.messages.Say("pmk: DefinedBinary unimplemented\n"_err_en_US);
|
||||
context.messages.Say("TODO: DefinedBinary unimplemented\n"_err_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -805,7 +849,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedBinary &) {
|
|||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context,
|
||||
evaluate::MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context,
|
||||
const IntrinsicTypeDefaultKinds &defaults, const parser::Expr &expr) {
|
||||
return evaluate::ExprAnalyzer{context, defaults}.Analyze(expr);
|
||||
}
|
||||
|
@ -813,8 +857,8 @@ MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context,
|
|||
class Mutator {
|
||||
public:
|
||||
Mutator(evaluate::FoldingContext &context,
|
||||
const IntrinsicTypeDefaultKinds &defaults, std::ostream &o)
|
||||
: context_{context}, defaults_{defaults}, out_{o} {}
|
||||
const IntrinsicTypeDefaultKinds &defaults)
|
||||
: context_{context}, defaults_{defaults} {}
|
||||
|
||||
template<typename A> bool Pre(A &) { return true /* visit children */; }
|
||||
template<typename A> void Post(A &) {}
|
||||
|
@ -822,12 +866,12 @@ public:
|
|||
bool Pre(parser::Expr &expr) {
|
||||
if (expr.typedExpr.get() == nullptr) {
|
||||
if (MaybeExpr checked{AnalyzeExpr(context_, defaults_, expr)}) {
|
||||
checked->Dump(out_ << "pmk checked: ") << '\n';
|
||||
checked->Dump(std::cout << "checked expression: ") << '\n';
|
||||
expr.typedExpr.reset(
|
||||
new evaluate::GenericExprWrapper{std::move(*checked)});
|
||||
} else {
|
||||
out_ << "pmk: expression analysis failed for an expression: ";
|
||||
DumpTree(out_, expr);
|
||||
std::cout << "expression analysis failed for this expression: ";
|
||||
DumpTree(std::cout, expr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -836,13 +880,12 @@ public:
|
|||
private:
|
||||
evaluate::FoldingContext &context_;
|
||||
const IntrinsicTypeDefaultKinds &defaults_;
|
||||
std::ostream &out_;
|
||||
};
|
||||
|
||||
void AnalyzeExpressions(parser::Program &program,
|
||||
evaluate::FoldingContext &context,
|
||||
const IntrinsicTypeDefaultKinds &defaults, std::ostream &o) {
|
||||
Mutator mutator{context, defaults, o};
|
||||
const IntrinsicTypeDefaultKinds &defaults) {
|
||||
Mutator mutator{context, defaults};
|
||||
parser::Walk(program, mutator);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,8 @@
|
|||
|
||||
#include "../evaluate/expression.h"
|
||||
#include "../evaluate/type.h"
|
||||
#include "../parser/message.h"
|
||||
#include "../parser/parse-tree.h"
|
||||
#include <cinttypes>
|
||||
#include <optional>
|
||||
#include <ostream> // TODO pmk
|
||||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
|
@ -36,11 +33,15 @@ struct IntrinsicTypeDefaultKinds {
|
|||
int defaultLogicalKind{evaluate::DefaultLogical::kind};
|
||||
};
|
||||
|
||||
MaybeExpr AnalyzeExpr(evaluate::FoldingContext &,
|
||||
const IntrinsicTypeDefaultKinds &, const parser::Expr &);
|
||||
// Semantic analysis of one expression.
|
||||
std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr(
|
||||
evaluate::FoldingContext &, const IntrinsicTypeDefaultKinds &,
|
||||
const parser::Expr &);
|
||||
|
||||
// Semantic analysis of all expressions in a parse tree, which is
|
||||
// decorated with typed representations for top-level expressions.
|
||||
void AnalyzeExpressions(parser::Program &, evaluate::FoldingContext &,
|
||||
const IntrinsicTypeDefaultKinds &, std::ostream &);
|
||||
const IntrinsicTypeDefaultKinds &);
|
||||
|
||||
} // namespace Fortran::semantics
|
||||
#endif // FORTRAN_SEMANTICS_EXPRESSION_H_
|
||||
|
|
|
@ -64,7 +64,7 @@ template<typename A>
|
|||
constexpr Legality IsLegalDoTerm(const parser::Statement<A> &) {
|
||||
if (std::is_same_v<A, common::Indirection<parser::EndDoStmt>> ||
|
||||
std::is_same_v<A, parser::EndDoStmt>) {
|
||||
return Legality::always;
|
||||
return Legality::always;
|
||||
} else {
|
||||
return Legality::never;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ std::string CompileFortran(
|
|||
}
|
||||
Fortran::semantics::ResolveNames(Fortran::semantics::Scope::globalScope,
|
||||
parseTree, parsing.cooked(), directories);
|
||||
const auto& Cook = parsing.cooked();
|
||||
const auto &Cook = parsing.cooked();
|
||||
bool Pass = Fortran::semantics::ValidateLabels(parseTree, Cook);
|
||||
if (!Pass) {
|
||||
std::cerr << "Semantic error(s), aborting\n";
|
||||
|
@ -244,8 +244,7 @@ std::string CompileFortran(
|
|||
Fortran::parser::ContextualMessages contextualMessages{whole, &messages};
|
||||
Fortran::evaluate::FoldingContext context{contextualMessages};
|
||||
Fortran::semantics::IntrinsicTypeDefaultKinds defaults;
|
||||
Fortran::semantics::AnalyzeExpressions(
|
||||
parseTree, context, defaults, std::cout);
|
||||
Fortran::semantics::AnalyzeExpressions(parseTree, context, defaults);
|
||||
messages.Emit(std::cerr, parsing.cooked());
|
||||
if (!messages.empty() &&
|
||||
(driver.warningsAreErrors || messages.AnyFatalError())) {
|
||||
|
|
Loading…
Reference in New Issue