From 27be6855bfe993fba43e10bce77c407055681c1f Mon Sep 17 00:00:00 2001 From: peter klausler Date: Tue, 7 Aug 2018 12:34:09 -0700 Subject: [PATCH] [flang] Expression analysis Original-commit: flang-compiler/f18@6b5e23ba28943f510a23a47daeb43d3a5dff72c2 Reviewed-on: https://github.com/flang-compiler/f18/pull/165 Tree-same-pre-rewrite: false --- flang/lib/evaluate/CMakeLists.txt | 1 + flang/lib/evaluate/type.cc | 41 ++++ flang/lib/evaluate/type.h | 6 + flang/lib/semantics/expression.cc | 330 ++++++++++++++++++++++++------ flang/lib/semantics/expression.h | 4 +- 5 files changed, 324 insertions(+), 58 deletions(-) create mode 100644 flang/lib/evaluate/type.cc diff --git a/flang/lib/evaluate/CMakeLists.txt b/flang/lib/evaluate/CMakeLists.txt index fef2c87531e9..12631a39de3a 100644 --- a/flang/lib/evaluate/CMakeLists.txt +++ b/flang/lib/evaluate/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(FortranEvaluate integer.cc logical.cc real.cc + type.cc variable.cc ) diff --git a/flang/lib/evaluate/type.cc b/flang/lib/evaluate/type.cc new file mode 100644 index 000000000000..58f9992d31b8 --- /dev/null +++ b/flang/lib/evaluate/type.cc @@ -0,0 +1,41 @@ +// 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 "type.h" +#include "../common/idioms.h" +#include +#include +#include + +namespace Fortran::evaluate { + +std::optional GenericScalar::ToInt64() const { + if (const auto *j{std::get_if>(&u)}) { + return std::visit( + [](const auto &k) { return std::optional{k.ToInt64()}; }, + j->u); + } + return std::nullopt; +} + +std::optional GenericScalar::ToString() const { + if (const auto *c{std::get_if>(&u)}) { + if (const std::string * s{std::get_if(&c->u)}) { + return std::optional{*s}; + } + } + return std::nullopt; +} + +} // namespace Fortran::evaluate diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 2f9b3916460e..d3ff8481ace3 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -26,6 +26,8 @@ #include "real.h" #include "../common/fortran.h" #include "../common/idioms.h" +#include +#include #include #include @@ -180,6 +182,10 @@ struct GenericScalar { template GenericScalar(std::enable_if_t, A> &&x) : u{std::move(x)} {} + + std::optional ToInt64() const; + std::optional ToString() const; + std::variant, ScalarConstant, ScalarConstant, ScalarConstant, diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 7a74e017348d..7ab2ad754949 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -19,16 +19,36 @@ 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 -std::optional AnalyzeHelper( - ExpressionAnalyzer &ea, const A &tree) { - return ea.Analyze(tree); +Result AnalyzeHelper(ExpressionAnalyzer &ea, const std::optional &x) { + if (x.has_value()) { + return AnalyzeHelper(ea, *x); + } else { + return std::nullopt; + } } template -std::optional AnalyzeHelper( - ExpressionAnalyzer &ea, const parser::Scalar &tree) { - std::optional result{AnalyzeHelper(ea, tree.thing)}; +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); @@ -39,9 +59,8 @@ std::optional AnalyzeHelper( } template -std::optional AnalyzeHelper( - ExpressionAnalyzer &ea, const parser::Constant &tree) { - std::optional result{AnalyzeHelper(ea, tree.thing)}; +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()) { @@ -53,9 +72,8 @@ std::optional AnalyzeHelper( } template -std::optional AnalyzeHelper( - ExpressionAnalyzer &ea, const parser::Integer &tree) { - std::optional result{AnalyzeHelper(ea, tree.thing)}; +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); @@ -65,44 +83,27 @@ std::optional AnalyzeHelper( } template<> -std::optional AnalyzeHelper( - ExpressionAnalyzer &ea, const parser::Name &n) { - // TODO +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; } -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 (std::optional 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); -} - template<> -std::optional AnalyzeHelper( +Result AnalyzeHelper( ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) { auto kind{ea.Analyze(std::get>(x.t), ea.defaultIntegerKind())}; @@ -123,8 +124,7 @@ std::optional AnalyzeHelper( } template<> -std::optional AnalyzeHelper( - ExpressionAnalyzer &ea, const parser::LiteralConstant &x) { +Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::LiteralConstant &x) { return std::visit( common::visitors{[&](const parser::IntLiteralConstant &c) { return AnalyzeHelper(ea, c); @@ -132,18 +132,234 @@ std::optional AnalyzeHelper( // TODO next [&](const parser::RealLiteralConstant &c) { return // AnalyzeHelper(ea, c); }, // TODO: remaining cases - [&](const auto &) { return std::optional{}; }}, + [&](const auto &) { return Result{}; }}, x.u); } -std::optional 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 std::optional{}; }}, +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 diff --git a/flang/lib/semantics/expression.h b/flang/lib/semantics/expression.h index e4c54457e126..4adb4fde05f7 100644 --- a/flang/lib/semantics/expression.h +++ b/flang/lib/semantics/expression.h @@ -26,6 +26,8 @@ namespace Fortran::semantics { class ExpressionAnalyzer { public: using KindParam = std::int64_t; + using Result = std::optional; + ExpressionAnalyzer(evaluate::FoldingContext &c, KindParam dIK) : context_{c}, defaultIntegerKind_{dIK} {} @@ -34,7 +36,7 @@ public: // Performs semantic checking on an expression. If successful, // returns its typed expression representation. - std::optional Analyze(const parser::Expr &); + Result Analyze(const parser::Expr &); KindParam Analyze(const std::optional &, KindParam defaultKind, KindParam kanjiKind = -1 /* not allowed here */);