[flang] Expression analysis
Original-commit: flang-compiler/f18@6b5e23ba28 Reviewed-on: https://github.com/flang-compiler/f18/pull/165 Tree-same-pre-rewrite: false
This commit is contained in:
parent
ce0b722997
commit
27be6855bf
|
@ -18,6 +18,7 @@ add_library(FortranEvaluate
|
|||
integer.cc
|
||||
logical.cc
|
||||
real.cc
|
||||
type.cc
|
||||
variable.cc
|
||||
)
|
||||
|
||||
|
|
41
flang/lib/evaluate/type.cc
Normal file
41
flang/lib/evaluate/type.cc
Normal file
|
@ -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 <cinttypes>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
std::optional<std::int64_t> GenericScalar::ToInt64() const {
|
||||
if (const auto *j{std::get_if<ScalarConstant<TypeCategory::Integer>>(&u)}) {
|
||||
return std::visit(
|
||||
[](const auto &k) { return std::optional<std::int64_t>{k.ToInt64()}; },
|
||||
j->u);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> GenericScalar::ToString() const {
|
||||
if (const auto *c{std::get_if<ScalarConstant<TypeCategory::Character>>(&u)}) {
|
||||
if (const std::string * s{std::get_if<std::string>(&c->u)}) {
|
||||
return std::optional<std::string>{*s};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Fortran::evaluate
|
|
@ -26,6 +26,8 @@
|
|||
#include "real.h"
|
||||
#include "../common/fortran.h"
|
||||
#include "../common/idioms.h"
|
||||
#include <cinttypes>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
|
@ -180,6 +182,10 @@ struct GenericScalar {
|
|||
template<typename A>
|
||||
GenericScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: u{std::move(x)} {}
|
||||
|
||||
std::optional<std::int64_t> ToInt64() const;
|
||||
std::optional<std::string> ToString() const;
|
||||
|
||||
std::variant<ScalarConstant<TypeCategory::Integer>,
|
||||
ScalarConstant<TypeCategory::Real>, ScalarConstant<TypeCategory::Complex>,
|
||||
ScalarConstant<TypeCategory::Character>,
|
||||
|
|
|
@ -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<typename A> 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<typename A>
|
||||
std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const A &tree) {
|
||||
return ea.Analyze(tree);
|
||||
Result AnalyzeHelper(ExpressionAnalyzer &ea, const std::optional<A> &x) {
|
||||
if (x.has_value()) {
|
||||
return AnalyzeHelper(ea, *x);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::Scalar<A> &tree) {
|
||||
std::optional<evaluate::GenericExpr> result{AnalyzeHelper(ea, tree.thing)};
|
||||
Result AnalyzeHelper(ExpressionAnalyzer &ea, const common::Indirection<A> &p) {
|
||||
return AnalyzeHelper(ea, *p);
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Scalar<A> &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<evaluate::GenericExpr> AnalyzeHelper(
|
|||
}
|
||||
|
||||
template<typename A>
|
||||
std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::Constant<A> &tree) {
|
||||
std::optional<evaluate::GenericExpr> result{AnalyzeHelper(ea, tree.thing)};
|
||||
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Constant<A> &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<evaluate::GenericExpr> AnalyzeHelper(
|
|||
}
|
||||
|
||||
template<typename A>
|
||||
std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::Integer<A> &tree) {
|
||||
std::optional<evaluate::GenericExpr> result{AnalyzeHelper(ea, tree.thing)};
|
||||
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Integer<A> &tree) {
|
||||
Result result{AnalyzeHelper(ea, tree.thing)};
|
||||
if (result.has_value() &&
|
||||
!std::holds_alternative<evaluate::AnyKindIntegerExpr>(result->u)) {
|
||||
ea.context().messages.Say("must be integer"_err_en_US);
|
||||
|
@ -65,44 +83,27 @@ std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
|||
}
|
||||
|
||||
template<>
|
||||
std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::Name &n) {
|
||||
// TODO
|
||||
Result AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::CharLiteralConstantSubstring &x) {
|
||||
const auto &range{std::get<parser::SubstringRange>(x.t)};
|
||||
if (!std::get<0>(range.t).has_value() && !std::get<1>(range.t).has_value()) {
|
||||
// "..."(:)
|
||||
return AnalyzeHelper(ea, std::get<parser::CharLiteralConstant>(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<evaluate::GenericScalar> lb{lower->ScalarValue()}) {
|
||||
if (std::optional<evaluate::GenericScalar> ub{upper->ScalarValue()}) {
|
||||
// TODO pmk continue here with ToInt64()
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
|
||||
const std::optional<parser::KindParam> &kindParam, KindParam defaultKind,
|
||||
KindParam kanjiKind) {
|
||||
if (!kindParam.has_value()) {
|
||||
return defaultKind;
|
||||
}
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](std::uint64_t k) { return static_cast<KindParam>(k); },
|
||||
[&](const parser::Scalar<
|
||||
parser::Integer<parser::Constant<parser::Name>>> &n) {
|
||||
if (std::optional<evaluate::GenericExpr> oge{
|
||||
AnalyzeHelper(*this, n)}) {
|
||||
if (std::optional<evaluate::GenericScalar> 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<evaluate::GenericExpr> AnalyzeHelper(
|
||||
Result AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) {
|
||||
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
||||
ea.defaultIntegerKind())};
|
||||
|
@ -123,8 +124,7 @@ std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
|||
}
|
||||
|
||||
template<>
|
||||
std::optional<evaluate::GenericExpr> 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<evaluate::GenericExpr> AnalyzeHelper(
|
|||
// TODO next [&](const parser::RealLiteralConstant &c) { return
|
||||
// AnalyzeHelper(ea, c); },
|
||||
// TODO: remaining cases
|
||||
[&](const auto &) { return std::optional<evaluate::GenericExpr>{}; }},
|
||||
[&](const auto &) { return Result{}; }},
|
||||
x.u);
|
||||
}
|
||||
|
||||
std::optional<evaluate::GenericExpr> 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<evaluate::GenericExpr>{}; }},
|
||||
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<parser::KindParam> &kindParam, KindParam defaultKind,
|
||||
KindParam kanjiKind) {
|
||||
if (!kindParam.has_value()) {
|
||||
return defaultKind;
|
||||
}
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](std::uint64_t k) { return static_cast<KindParam>(k); },
|
||||
[&](const parser::Scalar<
|
||||
parser::Integer<parser::Constant<parser::Name>>> &n) {
|
||||
if (Result oge{AnalyzeHelper(*this, n)}) {
|
||||
if (std::optional<evaluate::GenericScalar> 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
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace Fortran::semantics {
|
|||
class ExpressionAnalyzer {
|
||||
public:
|
||||
using KindParam = std::int64_t;
|
||||
using Result = std::optional<evaluate::GenericExpr>;
|
||||
|
||||
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<evaluate::GenericExpr> Analyze(const parser::Expr &);
|
||||
Result Analyze(const parser::Expr &);
|
||||
KindParam Analyze(const std::optional<parser::KindParam> &,
|
||||
KindParam defaultKind, KindParam kanjiKind = -1 /* not allowed here */);
|
||||
|
||||
|
|
Loading…
Reference in a new issue