summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-03-01 15:37:46 -0500
committerGitHub <noreply@github.com>2021-03-01 15:37:46 -0500
commit837a155b3d33035ee0739858f4ab25c65048ad6c (patch)
tree7abc4859a6669c9b8e0bcdaad6eb7b37471679ba
parentb3501add6c4dda798acf7b84b71b638d8d0b7898 (diff)
Doc improvements (#1729)
* #include an absolute path didn't work - because paths were taken to always be relative. * Split out AST 'printing'. * Replace listener with List<Section> * Section -> Part. * Kind -> Type Flags -> Kind for ASTPrinter::Part * Improve comments around ASTPrinter. * toString -> toText on Val derived types. toText appends to a StringBuilder. * Added toSlice free function. Added operator<< for Val derived types. Use << where appropriate in doing toText. * More work at mark down output. * Fill in sourceloc for enum case. Add more sophisticated location determination for EnumCase. Refactored documentation output into DocMarkdownWriter. * Improvements for sig output.
-rw-r--r--build/visual-studio/slang/slang.vcxproj2
-rw-r--r--build/visual-studio/slang/slang.vcxproj.filters6
-rw-r--r--source/core/slang-string.h4
-rw-r--r--source/slang/slang-ast-base.h8
-rw-r--r--source/slang/slang-ast-print.cpp274
-rw-r--r--source/slang/slang-ast-print.h162
-rw-r--r--source/slang/slang-ast-support-types.h3
-rw-r--r--source/slang/slang-ast-type.cpp133
-rw-r--r--source/slang/slang-ast-type.h34
-rw-r--r--source/slang/slang-ast-val.cpp78
-rw-r--r--source/slang/slang-ast-val.h16
-rw-r--r--source/slang/slang-check-expr.cpp4
-rw-r--r--source/slang/slang-check-impl.h16
-rw-r--r--source/slang/slang-check-overload.cpp198
-rw-r--r--source/slang/slang-doc.cpp389
-rw-r--r--source/slang/slang-doc.h5
-rw-r--r--source/slang/slang-parser.cpp2
-rw-r--r--source/slang/slang-syntax.cpp29
-rw-r--r--source/slang/slang.cpp50
19 files changed, 975 insertions, 438 deletions
diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj
index 7ddc3a2e0..e2d91ea76 100644
--- a/build/visual-studio/slang/slang.vcxproj
+++ b/build/visual-studio/slang/slang.vcxproj
@@ -194,6 +194,7 @@
<ClInclude Include="..\..\..\source\slang\slang-ast-dump.h" />
<ClInclude Include="..\..\..\source\slang\slang-ast-expr.h" />
<ClInclude Include="..\..\..\source\slang\slang-ast-modifier.h" />
+ <ClInclude Include="..\..\..\source\slang\slang-ast-print.h" />
<ClInclude Include="..\..\..\source\slang\slang-ast-reflect.h" />
<ClInclude Include="..\..\..\source\slang\slang-ast-stmt.h" />
<ClInclude Include="..\..\..\source\slang\slang-ast-support-types.h" />
@@ -317,6 +318,7 @@
<ClCompile Include="..\..\..\source\slang\slang-ast-builder.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-decl.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-dump.cpp" />
+ <ClCompile Include="..\..\..\source\slang\slang-ast-print.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-reflect.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-substitutions.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-type.cpp" />
diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters
index f8bc02d51..e27409c5d 100644
--- a/build/visual-studio/slang/slang.vcxproj.filters
+++ b/build/visual-studio/slang/slang.vcxproj.filters
@@ -33,6 +33,9 @@
<ClInclude Include="..\..\..\source\slang\slang-ast-modifier.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\source\slang\slang-ast-print.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\source\slang\slang-ast-reflect.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -398,6 +401,9 @@
<ClCompile Include="..\..\..\source\slang\slang-ast-dump.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\source\slang\slang-ast-print.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\source\slang\slang-ast-reflect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/source/core/slang-string.h b/source/core/slang-string.h
index 3fb184ac7..2312c0439 100644
--- a/source/core/slang-string.h
+++ b/source/core/slang-string.h
@@ -181,6 +181,10 @@ namespace Slang
char const* m_end;
};
+ // A more convenient way to make slices from *string literals*
+ template <size_t SIZE>
+ SLANG_FORCE_INLINE UnownedStringSlice toSlice(const char (&in)[SIZE]) { return UnownedStringSlice(in, SIZE - 1); }
+
// A `StringRepresentation` provides the backing storage for
// all reference-counted string-related types.
class StringRepresentation : public RefObject
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index b7810b49a..bb92c4738 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -98,7 +98,11 @@ class Val : public NodeBase
Val* substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
bool equalsVal(Val* val);
+
+ // Appends as text to the end of the builder
+ void toText(StringBuilder& out);
String toString();
+
HashCode getHashCode();
bool operator == (const Val & v)
{
@@ -108,10 +112,12 @@ class Val : public NodeBase
// Overrides should be public so base classes can access
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
};
+SLANG_FORCE_INLINE StringBuilder& operator<<(StringBuilder& io, Val* val) { SLANG_ASSERT(val); val->toText(io); return io; }
+
class Type;
template <typename T>
diff --git a/source/slang/slang-ast-print.cpp b/source/slang/slang-ast-print.cpp
new file mode 100644
index 000000000..29c034659
--- /dev/null
+++ b/source/slang/slang-ast-print.cpp
@@ -0,0 +1,274 @@
+// slang-ast-print.cpp
+#include "slang-ast-print.h"
+
+#include "slang-check-impl.h"
+
+namespace Slang {
+
+ASTPrinter::Part::Kind ASTPrinter::Part::getKind(ASTPrinter::Part::Type type)
+{
+ typedef ASTPrinter::Part::Kind Kind;
+ typedef ASTPrinter::Part::Type Type;
+
+ switch (type)
+ {
+ case Type::ParamType: return Kind::Type;
+ case Type::ParamName: return Kind::Name;
+ case Type::ReturnType: return Kind::Type;
+ case Type::DeclPath: return Kind::Name;
+ case Type::GenericParamType: return Kind::Type;
+ case Type::GenericParamValue: return Kind::Value;
+ case Type::GenericParamValueType: return Kind::Type;
+ default: break;
+ }
+ return Kind::None;
+}
+
+void ASTPrinter::addType(Type* type)
+{
+ type->toText(m_builder);
+}
+
+void ASTPrinter::addVal(Val* val)
+{
+ val->toText(m_builder);
+}
+
+void ASTPrinter::_addDeclName(Decl* decl)
+{
+ if (as<ConstructorDecl>(decl))
+ {
+ m_builder << "init";
+ }
+ else if (as<SubscriptDecl>(decl))
+ {
+ m_builder << "subscript";
+ }
+ else
+ {
+ m_builder << getText(decl->getName());
+ }
+}
+
+void ASTPrinter::addDeclPath(const DeclRef<Decl>& declRef)
+{
+ ScopePart scopePart(this, Part::Type::DeclPath);
+ _addDeclPathRec(declRef);
+}
+
+void ASTPrinter::_addDeclPathRec(const DeclRef<Decl>& declRef)
+{
+ auto& sb = m_builder;
+
+ // Find the parent declaration
+ auto parentDeclRef = declRef.getParent();
+
+ // If the immediate parent is a generic, then we probably
+ // want the declaration above that...
+ auto parentGenericDeclRef = parentDeclRef.as<GenericDecl>();
+ if (parentGenericDeclRef)
+ {
+ parentDeclRef = parentGenericDeclRef.getParent();
+ }
+
+ // Depending on what the parent is, we may want to format things specially
+ if (auto aggTypeDeclRef = parentDeclRef.as<AggTypeDecl>())
+ {
+ _addDeclPathRec(aggTypeDeclRef);
+ sb << ".";
+ }
+
+ _addDeclName(declRef.getDecl());
+
+ // If the parent declaration is a generic, then we need to print out its
+ // signature
+ if (parentGenericDeclRef)
+ {
+ auto genSubst = as<GenericSubstitution>(declRef.substitutions.substitutions);
+ SLANG_RELEASE_ASSERT(genSubst);
+ SLANG_RELEASE_ASSERT(genSubst->genericDecl == parentGenericDeclRef.getDecl());
+
+ // If the name we printed previously was an operator
+ // that ends with `<`, then immediately printing the
+ // generic arguments inside `<...>` may cause it to
+ // be hard to parse the operator name visually.
+ //
+ // We thus include a space between the declaration name
+ // and its generic arguments in this case.
+ //
+ if (sb.endsWith("<"))
+ {
+ sb << " ";
+ }
+
+ sb << "<";
+ bool first = true;
+ for (auto arg : genSubst->args)
+ {
+ // When printing the representation of a specialized
+ // generic declaration we don't want to include the
+ // argument values for subtype witnesses since these
+ // do not correspond to parameters of the generic
+ // as the user sees it.
+ //
+ if (as<Witness>(arg))
+ continue;
+
+ if (!first) sb << ", ";
+ addVal(arg);
+ first = false;
+ }
+ sb << ">";
+ }
+}
+
+void ASTPrinter::addDeclParams(const DeclRef<Decl>& declRef)
+{
+ auto& sb = m_builder;
+
+ if (auto funcDeclRef = declRef.as<CallableDecl>())
+ {
+ // This is something callable, so we need to also print parameter types for overloading
+ sb << "(";
+
+ bool first = true;
+ for (auto paramDeclRef : getParameters(funcDeclRef))
+ {
+ if (!first) sb << ", ";
+
+ ParamDecl* paramDecl = paramDeclRef;
+
+ {
+ ScopePart scopePart(this, Part::Type::ParamType);
+ addType(getType(m_astBuilder, paramDeclRef));
+ }
+
+ // Output the parameter name if there is one, and it's enabled in the options
+ if (m_optionFlags & OptionFlag::ParamNames && paramDecl->getName())
+ {
+ sb << " ";
+
+ {
+ ScopePart scopePart(this, Part::Type::ParamName);
+ sb << paramDecl->getName()->text;
+ }
+ }
+
+ first = false;
+ }
+
+ sb << ")";
+ }
+ else if (auto genericDeclRef = declRef.as<GenericDecl>())
+ {
+ sb << "<";
+ bool first = true;
+ for (auto paramDeclRef : getMembers(genericDeclRef))
+ {
+ if (auto genericTypeParam = paramDeclRef.as<GenericTypeParamDecl>())
+ {
+ if (!first) sb << ", ";
+ first = false;
+
+ {
+ ScopePart scopePart(this, Part::Type::GenericParamType);
+ sb << getText(genericTypeParam.getName());
+ }
+ }
+ else if (auto genericValParam = paramDeclRef.as<GenericValueParamDecl>())
+ {
+ if (!first) sb << ", ";
+ first = false;
+
+ {
+ ScopePart scopePart(this, Part::Type::GenericParamValue);
+ sb << getText(genericValParam.getName());
+ }
+
+ sb << ":";
+
+ {
+ ScopePart scopePart(this, Part::Type::GenericParamValueType);
+ addType(getType(m_astBuilder, genericValParam));
+ }
+ }
+ else
+ {
+ }
+ }
+ sb << ">";
+
+ addDeclParams(DeclRef<Decl>(getInner(genericDeclRef), genericDeclRef.substitutions));
+ }
+ else
+ {
+ }
+}
+
+void ASTPrinter::addDeclKindPrefix(Decl* decl)
+{
+ if (auto genericDecl = as<GenericDecl>(decl))
+ {
+ decl = genericDecl->inner;
+ }
+ if (as<FuncDecl>(decl))
+ {
+ m_builder << "func ";
+ }
+}
+
+void ASTPrinter::addDeclResultType(const DeclRef<Decl>& inDeclRef)
+{
+ DeclRef<Decl> declRef = inDeclRef;
+ if (auto genericDeclRef = declRef.as<GenericDecl>())
+ {
+ declRef = DeclRef<Decl>(getInner(genericDeclRef), genericDeclRef.substitutions);
+ }
+
+ if (as<ConstructorDecl>(declRef))
+ {
+ }
+ else if (auto callableDeclRef = declRef.as<CallableDecl>())
+ {
+ m_builder << " -> ";
+
+ {
+ ScopePart scopePart(this, Part::Type::ReturnType);
+ addType(getResultType(m_astBuilder, callableDeclRef));
+ }
+ }
+}
+
+/* static */void ASTPrinter::addDeclSignature(const DeclRef<Decl>& declRef)
+{
+ addDeclKindPrefix(declRef.getDecl());
+ addDeclPath(declRef);
+ addDeclParams(declRef);
+ addDeclResultType(declRef);
+}
+
+/* static */String ASTPrinter::getDeclSignatureString(DeclRef<Decl> declRef, ASTBuilder* astBuilder)
+{
+ ASTPrinter astPrinter(astBuilder);
+ astPrinter.addDeclSignature(declRef);
+ return astPrinter.getString();
+}
+
+/* static */String ASTPrinter::getDeclSignatureString(const LookupResultItem& item, ASTBuilder* astBuilder)
+{
+ return getDeclSignatureString(item.declRef, astBuilder);
+}
+
+/* static */UnownedStringSlice ASTPrinter::getPart(Part::Type partType, const UnownedStringSlice& slice, const List<Part>& parts)
+{
+ const Index index = parts.findFirstIndex([&](const Part& part) -> bool { return part.type == partType; });
+ return index >= 0 ? getPart(slice, parts[index]) : UnownedStringSlice();
+}
+
+UnownedStringSlice ASTPrinter::getPart(Part::Type partType) const
+{
+ return m_parts ? getPart(partType, getSlice(), *m_parts) : UnownedStringSlice();
+}
+
+
+} // namespace Slang
diff --git a/source/slang/slang-ast-print.h b/source/slang/slang-ast-print.h
new file mode 100644
index 000000000..7fb818898
--- /dev/null
+++ b/source/slang/slang-ast-print.h
@@ -0,0 +1,162 @@
+// slang-ast-print.h
+
+#ifndef SLANG_AST_PRINT_H
+#define SLANG_AST_PRINT_H
+
+#include "slang-ast-all.h"
+
+namespace Slang {
+
+class ASTPrinter
+{
+public:
+ typedef uint32_t OptionFlags;
+ struct OptionFlag
+ {
+ enum Enum : OptionFlags
+ {
+ ParamNames = 0x1, ///< If set will output parameter names
+ };
+ };
+
+ /// 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 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);
+
+ /// 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);
+
+ /// Get the specified part type. Returns empty slice if not found
+ UnownedStringSlice getPart(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 UnownedStringSlice(slice.begin() + part.start, slice.begin() + part.end); }
+ static UnownedStringSlice getPart(Part::Type partType, const UnownedStringSlice& slice, const List<Part>& parts);
+
+ /// 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);
+ 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
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 8338f0b21..6e4c90cc4 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -652,6 +652,7 @@ namespace Slang
// Debugging:
String toString() const;
+ void toText(StringBuilder& out) const;
};
template<typename T>
@@ -721,6 +722,8 @@ namespace Slang
}
};
+ SLANG_FORCE_INLINE StringBuilder& operator<<(StringBuilder& io, const DeclRefBase& declRef) { declRef.toText(io); return io; }
+
template<typename T>
DeclRef<T> DeclRefBase::as() const
{
diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp
index 79df8e48b..64b8c7515 100644
--- a/source/slang/slang-ast-type.cpp
+++ b/source/slang/slang-ast-type.cpp
@@ -77,9 +77,9 @@ Type* Type::getCanonicalType()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OverloadGroupType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String OverloadGroupType::_toStringOverride()
+void OverloadGroupType::_toTextOverride(StringBuilder& out)
{
- return "overload group";
+ out << toSlice("overload group");
}
bool OverloadGroupType::_equalsImplOverride(Type * /*type*/)
@@ -99,9 +99,9 @@ HashCode OverloadGroupType::_getHashCodeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! InitializerListType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String InitializerListType::_toStringOverride()
+void InitializerListType::_toTextOverride(StringBuilder& out)
{
- return "initializer list";
+ out << toSlice("initializer list");
}
bool InitializerListType::_equalsImplOverride(Type * /*type*/)
@@ -121,9 +121,9 @@ HashCode InitializerListType::_getHashCodeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ErrorType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String ErrorType::_toStringOverride()
+void ErrorType::_toTextOverride(StringBuilder& out)
{
- return "error";
+ out << toSlice("error");
}
bool ErrorType::_equalsImplOverride(Type* type)
@@ -150,9 +150,9 @@ HashCode ErrorType::_getHashCodeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DeclRefType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String DeclRefType::_toStringOverride()
+void DeclRefType::_toTextOverride(StringBuilder& out)
{
- return declRef.toString();
+ out << declRef;
}
HashCode DeclRefType::_getHashCodeOverride()
@@ -306,11 +306,9 @@ BasicExpressionType* BasicExpressionType::_getScalarTypeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VectorExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String VectorExpressionType::_toStringOverride()
+void VectorExpressionType::_toTextOverride(StringBuilder& out)
{
- StringBuilder sb;
- sb << "vector<" << elementType->toString() << "," << elementCount->toString() << ">";
- return sb.ProduceString();
+ out << toSlice("vector<") << elementType << toSlice(",") << elementCount << toSlice(">");
}
BasicExpressionType* VectorExpressionType::_getScalarTypeOverride()
@@ -320,11 +318,9 @@ BasicExpressionType* VectorExpressionType::_getScalarTypeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MatrixExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String MatrixExpressionType::_toStringOverride()
+void MatrixExpressionType::_toTextOverride(StringBuilder& out)
{
- StringBuilder sb;
- sb << "matrix<" << getElementType()->toString() << "," << getRowCount()->toString() << "," << getColumnCount()->toString() << ">";
- return sb.ProduceString();
+ out << toSlice("matrix<") << getElementType() << toSlice(",") << getRowCount() << toSlice(",") << getColumnCount() << toSlice(">");
}
BasicExpressionType* MatrixExpressionType::_getScalarTypeOverride()
@@ -401,21 +397,22 @@ HashCode ArrayExpressionType::_getHashCodeOverride()
return baseType->getHashCode();
}
-Slang::String ArrayExpressionType::_toStringOverride()
+void ArrayExpressionType::_toTextOverride(StringBuilder& out)
{
+ out << baseType;
+ out.appendChar('[');
if (arrayLength)
- return baseType->toString() + "[" + arrayLength->toString() + "]";
- else
- return baseType->toString() + "[]";
+ {
+ out << arrayLength;
+ }
+ out.appendChar(']');
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TypeType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String TypeType::_toStringOverride()
+void TypeType::_toTextOverride(StringBuilder& out)
{
- StringBuilder sb;
- sb << "typeof(" << type->toString() << ")";
- return sb.ProduceString();
+ out << toSlice("typeof(") << type << toSlice(")");
}
bool TypeType::_equalsImplOverride(Type * t)
@@ -440,10 +437,10 @@ HashCode TypeType::_getHashCodeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericDeclRefType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String GenericDeclRefType::_toStringOverride()
+void GenericDeclRefType::_toTextOverride(StringBuilder& out)
{
// TODO: what is appropriate here?
- return "<DeclRef<GenericDecl>>";
+ out << toSlice("<DeclRef<GenericDecl>>");
}
bool GenericDeclRefType::_equalsImplOverride(Type * type)
@@ -467,12 +464,9 @@ Type* GenericDeclRefType::_createCanonicalTypeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NamespaceType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String NamespaceType::_toStringOverride()
+void NamespaceType::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append("namespace ");
- result.append(declRef.toString());
- return result;
+ out << toSlice("namespace ") << declRef;
}
bool NamespaceType::_equalsImplOverride(Type * type)
@@ -504,9 +498,13 @@ Type* PtrTypeBase::getValueType()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NamedExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String NamedExpressionType::_toStringOverride()
+void NamedExpressionType::_toTextOverride(StringBuilder& out)
{
- return getText(declRef.getName());
+ Name* name = declRef.getName();
+ if (name)
+ {
+ out << name->text;
+ }
}
bool NamedExpressionType::_equalsImplOverride(Type * /*type*/)
@@ -538,19 +536,19 @@ HashCode NamedExpressionType::_getHashCodeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FuncType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String FuncType::_toStringOverride()
+void FuncType::_toTextOverride(StringBuilder& out)
{
- StringBuilder sb;
- sb << "(";
- UInt paramCount = getParamCount();
- for (UInt pp = 0; pp < paramCount; ++pp)
+ out << toSlice("(");
+ Index paramCount = getParamCount();
+ for (Index pp = 0; pp < paramCount; ++pp)
{
- if (pp != 0) sb << ", ";
- sb << getParamType(pp)->toString();
+ if (pp != 0)
+ {
+ out << toSlice(", ");
+ }
+ out << getParamType(pp);
}
- sb << ") -> ";
- sb << getResultType()->toString();
- return sb.ProduceString();
+ out << toSlice(") -> ") << getResultType();
}
bool FuncType::_equalsImplOverride(Type * type)
@@ -641,12 +639,9 @@ HashCode FuncType::_getHashCodeOverride()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExtractExistentialType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String ExtractExistentialType::_toStringOverride()
+void ExtractExistentialType::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append(declRef.toString());
- result.append(".This");
- return result;
+ out << declRef << toSlice(".This");
}
bool ExtractExistentialType::_equalsImplOverride(Type* type)
@@ -686,20 +681,21 @@ Val* ExtractExistentialType::_substituteImplOverride(ASTBuilder* astBuilder, Sub
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TaggedUnionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String TaggedUnionType::_toStringOverride()
+void TaggedUnionType::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append("__TaggedUnion(");
+ out << toSlice("__TaggedUnion(");
bool first = true;
for (auto caseType : caseTypes)
{
- if (!first) result.append(", ");
+ if (!first)
+ {
+ out << toSlice(", ");
+ }
first = false;
- result.append(caseType->toString());
+ out << caseType;
}
- result.append(")");
- return result;
+ out << toSlice(")");
}
bool TaggedUnionType::_equalsImplOverride(Type* type)
@@ -764,18 +760,14 @@ Val* TaggedUnionType::_substituteImplOverride(ASTBuilder* astBuilder, Substituti
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExistentialSpecializedType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String ExistentialSpecializedType::_toStringOverride()
+void ExistentialSpecializedType::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append("__ExistentialSpecializedType(");
- result.append(baseType->toString());
+ out << toSlice("__ExistentialSpecializedType(") << baseType;
for (auto arg : args)
{
- result.append(", ");
- result.append(arg.val->toString());
+ out << toSlice(", ") << arg.val;
}
- result.append(")");
- return result;
+ out << toSlice(")");
}
bool ExistentialSpecializedType::_equalsImplOverride(Type * type)
@@ -880,12 +872,9 @@ Val* ExistentialSpecializedType::_substituteImplOverride(ASTBuilder* astBuilder,
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ThisType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String ThisType::_toStringOverride()
+void ThisType::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append(interfaceDeclRef.toString());
- result.append(".This");
- return result;
+ out << interfaceDeclRef << toSlice(".This");
}
bool ThisType::_equalsImplOverride(Type * type)
@@ -940,13 +929,9 @@ Val* ThisType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet s
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AndType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-String AndType::_toStringOverride()
+void AndType::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append(left->toString());
- result.append(" & ");
- result.append(right->toString());
- return result;
+ out << left << toSlice(" & ") << right;
}
bool AndType::_equalsImplOverride(Type * type)
diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h
index d4d626182..f4aca515c 100644
--- a/source/slang/slang-ast-type.h
+++ b/source/slang/slang-ast-type.h
@@ -14,7 +14,7 @@ class OverloadGroupType : public Type
SLANG_AST_CLASS(OverloadGroupType)
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
@@ -28,7 +28,7 @@ class InitializerListType : public Type
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
@@ -40,7 +40,7 @@ class ErrorType : public Type
SLANG_AST_CLASS(ErrorType)
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
@@ -58,7 +58,7 @@ class DeclRefType : public Type
static DeclRefType* create(ASTBuilder* astBuilder, DeclRef<Decl> declRef);
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
@@ -393,7 +393,7 @@ class ArrayExpressionType : public Type
IntVal* arrayLength = nullptr;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
@@ -411,7 +411,7 @@ class TypeType : public Type
Type* type = nullptr;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
@@ -437,7 +437,7 @@ class VectorExpressionType : public ArithmeticExpressionType
IntVal* elementCount = nullptr;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
BasicExpressionType* _getScalarTypeOverride();
};
@@ -453,7 +453,7 @@ class MatrixExpressionType : public ArithmeticExpressionType
Type* getRowType();
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
BasicExpressionType* _getScalarTypeOverride();
private:
@@ -530,7 +530,7 @@ class NamedExpressionType : public Type
Type* innerType = nullptr;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
@@ -564,7 +564,7 @@ class FuncType : public Type
Type* getResultType() { return resultType; }
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
Type* _createCanonicalTypeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
bool _equalsImplOverride(Type* type);
@@ -581,7 +581,7 @@ class GenericDeclRefType : public Type
DeclRef<GenericDecl> const& getDeclRef() const { return declRef; }
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
@@ -603,7 +603,7 @@ class NamespaceType : public Type
DeclRef<NamespaceDeclBase> const& getDeclRef() const { return declRef; }
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
@@ -619,7 +619,7 @@ class ExtractExistentialType : public Type
DeclRef<InterfaceDecl> interfaceDeclRef;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
@@ -639,7 +639,7 @@ class TaggedUnionType : public Type
List<Type*> caseTypes;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
@@ -654,7 +654,7 @@ class ExistentialSpecializedType : public Type
ExpandedSpecializationArgs args;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
@@ -669,7 +669,7 @@ class ThisType : public Type
DeclRef<InterfaceDecl> interfaceDeclRef;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
@@ -687,7 +687,7 @@ class AndType : public Type
Type* right;
// Overrides should be public so base classes can access
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
bool _equalsImplOverride(Type* type);
HashCode _getHashCodeOverride();
Type* _createCanonicalTypeOverride();
diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp
index 5396749e5..97d79e290 100644
--- a/source/slang/slang-ast-val.cpp
+++ b/source/slang/slang-ast-val.cpp
@@ -26,9 +26,16 @@ bool Val::equalsVal(Val* val)
SLANG_AST_NODE_VIRTUAL_CALL(Val, equalsVal, (val))
}
+void Val::toText(StringBuilder& out)
+{
+ SLANG_AST_NODE_VIRTUAL_CALL(Val, toText, (out))
+}
+
String Val::toString()
{
- SLANG_AST_NODE_VIRTUAL_CALL(Val, toString, ())
+ StringBuilder builder;
+ toText(builder);
+ return builder;
}
HashCode Val::getHashCode()
@@ -52,10 +59,10 @@ bool Val::_equalsValOverride(Val* val)
//return false;
}
-String Val::_toStringOverride()
+void Val::_toTextOverride(StringBuilder& out)
{
+ SLANG_UNUSED(out);
SLANG_UNEXPECTED("Val::_toStringOverride not overridden");
- //return String();
}
HashCode Val::_getHashCodeOverride()
@@ -73,9 +80,9 @@ bool ConstantIntVal::_equalsValOverride(Val* val)
return false;
}
-String ConstantIntVal::_toStringOverride()
+void ConstantIntVal::_toTextOverride(StringBuilder& out)
{
- return String(value);
+ out << value;
}
HashCode ConstantIntVal::_getHashCodeOverride()
@@ -94,9 +101,13 @@ bool GenericParamIntVal::_equalsValOverride(Val* val)
return false;
}
-String GenericParamIntVal::_toStringOverride()
+void GenericParamIntVal::_toTextOverride(StringBuilder& out)
{
- return getText(declRef.getName());
+ Name* name = declRef.getName();
+ if (name)
+ {
+ out << name->text;
+ }
}
HashCode GenericParamIntVal::_getHashCodeOverride()
@@ -157,9 +168,9 @@ bool ErrorIntVal::_equalsValOverride(Val* val)
return false;
}
-String ErrorIntVal::_toStringOverride()
+void ErrorIntVal::_toTextOverride(StringBuilder& out)
{
- return "<error>";
+ out << toSlice("<error>");
}
HashCode ErrorIntVal::_getHashCodeOverride()
@@ -195,9 +206,9 @@ Val* TypeEqualityWitness::_substituteImplOverride(ASTBuilder* astBuilder, Substi
return rs;
}
-String TypeEqualityWitness::_toStringOverride()
+void TypeEqualityWitness::_toTextOverride(StringBuilder& out)
{
- return "TypeEqualityWitness(" + sub->toString() + ")";
+ out << toSlice("TypeEqualityWitness(") << sub << toSlice(")");
}
HashCode TypeEqualityWitness::_getHashCodeOverride()
@@ -319,17 +330,9 @@ Val* DeclaredSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, Sub
return rs;
}
-String DeclaredSubtypeWitness::_toStringOverride()
+void DeclaredSubtypeWitness::_toTextOverride(StringBuilder& out)
{
- StringBuilder sb;
- sb << "DeclaredSubtypeWitness(";
- sb << this->sub->toString();
- sb << ", ";
- sb << this->sup->toString();
- sb << ", ";
- sb << this->declRef.toString();
- sb << ")";
- return sb.ProduceString();
+ out << toSlice("DeclaredSubtypeWitness(") << sub << toSlice(", ") << sup << toSlice(", ") << declRef << toSlice(")");
}
HashCode DeclaredSubtypeWitness::_getHashCodeOverride()
@@ -392,18 +395,13 @@ Val* TransitiveSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, S
return result;
}
-String TransitiveSubtypeWitness::_toStringOverride()
+void TransitiveSubtypeWitness::_toTextOverride(StringBuilder& out)
{
// Note: we only print the constituent
// witnesses, and rely on them to print
// the starting and ending types.
- StringBuilder sb;
- sb << "TransitiveSubtypeWitness(";
- sb << this->subToMid->toString();
- sb << ", ";
- sb << this->midToSup->toString();
- sb << ")";
- return sb.ProduceString();
+
+ out << toSlice("TransitiveSubtypeWitness(") << subToMid << toSlice(", ") << midToSup << toSlice(")");
}
HashCode TransitiveSubtypeWitness::_getHashCodeOverride()
@@ -426,13 +424,9 @@ bool ExtractExistentialSubtypeWitness::_equalsValOverride(Val* val)
return false;
}
-String ExtractExistentialSubtypeWitness::_toStringOverride()
+void ExtractExistentialSubtypeWitness::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append("extractExistentialValue(");
- result.append(declRef.toString());
- result.append(")");
- return result;
+ out << toSlice("extractExistentialValue(") << declRef << toSlice(")");
}
HashCode ExtractExistentialSubtypeWitness::_getHashCodeOverride()
@@ -482,19 +476,21 @@ bool TaggedUnionSubtypeWitness::_equalsValOverride(Val* val)
return true;
}
-String TaggedUnionSubtypeWitness::_toStringOverride()
+void TaggedUnionSubtypeWitness::_toTextOverride(StringBuilder& out)
{
- String result;
- result.append("TaggedUnionSubtypeWitness(");
+ out << toSlice("TaggedUnionSubtypeWitness(");
bool first = true;
for (auto caseWitness : caseWitnesses)
{
- if (!first) result.append(", ");
+ if (!first)
+ {
+ out << toSlice(", ");
+ }
first = false;
- result.append(caseWitness->toString());
+ out << caseWitness;
}
- return result;
+ out << toSlice(")");
}
HashCode TaggedUnionSubtypeWitness::_getHashCodeOverride()
diff --git a/source/slang/slang-ast-val.h b/source/slang/slang-ast-val.h
index dc32b3faa..b76d6325f 100644
--- a/source/slang/slang-ast-val.h
+++ b/source/slang/slang-ast-val.h
@@ -23,7 +23,7 @@ class ConstantIntVal : public IntVal
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
protected:
@@ -42,7 +42,7 @@ class GenericParamIntVal : public IntVal
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
@@ -63,7 +63,7 @@ class ErrorIntVal : public IntVal
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
@@ -125,7 +125,7 @@ class TypeEqualityWitness : public SubtypeWitness
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
@@ -140,7 +140,7 @@ class DeclaredSubtypeWitness : public SubtypeWitness
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
@@ -158,7 +158,7 @@ class TransitiveSubtypeWitness : public SubtypeWitness
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
@@ -174,7 +174,7 @@ class ExtractExistentialSubtypeWitness : public SubtypeWitness
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
@@ -195,7 +195,7 @@ class TaggedUnionSubtypeWitness : public SubtypeWitness
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
- String _toStringOverride();
+ void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 736eee6fb..5c00cb64b 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -13,6 +13,8 @@
#include "slang-lookup.h"
+#include "slang-ast-print.h"
+
namespace Slang
{
DeclRefType* SemanticsVisitor::getExprDeclRefType(Expr * expr)
@@ -518,7 +520,7 @@ namespace Slang
for(auto item : lookupResult.items)
{
- String declString = getDeclSignatureString(item);
+ String declString = ASTPrinter::getDeclSignatureString(item, m_astBuilder);
getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString);
}
}
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index f1aae6a10..ad9de3f4b 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1420,22 +1420,6 @@ namespace Slang
Expr* funcExpr,
OverloadResolveContext& context);
- void formatType(StringBuilder& sb, Type* type);
-
- void formatVal(StringBuilder& sb, Val* val);
-
- void formatDeclPath(StringBuilder& sb, DeclRef<Decl> declRef);
-
- void formatDeclParams(StringBuilder& sb, DeclRef<Decl> declRef);
-
- void formatDeclResultType(StringBuilder& sb, DeclRef<Decl> const& declRef);
-
- void formatDeclSignature(StringBuilder& sb, DeclRef<Decl> declRef);
-
- String getDeclSignatureString(DeclRef<Decl> declRef);
-
- String getDeclSignatureString(LookupResultItem item);
-
String getCallSignatureString(
OverloadResolveContext& context);
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index a4a55c8ce..c4e4cbde4 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -2,6 +2,7 @@
#include "slang-check-impl.h"
#include "slang-lookup.h"
+#include "slang-ast-print.h"
// This file implements semantic checking logic related
// to resolving overloading call operations, by checking
@@ -531,7 +532,7 @@ namespace Slang
Diagnostics::genericArgumentInferenceFailed,
callString);
- String declString = getDeclSignatureString(candidate.item);
+ String declString = ASTPrinter::getDeclSignatureString(candidate.item, m_astBuilder);
getSink()->diagnose(candidate.item.declRef, Diagnostics::genericSignatureTried, declString);
goto error;
}
@@ -1268,197 +1269,6 @@ namespace Slang
}
}
- void SemanticsVisitor::formatType(StringBuilder& sb, Type* type)
- {
- sb << type->toString();
- }
-
- void SemanticsVisitor::formatVal(StringBuilder& sb, Val* val)
- {
- sb << val->toString();
- }
-
- static void formatDeclName(StringBuilder& sb, Decl* decl)
- {
- if(as<ConstructorDecl>(decl))
- {
- sb << "init";
- }
- else if(as<SubscriptDecl>(decl))
- {
- sb << "subscript";
- }
- else
- {
- sb << getText(decl->getName());
- }
- }
-
- void SemanticsVisitor::formatDeclPath(StringBuilder& sb, DeclRef<Decl> declRef)
- {
- // Find the parent declaration
- auto parentDeclRef = declRef.getParent();
-
- // If the immediate parent is a generic, then we probably
- // want the declaration above that...
- auto parentGenericDeclRef = parentDeclRef.as<GenericDecl>();
- if(parentGenericDeclRef)
- {
- parentDeclRef = parentGenericDeclRef.getParent();
- }
-
- // Depending on what the parent is, we may want to format things specially
- if(auto aggTypeDeclRef = parentDeclRef.as<AggTypeDecl>())
- {
- formatDeclPath(sb, aggTypeDeclRef);
- sb << ".";
- }
-
- formatDeclName(sb, declRef.getDecl());
-
- // If the parent declaration is a generic, then we need to print out its
- // signature
- if( parentGenericDeclRef )
- {
- auto genSubst = as<GenericSubstitution>(declRef.substitutions.substitutions);
- SLANG_RELEASE_ASSERT(genSubst);
- SLANG_RELEASE_ASSERT(genSubst->genericDecl == parentGenericDeclRef.getDecl());
-
- // If the name we printed previously was an operator
- // that ends with `<`, then immediately printing the
- // generic arguments inside `<...>` may cause it to
- // be hard to parse the operator name visually.
- //
- // We thus include a space between the declaration name
- // and its generic arguments in this case.
- //
- if(sb.endsWith("<")) sb << " ";
-
- sb << "<";
- bool first = true;
- for(auto arg : genSubst->args)
- {
- // When printing the representation of a specialized
- // generic declaration we don't want to include the
- // argument values for subtype witnesses since these
- // do not correspond to parameters of the generic
- // as the user sees it.
- //
- if(as<Witness>(arg))
- continue;
-
- if(!first) sb << ", ";
- formatVal(sb, arg);
- first = false;
- }
- sb << ">";
- }
- }
-
- void SemanticsVisitor::formatDeclParams(StringBuilder& sb, DeclRef<Decl> declRef)
- {
- if (auto funcDeclRef = declRef.as<CallableDecl>())
- {
-
- // This is something callable, so we need to also print parameter types for overloading
- sb << "(";
-
- bool first = true;
- for (auto paramDeclRef : getParameters(funcDeclRef))
- {
- if (!first) sb << ", ";
-
- formatType(sb, getType(m_astBuilder, paramDeclRef));
-
- first = false;
-
- }
-
- sb << ")";
- }
- else if(auto genericDeclRef = declRef.as<GenericDecl>())
- {
- sb << "<";
- bool first = true;
- for (auto paramDeclRef : getMembers(genericDeclRef))
- {
- if(auto genericTypeParam = paramDeclRef.as<GenericTypeParamDecl>())
- {
- if (!first) sb << ", ";
- first = false;
-
- sb << getText(genericTypeParam.getName());
- }
- else if(auto genericValParam = paramDeclRef.as<GenericValueParamDecl>())
- {
- if (!first) sb << ", ";
- first = false;
-
- sb << getText(genericValParam.getName());
- sb << ":";
- formatType(sb, getType(m_astBuilder, genericValParam));
- }
- else
- {}
- }
- sb << ">";
-
- formatDeclParams(sb, DeclRef<Decl>(getInner(genericDeclRef), genericDeclRef.substitutions));
- }
- else
- {
- }
- }
-
- static void formatDeclKindPrefix(StringBuilder& sb, Decl* decl)
- {
- if(auto genericDecl = as<GenericDecl>(decl))
- {
- decl = genericDecl->inner;
- }
- if(as<FuncDecl>(decl))
- {
- sb << "func ";
- }
- }
-
- void SemanticsVisitor::formatDeclResultType(StringBuilder& sb, DeclRef<Decl> const& inDeclRef)
- {
- DeclRef<Decl> declRef = inDeclRef;
- if(auto genericDeclRef = declRef.as<GenericDecl>())
- {
- declRef = DeclRef<Decl>(getInner(genericDeclRef), genericDeclRef.substitutions);
- }
-
- if(as<ConstructorDecl>(declRef))
- {}
- else if(auto callableDeclRef = declRef.as<CallableDecl>())
- {
- sb << " -> ";
- formatType(sb, getResultType(m_astBuilder, callableDeclRef));
- }
- }
-
- void SemanticsVisitor::formatDeclSignature(StringBuilder& sb, DeclRef<Decl> declRef)
- {
- formatDeclKindPrefix(sb, declRef.getDecl());
- formatDeclPath(sb, declRef);
- formatDeclParams(sb, declRef);
- formatDeclResultType(sb, declRef);
- }
-
- String SemanticsVisitor::getDeclSignatureString(DeclRef<Decl> declRef)
- {
- StringBuilder sb;
- formatDeclSignature(sb, declRef);
- return sb.ProduceString();
- }
-
- String SemanticsVisitor::getDeclSignatureString(LookupResultItem item)
- {
- return getDeclSignatureString(item.declRef);
- }
-
String SemanticsVisitor::getCallSignatureString(
OverloadResolveContext& context)
{
@@ -1469,7 +1279,7 @@ namespace Slang
for( UInt aa = 0; aa < argCount; ++aa )
{
if(aa != 0) argsListBuilder << ", ";
- argsListBuilder << context.getArgType(aa)->toString();
+ context.getArgType(aa)->toText(argsListBuilder);
}
argsListBuilder << ")";
return argsListBuilder.ProduceString();
@@ -1632,7 +1442,7 @@ namespace Slang
Index candidateIndex = 0;
for (auto candidate : context.bestCandidates)
{
- String declString = getDeclSignatureString(candidate.item);
+ String declString = ASTPrinter::getDeclSignatureString(candidate.item, m_astBuilder);
// declString = declString + "[" + String(candidate.conversionCostSum) + "]";
diff --git a/source/slang/slang-doc.cpp b/source/slang/slang-doc.cpp
index fa3e11030..c72250122 100644
--- a/source/slang/slang-doc.cpp
+++ b/source/slang/slang-doc.cpp
@@ -3,6 +3,9 @@
#include "../core/slang-string-util.h"
+#include "slang-ast-builder.h"
+#include "slang-ast-print.h"
+
namespace Slang {
/* TODO(JS):
@@ -33,19 +36,23 @@ public:
};
};
+ // NOTE! Don't change order without fixing isBefore and isAfter
enum class MarkupType
{
None,
- BlockBefore, /// /** */ or /*! */.
- BlockAfter, /// /*!< */ or /**< */
+ BlockBefore, /// /** */ or /*! */.
LineBangBefore, /// //! Can be multiple lines
LineSlashBefore, /// /// Can be multiple lines
+ BlockAfter, /// /*!< */ or /**< */
LineBangAfter, /// //!< Can be multiple lines
LineSlashAfter, /// ///< Can be multiple lines
};
+ static bool isBefore(MarkupType type) { return Index(type) >= Index(MarkupType::BlockBefore) && Index(type) <= Index(MarkupType::LineSlashBefore); }
+ static bool isAfter(MarkupType type) { return Index(type) >= Index(MarkupType::BlockAfter); }
+
struct IndexRange
{
SLANG_FORCE_INLINE Index getCount() const { return end - start; }
@@ -60,8 +67,12 @@ public:
Before,
AfterParam, ///< Can have trailing , or )
AfterSemicolon, ///< Can have a trailing ;
+ AfterEnumCase, ///< Can have a , or before }
};
+ static bool isAfter(Location location) { return Index(location) >= Index(Location::AfterParam); }
+ static bool isBefore(Location location) { return location == Location::Before; }
+
struct FoundMarkup
{
void reset()
@@ -199,6 +210,7 @@ void DocMarkupExtractor::_addDeclRec(Decl* decl)
}
else
#endif
+
if (ContainerDecl* containerDecl = as<ContainerDecl>(decl))
{
// Add the container - which could be a class, struct, enum, namespace, extension, generic etc.
@@ -465,7 +477,7 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio
const TokenList& toks = *info.tokenList;
const Index tokIndex = info.declTokenIndex;
- Index direction = (location == Location::Before) ? -1 : 1;
+ Index direction = isBefore(location) ? -1 : 1;
const Index count = toks.m_tokens.getCount();
for (Index i = tokIndex; i >= 0 && i < count; i += direction)
@@ -474,6 +486,26 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio
switch (tok.type)
{
+ case TokenType::BlockComment:
+ case TokenType::LineComment:
+ {
+ if (openParensCount == 0 && openBracketCount == 0)
+ {
+ // Determine the markup type
+ const MarkupType markupType = findMarkupType(tok);
+ // If the location wanted is before and the markup is, we'll assume this is it
+ if (isBefore(location) && isBefore(markupType))
+ {
+ return i;
+ }
+ // If we are looking for enum cases, and the markup is after, we'll assume this is it
+ if (location == Location::AfterEnumCase && isAfter(markupType))
+ {
+ return i;
+ }
+ }
+ break;
+ }
case TokenType::LParent:
{
++openParensCount;
@@ -481,12 +513,12 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio
}
case TokenType::RBracket:
{
- openBracketCount += Index(location == Location::Before);
+ openBracketCount += Index(isBefore(location));
break;
}
case TokenType::LBracket:
{
- openBracketCount -= Index(location == Location::Before);
+ openBracketCount -= Index(isBefore(location));
break;
}
case TokenType::RParent:
@@ -507,7 +539,7 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio
}
case TokenType::Comma:
{
- if (location == Location::AfterParam)
+ if (location == Location::AfterParam || location == Location::AfterEnumCase)
{
return i + 1;
}
@@ -516,7 +548,7 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio
case TokenType::RBrace:
{
// If we haven't hit a candidate yet before hitting } it's not going to work
- if (location == Location::Before)
+ if (location == Location::Before || location == Location::AfterEnumCase)
{
return -1;
}
@@ -536,16 +568,6 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio
}
break;
}
- case TokenType::LineComment:
- case TokenType::BlockComment:
- {
- // We hit a comment this could be the markup
- if (location == Location::Before && openParensCount == 0 && openBracketCount == 0)
- {
- return i;
- }
- break;
- }
default: break;
}
}
@@ -600,13 +622,13 @@ SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, Location locat
return SLANG_E_NOT_FOUND;
}
- const Index searchDirection = (location == Location::Before) ? -1 : 1;
+ const Index searchDirection = isBefore(location) ? -1 : 1;
// Get the type and flags
const MarkupType type = findMarkupType(toks[startIndex]);
const MarkupFlags flags = getFlags(type);
- const MarkupFlag::Enum requiredFlag = (location == Location::Before) ? MarkupFlag::Before : MarkupFlag::After;
+ const MarkupFlag::Enum requiredFlag = isBefore(location) ? MarkupFlag::Before : MarkupFlag::After;
if ((flags & requiredFlag) == 0)
{
return SLANG_E_NOT_FOUND;
@@ -714,6 +736,11 @@ SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, const Location
SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, Decl* decl, FoundMarkup& out)
{
+ if (auto enumCaseDecl = as<EnumCaseDecl>(decl))
+ {
+ Location locs[] = { Location::Before, Location::AfterEnumCase };
+ return _findMarkup(info, locs, SLANG_COUNT_OF(locs), out);
+ }
if (auto paramDecl = as<ParamDecl>(decl))
{
Location locs[] = { Location::Before, Location::AfterParam };
@@ -901,72 +928,320 @@ SlangResult DocMarkup::extract(ModuleDecl* moduleDecl, SourceManager* sourceMana
return context.extract(this, moduleDecl, sourceManager, sink);
}
-/* static */SlangResult DocumentationUtil::writeMarkdown(DocMarkup* markup, StringBuilder& out)
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DocMarkDownWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+
+struct DocMarkDownWriter
{
- for (const auto& entry : markup->getEntries())
+ typedef ASTPrinter::Part Part;
+ typedef ASTPrinter::PartPair PartPair;
+
+ struct Signature
{
- NodeBase* node = entry.m_node;
- Decl* decl = as<Decl>(node);
- if (!decl)
+ Part returnType;
+ List<PartPair> params;
+ Part name;
+ };
+
+ void write();
+
+ void writeCallable(const DocMarkup::Entry& entry, CallableDecl* callable);
+ void writeEnum(const DocMarkup::Entry& entry, EnumDecl* enumDecl);
+ void writeAggType(const DocMarkup::Entry& entry, AggTypeDecl* aggTypeDecl);
+
+ void writePreamble(const DocMarkup::Entry& entry);
+ void writeDescription(const DocMarkup::Entry& entry);
+
+ DocMarkDownWriter(DocMarkup* markup, ASTBuilder* astBuilder):
+ m_markup(markup),
+ m_astBuilder(astBuilder)
+ {
+ }
+
+ static void getSignature(const List<Part>& parts, Signature& outSig);
+
+ template <typename T>
+ void _appendAsBullets(FilteredMemberList<T>& in);
+
+ DocMarkup* m_markup;
+ ASTBuilder* m_astBuilder;
+ StringBuilder m_builder;
+};
+
+static void _appendAsSingleLine(const UnownedStringSlice& in, StringBuilder& out)
+{
+ List<UnownedStringSlice> lines;
+ StringUtil::calcLines(in, lines);
+
+ // Ideally we'd remove any extraneous whitespace, but for now just join
+ StringUtil::join(lines.getBuffer(), lines.getCount(), ' ', out);
+}
+
+template <typename T>
+void DocMarkDownWriter::_appendAsBullets(FilteredMemberList<T>& list)
+{
+ auto& out = m_builder;
+ for (auto element : list)
+ {
+ DocMarkup::Entry* paramEntry = m_markup->getEntry(element);
+
+ out << "* ";
+
+ Name* name = element->getName();
+ if (name)
{
- continue;
+ out << toSlice("_") << name->text << toSlice("_ ");
}
- // Skip these they will be output as part of their respective 'containers'
- if (as<ParamDecl>(decl) || as<EnumCaseDecl>(decl))
+ if (paramEntry)
{
- continue;
+ // Hmm, we'll want to make something multiline into a single line
+ _appendAsSingleLine(paramEntry->m_markup.getUnownedSlice(), out);
}
- if (CallableDecl* callableDecl = as<CallableDecl>(decl))
+ out << "\n";
+ }
+
+ out << toSlice("\n");
+}
+
+/* static */void DocMarkDownWriter::getSignature(const List<Part>& parts, Signature& outSig)
+{
+ const Index count = parts.getCount();
+ for (Index i = 0; i < count; ++i)
+ {
+ const auto& part = parts[i];
+ switch (part.type)
{
- out << entry.m_markup;
+ case Part::Type::ParamType:
+ {
+ PartPair pair;
+ pair.first = part;
+ if (parts[i + 1].type == Part::Type::ParamName)
+ {
+ pair.second = parts[i + 1];
+ i++;
+ }
+ outSig.params.add(pair);
+ break;
+ }
+ case Part::Type::ReturnType:
+ {
+ outSig.returnType = part;
+ break;
+ }
+ case Part::Type::DeclPath:
+ {
+ outSig.name = part;
+ break;
+ }
+ default: break;
+ }
+ }
+}
- // There's code to output sigs in the SemanticsVisitor - we probably need to extract that functionality
- // out so can be used here
+void DocMarkDownWriter::writeCallable(const DocMarkup::Entry& entry, CallableDecl* callableDecl)
+{
+ writePreamble(entry);
- // String declString = getDeclSignatureString(item);
+ auto& out = m_builder;
- auto params = callableDecl->getParameters();
- //const auto& returnType = callableDecl->returnType;
+ StringBuilder sigBuffer;
+ List<ASTPrinter::Part> parts;
+ ASTPrinter printer(m_astBuilder, ASTPrinter::OptionFlag::ParamNames, &parts);
- // Let's see if we can get markup on the parameters
- for (auto param : params)
- {
- DocMarkup::Entry* paramEntry = markup->getEntry(param);
+ printer.addDeclSignature(DeclRef<Decl>(callableDecl, nullptr));
- if (paramEntry)
- {
- out << paramEntry->m_markup;
+ Signature signature;
+ getSignature(parts, signature);
- auto type = param->getType();
+ const Index paramCount = signature.params.getCount();
- if (type)
- {
- out << type->toString();
- }
+ // Output the signature
+ {
+ // Extract the name
+ out << toSlice("# ") << printer.getPartSlice(signature.name) << toSlice("\n\n");
- Name* name = param->getName();
- if (name)
- {
- out << " ";
- out << name->text;
- }
- out << "\n\n";
+ out << toSlice("## Signature \n");
+ out << toSlice("```\n");
+ out << printer.getPartSlice(signature.returnType) << toSlice(" ");
+
+ out << printer.getPartSlice(signature.name);
+
+
+ if (paramCount > 0)
+ {
+ out << toSlice("(\n");
+
+ StringBuilder line;
+ for (Index i = 0; i < paramCount; ++i)
+ {
+ const auto& param = signature.params[i];
+ line.Clear();
+ // If we want to tab these over... we'll need to know how must space I have
+ line << " " << printer.getPartSlice(param.first);
+
+ Index indent = 25;
+ if (line.getLength() < indent)
+ {
+ line.appendRepeatedChar(' ', indent - line.getLength());
+ }
+ else
+ {
+ line.appendChar(' ');
}
+
+ line << printer.getPartSlice(param.second);
+ if (i < paramCount - 1)
+ {
+ line << ",\n";
+ }
+
+ out << line;
}
+
+ out << ");\n";
}
- else if (EnumDecl* enumDecl = as<EnumDecl>(decl))
+ else
+ {
+ out << toSlice("();\n");
+ }
+
+ out << "```\n\n";
+ }
+
+ // Only output params if there are any
+ if (paramCount)
+ {
+ out << "## Parameters\n\n";
+
+ auto params = callableDecl->getParameters();
+ _appendAsBullets(params);
+ }
+
+ writeDescription(entry);
+}
+
+void DocMarkDownWriter::writeEnum(const DocMarkup::Entry& entry, EnumDecl* enumDecl)
+{
+ writePreamble(entry);
+
+ auto& out = m_builder;
+
+ out << toSlice("# enum ");
+ Name* name = enumDecl->getName();
+ if (name)
+ {
+ out << name->text;
+ }
+ out << toSlice("\n\n");
+
+ out << toSlice("## Values \n\n");
+
+ auto cases = enumDecl->getMembersOfType<EnumCaseDecl>();
+ _appendAsBullets(cases);
+
+ writeDescription(entry);
+}
+
+void DocMarkDownWriter::writeAggType(const DocMarkup::Entry& entry, AggTypeDecl* aggTypeDecl)
+{
+ writePreamble(entry);
+
+ auto& out = m_builder;
+
+ // This could be lots of different things - struct/class/extension/interface/..
+
+ out << toSlice("# ");
+ if (as<StructDecl>(aggTypeDecl))
+ {
+ out << toSlice("struct ");
+ }
+ else if (as<ClassDecl>(aggTypeDecl))
+ {
+ out << toSlice("class ");
+ }
+ else
+ {
+ out << toSlice("?");
+ }
+
+ Name* name = aggTypeDecl->getName();
+ if (name)
+ {
+ out << name->text;
+ }
+ out << toSlice("\n\n");
+
+ out << "## Fields\n\n";
+
+ auto fields = aggTypeDecl->getMembersOfType<VarDecl>();
+ _appendAsBullets(fields);
+
+ writeDescription(entry);
+}
+
+void DocMarkDownWriter::writePreamble(const DocMarkup::Entry& entry)
+{
+ SLANG_UNUSED(entry);
+ auto& out = m_builder;
+
+ out << toSlice("\n");
+ out.appendRepeatedChar('-', 80);
+ out << toSlice("\n");
+}
+
+
+void DocMarkDownWriter::writeDescription(const DocMarkup::Entry& entry)
+{
+ auto& out = m_builder;
+
+ out << toSlice("\n## Description\n\n");
+ out << entry.m_markup;
+}
+
+void DocMarkDownWriter::write()
+{
+ for (const auto& entry : m_markup->getEntries())
+ {
+ NodeBase* node = entry.m_node;
+ Decl* decl = as<Decl>(node);
+ if (!decl)
+ {
+ continue;
+ }
+
+ // Skip these they will be output as part of their respective 'containers'
+ if (as<ParamDecl>(decl) || as<EnumCaseDecl>(decl))
{
+ continue;
+ }
+ if (CallableDecl* callableDecl = as<CallableDecl>(decl))
+ {
+ writeCallable(entry, callableDecl);
}
- else if (StructDecl* structDecl = as<StructDecl>(decl))
+ else if (EnumDecl* enumDecl = as<EnumDecl>(decl))
{
+ writeEnum(entry, enumDecl);
}
- else if (ClassDecl* classDecl = as<ClassDecl>(decl))
+ else if (AggTypeDecl* aggType = as<AggTypeDecl>(decl))
{
+ writeAggType(entry, aggType);
}
}
+}
+
+/* static */SlangResult DocumentationUtil::writeMarkdown(DocMarkup* markup, ASTBuilder* astBuilder, StringBuilder& out)
+{
+ // The ASTBuilder is needed in order to be able to create ast types that can then be printed.
+ // It is *assumed* here, that them being transient on this temporary ASTBuilder, doesn't mutate
+ // any of the nodes from the ASTBuilder/s for the things being documented
+
+ DocMarkDownWriter writer(markup, astBuilder);
+ writer.write();
+
+ Swap(out, writer.m_builder);
return SLANG_OK;
}
diff --git a/source/slang/slang-doc.h b/source/slang/slang-doc.h
index 49251808a..b2fd8c664 100644
--- a/source/slang/slang-doc.h
+++ b/source/slang/slang-doc.h
@@ -4,6 +4,7 @@
#include "../core/slang-basic.h"
#include "slang-ast-all.h"
+#include "slang-ast-print.h"
namespace Slang {
@@ -60,9 +61,11 @@ SLANG_INLINE DocMarkup::Entry* DocMarkup::getEntry(NodeBase* base)
return (indexPtr) ? &m_entries[*indexPtr] : nullptr;
}
+class SharedASTBuilder;
+
struct DocumentationUtil
{
- static SlangResult writeMarkdown(DocMarkup* markup, StringBuilder& out);
+ static SlangResult writeMarkdown(DocMarkup* markup, ASTBuilder* astBuilder, StringBuilder& out);
};
} // namespace Slang
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 395ea1ad1..bca493780 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -3620,6 +3620,8 @@ namespace Slang
static EnumCaseDecl* parseEnumCaseDecl(Parser* parser)
{
EnumCaseDecl* decl = parser->astBuilder->create<EnumCaseDecl>();
+ parser->FillPosition(decl);
+
decl->nameAndLoc = expectIdentifier(parser);
if(AdvanceIf(parser, TokenType::OpAssign))
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index d6e966aaa..62de6599c 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -20,23 +20,23 @@ void printDiagnosticArg(StringBuilder& sb, Decl* decl)
void printDiagnosticArg(StringBuilder& sb, Type* type)
{
- sb << type->toString();
+ type->toText(sb);
}
void printDiagnosticArg(StringBuilder& sb, Val* val)
{
- sb << val->toString();
+ val->toText(sb);
}
void printDiagnosticArg(StringBuilder& sb, TypeExp const& type)
{
- sb << type.type->toString();
+ type.type->toText(sb);
}
void printDiagnosticArg(StringBuilder& sb, QualType const& type)
{
if (type.type)
- sb << type.type->toString();
+ type.type->toText(sb);
else
sb << "<null>";
}
@@ -1104,13 +1104,22 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt
String DeclRefBase::toString() const
{
- if (!decl) return "";
-
- auto name = decl->getName();
- if (!name) return "";
+ StringBuilder builder;
+ toText(builder);
+ return builder;
+ }
- // TODO: need to print out substitutions too!
- return name->text;
+ void DeclRefBase::toText(StringBuilder& out) const
+ {
+ if (decl)
+ {
+ auto name = decl->getName();
+ if (name)
+ {
+ // TODO: need to print out substitutions too!
+ out << name->text;
+ }
+ }
}
bool SubstitutionSet::equals(const SubstitutionSet& substSet) const
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index e02715015..21f60c090 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -1639,25 +1639,7 @@ void FrontEndCompileRequest::parseTranslationUnit(
}
}
- if (shouldDocument)
- {
- RefPtr<DocMarkup> markup(new DocMarkup);
- markup->extract(translationUnit->getModuleDecl(), getSourceManager(), getSink());
-
- // Extract to a file
- const String& path = sourceFile->getPathInfo().foundPath;
- if (path.getLength())
- {
- String fileName = Path::getFileNameWithoutExt(path);
- fileName.append(".md");
-
- StringBuilder buf;
- DocumentationUtil::writeMarkdown(markup, buf);
-
- File::writeAllText(fileName, buf);
- }
- }
#if 0
// Test serialization
@@ -1816,6 +1798,38 @@ SlangResult FrontEndCompileRequest::executeActionsInner()
if (getSink()->getErrorCount() != 0)
return SLANG_FAIL;
+ // After semantic checking is performed we can try and output doc information for this
+ if (shouldDocument)
+ {
+ // Not 100% clear where best to get the ASTBuilder from, but from the linkage shouldn't
+ // cause any problems with scoping
+ ASTBuilder* astBuilder = getLinkage()->getASTBuilder();
+
+ for (TranslationUnitRequest* translationUnit : translationUnits)
+ {
+ RefPtr<DocMarkup> markup(new DocMarkup);
+
+ markup->extract(translationUnit->getModuleDecl(), getSourceManager(), getSink());
+
+ // Hmm.. we can have multiple sourcefiles. So fir now we just pick the first, so as to come up with
+ // a reasonable name
+ SourceFile* sourceFile = translationUnit->getSourceFiles()[0];
+
+ // Extract to a file
+ const String& path = sourceFile->getPathInfo().foundPath;
+ if (path.getLength())
+ {
+ String fileName = Path::getFileNameWithoutExt(path);
+ fileName.append(".md");
+
+ StringBuilder buf;
+ DocumentationUtil::writeMarkdown(markup, astBuilder, buf);
+
+ File::writeAllText(fileName, buf);
+ }
+ }
+ }
+
// Look up all the entry points that are expected,
// and use them to populate the `program` member.
//