// Copyright (c) 2018-2019, 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.h" #include "int-power.h" #include "tools.h" #include "variable.h" #include "../common/idioms.h" #include "../parser/message.h" #include #include #include #include using namespace Fortran::parser::literals; namespace Fortran::evaluate { // AsFortran() formatting template std::ostream &Operation::AsFortran(std::ostream &o) const { left().AsFortran(derived().Prefix(o)); if constexpr (operands > 1) { right().AsFortran(derived().Infix(o)); } return derived().Suffix(o); } template std::ostream &Convert::AsFortran(std::ostream &o) const { static_assert(TO::category == TypeCategory::Integer || TO::category == TypeCategory::Real || TO::category == TypeCategory::Character || TO::category == TypeCategory::Logical || !"Convert<> to bad category!"); if constexpr (TO::category == TypeCategory::Character) { this->left().AsFortran(o << "achar(iachar(") << ')'; } else if constexpr (TO::category == TypeCategory::Integer) { this->left().AsFortran(o << "int("); } else if constexpr (TO::category == TypeCategory::Real) { this->left().AsFortran(o << "real("); } else { this->left().AsFortran(o << "logical("); } return o << ",kind=" << TO::kind << ')'; } template std::ostream &Relational::Infix(std::ostream &o) const { switch (opr) { case RelationalOperator::LT: o << '<'; break; case RelationalOperator::LE: o << "<="; break; case RelationalOperator::EQ: o << "=="; break; case RelationalOperator::NE: o << "/="; break; case RelationalOperator::GE: o << ">="; break; case RelationalOperator::GT: o << '>'; break; } return o; } std::ostream &Relational::AsFortran(std::ostream &o) const { std::visit([&](const auto &rel) { rel.AsFortran(o); }, u); return o; } template std::ostream &LogicalOperation::Infix(std::ostream &o) const { switch (logicalOperator) { case LogicalOperator::And: o << ".and."; break; case LogicalOperator::Or: o << ".or."; break; case LogicalOperator::Eqv: o << ".eqv."; break; case LogicalOperator::Neqv: o << ".neqv."; break; } return o; } template std::ostream &Emit(std::ostream &o, const CopyableIndirection> &expr) { return expr.value().AsFortran(o); } template std::ostream &Emit(std::ostream &, const ArrayConstructorValues &); template std::ostream &Emit(std::ostream &o, const ImpliedDo &implDo) { o << '('; Emit(o, implDo.values()); o << ',' << ImpliedDoIndex::Result::AsFortran() << "::" << implDo.name().ToString() << '='; implDo.lower().AsFortran(o) << ','; implDo.upper().AsFortran(o) << ','; implDo.stride().AsFortran(o) << ')'; return o; } template std::ostream &Emit(std::ostream &o, const ArrayConstructorValues &values) { const char *sep{""}; for (const auto &value : values.values()) { o << sep; std::visit([&](const auto &x) { Emit(o, x); }, value.u); sep = ","; } return o; } template std::ostream &ArrayConstructor::AsFortran(std::ostream &o) const { o << '[' << GetType().AsFortran() << "::"; Emit(o, *this); return o << ']'; } template std::ostream &ArrayConstructor>::AsFortran( std::ostream &o) const { std::stringstream len; LEN().AsFortran(len); o << '[' << GetType().AsFortran(len.str()) << "::"; Emit(o, *this); return o << ']'; } std::ostream &ArrayConstructor::AsFortran(std::ostream &o) const { o << '[' << GetType().AsFortran() << "::"; Emit(o, *this); return o << ']'; } template std::ostream &ExpressionBase::AsFortran(std::ostream &o) const { std::visit( common::visitors{ [&](const BOZLiteralConstant &x) { o << "z'" << x.Hexadecimal() << "'"; }, [&](const NullPointer &) { o << "NULL()"; }, [&](const CopyableIndirection &s) { s.value().AsFortran(o); }, [&](const ImpliedDoIndex &i) { o << i.name.ToString(); }, [&](const auto &x) { x.AsFortran(o); }, }, derived().u); return o; } template Expr Expr>::LEN() const { return std::visit( common::visitors{ [](const Constant &c) { return AsExpr(Constant{c.LEN()}); }, [](const ArrayConstructor &a) { return a.LEN(); }, [](const Parentheses &x) { return x.left().LEN(); }, [](const Convert &x) { return std::visit( [&](const auto &kx) { return kx.LEN(); }, x.left().u); }, [](const Concat &c) { return c.left().LEN() + c.right().LEN(); }, [](const Extremum &c) { return Expr{ Extremum{c.left().LEN(), c.right().LEN()}}; }, [](const Designator &dr) { return dr.LEN(); }, [](const FunctionRef &fr) { return fr.LEN(); }, [](const SetLength &x) { return x.right(); }, }, u); } Expr::~Expr() {} #if defined(__APPLE__) && defined(__GNUC__) template typename ExpressionBase::Derived &ExpressionBase::derived() { return *static_cast(this); } template const typename ExpressionBase::Derived &ExpressionBase::derived() const { return *static_cast(this); } #endif template std::optional ExpressionBase::GetType() const { if constexpr (IsLengthlessIntrinsicType) { return Result::GetType(); } else { return std::visit( [](const auto &x) -> std::optional { using Ty = std::decay_t; if constexpr (!std::is_same_v && !std::is_same_v) { return x.GetType(); } return std::nullopt; // typeless really means "no type" }, derived().u); } } template int ExpressionBase::Rank() const { return std::visit( [](const auto &x) { if constexpr (std::is_same_v, BOZLiteralConstant>) { return 0; } else { return x.Rank(); } }, derived().u); } // Equality testing for classes without EVALUATE_UNION_CLASS_BOILERPLATE() bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const { return name == that.name; } template bool ImpliedDo::operator==(const ImpliedDo &that) const { return name_ == that.name_ && lower_ == that.lower_ && upper_ == that.upper_ && stride_ == that.stride_ && values_ == that.values_; } template bool ArrayConstructorValues::operator==( const ArrayConstructorValues &that) const { return values_ == that.values_; } template bool ArrayConstructor>::operator==( const ArrayConstructor &that) const { return length_ == that.length_ && static_cast(*this) == static_cast(that); } bool ArrayConstructor::operator==( const ArrayConstructor &that) const { return derivedTypeSpec_ == that.derivedTypeSpec_ && static_cast(*this) == static_cast(that); ; } StructureConstructor::StructureConstructor( const semantics::DerivedTypeSpec &spec, const StructureConstructorValues &values) : derivedTypeSpec_{&spec}, values_{values} {} StructureConstructor::StructureConstructor( const semantics::DerivedTypeSpec &spec, StructureConstructorValues &&values) : derivedTypeSpec_{&spec}, values_{std::move(values)} {} bool StructureConstructor::operator==(const StructureConstructor &that) const { return derivedTypeSpec_ == that.derivedTypeSpec_ && values_ == that.values_; } DynamicType StructureConstructor::GetType() const { return DynamicType{*derivedTypeSpec_}; } StructureConstructor &StructureConstructor::Add( const Symbol &symbol, Expr &&expr) { values_.emplace(&symbol, std::move(expr)); return *this; } std::ostream &StructureConstructor::AsFortran(std::ostream &o) const { DerivedTypeSpecAsFortran(o, *derivedTypeSpec_); if (values_.empty()) { o << '('; } else { char ch{'('}; for (const auto &[symbol, value] : values_) { value.value().AsFortran(o << ch << symbol->name().ToString() << '='); ch = ','; } } return o << ')'; } std::ostream &DerivedTypeSpecAsFortran( std::ostream &o, const semantics::DerivedTypeSpec &spec) { o << spec.typeSymbol().name().ToString(); if (!spec.parameters().empty()) { char ch{'('}; for (const auto &[name, value] : spec.parameters()) { value.GetExplicit()->AsFortran(o << ch << name.ToString() << '='); ch = ','; } o << ')'; } return o; } bool GenericExprWrapper::operator==(const GenericExprWrapper &that) const { return v == that.v; } // Template instantiations to resolve the "extern template" declarations // that appear in expression.h. FOR_EACH_INTRINSIC_KIND(template class Expr) FOR_EACH_CATEGORY_TYPE(template class Expr) FOR_EACH_INTEGER_KIND(template struct Relational) FOR_EACH_REAL_KIND(template struct Relational) FOR_EACH_CHARACTER_KIND(template struct Relational) template struct Relational; FOR_EACH_TYPE_AND_KIND(template class ExpressionBase) FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues) FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor) } // For reclamation of analyzed expressions to which owning pointers have // been embedded in the parse tree. This destructor appears here, where // definitions for all the necessary types are available, to obviate a // need to include lib/evaluate/*.h headers in the parser proper. DEFINE_OWNING_SPECIAL_FUNCTIONS(OwningPointer, evaluate::GenericExprWrapper)