summaryrefslogtreecommitdiff
path: root/source/compiler-core/slang-pretty-writer.h
blob: 6817047a21bbc7d9c315ed8a114fbc42c6399a3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#ifndef SLANG_CORE_PRETTY_WRITER_H
#define SLANG_CORE_PRETTY_WRITER_H


#include "../core/slang-char-util.h"
#include "../core/slang-string-util.h"
#include "../core/slang-string.h"

namespace Slang
{

struct PrettyWriter
{
    typedef PrettyWriter ThisType;

    friend struct CommaTrackerRAII;

    struct CommaState
    {
        bool needComma = false;
    };

    void writeRaw(const UnownedStringSlice& slice) { m_builder.append(slice); }
    void writeRaw(char const* begin, char const* end);
    void writeRaw(char const* begin) { writeRaw(UnownedStringSlice(begin)); }

    void writeRawChar(int c) { m_builder.appendChar(char(c)); }

    void writeHexChar(int c) { writeRawChar(CharUtil::getHexChar(Index(c))); }

    /// Adjusts indentation if at start of a line
    void adjust();

    /// Increase indentation
    void indent() { m_indent++; }
    /// Decreate indentation
    void dedent();

    /// Write taking into account any CR that might be in a slice
    void write(const UnownedStringSlice& slice);
    void write(char const* text) { write(UnownedStringSlice(text)); }
    void write(char const* text, size_t length) { write(UnownedStringSlice(text, length)); }

    /// Write the slice as an escaped string
    void writeEscapedString(const UnownedStringSlice& slice);

    /// Call before items in a comma-separated JSON list to emit the comma if/when needed
    void maybeComma();

    /// Get the builder the result is being constructed in
    StringBuilder& getBuilder() { return m_builder; }

    ThisType& operator<<(const UnownedStringSlice& slice)
    {
        write(slice);
        return *this;
    }
    ThisType& operator<<(const char* text)
    {
        write(text);
        return *this;
    }
    ThisType& operator<<(uint64_t val)
    {
        adjust();
        m_builder << val;
        return *this;
    }
    ThisType& operator<<(int64_t val)
    {
        adjust();
        m_builder << val;
        return *this;
    }
    ThisType& operator<<(int32_t val)
    {
        adjust();
        m_builder << val;
        return *this;
    }
    ThisType& operator<<(uint32_t val)
    {
        adjust();
        m_builder << val;
        return *this;
    }
    ThisType& operator<<(float val)
    {
        adjust();
        // We want to use a specific format, so we use the StringUtil to specify format, and not
        // just use <<
        StringUtil::appendFormat(m_builder, "%f", val);
        return *this;
    }

    bool m_startOfLine = true;
    int m_indent = 0;
    CommaState* m_commaState = nullptr;
    StringBuilder m_builder;
};

/// Type for tracking whether a comma is needed in a comma-separated JSON list
struct CommaTrackerRAII
{
    CommaTrackerRAII(PrettyWriter& writer)
        : m_writer(&writer), m_previousState(writer.m_commaState)
    {
        writer.m_commaState = &m_state;
    }

    ~CommaTrackerRAII() { m_writer->m_commaState = m_previousState; }

private:
    PrettyWriter::CommaState m_state;
    PrettyWriter* m_writer;
    PrettyWriter::CommaState* m_previousState;
};

} // namespace Slang


#endif