Raw File
slang-ast-print.h
// 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.
        };
    };

    /// 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 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);

        /// 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
back to top