diff options
Diffstat (limited to 'source/slang/slang-doc-mark-down.cpp')
| -rw-r--r-- | source/slang/slang-doc-mark-down.cpp | 860 |
1 files changed, 749 insertions, 111 deletions
diff --git a/source/slang/slang-doc-mark-down.cpp b/source/slang/slang-doc-mark-down.cpp index 82de7052e..384759474 100644 --- a/source/slang/slang-doc-mark-down.cpp +++ b/source/slang/slang-doc-mark-down.cpp @@ -4,9 +4,49 @@ #include "../core/slang-string-util.h" #include "slang-ast-builder.h" +#include "slang-lookup.h" namespace Slang { + +struct DocMarkDownWriter::StringListSet +{ + Index add(const HashSet<String>& set) + { + // -1 means empty, which we don't explicitly store + Index index = -1; + if (set.Count()) + { + List<String> values; + for (auto& value : set) + { + values.add(value); + } + // Sort so that can be compared for uniqueness + values.sort(); + + index = m_uniqueValues.indexOf(values); + if (index < 0) + { + index = m_uniqueValues.getCount(); + m_uniqueValues.add(values); + } + } + m_map.add(index); + return index; + } + + Index getValueIndex(Index index) const { return m_map[index]; } + List<String>& getValuesAt(Index valueIndex) { return m_uniqueValues[valueIndex]; } + const List<List<String>>& getUniqueValues() const { return m_uniqueValues; } + + StringListSet() {} + +protected: + List<Index> m_map; + List<List<String>> m_uniqueValues; +}; + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DocMarkDownWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ template <typename T> @@ -51,39 +91,141 @@ static void _appendAsSingleLine(const UnownedStringSlice& in, StringBuilder& out StringUtil::join(lines.getBuffer(), lines.getCount(), ' ', out); } -void DocMarkDownWriter::_appendAsBullets(const List<Decl*>& in) +void DocMarkDownWriter::_appendAsBullets(const List<NameAndText>& values, char wrapChar) { auto& out = m_builder; - for (auto decl : in) + for (const auto& value : values) { - DocMarkup::Entry* paramEntry = m_markup->getEntry(decl); - out << "* "; - Name* name = decl->getName(); - if (name) + const String& name = value.name; + if (name.getLength()) { - out << toSlice("_") << name->text << toSlice("_ "); + if (wrapChar) + { + out.appendChar(wrapChar); + out << name; + out.appendChar(wrapChar); + } + else + { + out << name; + } } - if (paramEntry) + if (value.text.getLength()) { + out.appendChar(' '); + // Hmm, we'll want to make something multiline into a single line - _appendAsSingleLine(paramEntry->m_markup.getUnownedSlice(), out); + _appendAsSingleLine(value.text.getUnownedSlice(), out); } out << "\n"; } +} - out << toSlice("\n"); +void DocMarkDownWriter::_appendAsBullets(const List<String>& values, char wrapChar) +{ + auto& out = m_builder; + for (const auto& value : values) + { + out << "* "; + + if (value.getLength()) + { + if (wrapChar) + { + out.appendChar(wrapChar); + out << value; + out.appendChar(wrapChar); + + } + else + { + out << value; + } + } + out << "\n"; + } } -template <typename T> -void DocMarkDownWriter::_appendAsBullets(FilteredMemberList<T>& list) +String DocMarkDownWriter::_getName(Decl* decl) { - List<Decl*> decls; - _toList(list, decls); - _appendAsBullets(decls); + StringBuilder buf; + ASTPrinter::appendDeclName(decl, buf); + return buf.ProduceString(); +} + +String DocMarkDownWriter::_getName(InheritanceDecl* decl) +{ + StringBuilder buf; + buf.Clear(); + buf << decl->base; + return buf.ProduceString(); +} + +DocMarkDownWriter::NameAndText DocMarkDownWriter::_getNameAndText(DocMarkup::Entry* entry, Decl* decl) +{ + NameAndText nameAndText; + + nameAndText.name = _getName(decl); + + // We could extract different text here, but for now just do all markup + if (entry) + { + // For now we'll just use all markup, but really we need something more sophisticated here + nameAndText.text = entry->m_markup; + } + + return nameAndText; +} + +DocMarkDownWriter::NameAndText DocMarkDownWriter::_getNameAndText(Decl* decl) +{ + DocMarkup::Entry* entry = m_markup->getEntry(decl); + return _getNameAndText(entry, decl); +} + +List<DocMarkDownWriter::NameAndText> DocMarkDownWriter::_getAsNameAndTextList(const List<Decl*>& in) +{ + List<NameAndText> out; + for (auto decl : in) + { + out.add(_getNameAndText(decl)); + } + return out; +} + +List<String> DocMarkDownWriter::_getAsStringList(const List<Decl*>& in) +{ + List<String> strings; + for (auto decl : in) + { + strings.add(_getName(decl)); + } + return strings; +} + +void DocMarkDownWriter::_appendCommaList(const List<String>& strings, char wrapChar) +{ + for (Index i = 0; i < strings.getCount(); ++i) + { + if (i > 0) + { + m_builder << toSlice(", "); + } + if (wrapChar) + { + m_builder.appendChar(wrapChar); + m_builder << strings[i]; + m_builder.appendChar(wrapChar); + } + else + { + m_builder << strings[i]; + } + } } /* static */void DocMarkDownWriter::getSignature(const List<Part>& parts, Signature& outSig) @@ -149,73 +291,81 @@ void DocMarkDownWriter::writeVar(const DocMarkup::Entry& entry, VarDecl* varDecl out << toSlice("```\n"); out << varDecl->type << toSlice(" ") << varDecl << toSlice("\n"); - out << toSlice("```\n"); + out << toSlice("```\n\n"); writeDescription(entry); } -void DocMarkDownWriter::writeCallable(const DocMarkup::Entry& entry, CallableDecl* callableDecl) +void DocMarkDownWriter::writeSignature(CallableDecl* callableDecl) { - writePreamble(entry); - auto& out = m_builder; List<ASTPrinter::Part> parts; + ASTPrinter printer(m_astBuilder, ASTPrinter::OptionFlag::ParamNames, &parts); - - GenericDecl* genericDecl = as<GenericDecl>(callableDecl->parentDecl); - - if (genericDecl) - { - printer.addDeclSignature(DeclRef<Decl>(genericDecl, nullptr)); - } - else - { - printer.addDeclSignature(DeclRef<Decl>(callableDecl, nullptr)); - } + printer.addDeclSignature(DeclRef<Decl>(callableDecl, nullptr)); Signature signature; getSignature(parts, signature); const Index paramCount = signature.params.getCount(); - // Output the signature - { - // Extract the name - out << toSlice("# ") << printer.getPartSlice(signature.name) << toSlice("\n\n"); - - out << toSlice("## Signature \n"); - out << toSlice("```\n"); - out << printer.getPartSlice(signature.returnType) << toSlice(" "); + { + // Some types (like constructors say) don't have any return type, so check before outputting + const UnownedStringSlice returnType = printer.getPartSlice(signature.returnType); + if (returnType.getLength() > 0) + { + out << returnType << toSlice(" "); + } + } - out << printer.getPartSlice(signature.name); + out << printer.getPartSlice(signature.name); - if (signature.genericParams.getCount()) +#if 0 + if (signature.genericParams.getCount()) + { + out << toSlice("<"); + const Index count = signature.genericParams.getCount(); + for (Index i = 0; i < count; ++i) { - out << toSlice("<"); - const Index count = signature.genericParams.getCount(); - for (Index i = 0; i < count; ++i) + const auto& genericParam = signature.genericParams[i]; + if (i > 0) { - const auto& genericParam = signature.genericParams[i]; - if (i > 0) - { - out << toSlice(", "); - } - out << printer.getPartSlice(genericParam.name); + out << toSlice(", "); + } + out << printer.getPartSlice(genericParam.name); - if (genericParam.type.type != Part::Type::None) - { - out << toSlice(" : "); - out << printer.getPartSlice(genericParam.type); - } + if (genericParam.type.type != Part::Type::None) + { + out << toSlice(" : "); + out << printer.getPartSlice(genericParam.type); } - out << toSlice(">"); } + out << toSlice(">"); + } +#endif - if (paramCount > 0) + switch (paramCount) + { + case 0: { + // Has no parameters + out << toSlice("();\n"); + break; + } + case 1: + { + // Place all on single line + out.appendChar('('); + const auto& param = signature.params[0]; + out << printer.getPartSlice(param.first) << toSlice(" ") << printer.getPartSlice(param.second); + out << ");\n"; + break; + } + default: + { + // Put each parameter on a line on it's own out << toSlice("(\n"); - StringBuilder line; for (Index i = 0; i < paramCount; ++i) { @@ -244,45 +394,371 @@ void DocMarkDownWriter::writeCallable(const DocMarkup::Entry& entry, CallableDec } out << ");\n"; + break; + } + } +} + +List<DocMarkDownWriter::NameAndText> DocMarkDownWriter::_getUniqueParams(const List<Decl*>& decls) +{ + List<NameAndText> out; + + Dictionary<Name*, Index> nameDict; + + for (auto decl : decls) + { + Name* name = decl->getName(); + if (!name) + { + continue; + } + + Index index = nameDict.GetOrAddValue(name, out.getCount()); + + if (index >= out.getCount()) + { + out.add(NameAndText{ getText(name), String() }); + } + + NameAndText& nameAndMarkup = out[index]; + if (nameAndMarkup.text.getLength() > 0) + { + continue; + } + + auto entry = m_markup->getEntry(decl); + if (entry && entry->m_markup.getLength()) + { + nameAndMarkup.text = entry->m_markup; + } + } + + return out; +} + +static void _addRequirements(Decl* decl, HashSet<String>& outRequirements) +{ + StringBuilder buf; + + if (auto spirvRequiredModifier = decl->findModifier<RequiredSPIRVVersionModifier>()) + { + buf.Clear(); + buf << "SPIR-V "; + spirvRequiredModifier->version.append(buf); + outRequirements.Add(buf); + } + + if (auto glslRequiredModifier = decl->findModifier<RequiredGLSLVersionModifier>()) + { + buf.Clear(); + buf << "GLSL" << glslRequiredModifier->versionNumberToken.getContent(); + outRequirements.Add(buf); + } + + if (auto cudaSMVersionModifier = decl->findModifier<RequiredCUDASMVersionModifier>()) + { + buf.Clear(); + buf << "CUDA SM "; + cudaSMVersionModifier->version.append(buf); + outRequirements.Add(buf); + } + + if (auto extensionModifier = decl->findModifier<RequiredGLSLExtensionModifier>()) + { + buf.Clear(); + buf << "GLSL " << extensionModifier->extensionNameToken.getContent(); + outRequirements.Add(buf); + } + + if (auto requiresNVAPIAttribute = decl->findModifier<RequiresNVAPIAttribute>()) + { + outRequirements.Add("NVAPI"); + } +} + +void DocMarkDownWriter::_maybeAppendSet(const UnownedStringSlice& title, const StringListSet& set) +{ + auto& out = m_builder; + + const auto& uniqueValues = set.getUniqueValues(); + + const Index uniqueCount = uniqueValues.getCount(); + if (uniqueCount > 0 && uniqueValues[0].getCount() > 0) + { + out << title; + if (uniqueCount > 1) + { + for (Index i = 0; i < uniqueCount; ++i) + { + out << (i + 1) << (". "); + _appendCommaList(uniqueValues[i], '`'); + out << toSlice("\n"); + } } else { - out << toSlice("();\n"); + _appendCommaList(uniqueValues[0], '`'); + out << toSlice("\n"); } + out << toSlice("\n"); + } +} - out << "```\n\n"; +static Decl* _getSameNameDecl(Decl* decl) +{ + auto parentDecl = decl->parentDecl; + + // Sanity check: there should always be a parent declaration. + // + SLANG_ASSERT(parentDecl); + if (!parentDecl) return nullptr; + + // If the declaration is the "inner" declaration of a generic, + // then we actually want to look one level up, because the + // peers/siblings of the declaration will belong to the same + // parent as the generic, not to the generic. + // + if (auto genericParentDecl = as<GenericDecl>(parentDecl)) + { + // Note: we need to check here to be sure `newDecl` + // is the "inner" declaration and not one of the + // generic parameters, or else we will end up + // checking them at the wrong scope. + // + if (decl == genericParentDecl->inner) + { + decl = parentDecl; + } } + return decl; +} + +static bool _isFirstOverridden(Decl* decl) +{ + decl = _getSameNameDecl(decl); + + ContainerDecl* parentDecl = decl->parentDecl; + + // Make sure we have the member dictionary. + buildMemberDictionary(parentDecl); + + Name* declName = decl->getName(); + if (declName) { - // The parameters, in order - List<Decl*> params; + Decl** firstDeclPtr = parentDecl->memberDictionary.TryGetValue(declName); + return (firstDeclPtr && *firstDeclPtr == decl) || (firstDeclPtr == nullptr); + } - if (genericDecl) + return false; +} + +void DocMarkDownWriter::writeCallableOverridable(const DocMarkup::Entry& entry, CallableDecl* callableDecl) +{ + auto& out = m_builder; + + writePreamble(entry); + + { + // Output the overridable path (ie without terminal generic parameters) + ASTPrinter printer(m_astBuilder); + printer.addOverridableDeclPath(DeclRef<Decl>(callableDecl, nullptr)); + // Extract the name + out << toSlice("# `") << printer.getStringBuilder() << toSlice("`\n\n"); + } + + writeDescription(entry); + + List<CallableDecl*> sigs; + { + Decl* sameNameDecl = _getSameNameDecl(callableDecl); + + for (Decl* curDecl = sameNameDecl; curDecl; curDecl = curDecl->nextInContainerWithSameName) + { + CallableDecl* sig = nullptr; + if (GenericDecl* genericDecl = as<GenericDecl>(curDecl)) + { + sig = as<CallableDecl>(genericDecl->inner); + } + else + { + sig = as<CallableDecl>(curDecl); + } + + if (!sig) + { + continue; + } + + // Want to add only the primary sig + if (sig->primaryDecl == nullptr || sig->primaryDecl == sig) + { + sigs.add(sig); + } + } + + // Lets put back into source order + sigs.sort([](CallableDecl* a, CallableDecl* b) -> bool { return a->loc.getRaw() < b->loc.getRaw(); }); + } + + // Set of sets of requirements, holds index map from addition to the set entry + StringListSet requirementsSetSet; + + // Similarly for targets + StringListSet targetSetSet; + + // We want to determine the unique signature, and then the requirements for the signature + { + for (Index i = 0; i < sigs.getCount(); ++i) { - for (Decl* decl : genericDecl->members) + CallableDecl* sig = sigs[i]; + // Add the requirements for all the different versions { - if (as<GenericTypeParamDecl>(decl) || - as<GenericValueParamDecl>(decl)) + HashSet<String> requirementsSet; + HashSet<String> targetSet; + for (CallableDecl* curSig = sig; curSig; curSig = curSig->nextDecl) { - params.add(decl); + _addRequirements(sig, requirementsSet); + + // Handle Target info + + for (auto targetIntrinsic : sig->getModifiersOfType<TargetIntrinsicModifier>()) + { + targetSet.Add(String(targetIntrinsic->targetToken.getContent()).toUpper()); + } + for (auto specializedForTarget : sig->getModifiersOfType<SpecializedForTargetModifier>()) + { + targetSet.Add(String(specializedForTarget->targetToken.getContent()).toUpper()); + } } + + requirementsSetSet.add(requirementsSet); + + // TODO(JS): This really isn't right, we ideally have markup that made hlsl availability explicit + // We *assume* that we have 'hlsl' for now + targetSet.Add(String("HLSL")); + targetSetSet.add(targetSet); } } + } + + // Output the signature + { + out << toSlice("## Signature \n\n"); + out << toSlice("```\n"); + + Index prevRequirementsIndex = -1; + Index prevTargetIndex = -1; - for (ParamDecl* paramDecl : callableDecl->getParameters()) + const Int sigCount = sigs.getCount(); + for (Index i = 0; i < sigCount; ++i) { - params.add(paramDecl); + auto sig = sigs[i]; + + // Output if needs unique requirements + if (requirementsSetSet.getUniqueValues().getCount() > 1) + { + const Index requirementsIndex = requirementsSetSet.getValueIndex(i); + if (requirementsIndex != prevRequirementsIndex) + { + if (requirementsIndex >= 0) + { + out << toSlice("/// See Requirement ") << (requirementsIndex + 1) << toSlice("\n"); + } + else + { + out << toSlice("/// No requirements\n"); + } + prevRequirementsIndex = requirementsIndex; + } + } + + if (targetSetSet.getUniqueValues().getCount() > 1) + { + const Index targetIndex = targetSetSet.getValueIndex(i); + if (targetIndex != prevTargetIndex) + { + if (targetIndex >= 0) + { + out << toSlice("/// See Target Availability ") << (targetIndex + 1) << toSlice("\n"); + } + else + { + out << toSlice("/// All Targets\n"); + } + prevTargetIndex = targetIndex; + } + } + + writeSignature(sig); } + out << "```\n\n"; + } - if (params.getCount()) + _maybeAppendSet(toSlice("## Requirements\n\n"), requirementsSetSet); + + // Target availability + + { + const auto& uniqueValues = targetSetSet.getUniqueValues(); + if (uniqueValues.getCount() == 1 && uniqueValues[0].getCount() == 1 && uniqueValues[0][0] == "hlsl") { - out << "## Parameters\n\n"; - // We have generic params and regular parameters, in this list - _appendAsBullets(params); + // TODO(JS): + // If something is marked up for hlsl, and nothing else, that indicates it might *only* be available on hlsl, but + // we don't correctly handle that here. + + // If the only thing we have is 'hlsl' - we injected that so we'll *assume* it's available everywhere, so + // don't bother outputting. + } + else + { + _maybeAppendSet(toSlice("## Target Availability\n\n"), targetSetSet); } } - writeDescription(entry); + { + // We will use the first documentation found for each parameter type + { + List<Decl*> paramDecls; + List<Decl*> genericDecls; + for (auto sig : sigs) + { + GenericDecl* genericDecl = as<GenericDecl>(sig->parentDecl); + + // NOTE! + // Here we assume the names of generic parameters are such that they are + + // We list generic parameters, as types of parameters, if they are directly associated with this + // callable. + if (genericDecl) + { + for (Decl* decl : genericDecl->members) + { + if (as<GenericTypeParamDecl>(decl) || + as<GenericValueParamDecl>(decl)) + { + genericDecls.add(decl); + } + } + } + + for (ParamDecl* paramDecl : sig->getParameters()) + { + paramDecls.add(paramDecl); + } + } + + if (paramDecls.getCount() > 0 || paramDecls.getCount() > 0) + { + out << "## Parameters\n\n"; + + // Get the unique generics + _appendAsBullets(_getUniqueParams(genericDecls), '`'); + // And parameters + _appendAsBullets(_getUniqueParams(paramDecls), '`'); + } + } + } } void DocMarkDownWriter::writeEnum(const DocMarkup::Entry& entry, EnumDecl* enumDecl) @@ -301,12 +777,55 @@ void DocMarkDownWriter::writeEnum(const DocMarkup::Entry& entry, EnumDecl* enumD out << toSlice("## Values \n\n"); - auto cases = enumDecl->getMembersOfType<EnumCaseDecl>(); - _appendAsBullets(cases); - + _appendAsBullets(_getAsNameAndTextList(enumDecl->getMembersOfType<EnumCaseDecl>()), '_'); + writeDescription(entry); } +void DocMarkDownWriter::_appendEscaped(const UnownedStringSlice& text) +{ + auto& out = m_builder; + + const char* start = text.begin(); + const char* cur = start; + const char*const end = text.end(); + + for (; cur < end; ++cur) + { + const char c = *cur; + + switch (c) + { + case '<': + case '>': + case '&': + case '"': + case '_': + { + // Flush if any before + if (cur > start) + { + out.append(start, cur); + } + // Prefix with the + out.appendChar('\\'); + + // Start will still include the char, for later flushing + start = cur; + break; + } + default: break; + } + } + + // Flush any remaining + if (cur > start) + { + out.append(start, cur); + } +} + + void DocMarkDownWriter::_appendDerivedFrom(const UnownedStringSlice& prefix, AggTypeDeclBase* aggTypeDecl) { auto& out = m_builder; @@ -330,43 +849,52 @@ void DocMarkDownWriter::_appendDerivedFrom(const UnownedStringSlice& prefix, Agg } } -void DocMarkDownWriter::writeAggType(const DocMarkup::Entry& entry, AggTypeDeclBase* aggTypeDecl) +void DocMarkDownWriter::_appendAggTypeName(AggTypeDeclBase* aggTypeDecl) { - writePreamble(entry); - auto& out = m_builder; // This could be lots of different things - struct/class/extension/interface/.. - out << toSlice("# "); + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(DeclRef<Decl>(aggTypeDecl, nullptr)); + if (as<StructDecl>(aggTypeDecl)) { - out << toSlice("struct "); + out << toSlice("struct ") << printer.getStringBuilder(); } else if (as<ClassDecl>(aggTypeDecl)) { - out << toSlice("class "); + out << toSlice("class ") << printer.getStringBuilder(); } else if (as<InterfaceDecl>(aggTypeDecl)) { - out << toSlice("interface "); + out << toSlice("interface ") << printer.getStringBuilder(); } else if (ExtensionDecl* extensionDecl = as<ExtensionDecl>(aggTypeDecl)) { out << toSlice("extension ") << extensionDecl->targetType; - _appendDerivedFrom(toSlice(" : "), extensionDecl); + _appendDerivedFrom(toSlice(" : "), extensionDecl); } else { out << toSlice("?"); } +} - Name* name = aggTypeDecl->getName(); - if (name) - { - out << name->text; - } - out << toSlice("\n\n"); +void DocMarkDownWriter::writeAggType(const DocMarkup::Entry& entry, AggTypeDeclBase* aggTypeDecl) +{ + writePreamble(entry); + + auto& out = m_builder; + + // We can write out he name using the printer + + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(DeclRef<Decl>(aggTypeDecl, nullptr)); + + out << toSlice("# `"); + _appendAggTypeName(aggTypeDecl); + out << toSlice("`\n\n"); { List<InheritanceDecl*> inheritanceDecls; @@ -374,41 +902,104 @@ void DocMarkDownWriter::writeAggType(const DocMarkup::Entry& entry, AggTypeDeclB if (inheritanceDecls.getCount()) { - out << "*Derives from:* "; + out << "*Implements:* "; + _appendCommaList(_getAsStringList(inheritanceDecls), '`'); + out << toSlice("\n\n"); + } + } - for (Index i = 0; i < inheritanceDecls.getCount(); ++i) - { - if (i > 0) + writeDescription(entry); + + { + List<AssocTypeDecl*> assocTypeDecls; + _getDecls<AssocTypeDecl>(aggTypeDecl, assocTypeDecls); + + if (assocTypeDecls.getCount()) + { + out << toSlice("# Associated types\n\n"); + + for (AssocTypeDecl* assocTypeDecl : assocTypeDecls) + { + out << "* _" << assocTypeDecl->getName()->text << "_ "; + + // Look up markup + DocMarkup::Entry* assocTypeDeclEntry = m_markup->getEntry(assocTypeDecl); + if (assocTypeDeclEntry) { - out << toSlice(", "); + _appendAsSingleLine(assocTypeDeclEntry->m_markup.getUnownedSlice(), out); + } + out << toSlice("\n"); + + List<InheritanceDecl*> inheritanceDecls; + _getDecls<InheritanceDecl>(assocTypeDecl, inheritanceDecls); + + if (inheritanceDecls.getCount()) + { + out << " "; + _appendCommaList(_getAsStringList(inheritanceDecls), '`'); + out << toSlice("\n"); } - out << inheritanceDecls[i]->base; } + out << toSlice("\n\n"); } } + if (GenericDecl* genericDecl = as<GenericDecl>(aggTypeDecl->parentDecl)) + { + // The parameters, in order + List<Decl*> params; + for (Decl* decl : genericDecl->members) + { + if (as<GenericTypeParamDecl>(decl) || + as<GenericValueParamDecl>(decl)) + { + params.add(decl); + } + } + + if (params.getCount()) + { + out << "## Generic Parameters\n\n"; + _appendAsBullets(_getAsNameAndTextList(params), '`'); + } + } + { List<Decl*> fields; _getDeclsOfType<VarDecl>(aggTypeDecl, fields); if (fields.getCount()) { out << "## Fields\n\n"; - _appendAsBullets(fields); + + _appendAsBullets(_getAsNameAndTextList(fields), '`'); } } { - List<Decl*> methods; - _getDeclsOfType<CallableDecl>(aggTypeDecl, methods); - if (methods.getCount()) + // Make sure we've got a query-able member dictionary + buildMemberDictionary(aggTypeDecl); + SLANG_ASSERT(aggTypeDecl->isMemberDictionaryValid()); + + List<Decl*> uniqueMethods; + for (const auto& pair : aggTypeDecl->memberDictionary) { + CallableDecl* callableDecl = as<CallableDecl>(pair.Value); + if (callableDecl && isVisible(callableDecl)) + { + uniqueMethods.add(callableDecl); + } + } + + if (uniqueMethods.getCount()) + { + // Put in source definition order + uniqueMethods.sort([](Decl* a, Decl* b) -> bool { return a->loc.getRaw() < b->loc.getRaw(); }); + out << "## Methods\n\n"; - _appendAsBullets(methods); + _appendAsBullets(_getAsStringList(uniqueMethods), '`'); } } - - writeDescription(entry); } void DocMarkDownWriter::writePreamble(const DocMarkup::Entry& entry) @@ -421,26 +1012,40 @@ void DocMarkDownWriter::writePreamble(const DocMarkup::Entry& entry) out << toSlice("\n"); } - void DocMarkDownWriter::writeDescription(const DocMarkup::Entry& entry) { auto& out = m_builder; - out << toSlice("\n## Description\n\n"); - out << entry.m_markup; + if (entry.m_markup.getLength() > 0) + { + out << toSlice("## Description\n\n"); + + out << entry.m_markup.getUnownedSlice(); +#if 0 + UnownedStringSlice text(entry.m_markup.getUnownedSlice()), line; + while (StringUtil::extractLine(text, line)) + { + out << line << toSlice("\n"); + } +#endif + out << toSlice("\n"); + } } void DocMarkDownWriter::writeDecl(const DocMarkup::Entry& entry, Decl* decl) { // Skip these they will be output as part of their respective 'containers' - if (as<ParamDecl>(decl) || as<EnumCaseDecl>(decl)) + if (as<ParamDecl>(decl) || as<EnumCaseDecl>(decl) || as<AssocTypeDecl>(decl) || as<InheritanceDecl>(decl)) { return; } if (CallableDecl* callableDecl = as<CallableDecl>(decl)) { - writeCallable(entry, callableDecl); + if (_isFirstOverridden(callableDecl)) + { + writeCallableOverridable(entry, callableDecl); + } } else if (EnumDecl* enumDecl = as<EnumDecl>(decl)) { @@ -452,6 +1057,12 @@ void DocMarkDownWriter::writeDecl(const DocMarkup::Entry& entry, Decl* decl) } else if (VarDecl* varDecl = as<VarDecl>(decl)) { + // If part of aggregate type will be output there. + if (as<AggTypeDecl>(varDecl->parentDecl)) + { + return; + } + writeVar(entry, varDecl); } else if (as<GenericDecl>(decl)) @@ -460,14 +1071,41 @@ void DocMarkDownWriter::writeDecl(const DocMarkup::Entry& entry, Decl* decl) } } +bool DocMarkDownWriter::isVisible(const Name* name) +{ + return name == nullptr || !name->text.startsWith(toSlice("__")); +} + +bool DocMarkDownWriter::isVisible(const DocMarkup::Entry& entry) +{ + // For now if it's not public it's not visible + if (entry.m_visibility != MarkupVisibility::Public) + { + return false; + } + + Decl* decl = as<Decl>(entry.m_node); + return decl == nullptr || isVisible(decl->getName()); +} + +bool DocMarkDownWriter::isVisible(Decl* decl) +{ + if (!isVisible(decl->getName())) + { + return false; + } + + auto entry = m_markup->getEntry(decl); + return entry == nullptr || entry->m_visibility == MarkupVisibility::Public; +} void DocMarkDownWriter::writeAll() { for (const auto& entry : m_markup->getEntries()) { - NodeBase* node = entry.m_node; - Decl* decl = as<Decl>(node); - if (decl) + Decl* decl = as<Decl>(entry.m_node); + + if (decl && isVisible(entry)) { writeDecl(entry, decl); } |
