Code View

cparse / cparse-1.3.0.2 / src / cparse / Generator.hh
// SPDX-License-Identifier: MIT
#pragma once

#include <iosfwd>
#include <string>
#include <vector>

/// \file Generator.hh
/// \brief Abstract base for code emitters: identifier casing, header guards,
///        C++ string encoding and a namespace-scope stack.

namespace fedem
{
  namespace parser
  {
    class Indentation;

    /// \brief Abstract base class for code generators.
    ///
    /// `Generator` collects the string-shaping work every code emitter needs
    /// and leaves the emitter-specific parts pure virtual:
    ///
    /// - **You provide** the output stream (`getStream()`), the indentation
    ///   tracker (`getIndentor()`), the actual emission (`generate()`), and the
    ///   namespace-scope mechanism (`openNamespaceScope()`,
    ///   `closeNamespaceScope()`, `getNamespacePath()`).
    /// - **The base provides** identifier case conversion, non-alphanumeric
    ///   sanitisation, `#include` filename derivation, header-guard derivation,
    ///   and `encodeCppString()` for turning arbitrary bytes into a valid C++
    ///   string literal body.
    ///
    /// The helper methods are `virtual` so a subclass can override a single
    /// naming rule without reimplementing the rest. All are `const noexcept`.
    /// Copy and move are deleted — a generator owns a stream position.
    ///
    /// The parsing side (`Cursor`, `Parser`) and the code-generation side never
    /// reference each other inside cparse; a grammar-driven generator couples
    /// them in its own subclass.
    ///
    /// \see https://cparse.fedem.eu/reference/generator — reference manual page.
    /// \see Indentation
    class Generator
    {
      public:
        /// \brief Default-construct. The namespace-name stack starts empty.
        /// \see https://cparse.fedem.eu/reference/generator-ctor
        Generator( );

        /// \brief Destructor.
        /// \see https://cparse.fedem.eu/reference/generator-dtor
        virtual ~Generator( );

        /// \brief The stream emitted code is written to. Supplied by the subclass.
        /// \return A reference to the subclass's output stream.
        /// \see https://cparse.fedem.eu/reference/generator-get-stream
        virtual std::ostream& getStream( ) = 0;

        /// \brief The indentation tracker used while emitting. Supplied by the subclass.
        /// \return A reference to the subclass's `Indentation`.
        /// \see https://cparse.fedem.eu/reference/generator-get-indentor
        virtual Indentation& getIndentor( ) = 0;

        /// \brief Emit. The whole point of the subclass; called by the client.
        /// \see https://cparse.fedem.eu/reference/generator-generate
        virtual void generate( ) = 0;

        /// \brief Derive a filename: UpperCamel of \p base concatenated with the
        ///        lower-cased \p ext (e.g. `"my thing"`, `".HH"` → `"MyThing.hh"`).
        /// \param base Logical name, words separated by `_` or space.
        /// \param ext  Extension, lower-cased as-is (include the dot).
        /// \return The derived filename.
        /// \see https://cparse.fedem.eu/reference/generator-generate-filename
        virtual std::string generateFilename( std::string const& base, std::string const& ext ) const noexcept;

        /// \brief Derive an include-guard macro from the current namespace path
        ///        and \p header.
        /// \param header Header name (without directory).
        /// \return The guard: upper-cased, non-alphanumerics to `_`, runs of `_`
        ///         collapsed, any leading `_` stripped.
        /// \see https://cparse.fedem.eu/reference/generator-generate-header-guard
        virtual std::string generateHeaderGuard( std::string const& header ) const noexcept;

        /// \brief Lower-case every character of \p base.
        /// \param base Input string.
        /// \return \p base with every character lower-cased.
        /// \see https://cparse.fedem.eu/reference/generator-convert-lower-case
        virtual std::string convertLowerCase( std::string const& base ) const noexcept;

        /// \brief Upper-case every character of \p base.
        /// \param base Input string.
        /// \return \p base with every character upper-cased.
        /// \see https://cparse.fedem.eu/reference/generator-convert-upper-case
        virtual std::string convertUpperCase( std::string const& base ) const noexcept;

        /// \brief Convert \p base to UpperCamelCase.
        /// \param base Input string; `_` and space are word separators and are
        ///        dropped.
        /// \return \p base as UpperCamelCase — the first letter of each word
        ///         capitalised, the rest lower-cased.
        /// \see https://cparse.fedem.eu/reference/generator-convert-upper-case-camel
        virtual std::string convertUpperCaseCamel( std::string const& base ) const noexcept;

        /// \brief Convert \p base to lowerCamelCase.
        /// \param base Input string; `_` and space are word separators.
        /// \return `convertUpperCaseCamel(base)` with the first character
        ///         lower-cased.
        /// \see https://cparse.fedem.eu/reference/generator-convert-lower-case-camel
        virtual std::string convertLowerCaseCamel( std::string const& base ) const noexcept;

        /// \brief Replace every non-alphanumeric character of \p base with \p rch.
        /// \param base Input string.
        /// \param rch  Replacement character.
        /// \return The substituted string.
        /// \see https://cparse.fedem.eu/reference/generator-replace-non-alphanums
        virtual std::string replaceNonAlphanums( std::string const& base, std::string::value_type const rch ) const noexcept;

        /// \brief Remove every non-alphanumeric character of \p base.
        /// \param base Input string.
        /// \return \p base with only its alphanumeric characters kept.
        /// \see https://cparse.fedem.eu/reference/generator-remove-non-alphanums
        virtual std::string removeNonAlphanums( std::string const& base ) const noexcept;

        /// \brief Push a namespace name onto the scope stack (and, typically,
        ///        emit its opening `namespace X {`). Supplied by the subclass.
        /// \see https://cparse.fedem.eu/reference/generator-open-namespace-scope
        virtual void openNamespaceScope( ) noexcept = 0;

        /// \brief Pop a namespace name from the scope stack (and, typically,
        ///        emit its closing `}`). Supplied by the subclass.
        /// \see https://cparse.fedem.eu/reference/generator-close-namespace-scope
        virtual void closeNamespaceScope( ) noexcept = 0;

        /// \brief The current namespace path. Supplied by the subclass; consumed
        ///        by `generateHeaderGuard()`.
        /// \return The path, e.g. `"fedem/parser"`.
        /// \see https://cparse.fedem.eu/reference/generator-get-namespace-path
        virtual std::string getNamespacePath( ) const noexcept = 0;

        /// \brief Encode \p str so it is valid inside a C++ double-quoted string
        ///        literal.
        /// \param str Raw bytes to encode (taken by value).
        /// \return \p str with known escapes applied (`\n`, `\t`, `\\`, `\"`, …)
        ///         and other non-printable bytes rendered as three-digit octal.
        /// \see https://cparse.fedem.eu/reference/generator-encode-cpp-string
        static std::string encodeCppString( std::string str ) noexcept;

      protected:
        /// \brief The namespace-name scope stack, innermost last.
        std::vector< std::string > namespaceNameContainer;

      private:
        Generator( Generator const& other ) = delete;
        Generator( Generator&& other ) = delete;
        Generator& operator=( Generator const& other ) = delete;
        Generator& operator=( Generator&& other ) = delete;
    };

  }  // namespace parser
}  // namespace fedem