2018-07-14 01:55:11 +02:00
|
|
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
//
|
|
|
|
// 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"
|
2018-07-14 01:55:11 +02:00
|
|
|
#include "../evaluate/expression.h"
|
2018-08-31 22:28:21 +02:00
|
|
|
#include "../evaluate/type.h"
|
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-11-06 00:03:46 +01:00
|
|
|
namespace Fortran::parser {
|
2018-11-13 20:29:54 +01:00
|
|
|
struct Expr;
|
|
|
|
struct Program;
|
2018-11-19 20:14:41 +01:00
|
|
|
template<typename> struct Scalar;
|
|
|
|
template<typename> struct Integer;
|
|
|
|
template<typename> struct Constant;
|
2018-12-04 01:44:25 +01:00
|
|
|
template<typename> struct Logical;
|
|
|
|
template<typename> struct DefaultChar;
|
2018-11-06 00:03:46 +01:00
|
|
|
}
|
|
|
|
|
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).
|
|
|
|
//
|
|
|
|
// The template function AnalyzeExpr is an internal interface
|
|
|
|
// between the implementation and the API used by semantic analysis.
|
|
|
|
// This template function has a few specializations here in the header
|
|
|
|
// file to handle what semantics might want to pass in as a top-level
|
|
|
|
// expression; other specializations appear in the implementation.
|
|
|
|
//
|
|
|
|
// The ExpressionAnalysisContext wraps a SemanticsContext reference
|
|
|
|
// and implements constraint checking on expressions using the
|
|
|
|
// parse tree node wrappers that mirror the grammar annotations used
|
|
|
|
// in the Fortran standard (i.e., scalar-, constant-, &c.). These
|
|
|
|
// constraint checks are performed in a deferred manner so that any
|
|
|
|
// errors are reported on the most accurate source location available.
|
|
|
|
|
2018-11-30 23:03:05 +01:00
|
|
|
namespace Fortran::evaluate {
|
2018-12-01 00:23:33 +01:00
|
|
|
class ExpressionAnalysisContext {
|
|
|
|
public:
|
2018-11-30 23:03:05 +01:00
|
|
|
using ConstraintChecker = bool (ExpressionAnalysisContext::*)(
|
|
|
|
Expr<SomeType> &);
|
|
|
|
|
2018-12-01 00:23:33 +01:00
|
|
|
ExpressionAnalysisContext(semantics::SemanticsContext &sc) : context_{sc} {}
|
|
|
|
ExpressionAnalysisContext(ExpressionAnalysisContext &i)
|
|
|
|
: context_{i.context_}, inner_{&i} {}
|
|
|
|
ExpressionAnalysisContext(ExpressionAnalysisContext &i, ConstraintChecker cc)
|
|
|
|
: context_{i.context_}, inner_{&i}, constraint_{cc} {}
|
|
|
|
|
|
|
|
semantics::SemanticsContext &context() const { return context_; }
|
2018-11-30 23:03:05 +01:00
|
|
|
|
|
|
|
template<typename... A> void Say(A... args) {
|
2018-12-01 00:23:33 +01:00
|
|
|
context_.foldingContext().messages.Say(std::forward<A>(args)...);
|
2018-11-30 23:03:05 +01:00
|
|
|
}
|
|
|
|
|
2018-12-01 00:23:33 +01:00
|
|
|
void CheckConstraints(std::optional<Expr<SomeType>> &);
|
2018-11-30 23:03:05 +01:00
|
|
|
bool ScalarConstraint(Expr<SomeType> &);
|
|
|
|
bool ConstantConstraint(Expr<SomeType> &);
|
|
|
|
bool IntegerConstraint(Expr<SomeType> &);
|
2018-12-04 01:44:25 +01:00
|
|
|
bool LogicalConstraint(Expr<SomeType> &);
|
|
|
|
bool DefaultCharConstraint(Expr<SomeType> &);
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2018-12-01 00:23:33 +01:00
|
|
|
protected:
|
|
|
|
semantics::SemanticsContext &context_;
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2018-12-01 00:23:33 +01:00
|
|
|
private:
|
|
|
|
ExpressionAnalysisContext *inner_{nullptr};
|
|
|
|
ConstraintChecker constraint_{nullptr};
|
2018-11-30 23:03:05 +01:00
|
|
|
};
|
2018-08-13 22:33:31 +02:00
|
|
|
|
2018-11-30 23:03:05 +01:00
|
|
|
template<typename PARSED>
|
2018-12-01 00:23:33 +01:00
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const PARSED &);
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2018-12-01 01:04:51 +01:00
|
|
|
// This extern template is the gateway into the rest of the expression
|
|
|
|
// analysis implementation in expression.cc.
|
2018-12-01 00:23:33 +01:00
|
|
|
extern template std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const parser::Expr &);
|
2018-11-30 23:03:05 +01:00
|
|
|
|
2018-12-04 01:44:25 +01:00
|
|
|
// Forward declarations of exposed specializations
|
|
|
|
template<typename A>
|
2018-12-04 02:20:28 +01:00
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
2018-12-04 01:44:25 +01:00
|
|
|
ExpressionAnalysisContext &, const common::Indirection<A> &);
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const parser::Scalar<A> &);
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const parser::Constant<A> &);
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const parser::Integer<A> &);
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const parser::Logical<A> &);
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &, const parser::DefaultChar<A> &);
|
|
|
|
|
|
|
|
// Indirections are silently traversed by AnalyzeExpr().
|
|
|
|
template<typename A>
|
2018-12-04 02:20:28 +01:00
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
2018-12-04 01:44:25 +01:00
|
|
|
ExpressionAnalysisContext &context, const common::Indirection<A> &x) {
|
|
|
|
return AnalyzeExpr(context, *x);
|
|
|
|
}
|
|
|
|
|
2018-12-01 01:04:51 +01:00
|
|
|
// These specializations create nested expression analysis contexts
|
|
|
|
// to implement constraint checking.
|
|
|
|
|
2018-11-30 23:03:05 +01:00
|
|
|
template<typename A>
|
2018-12-01 00:23:33 +01:00
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &context, const parser::Scalar<A> &expr) {
|
|
|
|
ExpressionAnalysisContext withCheck{
|
|
|
|
context, &ExpressionAnalysisContext::ScalarConstraint};
|
|
|
|
return AnalyzeExpr(withCheck, expr.thing);
|
2018-11-30 23:03:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
2018-12-01 00:23:33 +01:00
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &context, const parser::Constant<A> &expr) {
|
|
|
|
ExpressionAnalysisContext withCheck{
|
|
|
|
context, &ExpressionAnalysisContext::ConstantConstraint};
|
|
|
|
return AnalyzeExpr(withCheck, expr.thing);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &context, const parser::Integer<A> &expr) {
|
|
|
|
ExpressionAnalysisContext withCheck{
|
2018-12-04 01:44:25 +01:00
|
|
|
context, &ExpressionAnalysisContext::IntegerConstraint};
|
|
|
|
return AnalyzeExpr(withCheck, expr.thing);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &context, const parser::Logical<A> &expr) {
|
|
|
|
ExpressionAnalysisContext withCheck{
|
|
|
|
context, &ExpressionAnalysisContext::LogicalConstraint};
|
|
|
|
return AnalyzeExpr(withCheck, expr.thing);
|
|
|
|
}
|
|
|
|
template<typename A>
|
|
|
|
std::optional<Expr<SomeType>> AnalyzeExpr(
|
|
|
|
ExpressionAnalysisContext &context, const parser::DefaultChar<A> &expr) {
|
|
|
|
ExpressionAnalysisContext withCheck{
|
|
|
|
context, &ExpressionAnalysisContext::DefaultCharConstraint};
|
2018-12-01 00:23:33 +01:00
|
|
|
return AnalyzeExpr(withCheck, expr.thing);
|
|
|
|
}
|
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) {
|
|
|
|
evaluate::ExpressionAnalysisContext exprContext{context};
|
|
|
|
return AnalyzeExpr(exprContext, expr);
|
2018-11-30 23:03:05 +01:00
|
|
|
}
|
2018-11-19 20:14:41 +01:00
|
|
|
|
2018-09-12 20:20:30 +02:00
|
|
|
// Semantic analysis of all expressions in a parse tree, which is
|
|
|
|
// decorated with typed representations for top-level expressions.
|
2018-10-23 01:41:26 +02:00
|
|
|
void AnalyzeExpressions(parser::Program &, SemanticsContext &);
|
2018-10-25 14:55:23 +02:00
|
|
|
}
|
2018-07-14 01:55:11 +02:00
|
|
|
#endif // FORTRAN_SEMANTICS_EXPRESSION_H_
|