Skip to content

Commit

Permalink
Autogenerate TDLib .NET documentation.
Browse files Browse the repository at this point in the history
GitOrigin-RevId: 9a73b2786306b8b2deaeb967aa4633d1d1ed0a2d
  • Loading branch information
levlam committed Mar 16, 2018
1 parent 070f6ff commit 3856045
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 36 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ See [example/java](https://github.com/tdlib/td/tree/master/example/java) for exa
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".

When `TDLib` is built with `TD_ENABLE_DOTNET` option enabled, `C++` documentation is removed from some files. You need to checkout these files to return `C++` documentation back:
```
git checkout td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h
```

<a name="using-json"></a>
## Using from other programming languages
`TDLib` provides efficient native C++, Java, and .NET interfaces.
Expand Down
2 changes: 1 addition & 1 deletion example/csharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This is an example of building TDLib with `C++/CLI` support and an example of TD
C:\src\vcpkg> .\vcpkg.exe install openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
```
* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable.
* Build `TDLib` with CMake enabling .NET support and specifying correct path to `vcpkg` toolchain file:
* Build `TDLib` with CMake enabling `.NET` support and specifying correct path to `vcpkg` toolchain file:
```
cd <path to TDLib sources>/example/csharp
mkdir build
Expand Down
8 changes: 4 additions & 4 deletions example/csharp/TdExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
using System;
using System.Threading;

/**
* Example class for TDLib usage from C#.
*/
namespace TdExample
{
/// <summary>
/// Example class for TDLib usage from C#.
/// </summary>
class Example
{
private static Td.Client _client = null;
Expand Down Expand Up @@ -256,7 +256,7 @@ void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
}
else
{
// ok result is already received through UpdateAuthorizationState, nothing to do
// result is already received through UpdateAuthorizationState, nothing to do
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion example/uwp/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function export {
cp ${arch}/Debug/* -filter "Telegram.Td.*" -include "*.pdb","*.dll" vsix/Redist/Debug/${arch}/
cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pdb","*.dll" vsix/Redist/Retail/${arch}/

cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pri","*.winmd" vsix/References/CommonConfiguration/${arch}/
cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pri","*.winmd","*.xml" vsix/References/CommonConfiguration/${arch}/
}

cd vsix
Expand Down
12 changes: 9 additions & 3 deletions td/generate/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ if (NOT CMAKE_CROSSCOMPILING)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${GENERATE_COMMON_CMD}
COMMENT "Generate common tl source files"
DEPENDS generate_common scheme/mtproto_api.tlo scheme/telegram_api.tlo scheme/secret_api.tlo ${TL_TD_API_TLO}
DEPENDS generate_common scheme/mtproto_api.tlo scheme/telegram_api.tlo scheme/secret_api.tlo ${TL_TD_API_TLO} DoxygenTlDocumentationGenerator.php
)
if (TD_ENABLE_JNI)
target_compile_definitions(generate_common PRIVATE TD_ENABLE_JNI=1)
Expand Down Expand Up @@ -135,13 +135,19 @@ if (NOT CMAKE_CROSSCOMPILING)
endif()

if (TD_ENABLE_DOTNET)
if (PHP_EXECUTABLE)
set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TL_TD_API_TLO} && ${PHP_EXECUTABLE} DotnetTlDocumentationGenerator.php scheme/td_api.tl auto/td/telegram/TdDotNetApi.h)
else()
set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TL_TD_API_TLO})
endif()

add_executable(td_generate_dotnet_api generate_dotnet.cpp tl_writer_dotnet.h)
target_link_libraries(td_generate_dotnet_api PRIVATE tdtl)
add_custom_target(generate_dotnet_api
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND td_generate_dotnet_api ${TL_TD_API_TLO}
COMMAND ${GENERATE_DOTNET_API_CMD} ${TL_TD_API_TLO}
COMMENT "Generate .NET API files"
DEPENDS td_generate_dotnet_api ${TL_TD_API_TLO}
DEPENDS td_generate_dotnet_api ${TL_TD_API_TLO} DotnetTlDocumentationGenerator.php
)
endif()

Expand Down
223 changes: 223 additions & 0 deletions td/generate/DotnetTlDocumentationGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
<?php

require_once 'TlDocumentationGenerator.php';

class DotnetTlDocumentationGenerator extends TlDocumentationGenerator
{
protected function escapeDocumentation($doc)
{
$doc = htmlspecialchars($doc, ENT_XML1);
$doc = str_replace('*/', '*&#47;', $doc);
$doc = preg_replace_callback('/_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, $doc);
return $doc;
}

protected function getFieldName($name, $class_name)
{
$name = ucfirst($this->getParameterName($name, $class_name));
if ($name === $class_name) {
$name .= 'Value';
}
return $name;
}

protected function getParameterName($name, $class_name)
{
if (substr($name, 0, 6) === 'param_') {
$name = substr($name, 6);
}
$name = preg_replace_callback('/_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, trim($name));
return $name;
}

protected function getClassName($type)
{
return implode(array_map('ucfirst', explode('.', trim($type, "\r\n ;"))));
}

protected function getTypeName($type)
{
switch ($type) {
case 'Bool':
return 'bool';
case 'int32':
return 'int32';
case 'int53':
case 'int64':
return 'int64';
case 'double':
return 'float64';
case 'string':
return 'String^';
case 'bytes':
return 'Array<byte>^';
case 'bool':
case 'int':
case 'long':
case 'Int':
case 'Long':
case 'Int32':
case 'Int53':
case 'Int64':
case 'Double':
case 'String':
case 'Bytes':
$this->printError("Wrong type $type");
return '';
default:
if (substr($type, 0, 6) === 'vector') {
if ($type[6] !== '<' || $type[strlen($type) - 1] !== '>') {
$this->printError("Wrong vector subtype in $type");
return '';
}
return 'Array<'.$this->getTypeName(substr($type, 7, -1)).'>^';
}

if (preg_match('/[^A-Za-z0-9.]/', $type)) {
$this->printError("Wrong type $type");
return '';
}
return $this->getClassName($type).'^';
}
}

protected function getBaseClassName($is_function)
{
return $is_function ? 'Function' : 'Object';
}

protected function needRemoveLine($line)
{
return strpos(trim($line), '///') === 0;
}

protected function needSkipLine($line)
{
$line = trim($line);
return !$line || $line === 'public:' || $line === 'private:' || $line[0] === '}' ||
strpos($line, 'Unmanaged') > 0 || strpos($line, 'PrivateField') > 0 || strpos($line, 'get()') > 0 ||
strpos($line, 'void set(') === 0 || preg_match('/^[a-z]* class .*;/', $line) ||
strpos($line, 'namespace ') === 0 || strpos($line, '#include ') === 0;
}

protected function isHeaderLine($line)
{
return false;
}

protected function extractClassName($line)
{
if (strpos($line, 'public ref class ') !== false || strpos($line, 'public interface class ') !== false) {
return explode(' ', $line)[3];
}
return '';
}

protected function fixLine($line)
{
return $line;
}

protected function addGlobalDocumentation()
{
$this->addDocumentation('public interface class Object : BaseObject {', <<<EOT
/// <summary>
/// This class is a base class for all TDLib interface classes.
/// </summary>
EOT
);

$this->addDocumentation(' virtual String^ ToString() override;', <<<EOT
/// <summary>
/// Returns string representation of the object.
/// </summary>
/// <returns>Returns string representation of the object.</returns>
EOT
);

$this->addDocumentation('public interface class Function : BaseObject {', <<<EOT
/// <summary>
/// This class is a base class for all TDLib interface function-classes.
/// </summary>
EOT
);
}

protected function addAbstractClassDocumentation($class_name, $documentation)
{
$this->addDocumentation("public interface class $class_name : Object {", <<<EOT
/// <summary>
/// This class is an abstract base class.
/// $documentation
/// </summary>
EOT
);
}

protected function addClassDocumentation($class_name, $base_class_name, $description, $return_type)
{
$return_type_description = $return_type ? "\r\n/// <para>Returns <see cref=\"".substr($return_type, 0, -1).'"/>.</para>' : '';

$this->addDocumentation("public ref class $class_name sealed : $base_class_name {", <<<EOT
/// <summary>
/// $description$return_type_description
/// </summary>
EOT
);
}

protected function addFieldDocumentation($class_name, $field_name, $type_name, $field_info, $may_be_null)
{
$end = ';';
if (substr($type_name, 0, strlen($field_name)) === $field_name) {
$type_name = '::Telegram::Td::Api::'.$type_name;
$end = ' {';
}
$full_line = $class_name." property $type_name $field_name$end";
$this->addDocumentation($full_line, <<<EOT
/// <summary>
/// $field_info
/// </summary>
EOT
);
}

protected function addDefaultConstructorDocumentation($class_name)
{
$this->addDocumentation(" $class_name();", <<<EOT
/// <summary>
/// Default constructor.
/// </summary>
EOT
);
}

protected function addFullConstructorDocumentation($class_name, $known_fields, $info)
{
$full_constructor = " $class_name(";
$colon = '';
foreach ($known_fields as $name => $type) {
$field_type = $this->getTypeName($type);
if (substr($field_type, 0, 5) !== 'Array' && substr($field_type, 0, 6) !== 'String' &&
ucfirst($field_type) === $field_type) {
$field_type = '::Telegram::Td::Api::'.$field_type;
}
$full_constructor .= $colon.$field_type.' '.$this->getParameterName($name, $class_name);
$colon = ', ';
}
$full_constructor .= ');';

$full_doc = <<<EOT
/// <summary>
/// Constructor for initialization of all fields.
/// </summary>
EOT;
foreach ($known_fields as $name => $type) {
$full_doc .= '\r\n /// <param name="'.$this->getParameterName($name, $class_name).'">'.$info[$name]."</param>";
}
$this->addDocumentation($full_constructor, $full_doc);
}
}

$generator = new DotnetTlDocumentationGenerator();
$generator->generate($argv[1], $argv[2]);
16 changes: 8 additions & 8 deletions td/generate/DoxygenTlDocumentationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected function escapeDocumentation($doc)
return $doc;
}

protected function getFieldName($name)
protected function getFieldName($name, $class_name)
{
if (substr($name, 0, 6) === 'param_') {
$name = substr($name, 6);
Expand All @@ -53,7 +53,7 @@ protected function getFieldName($name)

protected function getClassName($type)
{
return implode(explode('.', trim($type, "\n ;")));
return implode(explode('.', trim($type, "\r\n ;")));
}

protected function getTypeName($type)
Expand Down Expand Up @@ -115,11 +115,11 @@ protected function needRemoveLine($line)
protected function needSkipLine($line)
{
$tline = trim($line);
return empty($tline) || $tline[0] == '}' || $tline == 'public:' || strpos($line, '#pragma ') === 0 ||
return empty($tline) || $tline[0] === '}' || $tline === 'public:' || strpos($line, '#pragma ') === 0 ||
strpos($line, '#include <') === 0 || strpos($tline, 'return ') === 0 || strpos($tline, 'namespace') === 0 ||
preg_match('/class [A-Za-z0-9_]*;/', $line) || $tline === 'if (value == nullptr) {' ||
strpos($line, 'JNIEnv') || strpos($line, 'jfieldID') || $tline === 'virtual ~Object() {' ||
$tline == 'virtual void store(TlStorerToString &s, const char *field_name) const = 0;';
$tline === 'virtual void store(TlStorerToString &s, const char *field_name) const = 0;';
}

protected function isHeaderLine($line)
Expand Down Expand Up @@ -322,7 +322,7 @@ protected function addAbstractClassDocumentation($class_name, $documentation)

protected function addClassDocumentation($class_name, $base_class_name, $description, $return_type)
{
$return_type_description = $return_type ? "\n *\n * Returns $return_type." : '';
$return_type_description = $return_type ? PHP_EOL.' *'.PHP_EOL." * Returns $return_type." : '';

$this->addDocumentation("class $class_name final : public $base_class_name {", <<<EOT
/**
Expand Down Expand Up @@ -352,11 +352,11 @@ protected function addDefaultConstructorDocumentation($class_name)

protected function addFullConstructorDocumentation($class_name, $known_fields, $info)
{
$explicit = count($known_fields) == 1 ? 'explicit ' : '';
$explicit = count($known_fields) === 1 ? 'explicit ' : '';
$full_constructor = " $explicit$class_name(";
$colon = '';
foreach ($known_fields as $name => $type) {
$full_constructor .= $colon.$this->getParameterTypeName($type).$this->getFieldName($name);
$full_constructor .= $colon.$this->getParameterTypeName($type).$this->getFieldName($name, $class_name);
$colon = ', ';
}
$full_constructor .= ');';
Expand All @@ -368,7 +368,7 @@ protected function addFullConstructorDocumentation($class_name, $known_fields, $
EOT;
foreach ($known_fields as $name => $type) {
$full_doc .= ' * \\param[in] '.$this->getFieldName($name).' '.$info[$name]."\n";
$full_doc .= ' * \\param[in] '.$this->getFieldName($name, $class_name).' '.$info[$name].PHP_EOL;
}
$full_doc .= ' */';
$this->addDocumentation($full_constructor, $full_doc);
Expand Down
Loading

0 comments on commit 3856045

Please sign in to comment.