// 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