Code View

mstring / mstring-1.3.1.2 / src / MMessage.hh
// 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 &parameters,
                            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 &parameters,
                               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 &parameters );
    void CallStreamer( const Message &message, bool loc,
                       const std::string &stream, const std::string &argumentPrefix,
                       const ParameterList &parameters );
};

/// \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 );