2019-01-07 19:55:09 +01:00
|
|
|
// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
2018-07-14 01:55:11 +02:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#ifndef FORTRAN_SEMANTICS_EXPRESSION_H_
|
|
|
|
#define FORTRAN_SEMANTICS_EXPRESSION_H_
|
|
|
|
|
2018-11-30 23:03:05 +01:00
|
|
|
#include "semantics.h"
|
2019-02-28 19:48:41 +01:00
|
|
|
#include "../common/Fortran.h"
|
2018-12-04 19:21:38 +01:00
|
|
|
#include "../common/indirection.h"
|
2018-07-14 01:55:11 +02:00
|
|
|
#include "../evaluate/expression.h"
|
2018-12-29 00:58:17 +01:00
|
|
|
#include "../evaluate/tools.h"
|
2018-08-31 22:28:21 +02:00
|
|
|
#include "../evaluate/type.h"
|
2019-01-23 01:30:32 +01:00
|
|
|
#include "../parser/char-block.h"
|
2018-12-29 00:58:17 +01:00
|
|
|
#include "../parser/parse-tree-visitor.h"
|
|
|
|
#include "../parser/parse-tree.h"
|
2019-01-23 01:30:32 +01:00
|
|
|
#include <map>
|
2018-07-14 01:55:11 +02:00
|
|
|
#include <optional>
|
2018-11-30 23:03:05 +01:00
|
|
|
#include <variant>
|
2018-07-14 01:55:11 +02:00
|
|
|
|
2018-12-29 00:58:17 +01:00
|
|
|
using namespace Fortran::parser::literals;
|
|
|
|
|
2018-11-06 00:03:46 +01:00
|
|
|
namespace Fortran::parser {
|
2018-12-29 00:58:17 +01:00
|
|
|
struct SourceLocationFindingVisitor {
|
|
|
|
template<typename A> bool Pre(const A &) { return true; }
|
|
|
|
template<typename A> void Post(const A &) {}
|
|
|
|
bool Pre(const Expr &);
|
|
|
|
template<typename A> bool Pre(const Statement<A> &stmt) {
|
|
|
|
source = stmt.source;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void Post(const CharBlock &);
|
|
|
|
|
|
|
|
CharBlock source;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename A> CharBlock FindSourceLocation(const A &x) {
|
|
|
|
SourceLocationFindingVisitor visitor;
|
|
|
|
Walk(x, visitor);
|
|
|
|
return visitor.source;
|
|
|
|
}
|
2018-11-06 00:03:46 +01:00
|
|
|
}
|
|
|
|
|
2019-01-10 00:06:07 +01:00
|
|
|
using namespace Fortran::parser::literals;
|
|
|
|
|
2018-12-01 01:04:51 +01:00
|
|
|
// The expression semantic analysis code has its implementation in
|
|
|
|
// namespace Fortran::evaluate, but the exposed API to it is in the
|
|
|
|
// namespace Fortran::semantics (below).
|
|
|
|
//
|
2019-03-07 23:46:31 +01:00
|
|
|
// The ExpressionAnalyzer wraps a SemanticsContext reference
|
2018-12-01 01:04:51 +01:00
|
|
|
// and implements constraint checking on expressions using the
|
|
|
|
// parse tree node wrappers that mirror the grammar annotations used
|
2018-12-29 00:58:17 +01:00
|
|
|
// in the Fortran standard (i.e., scalar-, constant-, &c.).
|
2018-12-01 01:04:51 +01:00
|
|
|
|
2018-11-30 23:03:05 +01:00
|
|
|
namespace Fortran::evaluate {
|
2019-03-07 23:46:31 +01:00
|
|
|
class ExpressionAnalyzer {
|
2018-12-01 00:23:33 +01:00
|
|
|
public:
|
2019-03-07 23:46:31 +01:00
|
|
|
using MaybeExpr = std::optional<Expr<SomeType>>;
|
|
|
|
|
|
|
|
explicit ExpressionAnalyzer(semantics::SemanticsContext &sc) : context_{sc} {}
|
|
|
|
ExpressionAnalyzer(ExpressionAnalyzer &) = default;
|
2018-12-01 00:23:33 +01:00
|
|
|
|
|
|
|
semantics::SemanticsContext &context() const { return context_; }
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2019-01-10 00:06:07 +01:00
|
|
|
FoldingContext &GetFoldingContext() const {
|
|
|
|
return context_.foldingContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
parser::ContextualMessages &GetContextualMessages() {
|
2019-02-01 01:04:17 +01:00
|
|
|
return GetFoldingContext().messages();
|
2019-01-10 00:06:07 +01:00
|
|
|
}
|
|
|
|
|
2019-02-14 21:51:20 +01:00
|
|
|
template<typename... A> parser::Message *Say(A... args) {
|
|
|
|
return GetContextualMessages().Say(std::forward<A>(args)...);
|
2018-11-30 23:03:05 +01:00
|
|
|
}
|
|
|
|
|
2019-02-14 21:51:20 +01:00
|
|
|
template<typename T, typename... A>
|
|
|
|
parser::Message *SayAt(const T &parsed, A... args) {
|
|
|
|
return Say(parser::FindSourceLocation(parsed), std::forward<A>(args)...);
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2019-01-10 00:06:07 +01:00
|
|
|
int GetDefaultKind(common::TypeCategory);
|
|
|
|
DynamicType GetDefaultKindOfType(common::TypeCategory);
|
2018-12-05 00:52:50 +01:00
|
|
|
|
2019-02-09 01:03:23 +01:00
|
|
|
// Return false and emit error if these checks fail:
|
|
|
|
bool CheckIntrinsicKind(TypeCategory, std::int64_t kind);
|
|
|
|
bool CheckIntrinsicSize(TypeCategory, std::int64_t size);
|
|
|
|
|
2019-01-23 01:30:32 +01:00
|
|
|
// Manage a set of active array constructor implied DO loops.
|
|
|
|
bool AddAcImpliedDo(parser::CharBlock, int);
|
|
|
|
void RemoveAcImpliedDo(parser::CharBlock);
|
|
|
|
std::optional<int> IsAcImpliedDo(parser::CharBlock) const;
|
|
|
|
|
2019-03-07 23:46:31 +01:00
|
|
|
Expr<SubscriptInteger> AnalyzeKindSelector(common::TypeCategory category,
|
|
|
|
const std::optional<parser::KindSelector> &);
|
2018-12-04 01:44:25 +01:00
|
|
|
|
2019-03-07 23:46:31 +01:00
|
|
|
MaybeExpr Analyze(const parser::Expr &);
|
|
|
|
MaybeExpr Analyze(const parser::Variable &);
|
2018-12-01 01:04:51 +01:00
|
|
|
|
2019-03-07 23:46:31 +01:00
|
|
|
template<typename A> MaybeExpr Analyze(const common::Indirection<A> &x) {
|
|
|
|
return Analyze(x.value());
|
|
|
|
}
|
|
|
|
template<typename A> MaybeExpr Analyze(const std::optional<A> &x) {
|
|
|
|
if (x.has_value()) {
|
|
|
|
return Analyze(*x);
|
|
|
|
} else {
|
|
|
|
return std::nullopt;
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
|
|
|
}
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2019-03-07 23:46:31 +01:00
|
|
|
// Implement constraint-checking wrappers from the Fortran grammar
|
|
|
|
template<typename A> MaybeExpr Analyze(const parser::Scalar<A> &x) {
|
|
|
|
auto result{Analyze(x.thing)};
|
|
|
|
if (result.has_value()) {
|
|
|
|
if (int rank{result->Rank()}; rank != 0) {
|
|
|
|
SayAt(x, "Must be a scalar value, but is a rank-%d array"_err_en_US,
|
|
|
|
rank);
|
|
|
|
}
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
return result;
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
template<typename A> MaybeExpr Analyze(const parser::Constant<A> &x) {
|
|
|
|
auto result{Analyze(x.thing)};
|
|
|
|
if (result.has_value()) {
|
|
|
|
*result = Fold(GetFoldingContext(), std::move(*result));
|
|
|
|
if (!IsConstantExpr(*result)) {
|
|
|
|
SayAt(x, "Must be a constant value"_err_en_US);
|
|
|
|
}
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
return result;
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
template<typename A> MaybeExpr Analyze(const parser::Integer<A> &x) {
|
|
|
|
auto result{Analyze(x.thing)};
|
|
|
|
if (result.has_value()) {
|
|
|
|
if (!std::holds_alternative<Expr<SomeInteger>>(result->u)) {
|
|
|
|
SayAt(x, "Must have INTEGER type"_err_en_US);
|
|
|
|
}
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
return result;
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
template<typename A> MaybeExpr Analyze(const parser::Logical<A> &x) {
|
|
|
|
auto result{Analyze(x.thing)};
|
|
|
|
if (result.has_value()) {
|
|
|
|
if (!std::holds_alternative<Expr<SomeLogical>>(result->u)) {
|
|
|
|
SayAt(x, "Must have LOGICAL type"_err_en_US);
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
template<typename A> MaybeExpr Analyze(const parser::DefaultChar<A> &x) {
|
|
|
|
auto result{Analyze(x.thing)};
|
|
|
|
if (result.has_value()) {
|
|
|
|
if (auto *charExpr{std::get_if<Expr<SomeCharacter>>(&result->u)}) {
|
|
|
|
if (charExpr->GetKind() ==
|
|
|
|
context().defaultKinds().GetDefaultKind(TypeCategory::Character)) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SayAt(x, "Must have default CHARACTER type"_err_en_US);
|
|
|
|
}
|
|
|
|
return result;
|
2018-12-29 00:58:17 +01:00
|
|
|
}
|
2019-03-07 23:46:31 +01:00
|
|
|
|
|
|
|
protected:
|
|
|
|
int IntegerTypeSpecKind(const parser::IntegerTypeSpec &);
|
|
|
|
|
|
|
|
private:
|
|
|
|
MaybeExpr Analyze(const parser::Designator &);
|
|
|
|
MaybeExpr Analyze(const parser::IntLiteralConstant &);
|
|
|
|
MaybeExpr Analyze(const parser::SignedIntLiteralConstant &);
|
|
|
|
MaybeExpr Analyze(const parser::RealLiteralConstant &);
|
|
|
|
MaybeExpr Analyze(const parser::SignedRealLiteralConstant &);
|
|
|
|
MaybeExpr Analyze(const parser::ComplexPart &);
|
|
|
|
MaybeExpr Analyze(const parser::ComplexLiteralConstant &);
|
|
|
|
MaybeExpr Analyze(const parser::LogicalLiteralConstant &);
|
|
|
|
MaybeExpr Analyze(const parser::CharLiteralConstant &);
|
|
|
|
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::CoindexedNamedObject &);
|
|
|
|
MaybeExpr Analyze(const parser::CharLiteralConstantSubstring &);
|
|
|
|
MaybeExpr Analyze(const parser::ArrayConstructor &);
|
|
|
|
MaybeExpr Analyze(const parser::StructureConstructor &);
|
|
|
|
MaybeExpr Analyze(const parser::FunctionReference &);
|
|
|
|
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 &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::Divide &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::Add &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::Subtract &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::ComplexConstructor &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::Concat &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::LT &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::LE &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::EQ &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::NE &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::GE &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::GT &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::AND &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::OR &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::EQV &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::NEQV &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::XOR &);
|
|
|
|
MaybeExpr Analyze(const parser::Expr::DefinedBinary &);
|
|
|
|
template<typename A> MaybeExpr Analyze(const A &x) {
|
|
|
|
return Analyze(x.u); // default case
|
|
|
|
}
|
|
|
|
template<typename... As> MaybeExpr Analyze(const std::variant<As...> &u) {
|
|
|
|
return std::visit([&](const auto &x) { return Analyze(x); }, u);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Analysis subroutines
|
|
|
|
int AnalyzeKindParam(const std::optional<parser::KindParam> &,
|
|
|
|
int defaultKind, int kanjiKind = -1);
|
|
|
|
template<typename PARSED> MaybeExpr IntLiteralConstant(const PARSED &);
|
|
|
|
MaybeExpr AnalyzeString(std::string &&, int kind);
|
|
|
|
std::optional<Expr<SubscriptInteger>> AsSubscript(MaybeExpr &&);
|
|
|
|
std::optional<Expr<SubscriptInteger>> TripletPart(
|
|
|
|
const std::optional<parser::Subscript> &);
|
|
|
|
std::optional<Subscript> AnalyzeSectionSubscript(
|
|
|
|
const parser::SectionSubscript &);
|
|
|
|
std::vector<Subscript> AnalyzeSectionSubscripts(
|
|
|
|
const std::list<parser::SectionSubscript> &);
|
|
|
|
MaybeExpr CompleteSubscripts(ArrayRef &&);
|
|
|
|
MaybeExpr ApplySubscripts(DataRef &&, std::vector<Subscript> &&);
|
|
|
|
MaybeExpr TopLevelChecks(DataRef &&);
|
|
|
|
std::optional<Expr<SubscriptInteger>> GetSubstringBound(
|
|
|
|
const std::optional<parser::ScalarIntExpr> &);
|
|
|
|
|
|
|
|
struct CallAndArguments {
|
|
|
|
ProcedureDesignator procedureDesignator;
|
|
|
|
ActualArguments arguments;
|
|
|
|
};
|
|
|
|
std::optional<CallAndArguments> Procedure(
|
|
|
|
const parser::ProcedureDesignator &, ActualArguments &);
|
|
|
|
|
|
|
|
semantics::SemanticsContext &context_;
|
|
|
|
std::map<parser::CharBlock, int> acImpliedDos_; // values are INTEGER kinds
|
|
|
|
};
|
2019-01-10 00:06:07 +01:00
|
|
|
|
|
|
|
template<typename L, typename R>
|
|
|
|
bool AreConformable(const L &left, const R &right) {
|
|
|
|
int leftRank{left.Rank()};
|
2019-01-10 01:39:58 +01:00
|
|
|
if (leftRank == 0) {
|
2019-01-10 00:06:07 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
int rightRank{right.Rank()};
|
|
|
|
return rightRank == 0 || leftRank == rightRank;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename L, typename R>
|
|
|
|
void ConformabilityCheck(
|
|
|
|
parser::ContextualMessages &context, const L &left, const R &right) {
|
|
|
|
if (!AreConformable(left, right)) {
|
|
|
|
context.Say("left operand has rank %d, right operand has rank %d"_err_en_US,
|
|
|
|
left.Rank(), right.Rank());
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 01:52:50 +01:00
|
|
|
} // namespace Fortran::evaluate
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2018-12-01 00:23:33 +01:00
|
|
|
namespace Fortran::semantics {
|
|
|
|
|
|
|
|
// Semantic analysis of one expression.
|
2018-11-30 23:03:05 +01:00
|
|
|
template<typename A>
|
2018-11-19 20:14:41 +01:00
|
|
|
std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr(
|
2018-12-01 00:23:33 +01:00
|
|
|
SemanticsContext &context, const A &expr) {
|
2019-03-07 23:46:31 +01:00
|
|
|
return evaluate::ExpressionAnalyzer{context}.Analyze(expr);
|
2018-11-30 23:03:05 +01:00
|
|
|
}
|
2018-11-19 20:14:41 +01:00
|
|
|
|
2019-01-10 00:06:07 +01:00
|
|
|
// Semantic analysis of an intrinsic type's KIND parameter expression.
|
2018-12-04 19:55:32 +01:00
|
|
|
evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector(
|
2019-03-06 01:52:50 +01:00
|
|
|
SemanticsContext &, common::TypeCategory,
|
2018-12-04 19:55:32 +01:00
|
|
|
const std::optional<parser::KindSelector> &);
|
2019-03-06 01:52:50 +01:00
|
|
|
|
2019-03-07 23:46:31 +01:00
|
|
|
// Semantic analysis of all expressions in a parse tree, which becomes
|
2019-03-06 01:52:50 +01:00
|
|
|
// decorated with typed representations for top-level expressions.
|
|
|
|
class ExprChecker : public virtual BaseChecker {
|
|
|
|
public:
|
|
|
|
explicit ExprChecker(SemanticsContext &context) : context_{context} {}
|
|
|
|
void Enter(const parser::Expr &);
|
2019-03-08 21:55:57 +01:00
|
|
|
void Enter(const parser::Variable &);
|
2019-03-06 01:52:50 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
SemanticsContext &context_;
|
|
|
|
};
|
|
|
|
} // namespace Fortran::semantics
|
2018-07-14 01:55:11 +02:00
|
|
|
#endif // FORTRAN_SEMANTICS_EXPRESSION_H_
|