From cfb57cd2d37e3aa3845f771413b5f97ceba5984f Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 1 Nov 2018 11:18:12 -0700 Subject: [PATCH] [flang] take literal substrings out of variable.h Original-commit: flang-compiler/f18@a762b70bebc5428adec75b85801aef8ee88bcf42 Reviewed-on: https://github.com/flang-compiler/f18/pull/225 Tree-same-pre-rewrite: false --- flang/lib/evaluate/expression.cc | 23 ++-- flang/lib/evaluate/expression.h | 28 ++++- flang/lib/evaluate/fold.cc | 68 ++++++++---- flang/lib/evaluate/type.h | 15 +-- flang/lib/evaluate/variable.cc | 173 ++++++++++-------------------- flang/lib/evaluate/variable.h | 51 ++++----- flang/lib/parser/characters.cc | 22 +++- flang/lib/parser/characters.h | 20 +++- flang/lib/semantics/expression.cc | 43 ++++++-- 9 files changed, 248 insertions(+), 195 deletions(-) diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 059bdf316682..d0a64b507579 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -58,6 +58,11 @@ template std::ostream &Relational::Infix(std::ostream &o) const { return o << '.' << EnumToString(opr) << '.'; } +template +std::ostream &LiteralSubstring::Prefix(std::ostream &o) const { + return o << KIND << '_' << parser::QuoteCharacterLiteral(string) << '('; +} + std::ostream &Relational::Dump(std::ostream &o) const { std::visit([&](const auto &rel) { rel.Dump(o); }, u); return o; @@ -81,12 +86,7 @@ template std::ostream &Constant::Dump(std::ostream &o) const { T::category == TypeCategory::Complex) { return o << value.DumpHexadecimal() << '_' << T::kind; } else if constexpr (T::category == TypeCategory::Character) { - if constexpr (T::kind == 1) { - return o << T::kind << '_' << parser::QuoteCharacterLiteral(value); - } else { - return o << T::kind - << "_'(wide character dumping unimplemented)'"; // TODO - } + return o << T::kind << '_' << parser::QuoteCharacterLiteral(value); } else if constexpr (T::category == TypeCategory::Logical) { if (value.IsTrue()) { o << ".TRUE."; @@ -149,10 +149,16 @@ std::ostream &ExpressionBase::Dump(std::ostream &o) const { } template Expr ArrayConstructor::LEN() const { - // TODO pmk: extract from type spec + // TODO pmk: extract from type spec in array constructor return AsExpr(Constant{0}); // TODO placeholder } +template Expr LiteralSubstring::LEN() const { + auto lower{this->left()}; + auto upper{this->right()}; + return std::move(upper) - std::move(lower) + Expr{1}; +} + template Expr Expr>::LEN() const { return std::visit( @@ -160,6 +166,7 @@ Expr Expr>::LEN() const { return AsExpr( Constant{c.value.size()}); }, + [](const LiteralSubstring &ls) { return ls.LEN(); }, [](const ArrayConstructor &a) { return a.LEN(); }, [](const Parentheses &x) { return x.left().LEN(); }, [](const Concat &c) { @@ -178,7 +185,7 @@ Expr::~Expr() {} template DynamicType ArrayConstructor::GetType() const { // TODO: pmk: parameterized derived types, CHARACTER length - return *result.GetType(); + return result.GetType(); } template diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 436617eb1f0f..f2ae391e8cf8 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -357,6 +357,25 @@ struct Concat static std::ostream &Infix(std::ostream &o) { return o << "//"; } }; +template +struct LiteralSubstring : public Operation, + Type, + SubscriptInteger, SubscriptInteger> { + using Result = Type; + using Operand = SubscriptInteger; + using String = Scalar; + using Base = Operation; + LiteralSubstring( + const String &s, const Expr &lower, const Expr &upper) + : string{s}, Base{lower, upper} {} + LiteralSubstring(String &&s, Expr &&lower, Expr &&upper) + : Base{std::move(lower), std::move(upper)}, string{std::move(s)} {} + + std::ostream &Prefix(std::ostream &) const; + Expr LEN() const; + String string; +}; + ENUM_CLASS(LogicalOperator, And, Or, Eqv, Neqv) template @@ -508,8 +527,9 @@ public: Expr LEN() const; - std::variant, ArrayConstructor, Designator, - FunctionRef, Parentheses, Concat, Extremum> + std::variant, LiteralSubstring, + ArrayConstructor, Designator, FunctionRef, + Parentheses, Concat, Extremum> u; }; @@ -551,9 +571,7 @@ template<> class Relational { public: using Result = LogicalResult; EVALUATE_UNION_CLASS_BOILERPLATE(Relational) - static constexpr std::optional GetType() { - return Result::GetType(); - } + static constexpr DynamicType GetType() { return Result::GetType(); } int Rank() const { return std::visit([](const auto &x) { return x.Rank(); }, u); } diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 40becd30c992..45e822505b12 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -34,25 +34,17 @@ Expr> FoldOperation(FoldingContext &, A &&x) { } // Designators -// At the moment, only substrings fold. -// TODO: Parameters, KIND type parameters +// At the moment, only empty substrings fold. +// TODO: Parameters, KIND type parameters, substrings of parameters template Expr> FoldOperation(FoldingContext &context, Designator> &&designator) { using CHAR = Type; if (auto *substring{std::get_if(&designator.u)}) { - if (auto folded{substring->Fold(context)}) { - if (auto *string{std::get_if>(&*folded)}) { - return Expr{Constant{std::move(*string)}}; - } - // A zero-length substring of an arbitrary data reference can - // be folded, but the C++ string type of the empty value will be - // std::string and that may not be right for multi-byte CHARACTER - // kinds. - if (auto length{ToInt64(Fold(context, substring->LEN()))}) { - if (*length == 0) { - return Expr{Constant{Scalar{}}}; - } + substring->Fold(context); + if (auto length{ToInt64(Fold(context, substring->LEN()))}) { + if (*length == 0) { + return Expr{Constant{Scalar{}}}; } } } @@ -353,22 +345,56 @@ Expr FoldOperation(FoldingContext &context, Extremum &&x) { template Expr> FoldOperation( FoldingContext &context, ComplexConstructor &&x) { - using COMPLEX = Type; + using Result = Type; if (auto folded{FoldOperands(context, x.left(), x.right())}) { - return Expr{ - Constant{Scalar{folded->first, folded->second}}}; + return Expr{ + Constant{Scalar{folded->first, folded->second}}}; } - return Expr{std::move(x)}; + return Expr{std::move(x)}; +} + +template +Expr> FoldOperation( + FoldingContext &context, LiteralSubstring &&x) { + using Result = Type; + x.left() = Fold(context, std::move(x.left())); + x.right() = Fold(context, std::move(x.right())); + auto lower{ToInt64(x.left())}; + auto upper{ToInt64(x.left())}; + if (lower.has_value() && *lower < 1) { + context.messages.Say("lower bound (%jd) on literal substring " + "is less than one"_en_US, + static_cast(*lower)); + lower = 1; + } + if (upper.has_value()) { + if (*upper < 1 || (lower.has_value() && *upper < *lower)) { + return Expr{Constant(Scalar{})}; + } + std::int64_t len = x.string.size(); + if (*upper > len) { + context.messages.Say("upper bound (%jd) on substring " + "is greater than character length (%jd)"_en_US, + static_cast(*upper), static_cast(len)); + upper = len; + } + if (lower.has_value()) { + Scalar substring{ + x.string.substr(*lower - 1, *upper - *lower + 1)}; + return Expr{Constant{substring}}; + } + } + return Expr{std::move(x)}; } template Expr> FoldOperation( FoldingContext &context, Concat &&x) { - using CHAR = Type; + using Result = Type; if (auto folded{FoldOperands(context, x.left(), x.right())}) { - return Expr{Constant{folded->first + folded->second}}; + return Expr{Constant{folded->first + folded->second}}; } - return Expr{std::move(x)}; + return Expr{std::move(x)}; } template diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 3357612727ff..48ddbd9a25a6 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -70,9 +70,7 @@ template struct TypeBase { // data types will have set this flag to true. static constexpr bool isSpecificIntrinsicType{true}; static constexpr DynamicType dynamicType{CATEGORY, KIND}; - static constexpr std::optional GetType() { - return {dynamicType}; - } + static constexpr DynamicType GetType() { return {dynamicType}; } static constexpr TypeCategory category{CATEGORY}; static constexpr int kind{KIND}; static std::string Dump() { return dynamicType.Dump(); } @@ -167,6 +165,11 @@ using SubscriptInteger = Type; using LogicalResult = Type; using LargestReal = Type; +// Many expressions, including subscripts, CHARACTER lengths, array bounds, +// and effective type parameter values, are of a maximal kind of INTEGER. +using IndirectSubscriptIntegerExpr = + CopyableIndirection>; + // A predicate that is true when a kind value is a kind that could possibly // be supported for an intrinsic type category on some target instruction // set architecture. @@ -244,9 +247,7 @@ public: CLASS_BOILERPLATE(SomeKind) explicit SomeKind(const semantics::DerivedTypeSpec &s) : spec_{&s} {} - std::optional GetType() const { - return {DynamicType{category, 0, spec_}}; - } + DynamicType GetType() const { return DynamicType{category, 0, spec_}; } const semantics::DerivedTypeSpec &spec() const { return *spec_; } std::string Dump() const; @@ -330,7 +331,7 @@ template struct Constant { template Constant(std::enable_if_t, A> &&x) : value(std::move(x)) {} - constexpr std::optional GetType() const { + constexpr DynamicType GetType() const { if constexpr (Result::isSpecificIntrinsicType) { return Result::GetType(); } else { diff --git a/flang/lib/evaluate/variable.cc b/flang/lib/evaluate/variable.cc index 0ce87541e75a..d3db661ab6e5 100644 --- a/flang/lib/evaluate/variable.cc +++ b/flang/lib/evaluate/variable.cc @@ -113,70 +113,38 @@ Expr Substring::last() const { if (last_.has_value()) { return **last_; } else { - return std::visit( - [](const auto &x) { - if constexpr (std::is_same_v>) { - return x.LEN(); - } else { - return AsExpr(Constant{x.size()}); - } - }, - u_); + return parent_.LEN(); } } -auto Substring::Fold(FoldingContext &context) -> std::optional { - std::optional lbi, ubi; - if (first_.has_value()) { - *first_ = evaluate::Fold(context, std::move(**first_)); - lbi = ToInt64(**first_); +void Substring::Fold(FoldingContext &context) { + if (!first_.has_value()) { + first_ = AsExpr(Constant{1}); } - if (last_.has_value()) { - *last_ = evaluate::Fold(context, std::move(**last_)); - ubi = ToInt64(**last_); + *first_ = evaluate::Fold(context, std::move(**first_)); + std::optional lbi{ToInt64(**first_)}; + if (lbi.has_value() && *lbi < 1) { + context.messages.Say( + "lower bound on substring (%jd) is less than one"_en_US, + static_cast(*lbi)); + *lbi = 1; + first_ = AsExpr(Constant{1}); } - if (lbi.has_value() && ubi.has_value()) { - if (*ubi < *lbi) { - // These cases are well defined, and they produce zero-length results. - u_ = ""s; + if (!last_.has_value()) { + last_ = parent_.LEN(); + } + *last_ = evaluate::Fold(context, std::move(**last_)); + if (std::optional ubi{ToInt64(**last_)}) { + if (*ubi < 1) { + *ubi = 0; + last_ = AsExpr(Constant{0}); + } + if (lbi.has_value() && *ubi < *lbi) { + // This case is well defined first_ = AsExpr(Constant{1}); last_ = AsExpr(Constant{0}); - return {Strings{""s}}; } - if (*lbi <= 0) { - context.messages.Say( - "lower bound on substring (%jd) is less than one"_en_US, - static_cast(*lbi)); - *lbi = 1; - first_ = AsExpr(Constant{1}); - } - if (*ubi <= 0) { - u_ = ""s; - last_ = AsExpr(Constant{0}); - return {Strings{""s}}; - } - return std::visit( - [&](const auto &x) -> std::optional { - if constexpr (std::is_same_v>) { - return std::nullopt; - } else { - std::int64_t len = x.size(); - if (*ubi > len) { - context.messages.Say( - "upper bound on substring (%jd) is greater than character length (%jd)"_en_US, - static_cast(*ubi), - static_cast(len)); - *ubi = len; - last_ = AsExpr(Constant{len}); - } - auto substring{x.substr(*lbi - 1, *ubi - *lbi + 1)}; - u_ = substring; - return std::make_optional(Strings{substring}); - } - }, - u_); } - return std::nullopt; } // Variable dumping @@ -300,7 +268,7 @@ std::ostream &CoarrayRef::Dump(std::ostream &o) const { std::ostream &DataRef::Dump(std::ostream &o) const { return Emit(o, u); } std::ostream &Substring::Dump(std::ostream &o) const { - Emit(o, u_) << '('; + Emit(o, parent_) << '('; Emit(o, first_) << ':'; return Emit(o, last_); } @@ -325,7 +293,9 @@ template std::ostream &Designator::Dump(std::ostream &o) const { static Expr SymbolLEN(const Symbol &sym) { return AsExpr(Constant{0}); // TODO } -Expr Component::LEN() const { return SymbolLEN(symbol()); } +Expr Component::LEN() const { + return SymbolLEN(GetLastSymbol()); +} Expr ArrayRef::LEN() const { return std::visit( common::visitors{[](const Symbol *s) { return SymbolLEN(*s); }, @@ -420,17 +390,7 @@ int DataRef::Rank() const { }, u); } -int Substring::Rank() const { - return std::visit( - [](const auto &x) { - if constexpr (std::is_same_v, DataRef>) { - return x.Rank(); - } else { - return 0; // parent string is a literal scalar - } - }, - u_); -} +int Substring::Rank() const { return parent_.Rank(); } int ComplexPart::Rank() const { return complex_.Rank(); } template int Designator::Rank() const { return std::visit( @@ -460,77 +420,62 @@ bool ProcedureDesignator::IsElemental() const { return 0; } -// GetFirstSymbol(), GetLastSymbol() -const Symbol *Component::GetFirstSymbol() const { +// GetFirstSymbol() & GetLastSymbol() +const Symbol &Component::GetFirstSymbol() const { return base_->GetFirstSymbol(); } -const Symbol *Component::GetLastSymbol() const { - return base_->GetLastSymbol(); -} -const Symbol *ArrayRef::GetFirstSymbol() const { - return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [=](const Component &component) { - return component.GetFirstSymbol(); - }}, +const Symbol &ArrayRef::GetFirstSymbol() const { + return *std::visit(common::visitors{[](const Symbol *sym) { return sym; }, + [=](const Component &component) { + return &component.GetFirstSymbol(); + }}, u); } -const Symbol *ArrayRef::GetLastSymbol() const { - return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [=](const Component &component) { - return component.GetLastSymbol(); - }}, +const Symbol &ArrayRef::GetLastSymbol() const { + return *std::visit(common::visitors{[](const Symbol *sym) { return sym; }, + [=](const Component &component) { + return &component.GetLastSymbol(); + }}, u); } -const Symbol *DataRef::GetFirstSymbol() const { - return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [=](const auto &x) { return x.GetFirstSymbol(); }}, +const Symbol &DataRef::GetFirstSymbol() const { + return *std::visit(common::visitors{[](const Symbol *sym) { return sym; }, + [=](const auto &x) { return &x.GetFirstSymbol(); }}, u); } -const Symbol *DataRef::GetLastSymbol() const { - return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [=](const auto &x) { return x.GetLastSymbol(); }}, +const Symbol &DataRef::GetLastSymbol() const { + return *std::visit(common::visitors{[](const Symbol *sym) { return sym; }, + [=](const auto &x) { return &x.GetLastSymbol(); }}, u); } -const Symbol *Substring::GetFirstSymbol() const { - if (const DataRef * dataRef{std::get_if(&u_)}) { - return dataRef->GetFirstSymbol(); - } else { - return nullptr; // substring of character literal - } +const Symbol &Substring::GetFirstSymbol() const { + return parent_.GetFirstSymbol(); } -const Symbol *Substring::GetLastSymbol() const { - if (const DataRef * dataRef{std::get_if(&u_)}) { - return dataRef->GetLastSymbol(); - } else { - return nullptr; // substring of character literal - } +const Symbol &Substring::GetLastSymbol() const { + return parent_.GetLastSymbol(); } -template const Symbol *Designator::GetFirstSymbol() const { - return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [=](const auto &x) { return x.GetFirstSymbol(); }}, +template const Symbol &Designator::GetFirstSymbol() const { + return *std::visit(common::visitors{[](const Symbol *sym) { return sym; }, + [=](const auto &x) { return &x.GetFirstSymbol(); }}, u); } -template const Symbol *Designator::GetLastSymbol() const { - return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [=](const auto &x) { return x.GetLastSymbol(); }}, +template const Symbol &Designator::GetLastSymbol() const { + return *std::visit(common::visitors{[](const Symbol *sym) { return sym; }, + [=](const auto &x) { return &x.GetLastSymbol(); }}, u); } const Symbol *ProcedureDesignator::GetSymbol() const { return std::visit(common::visitors{[](const Symbol *sym) { return sym; }, - [](const Component &c) { return c.GetLastSymbol(); }, + [](const Component &c) { return &c.GetLastSymbol(); }, [](const auto &) -> const Symbol * { return nullptr; }}, u); } template std::optional Designator::GetType() const { if constexpr (std::is_same_v) { - if (const Symbol * sym{GetLastSymbol()}) { - return GetSymbolType(*sym); - } else { - return std::nullopt; - } + return GetSymbolType(GetLastSymbol()); } else { - return Result::GetType(); + return {Result::GetType()}; } } std::optional ProcedureDesignator::GetType() const { diff --git a/flang/lib/evaluate/variable.h b/flang/lib/evaluate/variable.h index a190308600e7..7184be0acea4 100644 --- a/flang/lib/evaluate/variable.h +++ b/flang/lib/evaluate/variable.h @@ -43,14 +43,11 @@ using semantics::Symbol; struct DataRef; template struct Variable; -// Subscript and cosubscript expressions are of a kind that matches the -// address size, at least at the top level. -using IndirectSubscriptIntegerExpr = - CopyableIndirection>; - +// pmk: are these still needed? int GetSymbolRank(const Symbol &); const parser::CharBlock &GetSymbolName(const Symbol &); + // R913 structure-component & C920: Defined to be a multi-part // data-ref whose last part has no subscripts (or image-selector, although // that isn't explicit in the document). Pointer and allocatable components @@ -66,10 +63,9 @@ public: const DataRef &base() const { return *base_; } DataRef &base() { return *base_; } - const Symbol &symbol() const { return *symbol_; } int Rank() const; - const Symbol *GetFirstSymbol() const; - const Symbol *GetLastSymbol() const; + const Symbol &GetFirstSymbol() const; + const Symbol &GetLastSymbol() const { return *symbol_; } Expr LEN() const; std::ostream &Dump(std::ostream &) const; @@ -118,8 +114,8 @@ struct ArrayRef { : u{std::move(c)}, subscript(std::move(ss)) {} int Rank() const; - const Symbol *GetFirstSymbol() const; - const Symbol *GetLastSymbol() const; + const Symbol &GetFirstSymbol() const; + const Symbol &GetLastSymbol() const; Expr LEN() const; std::ostream &Dump(std::ostream &) const; @@ -146,8 +142,8 @@ public: CoarrayRef &set_team(Expr &&, bool isTeamNumber = false); int Rank() const; - const Symbol *GetFirstSymbol() const { return base_.front(); } - const Symbol *GetLastSymbol() const { return base_.back(); } + const Symbol &GetFirstSymbol() const { return *base_.front(); } + const Symbol &GetLastSymbol() const { return *base_.back(); } Expr LEN() const; std::ostream &Dump(std::ostream &) const; @@ -168,8 +164,8 @@ struct DataRef { explicit DataRef(const Symbol &n) : u{&n} {} int Rank() const; - const Symbol *GetFirstSymbol() const; - const Symbol *GetLastSymbol() const; + const Symbol &GetFirstSymbol() const; + const Symbol &GetLastSymbol() const; Expr LEN() const; std::ostream &Dump(std::ostream &) const; @@ -177,34 +173,33 @@ struct DataRef { }; // R908 substring, R909 parent-string, R910 substring-range. -// The base object of a substring can be a literal. +// The base object of a substring can be a literal, but those are represented +// as a LiteralSubstring expression. // In the F2018 standard, substrings of array sections are parsed as // variants of sections instead. class Substring { public: - using Strings = std::variant; CLASS_BOILERPLATE(Substring) - template - Substring(A &&parent, std::optional> &&first, + Substring(DataRef &&parent, std::optional> &&first, std::optional> &&last) - : u_{std::move(parent)} { + : parent_{std::move(parent)} { SetBounds(first, last); } Expr first() const; Expr last() const; int Rank() const; - const Symbol *GetFirstSymbol() const; - const Symbol *GetLastSymbol() const; + const Symbol &GetFirstSymbol() const; + const Symbol &GetLastSymbol() const; Expr LEN() const; - std::optional Fold(FoldingContext &); std::ostream &Dump(std::ostream &) const; + void Fold(FoldingContext &); + private: - using Variant = common::CombineVariants, Strings>; void SetBounds(std::optional> &, std::optional> &); - Variant u_; + DataRef parent_; std::optional first_, last_; }; @@ -219,8 +214,8 @@ public: const DataRef &complex() const { return complex_; } Part part() const { return part_; } int Rank() const; - const Symbol *GetFirstSymbol() const { return complex_.GetFirstSymbol(); } - const Symbol *GetLastSymbol() const { return complex_.GetLastSymbol(); } + const Symbol &GetFirstSymbol() const { return complex_.GetFirstSymbol(); } + const Symbol &GetLastSymbol() const { return complex_.GetLastSymbol(); } std::ostream &Dump(std::ostream &) const; private: @@ -253,8 +248,8 @@ public: std::optional GetType() const; int Rank() const; - const Symbol *GetFirstSymbol() const; - const Symbol *GetLastSymbol() const; + const Symbol &GetFirstSymbol() const; + const Symbol &GetLastSymbol() const; Expr LEN() const; std::ostream &Dump(std::ostream &o) const; diff --git a/flang/lib/parser/characters.cc b/flang/lib/parser/characters.cc index 62cf95342b84..29e16955aeb3 100644 --- a/flang/lib/parser/characters.cc +++ b/flang/lib/parser/characters.cc @@ -82,14 +82,30 @@ std::optional CountCharacters( return {chars}; } -std::string QuoteCharacterLiteral( - const std::string &str, bool doubleDoubleQuotes, bool doubleBackslash) { +template +std::string QuoteCharacterLiteralHelper( + const STRING &str, bool doubleDoubleQuotes, bool doubleBackslash) { std::string result{'"'}; const auto emit{[&](char ch) { result += ch; }}; - for (char ch : str) { + for (auto ch : str) { EmitQuotedChar(ch, emit, emit, doubleDoubleQuotes, doubleBackslash); } result += '"'; return result; } + +std::string QuoteCharacterLiteral( + const std::string &str, bool doubleDoubleQuotes, bool doubleBackslash) { + return QuoteCharacterLiteralHelper(str, doubleDoubleQuotes, doubleBackslash); +} + +std::string QuoteCharacterLiteral( + const std::u16string &str, bool doubleDoubleQuotes, bool doubleBackslash) { + return QuoteCharacterLiteralHelper(str, doubleDoubleQuotes, doubleBackslash); +} + +std::string QuoteCharacterLiteral( + const std::u32string &str, bool doubleDoubleQuotes, bool doubleBackslash) { + return QuoteCharacterLiteralHelper(str, doubleDoubleQuotes, doubleBackslash); +} } diff --git a/flang/lib/parser/characters.h b/flang/lib/parser/characters.h index ddf2a4747d51..f77c48c23e49 100644 --- a/flang/lib/parser/characters.h +++ b/flang/lib/parser/characters.h @@ -134,7 +134,7 @@ inline constexpr std::optional BackslashEscapeChar(char ch) { } template -void EmitQuotedChar(char ch, const NORMAL &emit, const INSERTED &insert, +void EmitQuotedChar(char32_t ch, const NORMAL &emit, const INSERTED &insert, bool doubleDoubleQuotes = true, bool doubleBackslash = true) { if (ch == '"') { if (doubleDoubleQuotes) { @@ -156,13 +156,29 @@ void EmitQuotedChar(char ch, const NORMAL &emit, const INSERTED &insert, insert('0' + ((ch >> 3) & 7)); insert('0' + (ch & 7)); } - } else { + } else if (ch <= 0x7f) { emit(ch); + } else if (ch <= 0x7ff) { + emit(0xc0 | ((ch >> 6) & 0x1f)); + emit(0x80 | (ch & 0x3f)); + } else if (ch <= 0xffff) { + emit(0xe0 | ((ch >> 12) & 0x0f)); + emit(0x80 | ((ch >> 6) & 0x3f)); + emit(0x80 | (ch & 0x3f)); + } else { + emit(0xf0 | ((ch >> 18) & 0x07)); + emit(0x80 | ((ch >> 12) & 0x3f)); + emit(0x80 | ((ch >> 6) & 0x3f)); + emit(0x80 | (ch & 0x3f)); } } std::string QuoteCharacterLiteral(const std::string &, bool doubleDoubleQuotes = true, bool doubleBackslash = true); +std::string QuoteCharacterLiteral(const std::u16string &, + bool doubleDoubleQuotes = true, bool doubleBackslash = true); +std::string QuoteCharacterLiteral(const std::u32string &, + bool doubleDoubleQuotes = true, bool doubleBackslash = true); std::optional UTF8CharacterBytes(const char *); std::optional EUC_JPCharacterBytes(const char *); diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index f1bc7e43b91c..ef97a6d60646 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -520,7 +520,7 @@ MaybeExpr TypedWrapper(DynamicType &&dyType, WRAPPED &&x) { // Wraps a data reference in a typed Designator<>. static MaybeExpr Designate(DataRef &&dataRef) { - const Symbol &symbol{*dataRef.GetLastSymbol()}; + const Symbol &symbol{dataRef.GetLastSymbol()}; if (std::optional dyType{GetSymbolType(symbol)}) { return TypedWrapper( std::move(*dyType), std::move(dataRef)); @@ -577,7 +577,7 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Substring &ss) { GetSubstringBound(std::get<0>(range.t))}; std::optional> last{ GetSubstringBound(std::get<1>(range.t))}; - const Symbol &symbol{*checked->GetLastSymbol()}; + const Symbol &symbol{checked->GetLastSymbol()}; if (std::optional dynamicType{GetSymbolType(symbol)}) { if (dynamicType->category == TypeCategory::Character) { return WrapperHelper A(:,:) @@ -804,8 +804,36 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::CoindexedNamedObject &co) { return std::nullopt; } -MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstantSubstring &) { - Say("TODO: CharLiteralConstantSubstring unimplemented"_err_en_US); +MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstantSubstring &x) { + const parser::SubstringRange &range{std::get(x.t)}; + std::optional> lower{ + GetSubstringBound(std::get<0>(range.t))}; + std::optional> upper{ + GetSubstringBound(std::get<1>(range.t))}; + if (MaybeExpr string{Analyze(std::get(x.t))}) { + if (auto *charExpr{std::get_if>(&string->u)}) { + Expr length{std::visit( + [](const auto &ckExpr) { return ckExpr.LEN(); }, charExpr->u)}; + if (!lower.has_value()) { + lower = Expr{1}; + } + if (!upper.has_value()) { + std::optional size{ToInt64(length)}; + CHECK(size.has_value()); + upper = Expr{static_cast(*size)}; + } + return std::visit( + [&](auto &&ckExpr) -> MaybeExpr { + using Result = ResultType; + auto *cp{std::get_if>(&ckExpr.u)}; + CHECK(cp != nullptr); // the parent was parsed as a constant string + return AsGenericExpr(Expr{Expr{ + LiteralSubstring{std::move(cp->value), + std::move(*lower), std::move(*upper)}}}); + }, + std::move(charExpr->u)); + } + } return std::nullopt; } @@ -1184,11 +1212,12 @@ MaybeExpr ExprAnalyzer::TopLevelChecks(DataRef &&dataRef) { void ExprAnalyzer::CheckUnsubscriptedComponent(const Component &component) { int baseRank{component.base().Rank()}; if (baseRank > 0) { - int componentRank{component.symbol().Rank()}; + const Symbol &symbol{component.GetLastSymbol()}; + int componentRank{symbol.Rank()}; if (componentRank > 0) { Say("reference to whole rank-%d component '%%%s' of " "rank-%d array of derived type is not allowed"_err_en_US, - componentRank, component.symbol().name().ToString().data(), baseRank); + componentRank, symbol.name().ToString().data(), baseRank); } } }