// 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. #include "expression.h" #include "../common/idioms.h" using namespace Fortran::parser::literals; namespace Fortran::semantics { using Result = ExpressionAnalyzer::Result; // AnalyzeHelper is a local template function that keeps the API // member function ExpressionAnalyzer::Analyze from having to be a // many-specialized template itself. template Result AnalyzeHelper(ExpressionAnalyzer &, const A &); template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr &expr) { return ea.Analyze(expr); } // Template wrappers are traversed with checking. template Result AnalyzeHelper(ExpressionAnalyzer &ea, const std::optional &x) { if (x.has_value()) { return AnalyzeHelper(ea, *x); } else { return std::nullopt; } } template Result AnalyzeHelper(ExpressionAnalyzer &ea, const common::Indirection &p) { return AnalyzeHelper(ea, *p); } template Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Scalar &tree) { Result result{AnalyzeHelper(ea, tree.thing)}; if (result.has_value()) { if (result->Rank() > 1) { ea.context().messages.Say("must be scalar"_err_en_US); return std::nullopt; } } return result; } template Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Constant &tree) { Result result{AnalyzeHelper(ea, tree.thing)}; if (result.has_value()) { result->Fold(ea.context()); if (!result->ScalarValue().has_value()) { ea.context().messages.Say("must be constant"_err_en_US); return std::nullopt; } } return result; } template Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Integer &tree) { Result result{AnalyzeHelper(ea, tree.thing)}; if (result.has_value() && !std::holds_alternative(result->u)) { ea.context().messages.Say("must be integer"_err_en_US); return std::nullopt; } return result; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::CharLiteralConstantSubstring &x) { const auto &range{std::get(x.t)}; if (!std::get<0>(range.t).has_value() && !std::get<1>(range.t).has_value()) { // "..."(:) return AnalyzeHelper(ea, std::get(x.t)); } Result lower{AnalyzeHelper(ea, std::get<0>(range.t))}; Result upper{AnalyzeHelper(ea, std::get<1>(range.t))}; if (lower.has_value() && upper.has_value()) { if (std::optional lb{lower->ScalarValue()}) { if (std::optional ub{upper->ScalarValue()}) { // TODO pmk continue here with ToInt64() } } } return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) { auto kind{ea.Analyze(std::get>(x.t), ea.defaultIntegerKind())}; std::uint64_t value{std::get(x.t)}; switch (kind) { #define CASE(k) \ case k: \ return {evaluate::GenericExpr{ \ evaluate::AnyKindIntegerExpr{evaluate::IntegerExpr{value}}}}; FOR_EACH_INTEGER_KIND(CASE, ) #undef CASE default: ea.context().messages.Say(parser::MessageFormattedText{ "unimplemented INTEGER kind (%ju)"_err_en_US, static_cast(kind)}); return std::nullopt; } } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::LiteralConstant &x) { return std::visit( common::visitors{[&](const parser::IntLiteralConstant &c) { return AnalyzeHelper(ea, c); }, // TODO next [&](const parser::RealLiteralConstant &c) { return // AnalyzeHelper(ea, c); }, // TODO: remaining cases [&](const auto &) { return Result{}; }}, x.u); } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Name &n) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::ArrayConstructor &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::StructureConstructor &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::TypeParamInquiry &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::FunctionReference &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::Expr::Parentheses &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::UnaryPlus &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Negate &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::NOT &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::Expr::PercentLoc &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::Expr::DefinedUnary &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Power &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Multiply &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Divide &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Add &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Subtract &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Concat &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::LT &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::LE &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::EQ &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::NE &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::GE &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::GT &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::AND &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::OR &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::EQV &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::NEQV &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::XOR &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::Expr::DefinedBinary &x) { // TODO return std::nullopt; } template<> Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::Expr::ComplexConstructor &x) { // TODO return std::nullopt; } Result ExpressionAnalyzer::Analyze(const parser::Expr &x) { return std::visit(common::visitors{[&](const parser::LiteralConstant &c) { return AnalyzeHelper(*this, c); }, // TODO: remaining cases [&](const auto &) { return Result{}; }}, x.u); } ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze( const std::optional &kindParam, KindParam defaultKind, KindParam kanjiKind) { if (!kindParam.has_value()) { return defaultKind; } return std::visit( common::visitors{ [](std::uint64_t k) { return static_cast(k); }, [&](const parser::Scalar< parser::Integer>> &n) { if (Result oge{AnalyzeHelper(*this, n)}) { if (std::optional ogs{ oge->ScalarValue()}) { // TODO pmk more here next } } return defaultKind; }, [&](parser::KindParam::Kanji) { if (kanjiKind >= 0) { return kanjiKind; } context().messages.Say("Kanji not allowed here"_err_en_US); return defaultKind; }}, kindParam->u); } } // namespace Fortran::semantics