template<typename T> std::ostream &Constant<T>::Dump(std::ostream &o) const {
if constexpr (T::category == TypeCategory::Integer) {
- return o << value.SignedDecimal() << '_' << Result::kind;
+ return o << value.SignedDecimal() << '_' << T::kind;
} else if constexpr (T::category == TypeCategory::Real ||
T::category == TypeCategory::Complex) {
- return o << value.DumpHexadecimal() << '_' << Result::kind;
+ return o << value.DumpHexadecimal() << '_' << T::kind;
} else if constexpr (T::category == TypeCategory::Character) {
- return o << Result::kind << '_' << parser::QuoteCharacterLiteral(value);
+ if constexpr (T::kind == 1) {
+ return o << T::kind << '_' << parser::QuoteCharacterLiteral(value);
+ } else {
+ return o << T::kind
+ << "_'(wide character dumping unimplemented)'"; // TODO
+ }
} else if constexpr (T::category == TypeCategory::Logical) {
if (value.IsTrue()) {
o << ".TRUE.";
template class Expr<Type<TypeCategory::Complex, 8>>;
template class Expr<Type<TypeCategory::Complex, 10>>;
template class Expr<Type<TypeCategory::Complex, 16>>;
-template class Expr<Type<TypeCategory::Character, 1>>; // TODO others
+template class Expr<Type<TypeCategory::Character, 1>>;
+template class Expr<Type<TypeCategory::Character, 2>>;
+template class Expr<Type<TypeCategory::Character, 4>>;
template class Expr<Type<TypeCategory::Logical, 1>>;
template class Expr<Type<TypeCategory::Logical, 2>>;
template class Expr<Type<TypeCategory::Logical, 4>>;
template struct Relational<Type<TypeCategory::Real, 8>>;
template struct Relational<Type<TypeCategory::Real, 10>>;
template struct Relational<Type<TypeCategory::Real, 16>>;
-template struct Relational<Type<TypeCategory::Character, 1>>; // TODO others
+template struct Relational<Type<TypeCategory::Character, 1>>;
+template struct Relational<Type<TypeCategory::Character, 2>>;
+template struct Relational<Type<TypeCategory::Character, 4>>;
template struct Relational<SomeType>;
template struct ExpressionBase<Type<TypeCategory::Integer, 1>>;
u;
};
-extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO more
+extern template class Expr<Type<TypeCategory::Character, 1>>;
+extern template class Expr<Type<TypeCategory::Character, 2>>;
+extern template class Expr<Type<TypeCategory::Character, 4>>;
// The Relational class template is a helper for constructing logical
// expressions with polymorphism over the cross product of the possible
};
template<> class Relational<SomeType> {
- // COMPLEX data is compared piecewise.
+ // COMPLEX data are compared piecewise.
using DirectlyComparableTypes =
common::CombineTuples<IntegerTypes, RealTypes, CharacterTypes>;
extern template struct Relational<Type<TypeCategory::Real, 8>>;
extern template struct Relational<Type<TypeCategory::Real, 10>>;
extern template struct Relational<Type<TypeCategory::Real, 16>>;
-extern template struct Relational<Type<TypeCategory::Character, 1>>; // TODO
- // more
+extern template struct Relational<Type<TypeCategory::Character, 1>>;
+extern template struct Relational<Type<TypeCategory::Character, 2>>;
+extern template struct Relational<Type<TypeCategory::Character, 4>>;
extern template struct Relational<SomeType>;
template<int KIND>
std::move(x.u));
}
+Expr<SomeLogical> LogicalNegation(Expr<SomeLogical> &&x) {
+ return std::visit(
+ [](auto &&xk) {
+ return AsCategoryExpr(
+ AsExpr(Not<ResultType<decltype(xk)>::kind>{std::move(xk)}));
+ },
+ std::move(x.u));
+}
+
template<typename T>
Expr<LogicalResult> PackageRelation(
RelationalOperator opr, Expr<T> &&x, Expr<T> &&y) {
// Generalizing packagers: these take operations and expressions of more
// specific types and wrap them in Expr<> containers of more abstract types.
-// TODO: Would these be better as conversion constructors in the classes?
-// TODO: Are the lvalue argument versions still needed?
-template<typename A> Expr<ResultType<A>> AsExpr(const A &x) { return {x}; }
template<typename A> Expr<ResultType<A>> AsExpr(A &&x) {
return {std::move(x)};
}
-template<TypeCategory CAT, int KIND>
-Expr<SomeKind<CAT>> AsCategoryExpr(const Expr<Type<CAT, KIND>> &x) {
- return {x};
-}
-
template<TypeCategory CAT, int KIND>
Expr<SomeKind<CAT>> AsCategoryExpr(Expr<Type<CAT, KIND>> &&x) {
return {std::move(x)};
x.u);
}
-template<typename A> Expr<SomeType> AsGenericExpr(const A &x) { return {x}; }
-
template<typename A> Expr<SomeType> AsGenericExpr(A &&x) {
return {std::move(x)};
}
-template<TypeCategory CAT, int KIND>
-Expr<SomeType> AsGenericExpr(const Expr<Type<CAT, KIND>> &x) {
- return {AsCategoryExpr(x)};
-}
template<TypeCategory CAT, int KIND>
Expr<SomeType> AsGenericExpr(Expr<Type<CAT, KIND>> &&x) {
return {AsCategoryExpr(std::move(x))};
std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &,
RelationalOperator, Expr<SomeType> &&, Expr<SomeType> &&);
+Expr<SomeLogical> LogicalNegation(Expr<SomeLogical> &&);
Expr<SomeLogical> BinaryLogicalOperation(
LogicalOperator, Expr<SomeLogical> &&, Expr<SomeLogical> &&);
using Scalar = value::Complex<typename Part::Scalar>;
};
-template<int KIND>
-struct Type<TypeCategory::Character, KIND>
- : public TypeBase<TypeCategory::Character, KIND> {
+template<>
+struct Type<TypeCategory::Character, 1>
+ : public TypeBase<TypeCategory::Character, 1> {
using Scalar = std::string;
};
+template<>
+struct Type<TypeCategory::Character, 2>
+ : public TypeBase<TypeCategory::Character, 2> {
+ using Scalar = std::u16string;
+};
+
+template<>
+struct Type<TypeCategory::Character, 4>
+ : public TypeBase<TypeCategory::Character, 4> {
+ using Scalar = std::u32string;
+};
+
template<int KIND>
struct Type<TypeCategory::Logical, KIND>
: public TypeBase<TypeCategory::Logical, KIND> {
std::ostream &Dump(std::ostream &) const;
private:
+ // TODO: character kinds > 1
std::variant<DataRef, std::string> u_;
std::optional<IndirectSubscriptIntegerExpr> first_, last_;
};
} // namespace Fortran::evaluate
-// This inclusion must follow the definitions in this header due to
-// mutual references.
-#include "expression.h"
-
#endif // FORTRAN_EVALUATE_VARIABLE_H_
return std::nullopt;
}
-MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::NOT &) {
- context.messages.Say("pmk: NOT unimplemented\n"_err_en_US);
+MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::NOT &x) {
+ if (MaybeExpr operand{AnalyzeHelper(*this, *x.v)}) {
+ return std::visit(common::visitors{[](Expr<SomeLogical> &&lx) -> MaybeExpr {
+ return {AsGenericExpr(
+ LogicalNegation(std::move(lx)))};
+ },
+ [=](auto &&) -> MaybeExpr {
+ // TODO pmk: INTEGER operand for bitwise extension?
+ context.messages.Say(
+ "Operand of .NOT. must be LOGICAL"_err_en_US);
+ return std::nullopt;
+ }},
+ std::move(operand->u));
+ }
return std::nullopt;
}
AnalyzeHelper(*this, *std::get<1>(x.t))));
}
-MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Concat &) {
- context.messages.Say("pmk: Concat unimplemented\n"_err_en_US);
+MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Concat &x) {
+ if (auto both{common::AllPresent(AnalyzeHelper(*this, *std::get<0>(x.t)),
+ AnalyzeHelper(*this, *std::get<1>(x.t)))}) {
+ return std::visit(
+ common::visitors{
+ [&](Expr<SomeCharacter> &&cx, Expr<SomeCharacter> &&cy) {
+ return std::visit(
+ [&](auto &&cxk, auto &&cyk) -> MaybeExpr {
+ using Ty = ResultType<decltype(cxk)>;
+ if constexpr (std::is_same_v<Ty,
+ ResultType<decltype(cyk)>>) {
+ return {AsGenericExpr(AsCategoryExpr(AsExpr(
+ Concat<Ty::kind>{std::move(cxk), std::move(cyk)})))};
+ } else {
+ context.messages.Say(
+ "Operands of // must be the same kind of CHARACTER"_err_en_US);
+ return std::nullopt;
+ }
+ },
+ std::move(cx.u), std::move(cy.u));
+ },
+ [&](auto &&, auto &&) -> MaybeExpr {
+ context.messages.Say(
+ "Operands of // must be CHARACTER"_err_en_US);
+ return std::nullopt;
+ },
+ },
+ std::move(std::get<0>(*both).u), std::move(std::get<1>(*both).u));
+ }
return std::nullopt;
}