llvm/flang/lib/semantics/expression.cc
peter klausler 27be6855bf [flang] Expression analysis
Original-commit: flang-compiler/f18@6b5e23ba28
Reviewed-on: https://github.com/flang-compiler/f18/pull/165
Tree-same-pre-rewrite: false
2018-08-09 10:15:03 -07:00

365 lines
9.5 KiB
C++

// 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<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>
Result AnalyzeHelper(ExpressionAnalyzer &ea, const std::optional<A> &x) {
if (x.has_value()) {
return AnalyzeHelper(ea, *x);
} else {
return std::nullopt;
}
}
template<typename A>
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);
return std::nullopt;
}
}
return result;
}
template<typename A>
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()) {
ea.context().messages.Say("must be constant"_err_en_US);
return std::nullopt;
}
}
return result;
}
template<typename A>
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);
return std::nullopt;
}
return result;
}
template<>
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;
}
template<>
Result AnalyzeHelper(
ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) {
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
ea.defaultIntegerKind())};
std::uint64_t value{std::get<std::uint64_t>(x.t)};
switch (kind) {
#define CASE(k) \
case k: \
return {evaluate::GenericExpr{ \
evaluate::AnyKindIntegerExpr{evaluate::IntegerExpr<k>{value}}}};
FOR_EACH_INTEGER_KIND(CASE, )
#undef CASE
default:
ea.context().messages.Say(parser::MessageFormattedText{
"unimplemented INTEGER kind (%ju)"_err_en_US,
static_cast<std::uintmax_t>(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<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