// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details. #pragma once #include #include #include #include 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 \ class x : isManipulator { \ public: \ Formatter& operator()(Formatter& f) const { \ f.x(); \ return f; \ } \ }; #define __DEFINE_MANIPULATOR1(x, t) \ template \ 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