[flang] Add FoldingContext to SemanticsContext

FoldingContext is now part of SemanticsContext. It is created at the
beginning with a default-constructed CharBlock as the location in its
ContextualMessages.

Add PushLocation() to ContextualMessages to remember the previous source
location and set a new one. The old one is restored when the returned
object goes out of scope.

SemanticsContext is now the only state passed in to class ExprAnalyzer,
class Mutator, AnalyzeExpr(), AnalyzeExpressions().

Add Say() convenience functions for reporting errors to ExprAnalyzer.

Original-commit: flang-compiler/f18@70c499ffc4
Reviewed-on: https://github.com/flang-compiler/f18/pull/215
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2018-10-22 16:41:26 -07:00
parent 16980c718a
commit 30dd289247
6 changed files with 138 additions and 146 deletions

View File

@ -289,4 +289,16 @@ bool Messages::AnyFatalError() const {
return false;
}
ContextualMessages::SavedState::SavedState(
ContextualMessages &msgs, CharBlock at)
: msgs_{msgs}, at_{msgs.at_} {
msgs.at_ = at;
}
ContextualMessages::SavedState::~SavedState() { msgs_.at_ = at_; }
ContextualMessages::SavedState ContextualMessages::PushLocation(
const CharBlock &at) {
return SavedState(*this, at);
}
} // namespace Fortran::parser

View File

@ -240,13 +240,24 @@ private:
class ContextualMessages {
public:
class SavedState {
public:
SavedState(ContextualMessages &, CharBlock);
~SavedState();
private:
ContextualMessages &msgs_;
CharBlock at_;
};
ContextualMessages(CharBlock at, Messages *m) : at_{at}, messages_{m} {}
ContextualMessages(CharBlock at, const ContextualMessages &context)
: at_{at}, messages_{context.messages_} {}
CharBlock at() const { return at_; }
Messages *messages() const { return messages_; }
// Set CharBlock for messages; restore when the returned value is deleted
SavedState PushLocation(const CharBlock &);
template<typename... A> void Say(A &&... args) {
if (messages_ != nullptr) {
messages_->Say(at_, std::forward<A>(args)...);

View File

@ -106,15 +106,7 @@ std::optional<DataRef> ExtractDataRef(std::optional<A> &&x) {
// member function that converts parse trees into (usually) generic
// expressions.
struct ExprAnalyzer {
ExprAnalyzer(FoldingContext &ctx,
const semantics::IntrinsicTypeDefaultKinds &dfts,
const IntrinsicProcTable &procs)
: context{ctx}, defaults{dfts}, intrinsics{procs} {}
ExprAnalyzer(const ExprAnalyzer &that, const parser::CharBlock &source)
: context{that.context,
parser::ContextualMessages{source, that.context.messages}},
defaults{that.defaults}, intrinsics{that.intrinsics} {}
ExprAnalyzer(semantics::SemanticsContext &context) : context{context} {}
MaybeExpr Analyze(const parser::Expr &);
MaybeExpr Analyze(const parser::CharLiteralConstantSubstring &);
@ -185,9 +177,14 @@ struct ExprAnalyzer {
std::optional<ProcedureDesignator> Procedure(
const parser::ProcedureDesignator &, const std::vector<ActualArgument> &);
FoldingContext context;
const semantics::IntrinsicTypeDefaultKinds &defaults;
const IntrinsicProcTable &intrinsics;
template<typename... A> void Say(A... args) {
context.foldingContext().messages.Say(std::forward<A>(args)...);
}
template<typename... A> void Say(const parser::CharBlock &at, A... args) {
context.foldingContext().messages.Say(at, std::forward<A>(args)...);
}
semantics::SemanticsContext &context;
};
// This helper template function handles the Scalar<>, Integer<>, and
@ -208,8 +205,7 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Scalar<A> &x) {
if (MaybeExpr result{AnalyzeHelper(ea, x.thing)}) {
int rank{result->Rank()};
if (rank > 0) {
ea.context.messages.Say(
"expression must be scalar, but has rank %d"_err_en_US, rank);
ea.Say("expression must be scalar, but has rank %d"_err_en_US, rank);
}
}
return std::nullopt;
@ -221,7 +217,7 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Integer<A> &x) {
if (std::holds_alternative<Expr<SomeInteger>>(result->u)) {
return result;
}
ea.context.messages.Say("expression must be INTEGER"_err_en_US);
ea.Say("expression must be INTEGER"_err_en_US);
}
return std::nullopt;
}
@ -229,10 +225,11 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Integer<A> &x) {
template<typename A>
MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Constant<A> &x) {
if (MaybeExpr result{AnalyzeHelper(ea, x.thing)}) {
if (std::optional<Constant<SomeType>> folded{result->Fold(ea.context)}) {
if (std::optional<Constant<SomeType>> folded{
result->Fold(ea.context.foldingContext())}) {
return {AsGenericExpr(std::move(*folded))};
}
ea.context.messages.Say("expression must be constant"_err_en_US);
ea.Say("expression must be constant"_err_en_US);
}
return std::nullopt;
}
@ -263,8 +260,8 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const parser::Designator &d) {
// Analyze something with source provenance
template<typename A> MaybeExpr AnalyzeSourced(ExprAnalyzer &ea, const A &x) {
if (!x.source.empty()) {
ExprAnalyzer nestedAnalyzer{ea, x.source};
return AnalyzeHelper(nestedAnalyzer, x);
auto save{ea.context.foldingContext().messages.PushLocation(x.source)};
return AnalyzeHelper(ea, x);
} else {
return AnalyzeHelper(ea, x);
}
@ -297,15 +294,14 @@ int ExprAnalyzer::Analyze(const std::optional<parser::KindParam> &kindParam,
}
}
}
context.messages.Say(
"KIND type parameter must be a scalar integer constant"_err_en_US);
Say("KIND type parameter must be a scalar integer constant"_err_en_US);
return defaultKind;
},
[&](parser::KindParam::Kanji) {
if (kanjiKind >= 0) {
return kanjiKind;
}
context.messages.Say("Kanji not allowed here"_err_en_US);
Say("Kanji not allowed here"_err_en_US);
return defaultKind;
}},
kindParam->u);
@ -315,13 +311,13 @@ int ExprAnalyzer::Analyze(const std::optional<parser::KindParam> &kindParam,
template<typename PARSED>
MaybeExpr IntLiteralConstant(ExprAnalyzer &ea, const PARSED &x) {
int kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
ea.defaults.GetDefaultKind(TypeCategory::Integer))};
ea.context.defaultKinds().GetDefaultKind(TypeCategory::Integer))};
auto value{std::get<0>(x.t)}; // std::(u)int64_t
auto result{common::SearchDynamicTypes(
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=%d)"_err_en_US, kind);
ea.Say("unsupported INTEGER(KIND=%d)"_err_en_US, kind);
}
return result;
}
@ -371,12 +367,12 @@ struct RealTypeVisitor {
MaybeExpr ExprAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
// Use a local message context around the real literal for better
// provenance on any messages.
parser::ContextualMessages ctxMsgs{x.real.source, context.messages};
FoldingContext localFoldingContext{ctxMsgs, context};
auto save{context.foldingContext().messages.PushLocation(x.real.source)};
// If a kind parameter appears, it defines the kind of the literal and any
// letter used in an exponent part (e.g., the 'E' in "6.02214E+23")
// should agree. In the absence of an explicit kind parameter, any exponent
// letter determines the kind. Otherwise, defaults apply.
auto &defaults{context.defaultKinds()};
int defaultKind{defaults.GetDefaultKind(TypeCategory::Real)};
const char *end{x.real.source.end()};
std::optional<int> letterKind;
@ -386,7 +382,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
case 'e': letterKind = defaults.GetDefaultKind(TypeCategory::Real); break;
case 'd': letterKind = defaults.doublePrecisionKind(); break;
case 'q': letterKind = defaults.quadPrecisionKind(); break;
default: ctxMsgs.Say("unknown exponent letter '%c'"_err_en_US, *p);
default: Say("unknown exponent letter '%c'"_err_en_US, *p);
}
break;
}
@ -396,13 +392,12 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
}
auto kind{Analyze(x.kind, defaultKind)};
if (letterKind.has_value() && kind != *letterKind) {
ctxMsgs.Say(
"explicit kind parameter on real constant disagrees with exponent letter"_en_US);
Say("explicit kind parameter on real constant disagrees with exponent letter"_en_US);
}
auto result{common::SearchDynamicTypes(
RealTypeVisitor{kind, x.real.source, context})};
RealTypeVisitor{kind, x.real.source, context.foldingContext()})};
if (!result.has_value()) {
ctxMsgs.Say("unsupported REAL(KIND=%d)"_err_en_US, kind);
Say("unsupported REAL(KIND=%d)"_err_en_US, kind);
}
return AsMaybeExpr(std::move(result));
}
@ -426,9 +421,9 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ComplexPart &x) {
}
MaybeExpr ExprAnalyzer::Analyze(const parser::ComplexLiteralConstant &z) {
return AsMaybeExpr(ConstructComplex(context.messages,
return AsMaybeExpr(ConstructComplex(context.foldingContext().messages,
Analyze(std::get<0>(z.t)), Analyze(std::get<1>(z.t)),
defaults.GetDefaultKind(TypeCategory::Real)));
context.defaultKinds().GetDefaultKind(TypeCategory::Real)));
}
MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstant &x) {
@ -438,20 +433,20 @@ 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=%d)"_err_en_US, kind);
Say("unsupported CHARACTER(KIND=%d)"_err_en_US, kind);
}
return result;
}
MaybeExpr ExprAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) {
auto kind{Analyze(std::get<std::optional<parser::KindParam>>(x.t),
defaults.GetDefaultKind(TypeCategory::Logical))};
context.defaultKinds().GetDefaultKind(TypeCategory::Logical))};
bool value{std::get<bool>(x.t)};
auto result{common::SearchDynamicTypes(
TypeKindVisitor<TypeCategory::Logical, Constant, bool>{
kind, std::move(value)})};
if (!result.has_value()) {
context.messages.Say("unsupported LOGICAL(KIND=%d)"_err_en_US, kind);
Say("unsupported LOGICAL(KIND=%d)"_err_en_US, kind);
}
return result;
}
@ -459,7 +454,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) {
MaybeExpr ExprAnalyzer::Analyze(const parser::HollerithLiteralConstant &x) {
return common::SearchDynamicTypes(
TypeKindVisitor<TypeCategory::Character, Constant, std::string>{
defaults.GetDefaultKind(TypeCategory::Character), x.v});
context.defaultKinds().GetDefaultKind(TypeCategory::Character), x.v});
}
MaybeExpr ExprAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
@ -475,12 +470,11 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
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());
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());
Say("BOZ literal %s too large"_err_en_US, x.v.data());
return std::nullopt;
}
return {AsGenericExpr(std::move(value.value))};
@ -533,29 +527,28 @@ static MaybeExpr Designate(DataRef &&dataRef) {
MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) {
if (n.symbol == nullptr) {
context.messages.Say(n.source,
Say(n.source,
"TODO INTERNAL: name '%s' was not resolved to a symbol"_err_en_US,
n.ToString().data());
} else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) {
context.messages.Say(
"TODO: PARAMETER references not yet implemented"_err_en_US);
Say("TODO: PARAMETER references not yet implemented"_err_en_US);
// TODO: enumerators, do they have the PARAMETER attribute?
} else {
if (MaybeExpr result{Designate(DataRef{*n.symbol})}) {
return result;
}
context.messages.Say(
n.source, "not of a supported type and kind"_err_en_US);
Say(n.source, "not of a supported type and kind"_err_en_US);
}
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)}) {
if (std::optional<Constant<SomeType>> folded{
value->Fold(context.foldingContext())}) {
return {AsGenericExpr(std::move(*folded))};
}
context.messages.Say(n.v.source, "must be a constant"_err_en_US);
Say(n.v.source, "must be a constant"_err_en_US);
}
return std::nullopt;
}
@ -582,8 +575,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Substring &ss) {
std::move(*checked), std::move(first), std::move(last)});
}
}
context.messages.Say(
"substring may apply only to CHARACTER"_err_en_US);
Say("substring may apply only to CHARACTER"_err_en_US);
}
}
}
@ -595,8 +587,7 @@ std::optional<Expr<SubscriptInteger>> ExprAnalyzer::AsSubscript(
MaybeExpr &&expr) {
if (expr.has_value()) {
if (expr->Rank() > 1) {
context.messages.Say(
"subscript expression has rank %d"_err_en_US, expr->Rank());
Say("subscript expression has rank %d"_err_en_US, expr->Rank());
}
if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
@ -606,7 +597,7 @@ std::optional<Expr<SubscriptInteger>> ExprAnalyzer::AsSubscript(
Convert<SubscriptInteger, TypeCategory::Integer>{
std::move(*intExpr)}}};
} else {
context.messages.Say("subscript expression is not INTEGER"_err_en_US);
Say("subscript expression is not INTEGER"_err_en_US);
}
}
return std::nullopt;
@ -617,8 +608,7 @@ std::optional<Expr<SubscriptInteger>> ExprAnalyzer::GetSubstringBound(
if (bound.has_value()) {
if (MaybeExpr expr{AnalyzeHelper(*this, *bound)}) {
if (expr->Rank() > 1) {
context.messages.Say(
"substring bound expression has rank %d"_err_en_US, expr->Rank());
Say("substring bound expression has rank %d"_err_en_US, expr->Rank());
}
if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
@ -628,8 +618,7 @@ std::optional<Expr<SubscriptInteger>> ExprAnalyzer::GetSubstringBound(
Convert<SubscriptInteger, TypeCategory::Integer>{
std::move(*intExpr)}}};
} else {
context.messages.Say(
"substring bound expression is not INTEGER"_err_en_US);
Say("substring bound expression is not INTEGER"_err_en_US);
}
}
}
@ -703,16 +692,14 @@ MaybeExpr ExprAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
}
int subscripts = ref.subscript.size();
if (subscripts != symbolRank) {
context.messages.Say(
"reference to rank-%d object '%s' has %d subscripts"_err_en_US,
Say("reference to rank-%d object '%s' has %d subscripts"_err_en_US,
symbolRank, symbol.name().ToString().data(), subscripts);
} else if (Component * component{std::get_if<Component>(&ref.u)}) {
int baseRank{component->Rank()};
if (baseRank > 0) {
int rank{ref.Rank()};
if (rank > 0) {
context.messages.Say(
"subscripts of rank-%d component reference have rank %d, but must all be scalar"_err_en_US,
Say("subscripts of rank-%d component reference have rank %d, but must all be scalar"_err_en_US,
baseRank, rank);
}
}
@ -721,8 +708,7 @@ MaybeExpr ExprAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
// C928 & C1002
if (Triplet * last{std::get_if<Triplet>(&ref.subscript.back().u)}) {
if (!last->upper().has_value() && details->isAssumedSize()) {
context.messages.Say(
"assumed-size array '%s' must have explicit final subscript upper bound value"_err_en_US,
Say("assumed-size array '%s' must have explicit final subscript upper bound value"_err_en_US,
symbol.name().ToString().data());
}
}
@ -740,8 +726,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayElement &ae) {
}
}
}
context.messages.Say(
"subscripts may be applied only to an object or component"_err_en_US);
Say("subscripts may be applied only to an object or component"_err_en_US);
return std::nullopt;
}
@ -754,17 +739,17 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) {
dtSpec = dtDyTy->derived;
}
if (sym == nullptr) {
context.messages.Say(sc.component.source,
Say(sc.component.source,
"component name was not resolved to a symbol"_err_en_US);
} else if (sym->detailsIf<semantics::TypeParamDetails>()) {
context.messages.Say(sc.component.source,
Say(sc.component.source,
"TODO: type parameter inquiry unimplemented"_err_en_US);
} else if (dtSpec == nullptr) {
context.messages.Say(sc.component.source,
Say(sc.component.source,
"TODO: base of component reference lacks a derived type"_err_en_US);
} else if (&sym->owner() != dtSpec->scope()) {
// TODO: extended derived types - insert explicit reference to base?
context.messages.Say(sc.component.source,
Say(sc.component.source,
"component is not in scope of derived TYPE(%s)"_err_en_US,
dtSpec->name().ToString().data());
} else if (std::optional<DataRef> dataRef{
@ -772,7 +757,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) {
Component component{std::move(*dataRef), *sym};
return Designate(DataRef{std::move(component)});
} else {
context.messages.Say(sc.component.source,
Say(sc.component.source,
"base of component reference must be a data reference"_err_en_US);
}
} else if (auto *zExpr{std::get_if<Expr<SomeComplex>>(&base->u)}) {
@ -780,7 +765,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) {
if (sc.component.source == parser::CharBlock{"im", 2}) {
part = ComplexPart::Part::IM;
} else if (sc.component.source != parser::CharBlock{"re", 2}) {
context.messages.Say(sc.component.source,
Say(sc.component.source,
"component of complex value must be %%RE or %%IM"_err_en_US);
return std::nullopt;
}
@ -795,7 +780,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) {
return {AsGenericExpr(std::move(realExpr))};
}
} else {
context.messages.Say("derived type required before '%%%s'"_err_en_US,
Say("derived type required before '%%%s'"_err_en_US,
sc.component.ToString().data());
}
}
@ -804,23 +789,22 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::StructureComponent &sc) {
MaybeExpr ExprAnalyzer::Analyze(const parser::CoindexedNamedObject &co) {
// TODO: CheckUnsubscriptedComponent or its equivalent
context.messages.Say("TODO: CoindexedNamedObject unimplemented"_err_en_US);
Say("TODO: CoindexedNamedObject unimplemented"_err_en_US);
return std::nullopt;
}
MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstantSubstring &) {
context.messages.Say(
"TODO: CharLiteralConstantSubstring unimplemented"_err_en_US);
Say("TODO: CharLiteralConstantSubstring unimplemented"_err_en_US);
return std::nullopt;
}
MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayConstructor &) {
context.messages.Say("TODO: ArrayConstructor unimplemented"_err_en_US);
Say("TODO: ArrayConstructor unimplemented"_err_en_US);
return std::nullopt;
}
MaybeExpr ExprAnalyzer::Analyze(const parser::StructureConstructor &) {
context.messages.Say("TODO: StructureConstructor unimplemented"_err_en_US);
Say("TODO: StructureConstructor unimplemented"_err_en_US);
return std::nullopt;
}
@ -831,8 +815,7 @@ std::optional<ProcedureDesignator> ExprAnalyzer::Procedure(
common::visitors{
[&](const parser::Name &n) -> std::optional<ProcedureDesignator> {
if (n.symbol == nullptr) {
context.messages.Say(
"TODO INTERNAL no symbol for procedure designator name '%s'"_err_en_US,
Say("TODO INTERNAL no symbol for procedure designator name '%s'"_err_en_US,
n.ToString().data());
return std::nullopt;
}
@ -849,15 +832,15 @@ std::optional<ProcedureDesignator> ExprAnalyzer::Procedure(
<< '\n';
CallCharacteristics cc{n.source, arg};
std::optional<SpecificIntrinsic> si{
intrinsics.Probe(cc, &context.messages)};
context.intrinsics().Probe(
cc, &context.foldingContext().messages)};
if (si) {
context.messages.Say(n.source,
Say(n.source,
"pmk debug: Probe succeeds: %s %s %d"_en_US,
si->name, si->type.Dump().data(), si->rank);
return {ProcedureDesignator{std::move(*si)}};
} else {
context.messages.Say(
n.source, "pmk debug: Probe failed"_en_US);
Say(n.source, "pmk debug: Probe failed"_en_US);
// TODO: if name is not INTRINSIC, call with implicit
// interface
}
@ -865,8 +848,7 @@ std::optional<ProcedureDesignator> ExprAnalyzer::Procedure(
return {ProcedureDesignator{*n.symbol}};
},
[&](const auto &) -> std::optional<ProcedureDesignator> {
context.messages.Say(
"TODO: unimplemented/invalid kind of symbol as procedure designator '%s'"_err_en_US,
Say("TODO: unimplemented/invalid kind of symbol as procedure designator '%s'"_err_en_US,
n.ToString().data());
return std::nullopt;
}},
@ -877,7 +859,7 @@ std::optional<ProcedureDesignator> ExprAnalyzer::Procedure(
if (MaybeExpr component{AnalyzeHelper(*this, pcr.v)}) {
// TODO distinguish PCR from TBP
// TODO optional PASS argument for TBP
context.messages.Say("TODO: proc component ref"_err_en_US);
Say("TODO: proc component ref"_err_en_US);
return std::nullopt;
} else {
return std::nullopt;
@ -903,21 +885,19 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::FunctionReference &funcRef) {
actualArgExpr = Analyze(*x);
},
[&](const parser::Name &n) {
context.messages.Say("TODO: procedure name actual arg"_err_en_US);
Say("TODO: procedure name actual arg"_err_en_US);
},
[&](const parser::ProcComponentRef &) {
context.messages.Say(
"TODO: proc component ref actual arg"_err_en_US);
Say("TODO: proc component ref actual arg"_err_en_US);
},
[&](const parser::AltReturnSpec &) {
context.messages.Say(
"alternate return specification cannot appear on function reference"_err_en_US);
Say("alternate return specification cannot appear on function reference"_err_en_US);
},
[&](const parser::ActualArg::PercentRef &) {
context.messages.Say("TODO: %REF() argument"_err_en_US);
Say("TODO: %REF() argument"_err_en_US);
},
[&](const parser::ActualArg::PercentVal &) {
context.messages.Say("TODO: %VAL() argument"_err_en_US);
Say("TODO: %VAL() argument"_err_en_US);
}},
std::get<parser::ActualArg>(arg.t).u);
if (actualArgExpr.has_value()) {
@ -981,8 +961,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) {
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);
Say("operand of unary + must be of a numeric type"_err_en_US);
}
}},
value->u);
@ -992,7 +971,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) {
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Negate &x) {
if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) {
return Negation(context.messages, std::move(*operand));
return Negation(context.foldingContext().messages, std::move(*operand));
}
return std::nullopt;
}
@ -1006,8 +985,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::NOT &x) {
[=](auto &&) -> MaybeExpr {
// TODO: accept INTEGER operand and maybe typeless
// if not overridden
context.messages.Say(
"Operand of .NOT. must be LOGICAL"_err_en_US);
Say("Operand of .NOT. must be LOGICAL"_err_en_US);
return std::nullopt;
}},
std::move(operand->u));
@ -1016,12 +994,12 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::NOT &x) {
}
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::PercentLoc &) {
context.messages.Say("TODO: %LOC unimplemented"_err_en_US);
Say("TODO: %LOC unimplemented"_err_en_US);
return std::nullopt;
}
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedUnary &) {
context.messages.Say("TODO: DefinedUnary unimplemented"_err_en_US);
Say("TODO: DefinedUnary unimplemented"_err_en_US);
return std::nullopt;
}
@ -1033,13 +1011,12 @@ MaybeExpr BinaryOperationHelper(ExprAnalyzer &ea, const PARSED &x) {
int leftRank{std::get<0>(*both).Rank()};
int rightRank{std::get<1>(*both).Rank()};
if (leftRank > 0 && rightRank > 0 && leftRank != rightRank) {
ea.context.messages.Say(
"left operand has rank %d, right operand has rank %d"_err_en_US,
ea.Say("left operand has rank %d, right operand has rank %d"_err_en_US,
leftRank, rightRank);
}
return NumericOperation<OPR>(ea.context.messages,
return NumericOperation<OPR>(ea.context.foldingContext().messages,
std::move(std::get<0>(*both)), std::move(std::get<1>(*both)),
ea.defaults.GetDefaultKind(TypeCategory::Real));
ea.context.defaultKinds().GetDefaultKind(TypeCategory::Real));
}
return std::nullopt;
}
@ -1065,10 +1042,10 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Subtract &x) {
}
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::ComplexConstructor &x) {
return AsMaybeExpr(ConstructComplex(context.messages,
return AsMaybeExpr(ConstructComplex(context.foldingContext().messages,
AnalyzeHelper(*this, *std::get<0>(x.t)),
AnalyzeHelper(*this, *std::get<1>(x.t)),
defaults.GetDefaultKind(TypeCategory::Real)));
context.defaultKinds().GetDefaultKind(TypeCategory::Real)));
}
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Concat &x) {
@ -1085,16 +1062,14 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Concat &x) {
return {AsGenericExpr(
Concat<Ty::kind>{std::move(cxk), std::move(cyk)})};
} else {
context.messages.Say(
"Operands of // must be the same kind of CHARACTER"_err_en_US);
Say("Operands of // must be the same kind of CHARACTER"_err_en_US);
return std::nullopt;
}
},
std::move(cx.u), std::move(cy.u));
},
[&](auto &&, auto &&) -> MaybeExpr {
context.messages.Say(
"Operands of // must be CHARACTER"_err_en_US);
Say("Operands of // must be CHARACTER"_err_en_US);
return std::nullopt;
},
},
@ -1109,7 +1084,7 @@ MaybeExpr RelationHelper(
ExprAnalyzer &ea, RelationalOperator opr, const PARSED &x) {
if (auto both{common::AllPresent(AnalyzeHelper(ea, *std::get<0>(x.t)),
AnalyzeHelper(ea, *std::get<1>(x.t)))}) {
return AsMaybeExpr(Relate(ea.context.messages, opr,
return AsMaybeExpr(Relate(ea.context.foldingContext().messages, opr,
std::move(std::get<0>(*both)), std::move(std::get<1>(*both))));
}
return std::nullopt;
@ -1155,8 +1130,7 @@ MaybeExpr LogicalHelper(
// TODO: extension: INTEGER and typeless operands
// ifort and PGI accept them if not overridden
// need to define IAND, IOR, IEOR intrinsic representation
ea.context.messages.Say(
"operands to LOGICAL operation must be LOGICAL"_err_en_US);
ea.Say("operands to LOGICAL operation must be LOGICAL"_err_en_US);
return {};
}},
std::move(std::get<0>(*both).u), std::move(std::get<1>(*both).u));
@ -1185,7 +1159,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::XOR &x) {
}
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::DefinedBinary &) {
context.messages.Say("TODO: DefinedBinary unimplemented"_err_en_US);
Say("TODO: DefinedBinary unimplemented"_err_en_US);
return std::nullopt;
}
@ -1207,8 +1181,7 @@ void ExprAnalyzer::CheckUnsubscriptedComponent(const Component &component) {
if (baseRank > 0) {
int componentRank{component.symbol().Rank()};
if (componentRank > 0) {
context.messages.Say(
"reference to whole rank-%d component '%%%s' of rank-%d array of derived type is not allowed"_err_en_US,
Say("reference to whole rank-%d component '%%%s' of rank-%d array of derived type is not allowed"_err_en_US,
componentRank, component.symbol().name().ToString().data(), baseRank);
}
}
@ -1218,26 +1191,21 @@ void ExprAnalyzer::CheckUnsubscriptedComponent(const Component &component) {
namespace Fortran::semantics {
evaluate::MaybeExpr AnalyzeExpr(evaluate::FoldingContext &context,
const IntrinsicTypeDefaultKinds &defaults,
const evaluate::IntrinsicProcTable &intrinsics, const parser::Expr &expr) {
return evaluate::ExprAnalyzer{context, defaults, intrinsics}.Analyze(expr);
evaluate::MaybeExpr AnalyzeExpr(
SemanticsContext &context, const parser::Expr &expr) {
return evaluate::ExprAnalyzer{context}.Analyze(expr);
}
class Mutator {
public:
Mutator(evaluate::FoldingContext &context,
const SemanticsContext &semanticsContext)
: context_{context}, semanticsContext_{semanticsContext} {}
Mutator(SemanticsContext &context) : context_{context} {}
template<typename A> bool Pre(A &) { return true /* visit children */; }
template<typename A> void Post(A &) {}
bool Pre(parser::Expr &expr) {
if (expr.typedExpr.get() == nullptr) {
if (MaybeExpr checked{
AnalyzeExpr(context_, semanticsContext_.defaultKinds(),
semanticsContext_.intrinsics(), expr)}) {
if (MaybeExpr checked{AnalyzeExpr(context_, expr)}) {
checked->Dump(std::cout << "checked expression: ") << '\n';
expr.typedExpr.reset(
new evaluate::GenericExprWrapper{std::move(*checked)});
@ -1250,14 +1218,11 @@ public:
}
private:
evaluate::FoldingContext &context_;
const SemanticsContext &semanticsContext_;
SemanticsContext &context_;
};
void AnalyzeExpressions(parser::Program &program,
evaluate::FoldingContext &context,
const SemanticsContext &semanticsContext) {
Mutator mutator{context, semanticsContext};
void AnalyzeExpressions(parser::Program &program, SemanticsContext &context) {
Mutator mutator{context};
parser::Walk(program, mutator);
}
} // namespace Fortran::semantics

View File

@ -29,13 +29,11 @@ using MaybeExpr = std::optional<evaluate::Expr<evaluate::SomeType>>;
// Semantic analysis of one expression.
std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr(
evaluate::FoldingContext &, const IntrinsicTypeDefaultKinds &,
const parser::Expr &);
SemanticsContext &, 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 SemanticsContext &);
void AnalyzeExpressions(parser::Program &, SemanticsContext &);
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_EXPRESSION_H_

View File

@ -14,6 +14,7 @@
#include "semantics.h"
#include "canonicalize-do.h"
#include "default-kinds.h"
#include "mod-file.h"
#include "resolve-labels.h"
#include "resolve-names.h"
@ -27,6 +28,13 @@ namespace Fortran::semantics {
static void DoDumpSymbols(std::ostream &, const Scope &, int indent = 0);
static void PutIndent(std::ostream &, int indent);
SemanticsContext::SemanticsContext(
const IntrinsicTypeDefaultKinds &defaultKinds)
: defaultKinds_{defaultKinds},
intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds)},
foldingContext_{evaluate::FoldingContext{
parser::ContextualMessages{parser::CharBlock{}, &messages_}}} {}
bool SemanticsContext::AnyFatalError() const {
return !messages_.empty() &&
(warningsAreErrors_ || messages_.AnyFatalError());
@ -52,10 +60,7 @@ bool Semantics::Perform() {
return false;
}
if (context_.debugExpressions()) {
parser::CharBlock whole{cooked_.data()};
parser::ContextualMessages contextualMessages{whole, &context_.messages()};
evaluate::FoldingContext foldingContext{contextualMessages};
AnalyzeExpressions(program_, foldingContext, context_);
AnalyzeExpressions(program_, context_);
}
return !AnyFatalError();
}

View File

@ -15,8 +15,8 @@
#ifndef FORTRAN_SEMANTICS_SEMANTICS_H_
#define FORTRAN_SEMANTICS_SEMANTICS_H_
#include "default-kinds.h"
#include "expression.h"
#include "../evaluate/common.h"
#include "scope.h"
#include "../evaluate/intrinsics.h"
#include "../parser/message.h"
@ -31,12 +31,11 @@ class CookedSource;
namespace Fortran::semantics {
class IntrinsicTypeDefaultKinds;
class SemanticsContext {
public:
SemanticsContext(const IntrinsicTypeDefaultKinds &defaultKinds)
: defaultKinds_{defaultKinds}, intrinsics_{
evaluate::IntrinsicProcTable::Configure(
defaultKinds)} {}
SemanticsContext(const IntrinsicTypeDefaultKinds &);
const IntrinsicTypeDefaultKinds &defaultKinds() const {
return defaultKinds_;
@ -50,6 +49,7 @@ public:
const evaluate::IntrinsicProcTable &intrinsics() const { return intrinsics_; }
Scope &globalScope() { return globalScope_; }
parser::Messages &messages() { return messages_; }
evaluate::FoldingContext& foldingContext() { return foldingContext_; }
SemanticsContext &set_searchDirectories(const std::vector<std::string> &x) {
searchDirectories_ = x;
@ -82,6 +82,7 @@ private:
const evaluate::IntrinsicProcTable intrinsics_;
Scope globalScope_;
parser::Messages messages_;
evaluate::FoldingContext foldingContext_;
};
class Semantics {