// SPDX-License-Identifier: MIT
#pragma once
#include <iosfwd>
#include <string>
#include "MWriter.hh"
#include "Message.hh"
/// \file MMessage.hh
/// \brief Writers for everything generated from one `$MESSAGE`: the
/// declarations in the header and the definitions in the source.
///
/// Per message the source gets up to two static text functions:
/// `InternalStreamerFunctionOf_<name>` writes the text to a `std::ostream`
/// (for the streamable class and the error function), and
/// `InternalBuilderOf_<name>` appends it to a `std::string` without a stream
/// (for the string and syslog functions and the exception's `What()`) —
/// several times faster than building through a `std::ostringstream`.
/// \brief The functions a `FunctionConcept` generates.
enum class FunctionKind { String, Error, Throw, Log };
class MessagePrototypeWriter
: public Writer
{
public:
MessagePrototypeWriter( std::ostream &stream, std::string &indent );
static std::string StreamableClassName( const Message &message );
static std::string ExceptionClassName( const Message &message );
/// \brief Whether the exception class needs the constructor taking a locale.
static bool ExceptionLocaleConstructor( const Message &message );
protected:
/// \brief Where a generated function lives and what it takes.
struct Placement
{
std::string className; ///< Qualifier of the definition; empty for a free function.
std::string name; ///< Function name without prefix / postfix.
ParameterList parameters; ///< Empty for MEMBER AS: the class' members are used.
bool constness;
std::string argumentPrefix; ///< "member_" for MEMBER AS.
};
static Placement Place( const Message &message, const FunctionConcept &concept );
void FunctionPrototype( const std::string &returnType,
const std::string &className,
const std::string &prefix,
const std::string &postfix,
const std::string &name,
const ParameterList ¶meters,
bool constness,
bool localeParm = true,
bool streamFunc = false ) const;
void LogFunctionPrototype( const std::string &returnType,
const std::string &className,
const std::string &prefix,
const std::string &postfix,
const std::string &name,
const ParameterList ¶meters,
bool constness,
const std::string &facility,
const std::string &level,
bool localeParm,
bool defaultVal ) const;
/// \brief The declarations of a function concept's function(s).
void Declarations( const Message &message, const FunctionConcept &concept,
FunctionKind kind, bool inClass ) const;
void WriteBaseClause( inheritance type, const std::string &parent ) const;
};
class MessageHeaderWriter
: public MessagePrototypeWriter
{
public:
MessageHeaderWriter( std::ostream &stream, std::string &indent );
void operator( )( const Message &message );
protected:
void StreamableClass( const Message &message ) const;
void ExceptionClass( const Message &message ) const;
};
class MessageCodeWriter
: public MessagePrototypeWriter
{
public:
MessageCodeWriter( std::ostream &stream, std::string &indent );
void operator( )( const Message &message );
protected:
void TextFunction( const Message &message, bool builder );
void Definitions( const Message &message, const FunctionConcept &concept, FunctionKind kind );
void ExceptionClass( const Message &message );
void StreamableClassBody( const Message &message );
void ClassConstructor( const Message &message,
const std::string &parent,
const std::string &className,
bool loc,
bool exception );
void CallBuilder( const Message &message, const std::string &locale,
const std::string &argumentPrefix, const ParameterList ¶meters );
void CallStreamer( const Message &message, bool loc,
const std::string &stream, const std::string &argumentPrefix,
const ParameterList ¶meters );
};
/// \brief Whether a message needs the stream / the string text function.
bool NeedsStreamer( const Message &message );
bool NeedsBuilder( const Message &message );
/// \brief Name of the helper the source defines when a message has several
/// languages; see `WriteLocaleMatcher()`.
extern const char *const LocaleMatcherName;
/// \brief Define the locale-name matcher: exact name, or the language followed
/// by '_', '.' or '@' — `[tr]` and `[tr_TR]` both select `tr_TR.UTF-8`.
void WriteLocaleMatcher( std::ostream &stream );