// Constraint checking
void ExpressionAnalysisContext::CheckConstraints(MaybeExpr &expr) {
- if (inner_ != nullptr) {
- inner_->CheckConstraints(expr);
- }
- if (constraint_ != nullptr && expr.has_value()) {
- if (!(this->*constraint_)(*expr)) {
- expr.reset();
+ if (expr.has_value()) {
+ if (inner_ != nullptr) {
+ inner_->CheckConstraints(expr);
+ }
+ if (constraint_ != nullptr) {
+ if (!(this->*constraint_)(*expr)) {
+ expr.reset();
+ }
}
}
}
return false;
}
+bool ExpressionAnalysisContext::LogicalConstraint(Expr<SomeType> &expr) {
+ if (std::holds_alternative<Expr<SomeLogical>>(expr.u)) {
+ return true;
+ }
+ Say("expression must be LOGICAL"_err_en_US);
+ return false;
+}
+
+bool ExpressionAnalysisContext::DefaultCharConstraint(Expr<SomeType> &expr) {
+ if (auto *charExpr{std::get_if<Expr<SomeCharacter>>(&expr.u)}) {
+ return charExpr->GetKind() ==
+ context.defaultKinds.GetDefaultKind(TypeCategory::Character);
+ }
+ Say("expression must be default CHARACTER"_err_en_US);
+ return false;
+}
+
// If a generic expression simply wraps a DataRef, extract it.
// TODO: put in tools.h?
template<typename A> std::optional<DataRef> ExtractDataRef(A &&) {
// Forward declarations of additional AnalyzeExpr specializations
template<typename... As>
MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &, const std::variant<As...> &);
-template<typename A>
-MaybeExpr AnalyzeExpr(
- ExpressionAnalysisContext &, const common::Indirection<A> &);
template<>
MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &, const parser::Designator &);
template<>
template MaybeExpr AnalyzeExpr(
ExpressionAnalysisContext &, const parser::Expr &);
-// Variants and indirections are silently traversed by AnalyzeExpr().
+// Variants are silently traversed by AnalyzeExpr().
template<typename... As>
MaybeExpr AnalyzeExpr(
ExpressionAnalysisContext &context, const std::variant<As...> &u) {
return std::visit([&](const auto &x) { return AnalyzeExpr(context, x); }, u);
}
-template<typename A>
-MaybeExpr AnalyzeExpr(
- ExpressionAnalysisContext &context, const common::Indirection<A> &x) {
- return AnalyzeExpr(context, *x);
-}
-
// Wraps a object in an explicitly typed representation (e.g., Designator<>
// or FunctionRef<>) that has been instantiated on a dynamically chosen type.
// TODO: move to tools.h?
template<typename> struct Scalar;
template<typename> struct Integer;
template<typename> struct Constant;
+template<typename> struct Logical;
+template<typename> struct DefaultChar;
}
// The expression semantic analysis code has its implementation in
bool ScalarConstraint(Expr<SomeType> &);
bool ConstantConstraint(Expr<SomeType> &);
bool IntegerConstraint(Expr<SomeType> &);
+ bool LogicalConstraint(Expr<SomeType> &);
+ bool DefaultCharConstraint(Expr<SomeType> &);
protected:
semantics::SemanticsContext &context_;
extern template std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const parser::Expr &);
+// Forward declarations of exposed specializations
+template<typename A>
+MaybeExpr AnalyzeExpr(
+ 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>
+MaybeExpr AnalyzeExpr(
+ ExpressionAnalysisContext &context, const common::Indirection<A> &x) {
+ return AnalyzeExpr(context, *x);
+}
+
// These specializations create nested expression analysis contexts
// to implement constraint checking.
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Integer<A> &expr) {
ExpressionAnalysisContext withCheck{
- context, &ExpressionAnalysisContext::ConstantConstraint};
+ 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};
return AnalyzeExpr(withCheck, expr.thing);
}
}