#ifndef FORTRAN_RUNTIME_FORMAT_H_
#define FORTRAN_RUNTIME_FORMAT_H_
#include "environment.h"
#include "io-error.h"
#include "flang/Common/Fortran.h"
#include "flang/Common/optional.h"
#include "flang/Decimal/decimal.h"
#include "flang/Runtime/freestanding-tools.h"
#include <cinttypes>
namespace Fortran::runtime {
class Descriptor;
}
namespace Fortran::runtime::io {
class IoStatementState;
enum EditingFlags {
blankZero = 1,
decimalComma = 2,
signPlus = 4,
};
struct MutableModes {
std::uint8_t editingFlags{0};
enum decimal::FortranRounding round{
executionEnvironment
.defaultOutputRoundingMode};
bool pad{true};
char delim{'\0'};
short scale{0};
bool inNamelist{false};
bool nonAdvancing{false};
};
struct DataEdit {
char descriptor;
RT_OFFLOAD_VAR_GROUP_BEGIN
static constexpr char ListDirected{'g'};
static constexpr char ListDirectedRealPart{'r'};
static constexpr char ListDirectedImaginaryPart{'z'};
static constexpr char ListDirectedNullValue{'n'};
static constexpr char DefinedDerivedType{'d'};
RT_OFFLOAD_VAR_GROUP_END
constexpr RT_API_ATTRS bool IsListDirected() const {
return descriptor == ListDirected || descriptor == ListDirectedRealPart ||
descriptor == ListDirectedImaginaryPart;
}
constexpr RT_API_ATTRS bool IsNamelist() const {
return IsListDirected() && modes.inNamelist;
}
char variation{'\0'};
Fortran::common::optional<int> width;
Fortran::common::optional<int> digits;
Fortran::common::optional<int> expoDigits;
MutableModes modes;
int repeat{1};
RT_OFFLOAD_VAR_GROUP_BEGIN
static constexpr std::size_t maxIoTypeChars{32};
static constexpr std::size_t maxVListEntries{4};
RT_OFFLOAD_VAR_GROUP_END
std::uint8_t ioTypeChars{0};
std::uint8_t vListEntries{0};
char ioType[maxIoTypeChars];
int vList[maxVListEntries];
};
template <typename CONTEXT> class FormatControl {
public:
using Context = CONTEXT;
using CharType = char;
RT_API_ATTRS FormatControl() {}
RT_API_ATTRS FormatControl(const Terminator &, const CharType *format,
std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
int maxHeight = maxMaxHeight);
static RT_API_ATTRS std::size_t GetNeededSize(int maxHeight) {
return sizeof(FormatControl) -
sizeof(Iteration) * (maxMaxHeight - maxHeight);
}
RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
Context &, int maxRepeat = 1);
RT_API_ATTRS void Finish(Context &);
private:
RT_OFFLOAD_VAR_GROUP_BEGIN
static constexpr std::uint8_t maxMaxHeight{100};
struct Iteration {
static constexpr int unlimited{-1};
int start{0};
int remaining{0};
};
RT_OFFLOAD_VAR_GROUP_END
RT_API_ATTRS void SkipBlanks() {
while (offset_ < formatLength_ &&
(format_[offset_] == ' ' || format_[offset_] == '\t' ||
format_[offset_] == '\v')) {
++offset_;
}
}
RT_API_ATTRS CharType PeekNext() {
SkipBlanks();
return offset_ < formatLength_ ? format_[offset_] : '\0';
}
RT_API_ATTRS CharType GetNextChar(IoErrorHandler &handler) {
SkipBlanks();
if (offset_ >= formatLength_) {
if (formatLength_ == 0) {
handler.SignalError(
IostatErrorInFormat, "Empty or badly assigned FORMAT");
} else {
handler.SignalError(
IostatErrorInFormat, "FORMAT missing at least one ')'");
}
return '\n';
}
return format_[offset_++];
}
RT_API_ATTRS int GetIntField(
IoErrorHandler &, CharType firstCh = '\0', bool *hadError = nullptr);
RT_API_ATTRS int CueUpNextDataEdit(Context &, bool stop = false);
static constexpr RT_API_ATTRS CharType Capitalize(CharType ch) {
return ch >= 'a' && ch <= 'z' ? ch + 'A' - 'a' : ch;
}
RT_API_ATTRS void ReportBadFormat(
Context &context, const char *msg, int offset) const {
if constexpr (std::is_same_v<CharType, char>) {
int firstNonBlank{0};
while (firstNonBlank < formatLength_ && format_[firstNonBlank] == ' ') {
++firstNonBlank;
}
int lastNonBlank{formatLength_ - 1};
while (lastNonBlank > firstNonBlank && format_[lastNonBlank] == ' ') {
--lastNonBlank;
}
if (firstNonBlank <= lastNonBlank) {
context.SignalError(IostatErrorInFormat,
"%s; at offset %d in format '%.*s'", msg, offset,
lastNonBlank - firstNonBlank + 1, format_ + firstNonBlank);
return;
}
}
context.SignalError(IostatErrorInFormat, "%s; at offset %d", msg, offset);
}
const std::uint8_t maxHeight_{maxMaxHeight};
std::uint8_t height_{0};
bool freeFormat_{false};
bool hitEnd_{false};
const CharType *format_{nullptr};
int formatLength_{0};
int offset_{0};
Iteration stack_[maxMaxHeight];
};
}
#endif