<?php require_once 'TlDocumentationGenerator.php'; class DoxygenTlDocumentationGenerator extends TlDocumentationGenerator { private function getParameterTypeName($type) { switch ($type) { case 'Bool': return 'bool '; case 'int32': return 'std::int32_t '; case 'int53': case 'int64': return 'std::int64_t '; case 'double': return 'double '; case 'string': case 'bytes': return 'std::string const &'; default: if (substr($type, 0, 6) === 'vector') { if ($type[6] !== '<' || $type[strlen($type) - 1] !== '>') { return ''; } return 'std::vector<'.$this->getTypeName(substr($type, 7, -1)).'> &&'; } if (preg_match('/[^A-Za-z0-9.]/', $type)) { return ''; } return 'object_ptr<'.$this->getClassName($type).'> &&'; } } protected function escapeDocumentation($doc) { $doc = htmlspecialchars($doc); $doc = str_replace('*/', '*/', $doc); $doc = str_replace('#', '\#', $doc); return $doc; } protected function getFieldName($name, $class_name) { if (substr($name, 0, 6) === 'param_') { $name = substr($name, 6); } return $name.'_'; } protected function getClassName($type) { return implode(explode('.', trim($type, "\r\n ;"))); } protected function getTypeName($type) { switch ($type) { case 'Bool': return 'bool'; case 'int32': return 'std::int32_t'; case 'int53': case 'int64': return 'std::int64_t'; case 'double': return 'double'; case 'string': case 'bytes': return 'std::string'; 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 'std::vector<'.$this->getTypeName(substr($type, 7, -1)).'>'; } if (preg_match('/[^A-Za-z0-9.]/', $type)) { $this->printError("Wrong type $type"); return ''; } return 'object_ptr<'.$this->getClassName($type).'>'; } } protected function getBaseClassName($is_function) { return $is_function ? 'Function' : 'Object'; } protected function needRemoveLine($line) { $line = trim($line); return strpos($line, '/**') === 0 || strpos($line, '*') === 0 || strpos($line, '///') === 0; } protected function needSkipLine($line) { $tline = trim($line); 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;'; } protected function isHeaderLine($line) { return strpos($line, 'template <') === 0; } protected function extractClassName($line) { if (strpos($line, 'class ') === 0) { return explode(' ', trim($line))[1]; } return ''; } protected function fixLine($line) { if (strpos($line, 'ID = ') > 0 || strpos($line, 'ReturnType = ') > 0 || strpos($line, 'using BaseObject = ') === 0) { return substr($line, 0, strpos($line, '=')); } if (strpos($line, 'class Function: ') === 0) { return 'class Function'; } if (strpos($line, 'class Object {') === 0 || strpos($line, 'class Object: public TlObject {') === 0) { return 'class Object'; } return $line; } protected function addGlobalDocumentation() { $this->addDocumentation('#include "td/tl/TlObject.h"', <<<EOT /** * \\file * Contains declarations of all functions and types which represent a public TDLib interface. */ EOT ); $this->addDocumentation('using BaseObject', <<<EOT /** * This class is a base class for all TDLib API classes and functions. */ EOT ); $this->addDocumentation('using object_ptr = ::td::tl_object_ptr<Type>;', <<<EOT /** * A smart wrapper to store a pointer to a TDLib API object. Can be treated as an analogue of std::unique_ptr. */ EOT ); $this->addDocumentation('object_ptr<Type> make_object(Args &&... args) {', <<<EOT /** * A function to create a dynamically allocated TDLib API object. Can be treated as an analogue of std::make_unique. * Usage example: * \\code * auto get_authorization_state_request = td::td_api::make_object<td::td_api::getAuthorizationState>(); * auto message_text = td::td_api::make_object<td::td_api::formattedText>("Hello, world!!!", * std::vector<td::td_api::object_ptr<td::td_api::textEntities>>()); * auto send_message_request = td::td_api::make_object<td::td_api::sendMessage>(chat_id, 0, false, false, nullptr, * td::td_api::make_object<td::td_api::inputMessageText>(std::move(message_text), false, true)); * \\endcode * * \\tparam Type Type of an object to construct. * \\param[in] args Arguments to pass to the object constructor. * \\return Wrapped pointer to the created object. */ EOT ); $this->addDocumentation('object_ptr<ToType> move_object_as(FromType &&from) {', <<<EOT /** * A function to cast a wrapped in td::td_api::object_ptr TDLib API object to its subclass or superclass. * Casting an object to an incorrect type will lead to undefined behaviour. * Usage example: * \\code * td::td_api::object_ptr<td::td_api::callState> call_state = ...; * switch (call_state->get_id()) { * case td::td_api::callStatePending::ID: { * auto state = td::td_api::move_object_as<td::td_api::callStatePending>(call_state); * // use state * break; * } * case td::td_api::callStateExchangingKeys::ID: { * // no additional fields, no casting is needed * break; * } * case td::td_api::callStateReady::ID: { * auto state = td::td_api::move_object_as<td::td_api::callStateReady>(call_state); * // use state * break; * } * case td::td_api::callStateHangingUp::ID: { * // no additional fields, no casting is needed * break; * } * case td::td_api::callStateDiscarded::ID: { * auto state = td::td_api::move_object_as<td::td_api::callStateDiscarded>(call_state); * // use state * break; * } * case td::td_api::callStateError::ID: { * auto state = td::td_api::move_object_as<td::td_api::callStateError>(call_state); * // use state * break; * } * default: * assert(false); * } * \\endcode * * \\tparam ToType Type of a TDLib API object to move to. * \\tparam FromType Type of a TDLib API object to move from, this is auto-deduced. * \\param[in] from Wrapped in td::td_api::object_ptr pointer to a TDLib API object. */ EOT ); $this->addDocumentation('std::string to_string(const BaseObject &value);', <<<EOT /** * Returns a string representation of the TDLib API object. * \\param[in] value The object. * \\return Object string representation. */ EOT ); $this->addDocumentation('std::string to_string(const object_ptr<T> &value) {', <<<EOT /** * Returns a string representation of the TDLib API object. * \\tparam T Object type, auto-deduced. * \\param[in] value The object. * \\return Object string representation. */ EOT ); $this->addDocumentation(' void store(TlStorerToString &s, const char *field_name) const final;', <<<EOT /** * Helper function for to_string method. Appends string representation of the object to the storer. * \\param[in] s Storer to which object string representation will be appended. * \\param[in] field_name Object field_name if applicable. */ EOT ); $this->addDocumentation('class Object', <<<EOT /** * This class is a base class for all TDLib API classes. */ EOT ); $this->addDocumentation('class Function', <<<EOT /** * This class is a base class for all TDLib API functions. */ EOT ); $this->addDocumentation(' static const std::int32_t ID', <<<EOT /// Identifier uniquely determining a type of the object. EOT ); $this->addDocumentation(' std::int32_t get_id() const final {', <<<EOT /** * Returns identifier uniquely determining a type of the object. * \\return this->ID. */ EOT ); $this->addDocumentation(' virtual std::int32_t get_id() const = 0;', <<<EOT /** * Returns identifier uniquely determining a type of the object. * \\return this->ID. */ EOT ); $this->addDocumentation(' using ReturnType', <<<EOT /// Typedef for the type returned by the function. EOT ); } protected function addAbstractClassDocumentation($class_name, $documentation) { $this->addDocumentation("class $class_name: public Object {", <<<EOT /** * This class is an abstract base class. * $documentation */ EOT ); } protected function getFunctionReturnTypeDescription($return_type, $for_constructor) { $shift = $for_constructor ? ' ' : ' '; return PHP_EOL.$shift.'*'.PHP_EOL.$shift."* Returns $return_type."; } protected function addClassDocumentation($class_name, $base_class_name, $description) { $this->addDocumentation("class $class_name final : public $base_class_name {", <<<EOT /** * $description */ EOT ); } protected function addFieldDocumentation($class_name, $field_name, $type_name, $field_info, $may_be_null) { $this->addDocumentation($class_name." $type_name $field_name;", <<<EOT /// $field_info EOT ); } protected function addDefaultConstructorDocumentation($class_name, $class_description) { $this->addDocumentation(" $class_name();", <<<EOT /** * $class_description */ EOT ); } protected function addFullConstructorDocumentation($class_name, $class_description, $known_fields, $info) { $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, $class_name); $colon = ', '; } $full_constructor .= ');'; $full_doc = <<<EOT /** * $class_description * EOT; foreach ($known_fields as $name => $type) { $full_doc .= ' * \\param[in] '.$this->getFieldName($name, $class_name).' '.$info[$name].PHP_EOL; } $full_doc .= ' */'; $this->addDocumentation($full_constructor, $full_doc); } } $generator = new DoxygenTlDocumentationGenerator(); $generator->generate($argv[1], $argv[2]);