Diana Picus | 651f58b | 2021-09-02 08:14:01 | [diff] [blame] | 1 | //===-- runtime/namelist.cpp ----------------------------------------------===// |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "namelist.h" |
| 10 | #include "descriptor-io.h" |
Peter Klausler | bad5205 | 2022-08-03 19:31:05 | [diff] [blame] | 11 | #include "emit-encoded.h" |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 12 | #include "io-stmt.h" |
Peter Klausler | 830c0b9 | 2021-09-01 23:00:53 | [diff] [blame] | 13 | #include "flang/Runtime/io-api.h" |
peter klausler | 89a927c | 2021-10-21 21:13:21 | [diff] [blame] | 14 | #include <algorithm> |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 15 | #include <cstring> |
| 16 | #include <limits> |
| 17 | |
| 18 | namespace Fortran::runtime::io { |
| 19 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 20 | RT_VAR_GROUP_BEGIN |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 21 | // Max size of a group, symbol or component identifier that can appear in |
| 22 | // NAMELIST input, plus a byte for NUL termination. |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 23 | static constexpr RT_CONST_VAR_ATTRS std::size_t nameBufferSize{201}; |
| 24 | RT_VAR_GROUP_END |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 25 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 26 | RT_OFFLOAD_API_GROUP_BEGIN |
| 27 | |
| 28 | static inline RT_API_ATTRS char32_t GetComma(IoStatementState &io) { |
Peter Klausler | 896a543 | 2022-01-20 00:25:41 | [diff] [blame] | 29 | return io.mutableModes().editingFlags & decimalComma ? char32_t{';'} |
| 30 | : char32_t{','}; |
| 31 | } |
| 32 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 33 | bool IODEF(OutputNamelist)(Cookie cookie, const NamelistGroup &group) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 34 | IoStatementState &io{*cookie}; |
| 35 | io.CheckFormattedStmtType<Direction::Output>("OutputNamelist"); |
Peter Klausler | 9772dbb | 2022-01-27 20:09:07 | [diff] [blame] | 36 | io.mutableModes().inNamelist = true; |
Peter Klausler | 9772dbb | 2022-01-27 20:09:07 | [diff] [blame] | 37 | ConnectionState &connection{io.GetConnectionState()}; |
Slava Zakharin | 8ebf741 | 2024-03-25 23:01:25 | [diff] [blame] | 38 | // The following lambda definition violates the conding style, |
| 39 | // but cuda-11.8 nvcc hits an internal error with the brace initialization. |
| 40 | |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 41 | // Internal function to advance records and convert case |
Slava Zakharin | 8ebf741 | 2024-03-25 23:01:25 | [diff] [blame] | 42 | const auto EmitUpperCase = [&](const char *prefix, std::size_t prefixLen, |
| 43 | const char *str, char suffix) -> bool { |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 44 | if ((connection.NeedAdvance(prefixLen) && |
| 45 | !(io.AdvanceRecord() && EmitAscii(io, " ", 1))) || |
| 46 | !EmitAscii(io, prefix, prefixLen) || |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 47 | (connection.NeedAdvance( |
| 48 | Fortran::runtime::strlen(str) + (suffix != ' ')) && |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 49 | !(io.AdvanceRecord() && EmitAscii(io, " ", 1)))) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 50 | return false; |
| 51 | } |
| 52 | for (; *str; ++str) { |
| 53 | char up{*str >= 'a' && *str <= 'z' ? static_cast<char>(*str - 'a' + 'A') |
| 54 | : *str}; |
Peter Klausler | bad5205 | 2022-08-03 19:31:05 | [diff] [blame] | 55 | if (!EmitAscii(io, &up, 1)) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 56 | return false; |
| 57 | } |
| 58 | } |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 59 | return suffix == ' ' || EmitAscii(io, &suffix, 1); |
Slava Zakharin | 8ebf741 | 2024-03-25 23:01:25 | [diff] [blame] | 60 | }; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 61 | // &GROUP |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 62 | if (!EmitUpperCase(" &", 2, group.groupName, ' ')) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 63 | return false; |
| 64 | } |
Peter Klausler | 3a96446d | 2022-02-17 23:32:06 | [diff] [blame] | 65 | auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()}; |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 66 | char comma{static_cast<char>(GetComma(io))}; |
| 67 | char prefix{' '}; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 68 | for (std::size_t j{0}; j < group.items; ++j) { |
| 69 | // [,]ITEM=... |
| 70 | const NamelistGroup::Item &item{group.item[j]}; |
Peter Klausler | 3a96446d | 2022-02-17 23:32:06 | [diff] [blame] | 71 | if (listOutput) { |
| 72 | listOutput->set_lastWasUndelimitedCharacter(false); |
| 73 | } |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 74 | if (!EmitUpperCase(&prefix, 1, item.name, '=')) { |
Peter Klausler | 7cf1608 | 2023-04-13 17:28:19 | [diff] [blame] | 75 | return false; |
| 76 | } |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 77 | prefix = comma; |
Peter Klausler | 7cf1608 | 2023-04-13 17:28:19 | [diff] [blame] | 78 | if (const auto *addendum{item.descriptor.Addendum()}; |
| 79 | addendum && addendum->derivedType()) { |
V Donaldson | 6f7a3b0 | 2023-05-16 20:34:57 | [diff] [blame] | 80 | const NonTbpDefinedIoTable *table{group.nonTbpDefinedIo}; |
Peter Klausler | 7cf1608 | 2023-04-13 17:28:19 | [diff] [blame] | 81 | if (!IONAME(OutputDerivedType)(cookie, item.descriptor, table)) { |
| 82 | return false; |
| 83 | } |
| 84 | } else if (!descr::DescriptorIO<Direction::Output>(io, item.descriptor)) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 85 | return false; |
| 86 | } |
| 87 | } |
| 88 | // terminal / |
Peter Klausler | f08b55d | 2024-01-15 18:02:52 | [diff] [blame] | 89 | return EmitUpperCase("/", 1, "", ' '); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 90 | } |
| 91 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 92 | static constexpr RT_API_ATTRS bool IsLegalIdStart(char32_t ch) { |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 93 | return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_' || |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 94 | ch == '@'; |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 95 | } |
| 96 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 97 | static constexpr RT_API_ATTRS bool IsLegalIdChar(char32_t ch) { |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 98 | return IsLegalIdStart(ch) || (ch >= '0' && ch <= '9'); |
| 99 | } |
| 100 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 101 | static constexpr RT_API_ATTRS char NormalizeIdChar(char32_t ch) { |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 102 | return static_cast<char>(ch >= 'A' && ch <= 'Z' ? ch - 'A' + 'a' : ch); |
| 103 | } |
| 104 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 105 | static RT_API_ATTRS bool GetLowerCaseName( |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 106 | IoStatementState &io, char buffer[], std::size_t maxLength) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 107 | std::size_t byteLength{0}; |
| 108 | if (auto ch{io.GetNextNonBlank(byteLength)}) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 109 | if (IsLegalIdStart(*ch)) { |
| 110 | std::size_t j{0}; |
| 111 | do { |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 112 | buffer[j] = NormalizeIdChar(*ch); |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 113 | io.HandleRelativePosition(byteLength); |
| 114 | ch = io.GetCurrentChar(byteLength); |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 115 | } while (++j < maxLength && ch && IsLegalIdChar(*ch)); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 116 | buffer[j++] = '\0'; |
| 117 | if (j <= maxLength) { |
| 118 | return true; |
| 119 | } |
| 120 | io.GetIoErrorHandler().SignalError( |
| 121 | "Identifier '%s...' in NAMELIST input group is too long", buffer); |
| 122 | } |
| 123 | } |
| 124 | return false; |
| 125 | } |
| 126 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 127 | static RT_API_ATTRS Fortran::common::optional<SubscriptValue> GetSubscriptValue( |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 128 | IoStatementState &io) { |
| 129 | Fortran::common::optional<SubscriptValue> value; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 130 | std::size_t byteCount{0}; |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 131 | Fortran::common::optional<char32_t> ch{io.GetCurrentChar(byteCount)}; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 132 | bool negate{ch && *ch == '-'}; |
Peter Klausler | 922c29c | 2022-01-12 23:10:20 | [diff] [blame] | 133 | if ((ch && *ch == '+') || negate) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 134 | io.HandleRelativePosition(byteCount); |
| 135 | ch = io.GetCurrentChar(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 136 | } |
| 137 | bool overflow{false}; |
| 138 | while (ch && *ch >= '0' && *ch <= '9') { |
| 139 | SubscriptValue was{value.value_or(0)}; |
| 140 | overflow |= was >= std::numeric_limits<SubscriptValue>::max() / 10; |
| 141 | value = 10 * was + *ch - '0'; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 142 | io.HandleRelativePosition(byteCount); |
| 143 | ch = io.GetCurrentChar(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 144 | } |
| 145 | if (overflow) { |
| 146 | io.GetIoErrorHandler().SignalError( |
| 147 | "NAMELIST input subscript value overflow"); |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 148 | return Fortran::common::nullopt; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 149 | } |
| 150 | if (negate) { |
| 151 | if (value) { |
| 152 | return -*value; |
| 153 | } else { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 154 | io.HandleRelativePosition(-byteCount); // give back '-' with no digits |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 155 | } |
| 156 | } |
| 157 | return value; |
| 158 | } |
| 159 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 160 | static RT_API_ATTRS bool HandleSubscripts(IoStatementState &io, |
| 161 | Descriptor &desc, const Descriptor &source, const char *name) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 162 | IoErrorHandler &handler{io.GetIoErrorHandler()}; |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 163 | // Allow for blanks in subscripts; they're nonstandard, but not |
| 164 | // ambiguous within the parentheses. |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 165 | SubscriptValue lower[maxRank], upper[maxRank], stride[maxRank]; |
| 166 | int j{0}; |
peter klausler | 89a927c | 2021-10-21 21:13:21 | [diff] [blame] | 167 | std::size_t contiguousStride{source.ElementBytes()}; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 168 | bool ok{true}; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 169 | std::size_t byteCount{0}; |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 170 | Fortran::common::optional<char32_t> ch{io.GetNextNonBlank(byteCount)}; |
Peter Klausler | 896a543 | 2022-01-20 00:25:41 | [diff] [blame] | 171 | char32_t comma{GetComma(io)}; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 172 | for (; ch && *ch != ')'; ++j) { |
| 173 | SubscriptValue dimLower{0}, dimUpper{0}, dimStride{0}; |
| 174 | if (j < maxRank && j < source.rank()) { |
| 175 | const Dimension &dim{source.GetDimension(j)}; |
| 176 | dimLower = dim.LowerBound(); |
| 177 | dimUpper = dim.UpperBound(); |
peter klausler | 89a927c | 2021-10-21 21:13:21 | [diff] [blame] | 178 | dimStride = |
| 179 | dim.ByteStride() / std::max<SubscriptValue>(contiguousStride, 1); |
| 180 | contiguousStride *= dim.Extent(); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 181 | } else if (ok) { |
| 182 | handler.SignalError( |
| 183 | "Too many subscripts for rank-%d NAMELIST group item '%s'", |
| 184 | source.rank(), name); |
| 185 | ok = false; |
| 186 | } |
| 187 | if (auto low{GetSubscriptValue(io)}) { |
| 188 | if (*low < dimLower || (dimUpper >= dimLower && *low > dimUpper)) { |
| 189 | if (ok) { |
| 190 | handler.SignalError("Subscript %jd out of range %jd..%jd in NAMELIST " |
| 191 | "group item '%s' dimension %d", |
| 192 | static_cast<std::intmax_t>(*low), |
| 193 | static_cast<std::intmax_t>(dimLower), |
| 194 | static_cast<std::intmax_t>(dimUpper), name, j + 1); |
| 195 | ok = false; |
| 196 | } |
| 197 | } else { |
| 198 | dimLower = *low; |
| 199 | } |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 200 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 201 | } |
| 202 | if (ch && *ch == ':') { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 203 | io.HandleRelativePosition(byteCount); |
| 204 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 205 | if (auto high{GetSubscriptValue(io)}) { |
| 206 | if (*high > dimUpper) { |
| 207 | if (ok) { |
| 208 | handler.SignalError( |
| 209 | "Subscript triplet upper bound %jd out of range (>%jd) in " |
| 210 | "NAMELIST group item '%s' dimension %d", |
| 211 | static_cast<std::intmax_t>(*high), |
| 212 | static_cast<std::intmax_t>(dimUpper), name, j + 1); |
| 213 | ok = false; |
| 214 | } |
| 215 | } else { |
| 216 | dimUpper = *high; |
| 217 | } |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 218 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 219 | } |
| 220 | if (ch && *ch == ':') { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 221 | io.HandleRelativePosition(byteCount); |
| 222 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 223 | if (auto str{GetSubscriptValue(io)}) { |
| 224 | dimStride = *str; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 225 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 226 | } |
| 227 | } |
| 228 | } else { // scalar |
| 229 | dimUpper = dimLower; |
| 230 | dimStride = 0; |
| 231 | } |
Peter Klausler | 896a543 | 2022-01-20 00:25:41 | [diff] [blame] | 232 | if (ch && *ch == comma) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 233 | io.HandleRelativePosition(byteCount); |
| 234 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 235 | } |
| 236 | if (ok) { |
| 237 | lower[j] = dimLower; |
| 238 | upper[j] = dimUpper; |
| 239 | stride[j] = dimStride; |
| 240 | } |
| 241 | } |
| 242 | if (ok) { |
| 243 | if (ch && *ch == ')') { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 244 | io.HandleRelativePosition(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 245 | if (desc.EstablishPointerSection(source, lower, upper, stride)) { |
| 246 | return true; |
| 247 | } else { |
| 248 | handler.SignalError( |
| 249 | "Bad subscripts for NAMELIST input group item '%s'", name); |
| 250 | } |
| 251 | } else { |
| 252 | handler.SignalError( |
| 253 | "Bad subscripts (missing ')') for NAMELIST input group item '%s'", |
| 254 | name); |
| 255 | } |
| 256 | } |
| 257 | return false; |
| 258 | } |
| 259 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 260 | static RT_API_ATTRS void StorageSequenceExtension( |
Peter Klausler | dea30ac | 2024-01-02 17:25:49 | [diff] [blame] | 261 | Descriptor &desc, const Descriptor &source) { |
| 262 | // Support the near-universal extension of NAMELIST input into a |
| 263 | // designatable storage sequence identified by its initial scalar array |
| 264 | // element. For example, treat "A(1) = 1. 2. 3." as if it had been |
| 265 | // "A(1:) = 1. 2. 3.". |
| 266 | if (desc.rank() == 0 && (source.rank() == 1 || source.IsContiguous())) { |
| 267 | if (auto stride{source.rank() == 1 |
| 268 | ? source.GetDimension(0).ByteStride() |
| 269 | : static_cast<SubscriptValue>(source.ElementBytes())}; |
| 270 | stride != 0) { |
| 271 | desc.raw().attribute = CFI_attribute_pointer; |
| 272 | desc.raw().rank = 1; |
| 273 | desc.GetDimension(0) |
| 274 | .SetBounds(1, |
| 275 | source.Elements() - |
| 276 | ((source.OffsetElement() - desc.OffsetElement()) / stride)) |
| 277 | .SetByteStride(stride); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 282 | static RT_API_ATTRS bool HandleSubstring( |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 283 | IoStatementState &io, Descriptor &desc, const char *name) { |
| 284 | IoErrorHandler &handler{io.GetIoErrorHandler()}; |
| 285 | auto pair{desc.type().GetCategoryAndKind()}; |
| 286 | if (!pair || pair->first != TypeCategory::Character) { |
| 287 | handler.SignalError("Substring reference to non-character item '%s'", name); |
| 288 | return false; |
| 289 | } |
| 290 | int kind{pair->second}; |
| 291 | SubscriptValue chars{static_cast<SubscriptValue>(desc.ElementBytes()) / kind}; |
| 292 | // Allow for blanks in substring bounds; they're nonstandard, but not |
| 293 | // ambiguous within the parentheses. |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 294 | Fortran::common::optional<SubscriptValue> lower, upper; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 295 | std::size_t byteCount{0}; |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 296 | Fortran::common::optional<char32_t> ch{io.GetNextNonBlank(byteCount)}; |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 297 | if (ch) { |
| 298 | if (*ch == ':') { |
| 299 | lower = 1; |
| 300 | } else { |
| 301 | lower = GetSubscriptValue(io); |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 302 | ch = io.GetNextNonBlank(byteCount); |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 303 | } |
| 304 | } |
Slava Zakharin | 8ebf741 | 2024-03-25 23:01:25 | [diff] [blame] | 305 | if (ch && *ch == ':') { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 306 | io.HandleRelativePosition(byteCount); |
| 307 | ch = io.GetNextNonBlank(byteCount); |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 308 | if (ch) { |
| 309 | if (*ch == ')') { |
| 310 | upper = chars; |
| 311 | } else { |
| 312 | upper = GetSubscriptValue(io); |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 313 | ch = io.GetNextNonBlank(byteCount); |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 314 | } |
| 315 | } |
| 316 | } |
| 317 | if (ch && *ch == ')') { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 318 | io.HandleRelativePosition(byteCount); |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 319 | if (lower && upper) { |
| 320 | if (*lower > *upper) { |
| 321 | // An empty substring, whatever the values are |
| 322 | desc.raw().elem_len = 0; |
| 323 | return true; |
| 324 | } |
Peter Klausler | 15e4a3c | 2024-01-25 23:15:20 | [diff] [blame] | 325 | if (*lower >= 1 && *upper <= chars) { |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 326 | // Offset the base address & adjust the element byte length |
| 327 | desc.raw().elem_len = (*upper - *lower + 1) * kind; |
| 328 | desc.set_base_addr(reinterpret_cast<void *>( |
| 329 | reinterpret_cast<char *>(desc.raw().base_addr) + |
| 330 | kind * (*lower - 1))); |
| 331 | return true; |
| 332 | } |
| 333 | } |
| 334 | handler.SignalError( |
| 335 | "Bad substring bounds for NAMELIST input group item '%s'", name); |
| 336 | } else { |
| 337 | handler.SignalError( |
| 338 | "Bad substring (missing ')') for NAMELIST input group item '%s'", name); |
| 339 | } |
| 340 | return false; |
| 341 | } |
| 342 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 343 | static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc, |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 344 | const Descriptor &source, const char *name) { |
| 345 | IoErrorHandler &handler{io.GetIoErrorHandler()}; |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 346 | char compName[nameBufferSize]; |
| 347 | if (GetLowerCaseName(io, compName, sizeof compName)) { |
| 348 | const DescriptorAddendum *addendum{source.Addendum()}; |
| 349 | if (const typeInfo::DerivedType * |
| 350 | type{addendum ? addendum->derivedType() : nullptr}) { |
| 351 | if (const typeInfo::Component * |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 352 | comp{type->FindDataComponent( |
| 353 | compName, Fortran::runtime::strlen(compName))}) { |
Peter Klausler | 6e7df70 | 2022-10-04 21:14:05 | [diff] [blame] | 354 | bool createdDesc{false}; |
| 355 | if (comp->rank() > 0 && source.rank() > 0) { |
| 356 | // If base and component are both arrays, the component name |
| 357 | // must be followed by subscripts; process them now. |
| 358 | std::size_t byteCount{0}; |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 359 | if (Fortran::common::optional<char32_t> next{ |
| 360 | io.GetNextNonBlank(byteCount)}; |
Peter Klausler | 6e7df70 | 2022-10-04 21:14:05 | [diff] [blame] | 361 | next && *next == '(') { |
| 362 | io.HandleRelativePosition(byteCount); // skip over '(' |
| 363 | StaticDescriptor<maxRank, true, 16> staticDesc; |
| 364 | Descriptor &tmpDesc{staticDesc.descriptor()}; |
| 365 | comp->CreatePointerDescriptor(tmpDesc, source, handler); |
| 366 | if (!HandleSubscripts(io, desc, tmpDesc, compName)) { |
| 367 | return false; |
| 368 | } |
| 369 | createdDesc = true; |
| 370 | } |
| 371 | } |
| 372 | if (!createdDesc) { |
| 373 | comp->CreatePointerDescriptor(desc, source, handler); |
| 374 | } |
| 375 | if (source.rank() > 0) { |
| 376 | if (desc.rank() > 0) { |
| 377 | handler.SignalError( |
| 378 | "NAMELIST component reference '%%%s' of input group " |
| 379 | "item %s cannot be an array when its base is not scalar", |
| 380 | compName, name); |
| 381 | return false; |
| 382 | } |
| 383 | desc.raw().rank = source.rank(); |
| 384 | for (int j{0}; j < source.rank(); ++j) { |
| 385 | const auto &srcDim{source.GetDimension(j)}; |
| 386 | desc.GetDimension(j) |
| 387 | .SetBounds(1, srcDim.UpperBound()) |
| 388 | .SetByteStride(srcDim.ByteStride()); |
| 389 | } |
| 390 | } |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 391 | return true; |
| 392 | } else { |
| 393 | handler.SignalError( |
| 394 | "NAMELIST component reference '%%%s' of input group item %s is not " |
| 395 | "a component of its derived type", |
| 396 | compName, name); |
| 397 | } |
peter klausler | 6d44387 | 2021-10-20 23:01:52 | [diff] [blame] | 398 | } else if (source.type().IsDerived()) { |
| 399 | handler.Crash("Derived type object '%s' in NAMELIST is missing its " |
| 400 | "derived type information!", |
| 401 | name); |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 402 | } else { |
| 403 | handler.SignalError("NAMELIST component reference '%%%s' of input group " |
| 404 | "item %s for non-derived type", |
| 405 | compName, name); |
| 406 | } |
| 407 | } else { |
| 408 | handler.SignalError("NAMELIST component reference of input group item %s " |
Peter Klausler | 3838245 | 2022-08-14 17:02:30 | [diff] [blame] | 409 | "has no name after '%%'", |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 410 | name); |
| 411 | } |
| 412 | return false; |
| 413 | } |
| 414 | |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 415 | // Advance to the terminal '/' of a namelist group or leading '&'/'$' |
| 416 | // of the next. |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 417 | static RT_API_ATTRS void SkipNamelistGroup(IoStatementState &io) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 418 | std::size_t byteCount{0}; |
| 419 | while (auto ch{io.GetNextNonBlank(byteCount)}) { |
| 420 | io.HandleRelativePosition(byteCount); |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 421 | if (*ch == '/' || *ch == '&' || *ch == '$') { |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 422 | break; |
| 423 | } else if (*ch == '\'' || *ch == '"') { |
| 424 | // Skip quoted character literal |
| 425 | char32_t quote{*ch}; |
| 426 | while (true) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 427 | if ((ch = io.GetCurrentChar(byteCount))) { |
| 428 | io.HandleRelativePosition(byteCount); |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 429 | if (*ch == quote) { |
| 430 | break; |
| 431 | } |
| 432 | } else if (!io.AdvanceRecord()) { |
| 433 | return; |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | } |
| 438 | } |
| 439 | |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 440 | bool IODEF(InputNamelist)(Cookie cookie, const NamelistGroup &group) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 441 | IoStatementState &io{*cookie}; |
| 442 | io.CheckFormattedStmtType<Direction::Input>("InputNamelist"); |
Peter Klausler | 9772dbb | 2022-01-27 20:09:07 | [diff] [blame] | 443 | io.mutableModes().inNamelist = true; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 444 | IoErrorHandler &handler{io.GetIoErrorHandler()}; |
peter klausler | e093cbb | 2021-07-21 20:07:04 | [diff] [blame] | 445 | auto *listInput{io.get_if<ListDirectedStatementState<Direction::Input>>()}; |
| 446 | RUNTIME_CHECK(handler, listInput != nullptr); |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 447 | // Find this namelist group's header in the input |
peter klausler | 4c15a97 | 2021-08-13 18:57:58 | [diff] [blame] | 448 | io.BeginReadingRecord(); |
Slava Zakharin | 71e0261 | 2024-03-15 21:25:47 | [diff] [blame] | 449 | Fortran::common::optional<char32_t> next; |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 450 | char name[nameBufferSize]; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 451 | RUNTIME_CHECK(handler, group.groupName != nullptr); |
Peter Klausler | 896a543 | 2022-01-20 00:25:41 | [diff] [blame] | 452 | char32_t comma{GetComma(io)}; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 453 | std::size_t byteCount{0}; |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 454 | while (true) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 455 | next = io.GetNextNonBlank(byteCount); |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 456 | while (next && *next != '&' && *next != '$') { |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 457 | // Extension: comment lines without ! before namelist groups |
| 458 | if (!io.AdvanceRecord()) { |
| 459 | next.reset(); |
| 460 | } else { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 461 | next = io.GetNextNonBlank(byteCount); |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 462 | } |
| 463 | } |
Peter Klausler | a5f5d72 | 2022-10-04 18:40:38 | [diff] [blame] | 464 | if (!next) { |
| 465 | handler.SignalEnd(); |
| 466 | return false; |
| 467 | } |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 468 | if (*next != '&' && *next != '$') { |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 469 | handler.SignalError( |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 470 | "NAMELIST input group does not begin with '&' or '$' (at '%lc')", |
| 471 | *next); |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 472 | return false; |
| 473 | } |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 474 | io.HandleRelativePosition(byteCount); |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 475 | if (!GetLowerCaseName(io, name, sizeof name)) { |
| 476 | handler.SignalError("NAMELIST input group has no name"); |
| 477 | return false; |
| 478 | } |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 479 | if (Fortran::runtime::strcmp(group.groupName, name) == 0) { |
Peter Klausler | d1123e3 | 2022-01-13 01:34:52 | [diff] [blame] | 480 | break; // found it |
| 481 | } |
| 482 | SkipNamelistGroup(io); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 483 | } |
| 484 | // Read the group's items |
| 485 | while (true) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 486 | next = io.GetNextNonBlank(byteCount); |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 487 | if (!next || *next == '/' || *next == '&' || *next == '$') { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 488 | break; |
| 489 | } |
| 490 | if (!GetLowerCaseName(io, name, sizeof name)) { |
| 491 | handler.SignalError( |
Peter Klausler | 896a543 | 2022-01-20 00:25:41 | [diff] [blame] | 492 | "NAMELIST input group '%s' was not terminated at '%c'", |
| 493 | group.groupName, static_cast<char>(*next)); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 494 | return false; |
| 495 | } |
| 496 | std::size_t itemIndex{0}; |
| 497 | for (; itemIndex < group.items; ++itemIndex) { |
Slava Zakharin | f3c31d7 | 2024-04-05 15:29:24 | [diff] [blame] | 498 | if (Fortran::runtime::strcmp(name, group.item[itemIndex].name) == 0) { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 499 | break; |
| 500 | } |
| 501 | } |
| 502 | if (itemIndex >= group.items) { |
| 503 | handler.SignalError( |
| 504 | "'%s' is not an item in NAMELIST group '%s'", name, group.groupName); |
| 505 | return false; |
| 506 | } |
| 507 | // Handle indexing and components, if any. No spaces are allowed. |
| 508 | // A copy of the descriptor is made if necessary. |
| 509 | const Descriptor &itemDescriptor{group.item[itemIndex].descriptor}; |
| 510 | const Descriptor *useDescriptor{&itemDescriptor}; |
| 511 | StaticDescriptor<maxRank, true, 16> staticDesc[2]; |
| 512 | int whichStaticDesc{0}; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 513 | next = io.GetCurrentChar(byteCount); |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 514 | bool hadSubscripts{false}; |
| 515 | bool hadSubstring{false}; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 516 | if (next && (*next == '(' || *next == '%')) { |
Peter Klausler | dea30ac | 2024-01-02 17:25:49 | [diff] [blame] | 517 | const Descriptor *lastSubscriptBase{nullptr}; |
| 518 | Descriptor *lastSubscriptDescriptor{nullptr}; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 519 | do { |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 520 | Descriptor &mutableDescriptor{staticDesc[whichStaticDesc].descriptor()}; |
| 521 | whichStaticDesc ^= 1; |
Peter Klausler | bad5205 | 2022-08-03 19:31:05 | [diff] [blame] | 522 | io.HandleRelativePosition(byteCount); // skip over '(' or '%' |
Peter Klausler | dea30ac | 2024-01-02 17:25:49 | [diff] [blame] | 523 | lastSubscriptDescriptor = nullptr; |
| 524 | lastSubscriptBase = nullptr; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 525 | if (*next == '(') { |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 526 | if (!hadSubstring && (hadSubscripts || useDescriptor->rank() == 0)) { |
| 527 | mutableDescriptor = *useDescriptor; |
| 528 | mutableDescriptor.raw().attribute = CFI_attribute_pointer; |
| 529 | if (!HandleSubstring(io, mutableDescriptor, name)) { |
| 530 | return false; |
| 531 | } |
| 532 | hadSubstring = true; |
| 533 | } else if (hadSubscripts) { |
| 534 | handler.SignalError("Multiple sets of subscripts for item '%s' in " |
| 535 | "NAMELIST group '%s'", |
| 536 | name, group.groupName); |
| 537 | return false; |
Peter Klausler | dea30ac | 2024-01-02 17:25:49 | [diff] [blame] | 538 | } else if (HandleSubscripts( |
| 539 | io, mutableDescriptor, *useDescriptor, name)) { |
| 540 | lastSubscriptBase = useDescriptor; |
| 541 | lastSubscriptDescriptor = &mutableDescriptor; |
Peter Klausler | bad5205 | 2022-08-03 19:31:05 | [diff] [blame] | 542 | } else { |
Peter Klausler | dea30ac | 2024-01-02 17:25:49 | [diff] [blame] | 543 | return false; |
peter klausler | 6d44387 | 2021-10-20 23:01:52 | [diff] [blame] | 544 | } |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 545 | hadSubscripts = true; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 546 | } else { |
peter klausler | 6d44387 | 2021-10-20 23:01:52 | [diff] [blame] | 547 | if (!HandleComponent(io, mutableDescriptor, *useDescriptor, name)) { |
| 548 | return false; |
| 549 | } |
Peter Klausler | 0ab1708 | 2022-01-07 21:39:28 | [diff] [blame] | 550 | hadSubscripts = false; |
| 551 | hadSubstring = false; |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 552 | } |
peter klausler | 79caf69 | 2021-06-17 20:13:19 | [diff] [blame] | 553 | useDescriptor = &mutableDescriptor; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 554 | next = io.GetCurrentChar(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 555 | } while (next && (*next == '(' || *next == '%')); |
Peter Klausler | dea30ac | 2024-01-02 17:25:49 | [diff] [blame] | 556 | if (lastSubscriptDescriptor) { |
| 557 | StorageSequenceExtension(*lastSubscriptDescriptor, *lastSubscriptBase); |
| 558 | } |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 559 | } |
| 560 | // Skip the '=' |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 561 | next = io.GetNextNonBlank(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 562 | if (!next || *next != '=') { |
| 563 | handler.SignalError("No '=' found after item '%s' in NAMELIST group '%s'", |
| 564 | name, group.groupName); |
| 565 | return false; |
| 566 | } |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 567 | io.HandleRelativePosition(byteCount); |
peter klausler | b8452db | 2021-10-20 20:56:47 | [diff] [blame] | 568 | // Read the values into the descriptor. An array can be short. |
Peter Klausler | 7cf1608 | 2023-04-13 17:28:19 | [diff] [blame] | 569 | if (const auto *addendum{useDescriptor->Addendum()}; |
| 570 | addendum && addendum->derivedType()) { |
V Donaldson | 6f7a3b0 | 2023-05-16 20:34:57 | [diff] [blame] | 571 | const NonTbpDefinedIoTable *table{group.nonTbpDefinedIo}; |
Peter Klausler | 750c8e3 | 2023-10-16 20:23:31 | [diff] [blame] | 572 | listInput->ResetForNextNamelistItem(/*inNamelistSequence=*/true); |
Peter Klausler | 7cf1608 | 2023-04-13 17:28:19 | [diff] [blame] | 573 | if (!IONAME(InputDerivedType)(cookie, *useDescriptor, table)) { |
| 574 | return false; |
| 575 | } |
Peter Klausler | 750c8e3 | 2023-10-16 20:23:31 | [diff] [blame] | 576 | } else { |
| 577 | listInput->ResetForNextNamelistItem(useDescriptor->rank() > 0); |
| 578 | if (!descr::DescriptorIO<Direction::Input>(io, *useDescriptor)) { |
| 579 | return false; |
| 580 | } |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 581 | } |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 582 | next = io.GetNextNonBlank(byteCount); |
Peter Klausler | 896a543 | 2022-01-20 00:25:41 | [diff] [blame] | 583 | if (next && *next == comma) { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 584 | io.HandleRelativePosition(byteCount); |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 585 | } |
| 586 | } |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 587 | if (next && *next == '/') { |
| 588 | io.HandleRelativePosition(byteCount); |
| 589 | } else if (*next && (*next == '&' || *next == '$')) { |
| 590 | // stop at beginning of next group |
| 591 | } else { |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 592 | handler.SignalError( |
| 593 | "No '/' found after NAMELIST group '%s'", group.groupName); |
| 594 | return false; |
| 595 | } |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 596 | return true; |
| 597 | } |
| 598 | |
Peter Klausler | 514b759 | 2022-08-14 17:29:21 | [diff] [blame] | 599 | bool IsNamelistNameOrSlash(IoStatementState &io) { |
Peter Klausler | 2c39975 | 2022-08-14 16:56:31 | [diff] [blame] | 600 | if (auto *listInput{ |
| 601 | io.get_if<ListDirectedStatementState<Direction::Input>>()}) { |
Peter Klausler | 750c8e3 | 2023-10-16 20:23:31 | [diff] [blame] | 602 | if (listInput->inNamelistSequence()) { |
Peter Klausler | e782360 | 2021-11-03 22:33:29 | [diff] [blame] | 603 | SavedPosition savedPosition{io}; |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 604 | std::size_t byteCount{0}; |
| 605 | if (auto ch{io.GetNextNonBlank(byteCount)}) { |
peter klausler | b8452db | 2021-10-20 20:56:47 | [diff] [blame] | 606 | if (IsLegalIdStart(*ch)) { |
| 607 | do { |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 608 | io.HandleRelativePosition(byteCount); |
| 609 | ch = io.GetCurrentChar(byteCount); |
peter klausler | b8452db | 2021-10-20 20:56:47 | [diff] [blame] | 610 | } while (ch && IsLegalIdChar(*ch)); |
Peter Klausler | bafbae2 | 2022-03-16 19:32:03 | [diff] [blame] | 611 | ch = io.GetNextNonBlank(byteCount); |
peter klausler | b8452db | 2021-10-20 20:56:47 | [diff] [blame] | 612 | // TODO: how to deal with NaN(...) ambiguity? |
Peter Klausler | e782360 | 2021-11-03 22:33:29 | [diff] [blame] | 613 | return ch && (*ch == '=' || *ch == '(' || *ch == '%'); |
Peter Klausler | 514b759 | 2022-08-14 17:29:21 | [diff] [blame] | 614 | } else { |
Peter Klausler | 120ad25 | 2024-01-02 16:42:10 | [diff] [blame] | 615 | return *ch == '/' || *ch == '&' || *ch == '$'; |
peter klausler | b8452db | 2021-10-20 20:56:47 | [diff] [blame] | 616 | } |
| 617 | } |
| 618 | } |
| 619 | } |
| 620 | return false; |
| 621 | } |
| 622 | |
Slava Zakharin | 8ebf741 | 2024-03-25 23:01:25 | [diff] [blame] | 623 | RT_OFFLOAD_API_GROUP_END |
| 624 | |
peter klausler | 6a1c3ef | 2021-05-05 18:37:49 | [diff] [blame] | 625 | } // namespace Fortran::runtime::io |