module ddoc_template; import core.stdc.string; import std.array, std.conv, std.string; import iz.memory, iz.sugar; import dparse.ast, dparse.lexer, dparse.parser, dparse.rollback_allocator; import common; /** * Finds the declaration at caretLine and write its ddoc template * and returns its DDOC template as a C string. * * Params: * src = the module source code, as a C string. * caretLine = the line where the declaration is located. * plusComment = indicates if the template use the "*" or the "+" decoration. */ export extern(C) const(char)* ddocTemplate(const(char)* src, int caretLine, bool plusComment) { LexerConfig config; RollbackAllocator rba; StringCache sCache = StringCache(StringCache.defaultBucketCount); scope mod = src[0 .. src.strlen] .getTokensForParser(config, &sCache) .parseModule("", &rba, &ignoreErrors); DDocTemplateGenerator dtg = construct!DDocTemplateGenerator(caretLine, plusComment); scope(exit) destruct(dtg); dtg.visit(mod); return dtg.result; } private void putLine(T...)(ref Appender!string a, T t) { static foreach (i; 0 .. T.length) a.put(t[i].to!string); a.put("\n"); } final class DDocTemplateGenerator: ASTVisitor { alias visit = ASTVisitor.visit; private: immutable int _caretline; immutable char c1; immutable char[2] c2; Appender!string app; bool _throws; public: this(int caretline, bool plusComment) { _caretline = caretline; c1 = plusComment ? '+' : '*'; c2 = plusComment ? "++" : "**"; } const(char)* result() { return app.data.toStringz(); } override void visit(const(ThrowStatement) ts) { _throws = true; } override void visit(const(Catch) c) { _throws = false; } override void visit(const(FunctionDeclaration) decl) { _throws = false; if (decl.name.line == _caretline) { decl.accept(this); app.putLine("/", c2, "\n ", c1, " \n ", c1, " \n ", c1, " ", c1); const TemplateParameterList tpl = safeAccess(decl).templateParameters.templateParameterList; if ((tpl && tpl.items.length) || (decl.parameters && decl.parameters.parameters.length)) { app.putLine(" ", c1, " \n ", c1, " Params:"); if (tpl) { foreach(const TemplateParameter p; tpl.items) { if (p.templateAliasParameter) app.putLine(" ", c1, " ", p.templateAliasParameter.identifier.text, " = "); else if (p.templateTupleParameter) app.putLine(" ", c1, " ", p.templateTupleParameter.identifier.text, " = "); else if (p.templateTypeParameter) app.putLine(" ", c1, " ", p.templateTypeParameter.identifier.text, " = "); else if (p.templateValueParameter) app.putLine(" ", c1, " ", p.templateValueParameter.identifier.text, " = "); } } if (decl.parameters) { foreach(i, const Parameter p; decl.parameters.parameters) { if (p.name.text != "") app.putLine(" ", c1, " ", p.name.text, " = "); else app.putLine(" ", c1, " __param", i, " = "); } } } if (const Type2 tp2 = safeAccess(decl).returnType.type2) { if (tp2.builtinType != tok!"void") app.putLine(" ", c1, " \n ", c1, " Returns: "); } if (_throws) { app.putLine(" ", c1, " \n ", c1, " Throws: "); } app.putLine(" ", c1, "/"); } else if (decl.name.line > _caretline) return; } override void visit(const(TemplateDeclaration) decl) { visitTemplateOrAggregate(decl); } override void visit(const(ClassDeclaration) decl) { visitTemplateOrAggregate(decl); } override void visit(const(StructDeclaration) decl) { visitTemplateOrAggregate(decl); } override void visit(const(UnionDeclaration) decl) { visitTemplateOrAggregate(decl); } override void visit(const(AutoDeclarationPart) decl) { if (decl.templateParameters) visitTemplateOrAggregate(decl); } private void visitTemplateOrAggregate(T)(const(T) decl) { size_t line; static if (__traits(hasMember, T, "name")) line = decl.name.line; else line = decl.identifier.line; if (_caretline == line) { app.putLine("/", c2, "\n ", c1, " \n ", c1, " \n ", c1, " ", c1); const TemplateParameterList tpl = safeAccess(decl).templateParameters.templateParameterList; if (tpl && tpl.items.length) { app.putLine(" ", c1, " \n ", c1, " Params:"); foreach(const TemplateParameter p; tpl.items) { if (p.templateAliasParameter) app.putLine(" ", c1, " ", p.templateAliasParameter.identifier.text, " = "); else if (p.templateTupleParameter) app.putLine(" ", c1, " ", p.templateTupleParameter.identifier.text, " = "); else if (p.templateTypeParameter) app.putLine(" ", c1, " ", p.templateTypeParameter.identifier.text, " = "); else if (p.templateValueParameter) app.putLine(" ", c1, " ", p.templateValueParameter.identifier.text, " = "); } } app.putLine(" ", c1, "/"); } else if (line > _caretline) return; decl.accept(this); } }