116 lines
5.0 KiB
C++
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
|