summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ast-print.h
blob: 84ad422b6c8ec277e063315b0461d44e26052067 (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// slang-ast-print.h

#ifndef SLANG_AST_PRINT_H
#define SLANG_AST_PRINT_H

#include "../core/slang-range.h"
#include "slang-ast-all.h"

namespace Slang
{

class ASTPrinter
{
public:
    typedef uint32_t OptionFlags;
    struct OptionFlag
    {
        enum Enum : OptionFlags
        {
            ParamNames = 0x01, ///< If set will output parameter names
            ModuleName = 0x02, ///< Writes out module names
            NoInternalKeywords =
                0x04, ///< Omits internal decoration keywords (e.g. __target_intrinsic).
            SimplifiedBuiltinType = 0x08, ///< Prints simplified builtin generic types (e.g. float3)
                                          ///< instead of its generic form.

            /// Use the original generic type name instead of the specialized
            /// type name defined on an extension when
            /// printing the target type of an extension decl.
            NoSpecializedExtensionTypeName = 0x10,
            // Output `= blah` when function type parameters have a default value
            DefaultParamValues = 0x20,
        };
    };

    /// Note that we could/can have a hierarchy of Parts - with overlapping spans.
    /// Moreover we could have less kinds, if we used the overlaps to signal out sections
    ///
    /// For example we could have a 'Param', 'Generic' span, and then have 'Name', 'Type' and
    /// 'Value'. So a param type, would be the 'Type' defined in a Param span. Moreover you could
    /// have the hierarchy of Types, and then such that you can pull out specific parts that make up
    /// a type.
    ///
    /// This is powerful/flexible - but requires more complexity at the use sites, so for now we use
    /// this simpler mechanism.

    /// Defines part of the structure of the output printed.
    struct Part
    {
        enum class Kind
        {
            None,
            Type,
            Value,
            Name,
        };

        enum class Type
        {
            None,
            ParamType,             ///< The type associated with a parameter
            ParamName,             ///< The name associated with a parameter
            ReturnType,            ///< The return type
            DeclPath,              ///< The declaration path (NOT including the actual decl name)
            GenericParamType,      ///< Generic parameter type
            GenericParamValue,     ///< Generic parameter value
            GenericParamValueType, ///< The type requirement for a value type
        };

        static Kind getKind(Type type);
        static Part make(Type type, Index start, Index end)
        {
            Part part;
            part.type = type;
            part.start = start;
            part.end = end;
            return part;
        }

        Type type = Type::None;
        Index start;
        Index end;
    };

    struct PartPair
    {
        Part first;
        Part second;
    };

    struct ScopePart
    {
        ScopePart(ASTPrinter* printer, Part::Type type)
            : m_printer(printer), m_type(type), m_startIndex(printer->m_builder.getLength())
        {
        }
        ~ScopePart()
        {
            List<Part>* parts = m_printer->m_parts;
            if (parts)
            {
                parts->add(Part::make(m_type, m_startIndex, m_printer->m_builder.getLength()));
            }
        }

        Part::Type m_type;
        Index m_startIndex;
        ASTPrinter* m_printer;
    };

    /// We might want options to change how things are output, for example we may want to output
    /// parameter names if there are any

    /// Get the currently built up string
    StringBuilder& getStringBuilder() { return m_builder; }
    /// Get the current offset, for the end of the string builder - useful for building up ranges
    Index getOffset() const { return m_builder.getLength(); }

    /// Reset the state
    void reset() { m_builder.clear(); }

    /// Get the current string
    String getString() { return m_builder.produceString(); }

    /// Get contents as a slice
    UnownedStringSlice getSlice() const { return m_builder.getUnownedSlice(); }

    /// Add a type
    void addType(Type* type);
    /// Add an expr
    void addExpr(Expr* type);
    /// Add a value
    void addVal(Val* val);

    /// Add the path to the declaration including the declaration name
    void addDeclPath(const DeclRef<Decl>& declRef);

    /// Add the path such that it encapsulates all overridable decls (ie is without terminal generic
    /// parameters)
    void addOverridableDeclPath(const DeclRef<Decl>& declRef);

    /// Add just the parameters from a declaration.
    /// Will output the generic parameters (if it's a generic) in <> before the parameters ()
    void addDeclParams(const DeclRef<Decl>& declRef, List<Range<Index>>* outParamRange = nullptr);

    /// Add a prefix that describes the kind of declaration
    void addDeclKindPrefix(Decl* decl);

    /// Add the result type
    /// Should be called after the decl params
    void addDeclResultType(const DeclRef<Decl>& inDeclRef);

    /// Add the signature for the decl
    void addDeclSignature(const DeclRef<Decl>& declRef);

    /// Add generic parameters
    void addGenericParams(
        const DeclRef<GenericDecl>& genericDeclRef,
        List<Slang::Range<Index>>* outParamRanges = nullptr);

    /// Get the specified part type. Returns empty slice if not found
    UnownedStringSlice getPartSlice(Part::Type partType) const;
    /// Get the slice for a part
    UnownedStringSlice getPartSlice(const Part& part) const { return getPart(getSlice(), part); }

    /// Gets the specified part type
    static UnownedStringSlice getPart(const UnownedStringSlice& slice, const Part& part)
    {
        return (part.type != Part::Type::None)
                   ? UnownedStringSlice(slice.begin() + part.start, slice.begin() + part.end)
                   : UnownedStringSlice();
    }
    static UnownedStringSlice getPart(
        Part::Type partType,
        const UnownedStringSlice& slice,
        const List<Part>& parts);

    static void appendDeclName(Decl* decl, StringBuilder& out);

    /// Ctor
    ASTPrinter(ASTBuilder* astBuilder, OptionFlags optionFlags = 0, List<Part>* parts = nullptr)
        : m_astBuilder(astBuilder), m_parts(parts), m_optionFlags(optionFlags)
    {
    }

    static String getDeclSignatureString(const LookupResultItem& item, ASTBuilder* astBuilder);
    static String getDeclSignatureString(DeclRef<Decl> declRef, ASTBuilder* astBuilder);

protected:
    void _addDeclPathRec(const DeclRef<Decl>& declRef, Index depth);
    void _addDeclName(Decl* decl);

    OptionFlags m_optionFlags; ///< Flags controlling output
    List<Part>* m_parts;       ///< Optional parts list
    ASTBuilder* m_astBuilder;  ///< Required as types are setup as part of printing
    StringBuilder m_builder;   ///< The output of the 'printing' process
};

} // namespace Slang

#endif // SLANG_AST_PRINT_H