Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

116 lines
5.0 KiB
C++

// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
#pragma once
#include <optional>
#include <string>
#include <utility>
#include <hilti/base/util.h>
namespace hilti {
/**
* Base class providing support for generating "C-style" code.
*
* The class handles basic formatting, such as code indentation and white
* space insertion. The main output method for user code is `printString()`.
* For most of the formatting methods, there are corresponding i/o stream
* manipulators so that one can writem, e.g., `my_formatter << eol();`.
*/
class CodeFormatter {
public:
/** @param comment string beginning a comment line in the target language */
explicit CodeFormatter(std::string comment = "//") : _comment(std::move(comment)) {}
~CodeFormatter() = default;
/** Writes all output generated so far to an external stream. */
bool output(std::ostream& out) { return util::copyStream(_out, out); }
/** Returns a string representation of all output generated so far. */
auto str() const { return _out.str(); }
/** Signals the beginning of a new line. */
void next();
/** Inserts an empty line as a separator. */
void separator();
/**< Signals the end of a line. This will insert a newline. */
void eol();
/**< Signals the end of a statement. This will insert both a semicolon and a newline. */
void eos();
/** Surrounds a string with quotation mark and escapes it appropriately. */
void quoted(const std::string& s);
/** Inserts a comment line, prefixing it with the comment prefix. */
void comment(const std::string& s);
/** Increates the indentation by one level. */
void indent() { _indent += 1; }
/** Decreates the indentation by one level. */
void dedent() { _indent -= 1; }
/** Returns an stream with the output so far. */
auto& stream() { return _out; }
/** Adds a string to the output. */
CodeFormatter& printString(const std::string& s);
CodeFormatter(const CodeFormatter&) = delete;
CodeFormatter(CodeFormatter&&) = delete;
CodeFormatter& operator=(const CodeFormatter& f) = delete;
CodeFormatter& operator=(CodeFormatter&& f) = delete;
private:
std::stringstream _out;
std::string _comment;
int _indent = 0;
bool _did_sep = true;
bool _at_bol = true;
bool _in_comment = false;
};
namespace code_formatter {
class isManipulator {};
} // namespace code_formatter
#define __DEFINE_MANIPULATOR0(x) \
template<typename Formatter> \
class x : isManipulator { \
public: \
Formatter& operator()(Formatter& f) const { \
f.x(); \
return f; \
} \
};
#define __DEFINE_MANIPULATOR1(x, t) \
template<typename Formatter> \
class x : isManipulator { \
t _t; \
\
public: \
x(t _t) : _t(std::move(_t)) {} \
Formatter& operator()(Formatter& f) const { \
f.x(_t); \
return f; \
} \
};
namespace code_formatter {
__DEFINE_MANIPULATOR0(dedent)
__DEFINE_MANIPULATOR0(eol)
__DEFINE_MANIPULATOR0(eos)
__DEFINE_MANIPULATOR0(indent)
__DEFINE_MANIPULATOR0(separator)
__DEFINE_MANIPULATOR1(quoted, std::string)
__DEFINE_MANIPULATOR1(comment, std::string)
} // namespace code_formatter
} // namespace hilti