[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:
peter klausler 2018-09-12 11:20:30 -07:00
parent 9236fa92ae
commit 6c6234be9e
9 changed files with 210 additions and 167 deletions

View File

@ -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>>;

View File

@ -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>>;

View File

@ -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>...>;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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_

View File

@ -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;
}

View File

@ -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())) {