forked from mirrors/linphone-iphone
Partial merge from 'master' about wrapper and documentation generation scripts
This commit is contained in:
parent
a97c048420
commit
5cf9e549f3
24 changed files with 2379 additions and 769 deletions
|
|
@ -171,7 +171,7 @@ if(ENABLE_LIME)
|
|||
endif()
|
||||
set(HAVE_LIME 1)
|
||||
endif()
|
||||
if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER)
|
||||
if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER OR ENABLE_SPHINX_DOC)
|
||||
find_package(PythonInterp REQUIRED)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -21,22 +21,23 @@
|
|||
############################################################################
|
||||
|
||||
add_subdirectory(doxygen)
|
||||
add_subdirectory(sphinx)
|
||||
|
||||
if(ENABLE_JAVADOC)
|
||||
find_package(Java REQUIRED)
|
||||
set(JAVADOC_PACKAGES "org.linphone.core org.linphone.mediastream")
|
||||
set(JAVADOC_CLASSPATHS
|
||||
"${PROJECT_SOURCE_DIR}/java/common"
|
||||
"${PROJECT_SOURCE_DIR}/java/j2se"
|
||||
"${PROJECT_SOURCE_DIR}/mediastreamer2/java/src"
|
||||
)
|
||||
string(REPLACE ";" ":" JAVADOC_CLASSPATHS "${JAVADOC_CLASSPATHS}")
|
||||
set(JAVADOC_TITLE "Linphone SDK ${PROJECT_VERSION} reference documentation")
|
||||
set(JAVADOC_JAVA_REFERENCE "http://docs.oracle.com/javase/8/docs/api/")
|
||||
set(JAVADOC_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc/java")
|
||||
set(JAVADOC_LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/javadoc.log")
|
||||
configure_file("generate_javadoc.sh.in" "generate_javadoc.sh" @ONLY)
|
||||
add_custom_target(javadoc ALL
|
||||
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/generate_javadoc.sh"
|
||||
)
|
||||
find_package(Java REQUIRED)
|
||||
set(JAVADOC_PACKAGES "org.linphone.core org.linphone.mediastream")
|
||||
set(JAVADOC_CLASSPATHS
|
||||
"${PROJECT_SOURCE_DIR}/java/common"
|
||||
"${PROJECT_SOURCE_DIR}/java/j2se"
|
||||
"${PROJECT_SOURCE_DIR}/mediastreamer2/java/src"
|
||||
)
|
||||
string(REPLACE ";" ":" JAVADOC_CLASSPATHS "${JAVADOC_CLASSPATHS}")
|
||||
set(JAVADOC_TITLE "Linphone SDK ${PROJECT_VERSION} reference documentation")
|
||||
set(JAVADOC_JAVA_REFERENCE "http://docs.oracle.com/javase/8/docs/api/")
|
||||
set(JAVADOC_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc/java")
|
||||
set(JAVADOC_LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/javadoc.log")
|
||||
configure_file("generate_javadoc.sh.in" "generate_javadoc.sh" @ONLY)
|
||||
add_custom_target(javadoc ALL
|
||||
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/generate_javadoc.sh"
|
||||
)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -22,12 +22,9 @@
|
|||
|
||||
if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER)
|
||||
find_package(Doxygen)
|
||||
if (DOXYGEN_FOUND)
|
||||
if (DOXYGEN_DOT_FOUND)
|
||||
set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox
|
||||
${LINPHONE_HEADER_FILES}
|
||||
)
|
||||
if(DOXYGEN_FOUND)
|
||||
if(DOXYGEN_DOT_FOUND)
|
||||
set(top_srcdir "${PROJECT_SOURCE_DIR}")
|
||||
set(DOXYGEN_INPUT "")
|
||||
foreach (HEADER_FILE ${LINPHONE_HEADER_FILES})
|
||||
string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${HEADER_FILE}\"")
|
||||
|
|
@ -35,21 +32,28 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRA
|
|||
string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${CMAKE_CURRENT_SOURCE_DIR}\"")
|
||||
string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${PROJECT_SOURCE_DIR}/coreapi/help/examples/C\"")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${CMAKE_CURRENT_BINARY_DIR}/xml/index.xml"
|
||||
set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox
|
||||
${LINPHONE_HEADER_FILES}
|
||||
)
|
||||
set(XML_DIR "${CMAKE_CURRENT_BINARY_DIR}/xml")
|
||||
set(LINPHONE_DOXYGEN_XML_DIR ${XML_DIR} PARENT_SCOPE)
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml"
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/*
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/*
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
DEPENDS ${DOC_INPUT_FILES}
|
||||
)
|
||||
add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${CMAKE_CURRENT_BINARY_DIR}/xml/index.xml")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html" "${CMAKE_CURRENT_BINARY_DIR}/xml"
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}")
|
||||
else ()
|
||||
add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html" "${XML_DIR}"
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}")
|
||||
else()
|
||||
if (ENABLE_CXX_WRAPPER)
|
||||
message(FATAL_ERROR "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
|
||||
else ()
|
||||
else()
|
||||
message(WARNING "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@
|
|||
* @brief Initializing liblinphone.
|
||||
**/
|
||||
|
||||
/**
|
||||
* @defgroup logging Logging
|
||||
* @brief Logging service of Linphone.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup call_control Call control
|
||||
* @brief Placing and receiving calls.
|
||||
|
|
|
|||
61
coreapi/help/doc/sphinx/CMakeLists.txt
Normal file
61
coreapi/help/doc/sphinx/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
############################################################################
|
||||
# CMakeLists.txt
|
||||
# Copyright (C) 2017 Belledonne Communications, Grenoble France
|
||||
#
|
||||
############################################################################
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
if (ENABLE_SPHINX_DOC)
|
||||
set(GENERATED_LANGUAGES c cpp csharp)
|
||||
set(DOCUMENTATION_DIRS )
|
||||
set(GENERATED_SPHINX_SOURCES )
|
||||
foreach(LANGUAGE_ ${GENERATED_LANGUAGES})
|
||||
set(DOCUMENTATION_DIR ${CMAKE_CURRENT_BINARY_DIR}/source/${LANGUAGE_})
|
||||
list(APPEND DOCUMENTATION_DIRS ${DOCUMENTATION_DIR})
|
||||
list(APPEND GENERATED_SPHINX_SOURCES ${DOCUMENTATION_DIR}/index.rst)
|
||||
endforeach(LANGUAGE_)
|
||||
|
||||
set(PYTHON_SCRIPTS gendoc.py
|
||||
${linphone_SOURCE_DIR}/tools/abstractapi.py
|
||||
${linphone_SOURCE_DIR}/tools/genapixml.py
|
||||
${linphone_SOURCE_DIR}/tools/metadoc.py
|
||||
${linphone_SOURCE_DIR}/tools/metaname.py
|
||||
)
|
||||
set(MUSTACHE_TEMPLATES class_page.mustache
|
||||
enums_page.mustache
|
||||
index_page.mustache
|
||||
)
|
||||
configure_file(conf.py.in source/conf.py)
|
||||
configure_file(source/index.rst source/index.rst COPYONLY)
|
||||
add_custom_command(OUTPUT ${GENERATED_SPHINX_SOURCES}
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f ${DOCUMENTATION_DIRS}
|
||||
COMMAND ${PYTHON_EXECUTABLE} '${CMAKE_CURRENT_SOURCE_DIR}/gendoc.py' '${LINPHONE_DOXYGEN_XML_DIR}' -o 'source'
|
||||
DEPENDS ${PYTHON_SCRIPTS}
|
||||
${MUSTACHE_TEMPLATES}
|
||||
${LINPHONE_DOXYGEN_XML_DIR}/index.xml
|
||||
linphone-doc
|
||||
)
|
||||
add_custom_command(OUTPUT build/html/index.html
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory build
|
||||
COMMAND ${PYTHON_EXECUTABLE} -msphinx -M html 'source' 'build'
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/source/conf.py
|
||||
${CMAKE_CURRENT_BINARY_DIR}/source/index.rst
|
||||
${GENERATED_SPHINX_SOURCES}
|
||||
)
|
||||
add_custom_target(sphinx-doc ALL DEPENDS build/html/index.html)
|
||||
endif()
|
||||
151
coreapi/help/doc/sphinx/class_page.mustache
Normal file
151
coreapi/help/doc/sphinx/class_page.mustache
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
{{#make_chapter}}{{{className}}} class{{/make_chapter}}
|
||||
|
||||
.. {{#write_declarator}}class{{/write_declarator}}:: {{{fullClassName}}}
|
||||
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
|
||||
{{{selector}}}
|
||||
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
||||
{{#hasProperties}}
|
||||
Properties
|
||||
----------
|
||||
|
||||
{{{propertiesSummary}}}
|
||||
{{/hasProperties}}
|
||||
|
||||
{{#hasMethods}}
|
||||
Methods
|
||||
-------
|
||||
|
||||
{{{instanceMethodsSummary}}}
|
||||
{{/hasMethods}}
|
||||
|
||||
{{#hasClassMethods}}
|
||||
Class methods
|
||||
-------------
|
||||
|
||||
{{{classMethodsSummary}}}
|
||||
{{/hasClassMethods}}
|
||||
|
||||
Detailed descriptions
|
||||
=====================
|
||||
|
||||
{{#hasProperties}}
|
||||
Properties
|
||||
----------
|
||||
|
||||
{{#properties}}
|
||||
{{{title}}}
|
||||
|
||||
{{#hasNamespaceDeclarator}}
|
||||
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
|
||||
{{/hasNamespaceDeclarator}}
|
||||
|
||||
{{#getter}}
|
||||
.. {{#write_declarator}}method{{/write_declarator}}:: {{{prototype}}}
|
||||
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
|
||||
{{{selector}}}
|
||||
{{/getter}}
|
||||
|
||||
{{#setter}}
|
||||
.. {{#write_declarator}}method{{/write_declarator}}:: {{{prototype}}}
|
||||
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
|
||||
{{{selector}}}
|
||||
{{/setter}}
|
||||
|
||||
{{/properties}}
|
||||
{{/hasProperties}}
|
||||
|
||||
{{#hasMethods}}
|
||||
Public methods
|
||||
--------------
|
||||
|
||||
{{#hasNamespaceDeclarator}}
|
||||
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
|
||||
{{/hasNamespaceDeclarator}}
|
||||
|
||||
{{#methods}}
|
||||
.. {{#write_declarator}}method{{/write_declarator}}:: {{{prototype}}}
|
||||
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
|
||||
{{{selector}}}
|
||||
|
||||
{{/methods}}
|
||||
|
||||
{{/hasMethods}}
|
||||
{{#hasClassMethods}}
|
||||
Class methods
|
||||
-------------
|
||||
|
||||
{{#hasNamespaceDeclarator}}
|
||||
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
|
||||
{{/hasNamespaceDeclarator}}
|
||||
|
||||
{{#classMethods}}
|
||||
.. {{#write_declarator}}method{{/write_declarator}}:: static {{{prototype}}}
|
||||
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
|
||||
{{{selector}}}
|
||||
|
||||
{{/classMethods}}
|
||||
{{/hasClassMethods}}
|
||||
158
coreapi/help/doc/sphinx/conf.py.in
Normal file
158
coreapi/help/doc/sphinx/conf.py.in
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Linphone API documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Jun 19 11:58:21 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx_csharp.csharp']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Linphone Core API'
|
||||
copyright = '2017, Belledonne Communications SARL'
|
||||
author = 'Belledonne Communications SARL'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '${LINPHONE_MAJOR_VERSION}.${LINPHONE_MINOR_VERSION}'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '${LINPHONE_VERSION}'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#html_theme = 'alabaster'
|
||||
html_theme = 'classic'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'LinphoneAPIdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'LinphoneAPI.tex', 'Linphone API Documentation',
|
||||
'Belledonne Communications SARL', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'linphoneapi', 'Linphone Core API Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'LinphoneCoreAPI', 'Linphone Core API Documentation',
|
||||
author, 'LinphoneCoreAPI', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
30
coreapi/help/doc/sphinx/enums_page.mustache
Normal file
30
coreapi/help/doc/sphinx/enums_page.mustache
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{{#enums}}
|
||||
{{{sectionName}}}
|
||||
|
||||
.. {{#write_declarator}}enum{{/write_declarator}}:: {{{fullName}}}
|
||||
|
||||
{{#briefDesc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDesc}}
|
||||
|
||||
{{{selector}}}
|
||||
|
||||
{{#hasNamespaceDeclarator}}
|
||||
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{namespace}}}
|
||||
{{/hasNamespaceDeclarator}}
|
||||
|
||||
{{#enumerators}}
|
||||
.. {{#write_declarator}}enumerator{{/write_declarator}}:: {{{name}}}{{#value}} = {{{value}}}{{/value}}
|
||||
|
||||
{{#briefDesc}}
|
||||
{{#lines}}
|
||||
{{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDesc}}
|
||||
|
||||
{{{selector}}}
|
||||
|
||||
{{/enumerators}}
|
||||
{{/enums}}
|
||||
377
coreapi/help/doc/sphinx/gendoc.py
Executable file
377
coreapi/help/doc/sphinx/gendoc.py
Executable file
|
|
@ -0,0 +1,377 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2017 Belledonne Communications SARL
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import pystache
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', 'tools'))
|
||||
import abstractapi
|
||||
import genapixml as capi
|
||||
import metaname
|
||||
import metadoc
|
||||
|
||||
|
||||
class RstTools:
|
||||
@staticmethod
|
||||
def make_chapter(text):
|
||||
return RstTools.make_section(text, char='*', overline=True)
|
||||
|
||||
@staticmethod
|
||||
def make_section(text, char='=', overline=False):
|
||||
size = len(text)
|
||||
underline = (char*size)
|
||||
lines = [text, underline]
|
||||
if overline:
|
||||
lines.insert(0, underline)
|
||||
return '\n'.join(lines)
|
||||
|
||||
@staticmethod
|
||||
def make_subsection(text):
|
||||
return RstTools.make_section(text, char='-')
|
||||
|
||||
@staticmethod
|
||||
def make_subsubsection(text):
|
||||
return RstTools.make_section(text, char='^')
|
||||
|
||||
class Table:
|
||||
def __init__(self):
|
||||
self._rows = []
|
||||
self._widths = []
|
||||
self._heights = []
|
||||
|
||||
@property
|
||||
def rows(self):
|
||||
return self._rows
|
||||
|
||||
def addrow(self, row):
|
||||
if len(self._widths) == 0:
|
||||
self._widths.append(0)
|
||||
self._widths *= len(row)
|
||||
elif len(row) != len(self._widths):
|
||||
raise ValueError('row width mismatch table width')
|
||||
|
||||
height = 0
|
||||
row2 = []
|
||||
|
||||
i = 0
|
||||
while i<len(row):
|
||||
lines = str(row[i]).split(sep='\n')
|
||||
row2.append(lines)
|
||||
width = len(max(lines, key=len))
|
||||
self._widths[i] = max(self._widths[i], width)
|
||||
height = max(height, len(lines))
|
||||
i += 1
|
||||
|
||||
self._rows.append(row2)
|
||||
self._heights.append(height)
|
||||
|
||||
def _make_hline(self):
|
||||
res = '+'
|
||||
for width in self._widths:
|
||||
res += ('-' * (width+2))
|
||||
res += '+'
|
||||
res += '\n'
|
||||
return res
|
||||
|
||||
def _make_row(self, idx):
|
||||
res = ''
|
||||
row = self._rows[idx]
|
||||
j = 0
|
||||
while j < self._heights[idx]:
|
||||
res += '|'
|
||||
i = 0
|
||||
while i < len(row):
|
||||
line = row[i][j] if j < len(row[i]) else ''
|
||||
res += ' {0} '.format(line)
|
||||
res += (' ' * (self._widths[i]-len(line)))
|
||||
res += '|'
|
||||
i += 1
|
||||
res += '\n'
|
||||
j += 1
|
||||
return res
|
||||
|
||||
def __str__(self):
|
||||
if len(self._rows) == 0 or len(self._widths) == 0:
|
||||
return ''
|
||||
else:
|
||||
res = self._make_hline()
|
||||
i = 0
|
||||
while i<len(self._rows):
|
||||
res += self._make_row(i)
|
||||
res += self._make_hline()
|
||||
i += 1
|
||||
return res
|
||||
|
||||
|
||||
class LangInfo:
|
||||
def __init__(self, langCode):
|
||||
self.langCode = langCode
|
||||
self.displayName = LangInfo._lang_code_to_display_name(langCode)
|
||||
self.nameTranslator = metaname.Translator.get(langCode)
|
||||
self.langTranslator = abstractapi.Translator.get(langCode)
|
||||
self.docTranslator = metadoc.SphinxTranslator(langCode)
|
||||
|
||||
@staticmethod
|
||||
def _lang_code_to_display_name(langCode):
|
||||
if langCode == 'C':
|
||||
return 'C'
|
||||
elif langCode == 'Cpp':
|
||||
return 'C++'
|
||||
elif langCode == 'CSharp':
|
||||
return 'C#'
|
||||
else:
|
||||
raise ValueError("Invalid language code: '{0}'".format(langCode))
|
||||
|
||||
|
||||
class SphinxPage(object):
|
||||
def __init__(self, lang, langs, filename):
|
||||
object.__init__(self)
|
||||
self.lang = lang
|
||||
self.langs = langs
|
||||
self.filename = filename
|
||||
|
||||
@property
|
||||
def hasNamespaceDeclarator(self):
|
||||
return ('namespaceDeclarator' in dir(self.docTranslator))
|
||||
|
||||
@property
|
||||
def language(self):
|
||||
return self.lang.displayName
|
||||
|
||||
@property
|
||||
def docTranslator(self):
|
||||
return self.lang.docTranslator
|
||||
|
||||
def make_chapter(self):
|
||||
return lambda text: RstTools.make_chapter(pystache.render(text, self))
|
||||
|
||||
def make_section(self):
|
||||
return lambda text: RstTools.make_section(pystache.render(text, self))
|
||||
|
||||
def make_subsection(self):
|
||||
return lambda text: RstTools.make_subsection(pystache.render(text, self.properties))
|
||||
|
||||
def write_declarator(self):
|
||||
return lambda text: self.docTranslator.get_declarator(text)
|
||||
|
||||
def write(self, directory):
|
||||
r = pystache.Renderer()
|
||||
filepath = os.path.join(directory, self.filename)
|
||||
with open(filepath, mode='w') as f:
|
||||
f.write(r.render(self))
|
||||
|
||||
def _get_translated_namespace(self, obj):
|
||||
namespace = obj.find_first_ancestor_by_type(abstractapi.Namespace)
|
||||
return namespace.name.translate(self.lang.nameTranslator, recursive=True)
|
||||
|
||||
def _make_selector(self, obj):
|
||||
links = []
|
||||
ref = metadoc.Reference(None)
|
||||
ref.relatedObject = obj
|
||||
for lang in self.langs:
|
||||
if lang is self.lang:
|
||||
link = lang.displayName
|
||||
else:
|
||||
link = ref.translate(lang.docTranslator, label=lang.displayName)
|
||||
|
||||
links.append(link)
|
||||
|
||||
return ' '.join(links)
|
||||
|
||||
@staticmethod
|
||||
def _classname_to_filename(classname):
|
||||
return classname.to_snake_case(fullName=True) + '.rst'
|
||||
|
||||
|
||||
class IndexPage(SphinxPage):
|
||||
def __init__(self, lang, langs):
|
||||
SphinxPage.__init__(self, lang, langs, 'index.rst')
|
||||
self.tocEntries = []
|
||||
|
||||
def add_class_entry(self, _class):
|
||||
self.tocEntries.append({'entryName': SphinxPage._classname_to_filename(_class.name)})
|
||||
|
||||
|
||||
class EnumsPage(SphinxPage):
|
||||
def __init__(self, lang, langs, enums):
|
||||
SphinxPage.__init__(self, lang, langs, 'enums.rst')
|
||||
self._translate_enums(enums)
|
||||
|
||||
def _translate_enums(self, enums):
|
||||
self.enums = []
|
||||
for enum in enums:
|
||||
translatedEnum = {
|
||||
'name' : enum.name.translate(self.lang.nameTranslator),
|
||||
'fullName' : enum.name.translate(self.lang.nameTranslator, recursive=True),
|
||||
'briefDesc' : enum.briefDescription.translate(self.docTranslator),
|
||||
'enumerators' : self._translate_enum_values(enum),
|
||||
'selector' : self._make_selector(enum)
|
||||
}
|
||||
translatedEnum['namespace'] = self._get_translated_namespace(enum) if self.lang.langCode == 'Cpp' else translatedEnum['fullName']
|
||||
translatedEnum['sectionName'] = RstTools.make_section(translatedEnum['name'])
|
||||
self.enums.append(translatedEnum)
|
||||
|
||||
def _translate_enum_values(self, enum):
|
||||
translatedEnumerators = []
|
||||
for enumerator in enum.enumerators:
|
||||
translatedValue = {
|
||||
'name' : enumerator.name.translate(self.lang.nameTranslator),
|
||||
'briefDesc' : enumerator.briefDescription.translate(self.docTranslator),
|
||||
'value' : enumerator.translate_value(self.lang.langTranslator),
|
||||
'selector' : self._make_selector(enumerator)
|
||||
}
|
||||
translatedEnumerators.append(translatedValue)
|
||||
|
||||
return translatedEnumerators
|
||||
|
||||
|
||||
class ClassPage(SphinxPage):
|
||||
def __init__(self, _class, lang, langs):
|
||||
filename = SphinxPage._classname_to_filename(_class.name)
|
||||
SphinxPage.__init__(self, lang, langs, filename)
|
||||
self.namespace = self._get_translated_namespace(_class)
|
||||
self.className = _class.name.translate(self.lang.nameTranslator)
|
||||
self.fullClassName = _class.name.translate(self.lang.nameTranslator, recursive=True)
|
||||
self.briefDoc = _class.briefDescription.translate(self.docTranslator)
|
||||
self.detailedDoc = _class.detailedDescription.translate(self.docTranslator) if _class.detailedDescription is not None else None
|
||||
self.properties = self._translate_properties(_class.properties)
|
||||
self.methods = self._translate_methods(_class.instanceMethods)
|
||||
self.classMethods = self._translate_methods(_class.classMethods)
|
||||
self.selector = self._make_selector(_class)
|
||||
|
||||
@property
|
||||
def hasMethods(self):
|
||||
return len(self.methods) > 0
|
||||
|
||||
@property
|
||||
def hasClassMethods(self):
|
||||
return len(self.classMethods) > 0
|
||||
|
||||
@property
|
||||
def hasProperties(self):
|
||||
return len(self.properties) > 0
|
||||
|
||||
def _translate_properties(self, properties):
|
||||
translatedProperties = []
|
||||
for property_ in properties:
|
||||
propertyAttr = {
|
||||
'name' : property_.name.translate(self.lang.nameTranslator),
|
||||
'ref_label' : '{0}_{1}'.format(self.lang.langCode, property_.name.to_snake_case(fullName=True)),
|
||||
'getter' : self._translate_method(property_.getter) if property_.getter is not None else None,
|
||||
'setter' : self._translate_method(property_.setter) if property_.setter is not None else None
|
||||
}
|
||||
propertyAttr['title'] = RstTools.make_subsubsection(propertyAttr['name'])
|
||||
translatedProperties.append(propertyAttr)
|
||||
return translatedProperties
|
||||
|
||||
def _translate_methods(self, methods):
|
||||
translatedMethods = []
|
||||
for method in methods:
|
||||
translatedMethods.append(self._translate_method(method))
|
||||
return translatedMethods
|
||||
|
||||
def _translate_method(self, method):
|
||||
prototypeParams = {}
|
||||
if self.lang.langCode == 'Cpp':
|
||||
prototypeParams['showStdNs'] = True
|
||||
methAttr = {
|
||||
'prototype' : method.translate_as_prototype(self.lang.langTranslator, **prototypeParams),
|
||||
'briefDoc' : method.briefDescription.translate(self.docTranslator),
|
||||
'detailedDoc' : method.detailedDescription.translate(self.docTranslator),
|
||||
'selector' : self._make_selector(method)
|
||||
}
|
||||
reference = metadoc.FunctionReference(None)
|
||||
reference.relatedObject = method
|
||||
methAttr['link'] = reference.translate(self.lang.docTranslator)
|
||||
return methAttr
|
||||
|
||||
@property
|
||||
def propertiesSummary(self):
|
||||
table = RstTools.Table()
|
||||
for property_ in self.properties:
|
||||
reference = ':ref:`{0}`'.format(property_['ref_label'])
|
||||
briefDoc = property_['getter']['briefDoc'] if property_['getter'] is not None else property_['setter']['briefDoc']
|
||||
briefDoc = '\n'.join([line['line'] for line in briefDoc['lines']])
|
||||
table.addrow([reference, briefDoc])
|
||||
return table
|
||||
|
||||
@property
|
||||
def instanceMethodsSummary(self):
|
||||
table = RstTools.Table()
|
||||
for method in self.methods:
|
||||
briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']])
|
||||
table.addrow([method['link'], briefDoc])
|
||||
return table
|
||||
|
||||
@property
|
||||
def classMethodsSummary(self):
|
||||
table = RstTools.Table()
|
||||
for method in self.classMethods:
|
||||
briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']])
|
||||
table.addrow([method['link'], briefDoc])
|
||||
return table
|
||||
|
||||
|
||||
class DocGenerator:
|
||||
def __init__(self, api):
|
||||
self.api = api
|
||||
self.languages = [
|
||||
LangInfo('C'),
|
||||
LangInfo('Cpp'),
|
||||
LangInfo('CSharp')
|
||||
]
|
||||
|
||||
def generate(self, outputdir):
|
||||
for lang in self.languages:
|
||||
subdirectory = lang.langCode.lower()
|
||||
directory = os.path.join(args.outputdir, subdirectory)
|
||||
if not os.path.exists(directory):
|
||||
os.mkdir(directory)
|
||||
|
||||
enumsPage = EnumsPage(lang, self.languages, absApiParser.enums)
|
||||
enumsPage.write(directory)
|
||||
|
||||
indexPage = IndexPage(lang, self.languages)
|
||||
for _class in absApiParser.classes:
|
||||
page = ClassPage(_class, lang, self.languages)
|
||||
page.write(directory)
|
||||
indexPage.add_class_entry(_class)
|
||||
|
||||
indexPage.write(directory)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
argparser = argparse.ArgumentParser(description='Generate a sphinx project to generate the documentation of Linphone Core API.')
|
||||
argparser.add_argument('xmldir', type=str, help='directory holding the XML documentation of the C API generated by Doxygen')
|
||||
argparser.add_argument('-o --output', type=str, help='directory into where Sphinx source files will be written', dest='outputdir', default='.')
|
||||
args = argparser.parse_args()
|
||||
|
||||
cProject = capi.Project()
|
||||
cProject.initFromDir(args.xmldir)
|
||||
cProject.check()
|
||||
|
||||
absApiParser = abstractapi.CParser(cProject)
|
||||
absApiParser.parse_all()
|
||||
|
||||
docGenerator = DocGenerator(absApiParser)
|
||||
docGenerator.generate(args.outputdir)
|
||||
|
||||
19
coreapi/help/doc/sphinx/index_page.mustache
Normal file
19
coreapi/help/doc/sphinx/index_page.mustache
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{{#make_section}}{{{language}}} API{{/make_section}}
|
||||
|
||||
Index of classes
|
||||
----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
{{#tocEntries}}
|
||||
{{{entryName}}}
|
||||
{{/tocEntries}}
|
||||
|
||||
Index of enums
|
||||
--------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth 1
|
||||
|
||||
enums.rst
|
||||
24
coreapi/help/doc/sphinx/source/index.rst
Normal file
24
coreapi/help/doc/sphinx/source/index.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.. Linphone API documentation master file, created by
|
||||
sphinx-quickstart on Mon Jun 19 11:58:21 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Linphone API's documentation!
|
||||
========================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Contents:
|
||||
|
||||
c/index.rst
|
||||
cpp/index.rst
|
||||
csharp/index.rst
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
|
@ -1055,6 +1055,10 @@ typedef enum _LinphoneTransportType {
|
|||
*/
|
||||
typedef struct _LinphoneTunnel LinphoneTunnel;
|
||||
|
||||
/**
|
||||
* @brief Tunnel settings.
|
||||
* @ingroup tunnel
|
||||
*/
|
||||
typedef struct _LinphoneTunnelConfig LinphoneTunnelConfig;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
# Copyright (C) 2017 Belledonne Communications SARL
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
|
||||
import re
|
||||
import genapixml as CApi
|
||||
import metaname
|
||||
|
||||
|
||||
class Error(RuntimeError):
|
||||
|
|
@ -27,170 +29,24 @@ class BlacklistedException(Error):
|
|||
pass
|
||||
|
||||
|
||||
class Name(object):
|
||||
camelCaseParsingRegex = re.compile('[A-Z][a-z0-9]*')
|
||||
lowerCamelCaseSplitingRegex = re.compile('([a-z][a-z0-9]*)([A-Z][a-z0-9]*)')
|
||||
|
||||
def __init__(self):
|
||||
self.words = []
|
||||
self.prev = None
|
||||
|
||||
def copy(self):
|
||||
nameType = type(self)
|
||||
name = nameType()
|
||||
name.words = list(self.words)
|
||||
name.prev = None if self.prev is None else self.prev.copy()
|
||||
return name
|
||||
|
||||
def delete_prefix(self, prefix):
|
||||
it = self
|
||||
_next = None
|
||||
while it is not None and it.words != prefix.words:
|
||||
_next = it
|
||||
it = it.prev
|
||||
|
||||
if it is None or it != prefix:
|
||||
raise Error('no common prefix')
|
||||
elif _next is not None:
|
||||
_next.prev = None
|
||||
|
||||
def _set_namespace(self, namespace):
|
||||
self.prev = namespace
|
||||
if self.prev is not None:
|
||||
prefix = namespace.to_word_list()
|
||||
i = 0
|
||||
while i<len(self.words) and i<len(prefix) and self.words[i] == prefix[i]:
|
||||
i += 1
|
||||
if i == len(self.words):
|
||||
raise Error('name equal to namespace \'{0}\'', self.words)
|
||||
else:
|
||||
self.words = self.words[i:]
|
||||
|
||||
def _lower_all_words(self):
|
||||
i = 0
|
||||
while i<len(self.words):
|
||||
self.words[i] = self.words[i].lower()
|
||||
i += 1
|
||||
|
||||
def from_snake_case(self, name, namespace=None):
|
||||
self.words = name.split('_')
|
||||
Name._set_namespace(self, namespace)
|
||||
|
||||
def from_camel_case(self, name, islowercased=False, namespace=None):
|
||||
if not islowercased:
|
||||
self.words = Name.camelCaseParsingRegex.findall(name)
|
||||
else:
|
||||
match = Name.lowerCamelCaseSplitingRegex.match(name)
|
||||
self.words = [match.group(1)]
|
||||
self.words += Name.camelCaseParsingRegex.findall(match.group(2))
|
||||
|
||||
Name._lower_all_words(self)
|
||||
Name._set_namespace(self, namespace)
|
||||
|
||||
def to_snake_case(self, fullName=False, upper=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = '_'.join(self.words)
|
||||
if upper:
|
||||
res = res.upper()
|
||||
return res
|
||||
else:
|
||||
return Name.to_snake_case(self.prev, fullName=True, upper=upper) + '_' + Name.to_snake_case(self, upper=upper)
|
||||
|
||||
def to_camel_case(self, lower=False, fullName=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = ''
|
||||
for elem in self.words:
|
||||
if elem is self.words[0] and lower:
|
||||
res += elem
|
||||
else:
|
||||
res += elem.title()
|
||||
return res
|
||||
else:
|
||||
return Name.to_camel_case(self.prev, fullName=True, lower=lower) + Name.to_camel_case(self)
|
||||
|
||||
def concatenate(self, upper=False, fullName=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = ''
|
||||
for elem in self.words:
|
||||
if upper:
|
||||
res += elem.upper()
|
||||
else:
|
||||
res += elem
|
||||
return res
|
||||
else:
|
||||
return Name.concatenate(self.prev, upper=upper, fullName=True) + Name.concatenate(self, upper=upper)
|
||||
|
||||
def to_word_list(self):
|
||||
if self.prev is None:
|
||||
return list(self.words)
|
||||
else:
|
||||
return Name.to_word_list(self.prev) + self.words
|
||||
|
||||
@staticmethod
|
||||
def find_common_parent(name1, name2):
|
||||
if name1.prev is None or name2.prev is None:
|
||||
return None
|
||||
elif name1.prev is name2.prev:
|
||||
return name1.prev
|
||||
else:
|
||||
commonParent = Name.find_common_parent(name1.prev, name2)
|
||||
if commonParent is not None:
|
||||
return commonParent
|
||||
else:
|
||||
return Name.find_common_parent(name1, name2.prev)
|
||||
|
||||
|
||||
class ClassName(Name):
|
||||
def to_c(self):
|
||||
return Name.to_camel_case(self, fullName=True)
|
||||
|
||||
|
||||
class InterfaceName(ClassName):
|
||||
def to_c(self):
|
||||
return ClassName.to_c(self)[:-8] + 'Cbs'
|
||||
|
||||
|
||||
class EnumName(ClassName):
|
||||
class Constant:
|
||||
pass
|
||||
|
||||
|
||||
class EnumValueName(ClassName):
|
||||
pass
|
||||
class Nil(Constant):
|
||||
def translate(self, langTranslator):
|
||||
return langTranslator.nilToken
|
||||
|
||||
|
||||
class MethodName(Name):
|
||||
regex = re.compile('^\d+$')
|
||||
class Boolean(Constant):
|
||||
def __init__(self, value=False):
|
||||
self.value = value
|
||||
|
||||
def __init__(self):
|
||||
self.overloadRef = 0
|
||||
def __bool__(self):
|
||||
return self.value
|
||||
|
||||
def from_snake_case(self, name, namespace=None):
|
||||
Name.from_snake_case(self, name, namespace=namespace)
|
||||
if len(self.words) > 0:
|
||||
suffix = self.words[-1]
|
||||
if MethodName.regex.match(suffix) is not None:
|
||||
self.overloadRef = int(suffix)
|
||||
del self.words[-1]
|
||||
|
||||
def to_c(self):
|
||||
suffix = ('_' + str(self.overloadRef)) if self.overloadRef > 0 else ''
|
||||
return self.to_snake_case(fullName=True) + suffix
|
||||
|
||||
|
||||
class ArgName(Name):
|
||||
def to_c(self):
|
||||
return self.to_snake_case()
|
||||
|
||||
|
||||
class PropertyName(ArgName):
|
||||
pass
|
||||
|
||||
|
||||
class NamespaceName(Name):
|
||||
def __init__(self, *params):
|
||||
Name.__init__(self)
|
||||
if len(params) > 0:
|
||||
self.words = params[0]
|
||||
def translate(self, langTranslator):
|
||||
return langTranslator.trueConstantToken if self else langTranslator.falseConstantToken
|
||||
|
||||
|
||||
class Object(object):
|
||||
|
|
@ -199,9 +55,12 @@ class Object(object):
|
|||
self.parent = None
|
||||
self.deprecated = False
|
||||
|
||||
def find_first_ancestor_by_type(self, _type):
|
||||
def __lt__(self, other):
|
||||
return self.name < other.name
|
||||
|
||||
def find_first_ancestor_by_type(self, *types):
|
||||
ancestor = self.parent
|
||||
while ancestor is not None and type(ancestor) is not _type:
|
||||
while ancestor is not None and type(ancestor) not in types:
|
||||
ancestor = ancestor.parent
|
||||
return ancestor
|
||||
|
||||
|
|
@ -211,7 +70,7 @@ class Type(Object):
|
|||
Object.__init__(self, name)
|
||||
self.isconst = isconst
|
||||
self.isref = isref
|
||||
self.cname = None
|
||||
self.cDecl = None
|
||||
|
||||
|
||||
class BaseType(Type):
|
||||
|
|
@ -219,18 +78,27 @@ class BaseType(Type):
|
|||
Type.__init__(self, name, isconst=isconst, isref=isref)
|
||||
self.size = size
|
||||
self.isUnsigned = isUnsigned
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_base_type(self, **params)
|
||||
|
||||
|
||||
class EnumType(Type):
|
||||
def __init__(self, name, isconst=False, isref=False, enumDesc=None):
|
||||
Type.__init__(self, name, isconst=isconst, isref=isref)
|
||||
self.desc = enumDesc
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_enum_type(self, **params)
|
||||
|
||||
|
||||
class ClassType(Type):
|
||||
def __init__(self, name, isconst=False, isref=False, classDesc=None):
|
||||
Type.__init__(self, name, isconst=isconst, isref=isref)
|
||||
self.desc = classDesc
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_class_type(self, **params)
|
||||
|
||||
|
||||
class ListType(Type):
|
||||
|
|
@ -239,23 +107,43 @@ class ListType(Type):
|
|||
self.containedTypeName = containedTypeName
|
||||
self._containedTypeDesc = None
|
||||
|
||||
def set_contained_type_desc(self, desc):
|
||||
def _set_contained_type_desc(self, desc):
|
||||
self._containedTypeDesc = desc
|
||||
desc.parent = self
|
||||
|
||||
def get_contained_type_desc(self):
|
||||
def _get_contained_type_desc(self):
|
||||
return self._containedTypeDesc
|
||||
|
||||
containedTypeDesc = property(fset=set_contained_type_desc, fget=get_contained_type_desc)
|
||||
containedTypeDesc = property(fset=_set_contained_type_desc, fget=_get_contained_type_desc)
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_list_type(self, **params)
|
||||
|
||||
|
||||
class DocumentableObject(Object):
|
||||
def __init__(self, name):
|
||||
Object.__init__(self, name)
|
||||
self.briefDescription = None
|
||||
self.detailedDescription = None
|
||||
self._briefDescription = None
|
||||
self._detailedDescription = None
|
||||
self.deprecated = None
|
||||
|
||||
def _get_brief_description(self):
|
||||
return self._briefDescription
|
||||
|
||||
def _set_brief_description(self, description):
|
||||
self._briefDescription = description
|
||||
description.relatedObject = self
|
||||
|
||||
def _get_detailed_description(self):
|
||||
return self._detailedDescription
|
||||
|
||||
def _set_detailed_description(self, description):
|
||||
self._detailedDescription = description
|
||||
description.relatedObject = self
|
||||
|
||||
briefDescription = property(fget=_get_brief_description, fset=_set_brief_description)
|
||||
detailedDescription = property(fget=_get_detailed_description, fset=_set_detailed_description)
|
||||
|
||||
def set_from_c(self, cObject, namespace=None):
|
||||
self.briefDescription = cObject.briefDescription
|
||||
self.detailedDescription = cObject.detailedDescription
|
||||
|
|
@ -281,32 +169,38 @@ class Namespace(DocumentableObject):
|
|||
child.parent = self
|
||||
|
||||
|
||||
GlobalNs = Namespace('')
|
||||
|
||||
|
||||
class Flag:
|
||||
def __init__(self, position):
|
||||
self.position = position
|
||||
|
||||
|
||||
class EnumValue(DocumentableObject):
|
||||
class Enumerator(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.value = None
|
||||
|
||||
def value_from_string(self, stringValue):
|
||||
m = re.match('^1\s*<<\s*([0-9]+)$', stringValue)
|
||||
m = re.match('^\s*1\s*<<\s*([0-9]+)$', stringValue)
|
||||
if m is not None:
|
||||
self.value = Flag(int(m.group(1)))
|
||||
else:
|
||||
self.value = int(stringValue, base=0)
|
||||
|
||||
def translate_value(self, translator):
|
||||
return translator.translate_enumerator_value(self.value)
|
||||
|
||||
|
||||
class Enum(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.values = []
|
||||
self.enumerators = []
|
||||
|
||||
def add_value(self, value):
|
||||
self.values.append(value)
|
||||
value.parent = self
|
||||
def add_enumerator(self, enumerator):
|
||||
self.enumerators.append(enumerator)
|
||||
enumerator.parent = self
|
||||
|
||||
def set_from_c(self, cEnum, namespace=None):
|
||||
Object.set_from_c(self, cEnum, namespace=namespace)
|
||||
|
|
@ -316,14 +210,14 @@ class Enum(DocumentableObject):
|
|||
else:
|
||||
name = cEnum.name
|
||||
|
||||
self.name = EnumName()
|
||||
self.name = metaname.EnumName()
|
||||
self.name.prev = None if namespace is None else namespace.name
|
||||
self.name.set_from_c(name)
|
||||
|
||||
for cEnumValue in cEnum.values:
|
||||
aEnumValue = EnumValue()
|
||||
aEnumValue = Enumerator()
|
||||
aEnumValue.set_from_c(cEnumValue, namespace=self)
|
||||
self.add_value(aEnumValue)
|
||||
self.add_enumerator(aEnumValue)
|
||||
|
||||
|
||||
class Argument(DocumentableObject):
|
||||
|
|
@ -342,6 +236,9 @@ class Argument(DocumentableObject):
|
|||
return self._type
|
||||
|
||||
type = property(fset=_set_type, fget=_get_type)
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_argument(self, **params)
|
||||
|
||||
|
||||
class Method(DocumentableObject):
|
||||
|
|
@ -352,10 +249,14 @@ class Method(DocumentableObject):
|
|||
def __init__(self, name, type=Type.Instance):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.type = type
|
||||
self.constMethod = False
|
||||
self.isconst = False
|
||||
self.args = []
|
||||
self._returnType = None
|
||||
|
||||
|
||||
def add_arguments(self, arg):
|
||||
self.args.append(arg)
|
||||
arg.parent = self
|
||||
|
||||
def _set_return_type(self, returnType):
|
||||
self._returnType = returnType
|
||||
returnType.parent = self
|
||||
|
|
@ -363,11 +264,10 @@ class Method(DocumentableObject):
|
|||
def _get_return_type(self):
|
||||
return self._returnType
|
||||
|
||||
def add_arguments(self, arg):
|
||||
self.args.append(arg)
|
||||
arg.parent = self
|
||||
|
||||
returnType = property(fset=_set_return_type, fget=_get_return_type)
|
||||
|
||||
def translate_as_prototype(self, translator, **params):
|
||||
return translator.translate_method_as_prototype(self, **params)
|
||||
|
||||
|
||||
class Property(DocumentableObject):
|
||||
|
|
@ -427,6 +327,11 @@ class Class(DocumentableObject):
|
|||
return self._listenerInterface
|
||||
|
||||
listenerInterface = property(fget=get_listener_interface, fset=set_listener_interface)
|
||||
|
||||
def sort(self):
|
||||
self.properties.sort()
|
||||
self.instanceMethods.sort()
|
||||
self.classMethods.sort()
|
||||
|
||||
|
||||
class Interface(DocumentableObject):
|
||||
|
|
@ -443,6 +348,9 @@ class Interface(DocumentableObject):
|
|||
return self._listenedClass
|
||||
|
||||
listenedClass = property(fget=get_listened_class)
|
||||
|
||||
def sort(self):
|
||||
self.methods.sort()
|
||||
|
||||
|
||||
class CParser(object):
|
||||
|
|
@ -469,6 +377,7 @@ class CParser(object):
|
|||
self.cProject = cProject
|
||||
|
||||
self.enumsIndex = {}
|
||||
self.enums = []
|
||||
for enum in self.cProject.enums:
|
||||
if enum.associatedTypedef is None:
|
||||
self.enumsIndex[enum.name] = None
|
||||
|
|
@ -477,6 +386,8 @@ class CParser(object):
|
|||
|
||||
self.classesIndex = {}
|
||||
self.interfacesIndex = {}
|
||||
self.classes = []
|
||||
self.interfaces = []
|
||||
for _class in self.cProject.classes:
|
||||
if _class.name not in self.classBl:
|
||||
if _class.name.endswith('Cbs'):
|
||||
|
|
@ -496,15 +407,15 @@ class CParser(object):
|
|||
if _property.getter is not None:
|
||||
self.methodsIndex[_property.getter.name] = None
|
||||
|
||||
name = NamespaceName()
|
||||
name = metaname.NamespaceName()
|
||||
name.from_snake_case('linphone')
|
||||
|
||||
self.namespace = Namespace(name)
|
||||
|
||||
def _is_blacklisted(self, name):
|
||||
if type(name) is MethodName:
|
||||
if type(name) is metaname.MethodName:
|
||||
return name.to_camel_case(lower=True) in self.methodBl or name.to_c() in self.functionBl
|
||||
elif type(name) is ClassName:
|
||||
elif type(name) is metaname.ClassName:
|
||||
return name.to_c() in self.classBl
|
||||
else:
|
||||
return False
|
||||
|
|
@ -526,6 +437,7 @@ class CParser(object):
|
|||
|
||||
|
||||
self._clean_all_indexes()
|
||||
self._sortall()
|
||||
self._fix_all_types()
|
||||
self._fix_all_docs()
|
||||
|
||||
|
|
@ -542,6 +454,15 @@ class CParser(object):
|
|||
for key in keysToRemove:
|
||||
del index[key]
|
||||
|
||||
def _sortall(self):
|
||||
self.enums.sort()
|
||||
self.classes.sort()
|
||||
self.interfaces.sort()
|
||||
for class_ in self.classes:
|
||||
class_.sort()
|
||||
for interface in self.interfaces:
|
||||
interface.sort()
|
||||
|
||||
def _class_is_refcountable(self, _class):
|
||||
if _class.name in self.forcedRefcountableClasses:
|
||||
return True
|
||||
|
|
@ -609,11 +530,19 @@ class CParser(object):
|
|||
|
||||
def _fix_all_docs(self):
|
||||
for _class in self.classesIndex.values():
|
||||
if _class.briefDescription is not None:
|
||||
_class.briefDescription.resolve_all_references(self)
|
||||
self._fix_doc(_class)
|
||||
for enum in self.enumsIndex.values():
|
||||
self._fix_doc(enum)
|
||||
for enumerator in enum.enumerators:
|
||||
self._fix_doc(enumerator)
|
||||
for method in self.methodsIndex.values():
|
||||
if method.briefDescription is not None:
|
||||
method.briefDescription.resolve_all_references(self)
|
||||
self._fix_doc(method)
|
||||
|
||||
def _fix_doc(self, obj):
|
||||
if obj.briefDescription is not None:
|
||||
obj.briefDescription.resolve_all_references(self)
|
||||
if obj.detailedDescription is not None:
|
||||
obj.detailedDescription.resolve_all_references(self)
|
||||
|
||||
def parse_enum(self, cenum):
|
||||
if 'associatedTypedef' in dir(cenum):
|
||||
|
|
@ -621,25 +550,28 @@ class CParser(object):
|
|||
else:
|
||||
nameStr = cenum.name
|
||||
|
||||
name = EnumName()
|
||||
name = metaname.EnumName()
|
||||
name.from_camel_case(nameStr, namespace=self.namespace.name)
|
||||
enum = Enum(name)
|
||||
enum.briefDescription = cenum.briefDoc
|
||||
enum.detailedDescription = cenum.detailedDoc
|
||||
self.namespace.add_child(enum)
|
||||
|
||||
for cEnumValue in cenum.values:
|
||||
valueName = EnumValueName()
|
||||
valueName = metaname.EnumeratorName()
|
||||
valueName.from_camel_case(cEnumValue.name, namespace=name)
|
||||
aEnumValue = EnumValue(valueName)
|
||||
aEnumValue = Enumerator(valueName)
|
||||
aEnumValue.briefDescription = cEnumValue.briefDoc
|
||||
aEnumValue.detailedDescription = cEnumValue.detailedDoc
|
||||
if cEnumValue.value is not None:
|
||||
try:
|
||||
aEnumValue.value_from_string(cEnumValue.value)
|
||||
except ValueError:
|
||||
raise Error('{0} enum value has an invalid definition ({1})'.format(cEnumValue.name, cEnumValue.value))
|
||||
enum.add_value(aEnumValue)
|
||||
enum.add_enumerator(aEnumValue)
|
||||
|
||||
self.enumsIndex[nameStr] = enum
|
||||
self.enums.append(enum)
|
||||
return enum
|
||||
|
||||
def parse_class(self, cclass):
|
||||
|
|
@ -649,17 +581,20 @@ class CParser(object):
|
|||
if cclass.name.endswith('Cbs'):
|
||||
_class = self._parse_listener(cclass)
|
||||
self.interfacesIndex[cclass.name] = _class
|
||||
self.interfaces.append(_class)
|
||||
else:
|
||||
_class = self._parse_class(cclass)
|
||||
self.classesIndex[cclass.name] = _class
|
||||
self.classes.append(_class)
|
||||
self.namespace.add_child(_class)
|
||||
return _class
|
||||
|
||||
def _parse_class(self, cclass):
|
||||
name = ClassName()
|
||||
name = metaname.ClassName()
|
||||
name.from_camel_case(cclass.name, namespace=self.namespace.name)
|
||||
_class = Class(name)
|
||||
_class.briefDescription = cclass.briefDoc
|
||||
_class.detailedDescription = cclass.detailedDoc
|
||||
|
||||
for cproperty in cclass.properties.values():
|
||||
try:
|
||||
|
|
@ -700,7 +635,7 @@ class CParser(object):
|
|||
return _class
|
||||
|
||||
def _parse_property(self, cproperty, namespace=None):
|
||||
name = PropertyName()
|
||||
name = metaname.PropertyName()
|
||||
name.from_snake_case(cproperty.name)
|
||||
if (cproperty.setter is not None and len(cproperty.setter.arguments) == 1) or (cproperty.getter is not None and len(cproperty.getter.arguments) == 0):
|
||||
methodType = Method.Type.Class
|
||||
|
|
@ -717,7 +652,7 @@ class CParser(object):
|
|||
|
||||
|
||||
def _parse_listener(self, cclass):
|
||||
name = InterfaceName()
|
||||
name = metaname.InterfaceName()
|
||||
name.from_camel_case(cclass.name, namespace=self.namespace.name)
|
||||
|
||||
if name.words[len(name.words)-1] == 'cbs':
|
||||
|
|
@ -727,6 +662,7 @@ class CParser(object):
|
|||
|
||||
listener = Interface(name)
|
||||
listener.briefDescription = cclass.briefDoc
|
||||
listener.detailedDescription = cclass.detailedDoc
|
||||
|
||||
for property in cclass.properties.values():
|
||||
if property.name != 'user_data':
|
||||
|
|
@ -739,7 +675,7 @@ class CParser(object):
|
|||
return listener
|
||||
|
||||
def _parse_listener_property(self, property, listener, events):
|
||||
methodName = MethodName()
|
||||
methodName = metaname.MethodName()
|
||||
methodName.from_snake_case(property.name)
|
||||
methodName.words.insert(0, 'on')
|
||||
methodName.prev = listener.name
|
||||
|
|
@ -759,7 +695,7 @@ class CParser(object):
|
|||
method = Method(methodName)
|
||||
method.returnType = self.parse_type(event.returnArgument)
|
||||
for arg in event.arguments:
|
||||
argName = ArgName()
|
||||
argName = metaname.ArgName()
|
||||
argName.from_snake_case(arg.name)
|
||||
argument = Argument(argName, self.parse_type(arg))
|
||||
method.add_arguments(argument)
|
||||
|
|
@ -767,7 +703,7 @@ class CParser(object):
|
|||
return method
|
||||
|
||||
def parse_method(self, cfunction, namespace, type=Method.Type.Instance):
|
||||
name = MethodName()
|
||||
name = metaname.MethodName()
|
||||
name.from_snake_case(cfunction.name, namespace=namespace)
|
||||
|
||||
if self._is_blacklisted(name):
|
||||
|
|
@ -775,15 +711,16 @@ class CParser(object):
|
|||
|
||||
method = Method(name, type=type)
|
||||
method.briefDescription = cfunction.briefDoc
|
||||
method.detailedDescription = cfunction.detailedDoc
|
||||
method.deprecated = cfunction.deprecated
|
||||
method.returnType = self.parse_type(cfunction.returnArgument)
|
||||
|
||||
for arg in cfunction.arguments:
|
||||
if type == Method.Type.Instance and arg is cfunction.arguments[0]:
|
||||
method.constMethod = ('const' in arg.completeType.split(' '))
|
||||
method.isconst = ('const' in arg.completeType.split(' '))
|
||||
else:
|
||||
aType = self.parse_type(arg)
|
||||
argName = ArgName()
|
||||
argName = metaname.ArgName()
|
||||
argName.from_snake_case(arg.name)
|
||||
absArg = Argument(argName, aType)
|
||||
method.add_arguments(absArg)
|
||||
|
|
@ -807,7 +744,7 @@ class CParser(object):
|
|||
else:
|
||||
raise Error('Unknown C type \'{0}\''.format(cType.ctype))
|
||||
|
||||
absType.cname = cType.completeType
|
||||
absType.cDecl = cType.completeType
|
||||
return absType
|
||||
|
||||
def parse_c_base_type(self, cDecl):
|
||||
|
|
@ -871,3 +808,341 @@ class CParser(object):
|
|||
return BaseType(name, **param)
|
||||
else:
|
||||
raise Error('could not find type in \'{0}\''.format(cDecl))
|
||||
|
||||
|
||||
class Translator:
|
||||
instances = {}
|
||||
|
||||
@staticmethod
|
||||
def get(langCode):
|
||||
try:
|
||||
if langCode not in Translator.instances:
|
||||
className = langCode + 'LangTranslator'
|
||||
_class = globals()[className]
|
||||
Translator.instances[langCode] = _class()
|
||||
|
||||
return Translator.instances[langCode]
|
||||
except KeyError:
|
||||
raise ValueError("Invalid language code: '{0}'".format(langCode))
|
||||
|
||||
|
||||
class CLikeLangTranslator(Translator):
|
||||
def translate_enumerator_value(self, value):
|
||||
if value is None:
|
||||
return None
|
||||
elif isinstance(value, int):
|
||||
return str(value)
|
||||
elif isinstance(value, Flag):
|
||||
return '1<<{0}'.format(value.position)
|
||||
else:
|
||||
raise TypeError('invalid enumerator value type: {0}'.format(value))
|
||||
|
||||
def translate_argument(self, argument, **kargs):
|
||||
return '{0} {1}'.format(argument.type.translate(self, **kargs), argument.name.translate(self.nameTranslator))
|
||||
|
||||
|
||||
class CLangTranslator(CLikeLangTranslator):
|
||||
def __init__(self):
|
||||
self.nameTranslator = metaname.Translator.get('C')
|
||||
self.nilToken = 'NULL'
|
||||
self.falseConstantToken = 'FALSE'
|
||||
self.trueConstantToken = 'TRUE'
|
||||
|
||||
def translate_base_type(self, _type):
|
||||
return _type.cDecl
|
||||
|
||||
def translate_enum_type(self, _type):
|
||||
return _type.cDecl
|
||||
|
||||
def translate_class_type(self, _type):
|
||||
return _type.cDecl
|
||||
|
||||
def translate_list_type(self, _type):
|
||||
return _type.cDecl
|
||||
|
||||
def translate_enumerator_value(self, value):
|
||||
if value is None:
|
||||
return None
|
||||
elif isinstance(value, int):
|
||||
return str(value)
|
||||
elif isinstance(value, Flag):
|
||||
return '1<<{0}'.format(value.position)
|
||||
else:
|
||||
raise TypeError('invalid enumerator value type: {0}'.format(value))
|
||||
|
||||
def translate_method_as_prototype(self, method, **params):
|
||||
_class = method.find_first_ancestor_by_type(Class)
|
||||
params = '{const}{className} *obj'.format(
|
||||
className=_class.name.to_c(),
|
||||
const='const ' if method.isconst else ''
|
||||
)
|
||||
for arg in method.args:
|
||||
params += (', ' + arg.translate(self))
|
||||
|
||||
return '{returnType} {name}({params})'.format(
|
||||
returnType=method.returnType.translate(self),
|
||||
name=method.name.translate(self.nameTranslator),
|
||||
params=params
|
||||
)
|
||||
|
||||
|
||||
class CppLangTranslator(CLikeLangTranslator):
|
||||
def __init__(self):
|
||||
self.nameTranslator = metaname.Translator.get('Cpp')
|
||||
self.nilToken = 'nullptr'
|
||||
self.falseConstantToken = 'false'
|
||||
self.trueConstantToken = 'true'
|
||||
self.ambigousTypes = []
|
||||
|
||||
def translate_base_type(self, _type, showStdNs=True, namespace=None):
|
||||
if _type.name == 'void':
|
||||
if _type.isref:
|
||||
return 'void *'
|
||||
else:
|
||||
return 'void'
|
||||
elif _type.name == 'boolean':
|
||||
res = 'bool'
|
||||
elif _type.name == 'character':
|
||||
res = 'char'
|
||||
elif _type.name == 'size':
|
||||
res = 'size_t'
|
||||
elif _type.name == 'time':
|
||||
res = 'time_t'
|
||||
elif _type.name == 'integer':
|
||||
if _type.size is None:
|
||||
res = 'int'
|
||||
elif isinstance(_type.size, str):
|
||||
res = _type.size
|
||||
else:
|
||||
res = 'int{0}_t'.format(_type.size)
|
||||
|
||||
elif _type.name == 'floatant':
|
||||
if _type.size is not None and _type.size == 'double':
|
||||
res = 'double'
|
||||
else:
|
||||
res = 'float'
|
||||
elif _type.name == 'status':
|
||||
res = 'linphone::Status'
|
||||
elif _type.name == 'string':
|
||||
res = CppLangTranslator.prepend_std('string', showStdNs)
|
||||
if type(_type.parent) is Argument:
|
||||
res += ' &'
|
||||
elif _type.name == 'string_array':
|
||||
res = '{0}<{1}>'.format(
|
||||
CppLangTranslator.prepend_std('list', showStdNs),
|
||||
CppLangTranslator.prepend_std('string', showStdNs)
|
||||
)
|
||||
if type(_type.parent) is Argument:
|
||||
res += ' &'
|
||||
else:
|
||||
raise Error('\'{0}\' is not a base abstract type'.format(_type.name))
|
||||
|
||||
if _type.isUnsigned:
|
||||
if _type.name == 'integer' and isinstance(_type.size, int):
|
||||
res = 'u' + res
|
||||
else:
|
||||
res = 'unsigned ' + res
|
||||
|
||||
if _type.isconst:
|
||||
if _type.name not in ['string', 'string_array'] or type(_type.parent) is Argument:
|
||||
res = 'const ' + res
|
||||
|
||||
if _type.isref:
|
||||
res += ' *'
|
||||
return res
|
||||
|
||||
def translate_enum_type(self, _type, showStdNs=True, namespace=None):
|
||||
if _type.desc is None:
|
||||
raise Error('{0} has not been fixed'.format(_type.name))
|
||||
|
||||
if namespace is not None:
|
||||
nsName = namespace.name if namespace is not GlobalNs else None
|
||||
else:
|
||||
method = _type.find_first_ancestor_by_type(Method)
|
||||
nsName = metaname.Name.find_common_parent(_type.desc.name, method.name)
|
||||
|
||||
return _type.desc.name.translate(self.nameTranslator, recursive=True, topAncestor=nsName)
|
||||
|
||||
def translate_class_type(self, _type, showStdNs=True, namespace=None):
|
||||
if _type.desc is None:
|
||||
raise Error('{0} has not been fixed'.format(_type.name))
|
||||
|
||||
if namespace is not None:
|
||||
nsName = namespace.name if namespace is not GlobalNs else None
|
||||
else:
|
||||
method = _type.find_first_ancestor_by_type(Method)
|
||||
nsName = metaname.Name.find_common_parent(_type.desc.name, method.name)
|
||||
|
||||
if _type.desc.name.to_c() in self.ambigousTypes:
|
||||
nsName = None
|
||||
|
||||
res = _type.desc.name.translate(self.nameTranslator, recursive=True, topAncestor=nsName)
|
||||
|
||||
if _type.desc.refcountable:
|
||||
if _type.isconst:
|
||||
res = 'const ' + res
|
||||
if type(_type.parent) is Argument:
|
||||
return 'const {0}<{1}> &'.format(
|
||||
CppLangTranslator.prepend_std('shared_ptr', showStdNs),
|
||||
res
|
||||
)
|
||||
else:
|
||||
return '{0}<{1}>'.format(
|
||||
CppLangTranslator.prepend_std('shared_ptr', showStdNs),
|
||||
res
|
||||
)
|
||||
else:
|
||||
if type(_type.parent) is Argument:
|
||||
return 'const {0} &'.format(res)
|
||||
else:
|
||||
return '{0}'.format(res)
|
||||
|
||||
def translate_list_type(self, _type, showStdNs=True, namespace=None):
|
||||
if _type.containedTypeDesc is None:
|
||||
raise Error('{0} has not been fixed'.format(_type.containedTypeName))
|
||||
elif isinstance(_type.containedTypeDesc, BaseType):
|
||||
res = _type.containedTypeDesc.translate(self)
|
||||
else:
|
||||
res = _type.containedTypeDesc.translate(self, showStdNs=showStdNs, namespace=namespace)
|
||||
|
||||
if type(_type.parent) is Argument:
|
||||
return 'const {0}<{1} > &'.format(
|
||||
CppLangTranslator.prepend_std('list', showStdNs),
|
||||
res
|
||||
)
|
||||
else:
|
||||
return '{0}<{1} >'.format(
|
||||
CppLangTranslator.prepend_std('list', showStdNs),
|
||||
res
|
||||
)
|
||||
|
||||
def translate_method_as_prototype(self, method, showStdNs=True, namespace=None):
|
||||
_class = method.find_first_ancestor_by_type(Class, Interface)
|
||||
if namespace is not None:
|
||||
if _class.name.to_c() in self.ambigousTypes:
|
||||
nsName = None
|
||||
else:
|
||||
nsName = namespace.name if namespace is not GlobalNs else None
|
||||
else:
|
||||
nsName = _class.name
|
||||
|
||||
argsString = ''
|
||||
argStrings = []
|
||||
for arg in method.args:
|
||||
argStrings.append(arg.translate(self, showStdNs=showStdNs, namespace=namespace))
|
||||
argsString = ', '.join(argStrings)
|
||||
|
||||
return '{_return} {name}({args}){const}'.format(
|
||||
_return=method.returnType.translate(self, ),
|
||||
name=method.name.translate(self.nameTranslator, recursive=True, topAncestor=nsName),
|
||||
args=argsString,
|
||||
const=' const' if method.isconst else ''
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def prepend_std(string, prepend):
|
||||
return 'std::' + string if prepend else string
|
||||
|
||||
|
||||
class CSharpLangTranslator(CLikeLangTranslator):
|
||||
def __init__(self):
|
||||
self.nameTranslator = metaname.Translator.get('CSharp')
|
||||
self.nilToken = 'null'
|
||||
self.falseConstantToken = 'false'
|
||||
self.trueConstantToken = 'true'
|
||||
|
||||
def translate_base_type(self, _type, dllImport=True):
|
||||
if _type.name == 'void':
|
||||
if _type.isref:
|
||||
return 'IntPtr'
|
||||
return 'void'
|
||||
elif _type.name == 'status':
|
||||
if dllImport:
|
||||
return 'int'
|
||||
else:
|
||||
return 'void'
|
||||
elif _type.name == 'boolean':
|
||||
if dllImport:
|
||||
res = 'char'
|
||||
else:
|
||||
res = 'bool'
|
||||
elif _type.name == 'integer':
|
||||
if _type.isUnsigned:
|
||||
res = 'uint'
|
||||
else:
|
||||
res = 'int'
|
||||
elif _type.name == 'string':
|
||||
if dllImport:
|
||||
if type(_type.parent) is Argument:
|
||||
return 'string'
|
||||
else:
|
||||
res = 'IntPtr' # Return as IntPtr and get string with Marshal.PtrToStringAnsi()
|
||||
else:
|
||||
return 'string'
|
||||
elif _type.name == 'character':
|
||||
if _type.isUnsigned:
|
||||
res = 'byte'
|
||||
else:
|
||||
res = 'sbyte'
|
||||
elif _type.name == 'time':
|
||||
res = 'long' #TODO check
|
||||
elif _type.name == 'size':
|
||||
res = 'long' #TODO check
|
||||
elif _type.name == 'floatant':
|
||||
return 'float'
|
||||
elif _type.name == 'string_array':
|
||||
if dllImport or type(_type.parent) is Argument:
|
||||
return 'IntPtr'
|
||||
else:
|
||||
return 'IEnumerable<string>'
|
||||
else:
|
||||
raise Error('\'{0}\' is not a base abstract type'.format(_type.name))
|
||||
|
||||
return res
|
||||
|
||||
def translate_enum_type(self, _type, dllImport=True):
|
||||
if dllImport and type(_type.parent) is Argument:
|
||||
return 'int'
|
||||
else:
|
||||
return _type.desc.name.translate(self.nameTranslator)
|
||||
|
||||
def translate_class_type(self, _type, dllImport=True):
|
||||
return "IntPtr" if dllImport else _type.desc.name.translate(self.nameTranslator)
|
||||
|
||||
def translate_list_type(self, _type, dllImport=True):
|
||||
if dllImport:
|
||||
return 'IntPtr'
|
||||
else:
|
||||
if type(_type.containedTypeDesc) is BaseType:
|
||||
if _type.containedTypeDesc.name == 'string':
|
||||
return 'IEnumerable<string>'
|
||||
else:
|
||||
raise Error('translation of bctbx_list_t of basic C types is not supported')
|
||||
elif type(_type.containedTypeDesc) is ClassType:
|
||||
ptrType = _type.containedTypeDesc.desc.name.translate(self.nameTranslator)
|
||||
return 'IEnumerable<' + ptrType + '>'
|
||||
else:
|
||||
if _type.containedTypeDesc:
|
||||
raise Error('translation of bctbx_list_t of enums')
|
||||
else:
|
||||
raise Error('translation of bctbx_list_t of unknow type !')
|
||||
|
||||
def translate_argument(self, arg, dllImport=True):
|
||||
return '{0} {1}'.format(
|
||||
arg.type.translate(self, dllImport=dllImport),
|
||||
arg.name.translate(self.nameTranslator)
|
||||
)
|
||||
|
||||
def translate_method_as_prototype(self, method):
|
||||
kargs = {
|
||||
'static' : 'static ' if method.type == Method.Type.Class else '',
|
||||
'override' : 'override ' if method.name.translate(self.nameTranslator) == 'ToString' else '',
|
||||
'returnType' : method.returnType.translate(self, dllImport=False),
|
||||
'name' : method.name.translate(self.nameTranslator),
|
||||
'args' : ''
|
||||
}
|
||||
for arg in method.args:
|
||||
if kargs['args'] != '':
|
||||
kargs['args'] += ', '
|
||||
kargs['args'] += arg.translate(self, dllImport=False)
|
||||
return '{static}{override}{returnType} {name}({args})'.format(**kargs)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class CObject:
|
|||
self.detailedDescription = None
|
||||
self.deprecated = False
|
||||
self.briefDoc = None
|
||||
self.detailedDoc = None
|
||||
|
||||
|
||||
class CEnumValue(CObject):
|
||||
|
|
@ -339,6 +340,7 @@ class Project:
|
|||
if st.associatedTypedef == td:
|
||||
cclass = CClass(st)
|
||||
cclass.briefDoc = td.briefDoc
|
||||
cclass.detailedDoc = td.detailedDoc
|
||||
self.add(cclass)
|
||||
break
|
||||
elif ('Linphone' + td.definition) == td.name:
|
||||
|
|
@ -346,6 +348,7 @@ class Project:
|
|||
st.associatedTypedef = td
|
||||
cclass = CClass(st)
|
||||
cclass.briefDoc = td.briefDoc
|
||||
cclass.detailedDoc = td.detailedDoc
|
||||
self.add(st)
|
||||
self.add(cclass)
|
||||
# Sort classes by length of name (longest first), so that methods are put in the right class
|
||||
|
|
@ -389,6 +392,7 @@ class Project:
|
|||
ev.deprecated = True
|
||||
ev.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
ev.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
ev.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
ev.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return ev
|
||||
|
||||
|
|
@ -401,6 +405,7 @@ class Project:
|
|||
e.deprecated = True
|
||||
e.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
e.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
e.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
e.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
enumvalues = node.findall("enumvalue[@prot='public']")
|
||||
for enumvalue in enumvalues:
|
||||
|
|
@ -424,6 +429,7 @@ class Project:
|
|||
sm.deprecated = True
|
||||
sm.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
sm.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
sm.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
sm.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return sm
|
||||
|
||||
|
|
@ -434,6 +440,7 @@ class Project:
|
|||
s.deprecated = True
|
||||
s.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
s.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
s.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
s.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
structmembers = node.findall("sectiondef/memberdef[@kind='variable'][@prot='public']")
|
||||
for structmember in structmembers:
|
||||
|
|
@ -503,6 +510,7 @@ class Project:
|
|||
f.deprecated = True
|
||||
f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
f.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
f.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return f
|
||||
else:
|
||||
|
|
@ -515,6 +523,7 @@ class Project:
|
|||
td.deprecated = True
|
||||
td.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
td.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
td.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
td.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return td
|
||||
return None
|
||||
|
|
@ -531,6 +540,11 @@ class Project:
|
|||
internal = node.find("./detaileddescription/internal")
|
||||
if internal is not None:
|
||||
return None
|
||||
|
||||
# The doc must be parsed here since the XML tree is to be modified in below code
|
||||
briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
detailedDoc = self.docparser.parse_description(node.find('./detaileddescription'))
|
||||
|
||||
missingDocWarning = ''
|
||||
name = node.find('./name').text
|
||||
t = ''.join(node.find('./type').itertext())
|
||||
|
|
@ -574,10 +588,11 @@ class Project:
|
|||
if deprecatedNode is not None:
|
||||
f.deprecated = True
|
||||
f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
f.briefDoc = self.docparser.parse_description(node.find('./briefdescription'))
|
||||
f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
if f.briefDescription == '' and ''.join(f.detailedDescription.itertext()).strip() == '':
|
||||
return None
|
||||
f.briefDoc = briefDoc
|
||||
f.detailedDoc = detailedDoc
|
||||
locationNode = node.find('./location')
|
||||
if locationNode is not None:
|
||||
f.location = locationNode.get('file')
|
||||
|
|
|
|||
589
tools/metadoc.py
589
tools/metadoc.py
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) 2017 Belledonne Communications SARL
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
|
@ -16,17 +14,131 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import metaname
|
||||
import abstractapi
|
||||
import re
|
||||
|
||||
|
||||
class Nil:
|
||||
class ParsingError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class Reference:
|
||||
class UnreleasedNodeError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class ChildrenList(list):
|
||||
def __init__(self, node):
|
||||
list.__init__(self)
|
||||
self.node = node
|
||||
|
||||
def __setitem__(self, key, child):
|
||||
if child.parent is not None:
|
||||
raise UnreleasedNodeError()
|
||||
self[key].parent = None
|
||||
list.__setitem__(self, key, child)
|
||||
child.parent = self.node
|
||||
|
||||
def __delitem__(self, key):
|
||||
self[key].parent = None
|
||||
list.__delitem__(self, key)
|
||||
|
||||
def __iadd__(self, other):
|
||||
list.__iadd__(self, other)
|
||||
for child in other:
|
||||
child.parent = self.node
|
||||
return self
|
||||
|
||||
def append(self, child):
|
||||
list.append(self, child)
|
||||
child.parent = self.node
|
||||
|
||||
def removeall(self):
|
||||
children = []
|
||||
while len(self) > 0:
|
||||
children.append(self[0])
|
||||
del self[0]
|
||||
return children
|
||||
|
||||
|
||||
class TreeNode(object):
|
||||
def __init__(self):
|
||||
self.parent = None
|
||||
|
||||
def find_ancestor(self, ancestorType):
|
||||
ancestor = self.parent
|
||||
while ancestor is not None and type(ancestor) is not ancestorType:
|
||||
ancestor = ancestor.parent
|
||||
return ancestor
|
||||
|
||||
def find_root(self):
|
||||
node = self
|
||||
while node.parent is not None:
|
||||
node = node.parent
|
||||
return node
|
||||
|
||||
|
||||
class SingleChildTreeNode(TreeNode):
|
||||
def __init__(self):
|
||||
TreeNode.__init__(self)
|
||||
self._child = None
|
||||
|
||||
def _setchild(self, child):
|
||||
if child is not None and child.parent is not None:
|
||||
raise UnreleasedNodeError()
|
||||
if self._child is not None:
|
||||
self._child.parent = None
|
||||
self._child = child
|
||||
if child is not None:
|
||||
child.parent = self
|
||||
|
||||
def _getchild(self):
|
||||
return self._child
|
||||
|
||||
def _delchild(self):
|
||||
if self._child is not None:
|
||||
self._child.parent = None
|
||||
del self._child
|
||||
|
||||
child = property(fset=_setchild, fget=_getchild, fdel=_delchild)
|
||||
|
||||
|
||||
class MultiChildTreeNode(TreeNode):
|
||||
def __init__(self):
|
||||
TreeNode.__init__(self)
|
||||
self.children = ChildrenList(self)
|
||||
|
||||
|
||||
class ParagraphPart(TreeNode):
|
||||
pass
|
||||
|
||||
|
||||
class TextPart(ParagraphPart):
|
||||
def __init__(self, text):
|
||||
ParagraphPart.__init__(self)
|
||||
self.text = text
|
||||
|
||||
def translate(self, docTranslator, **kargs):
|
||||
return docTranslator.translate_text(self)
|
||||
|
||||
|
||||
class LanguageKeyword(ParagraphPart):
|
||||
def __init__(self, keyword):
|
||||
ParagraphPart.__init__(self)
|
||||
self.keyword = keyword
|
||||
|
||||
def translate(self, docTranslator, **kargs):
|
||||
return docTranslator.translate_keyword(self)
|
||||
|
||||
|
||||
class Reference(ParagraphPart):
|
||||
def __init__(self, cname):
|
||||
ParagraphPart.__init__(self)
|
||||
self.cname = cname
|
||||
self.relatedObject = None
|
||||
|
||||
def translate(self, docTranslator, **kargs):
|
||||
return docTranslator.translate_reference(self, **kargs)
|
||||
|
||||
|
||||
class ClassReference(Reference):
|
||||
|
|
@ -45,54 +157,210 @@ class FunctionReference(Reference):
|
|||
print('doc reference pointing on an unknown object ({0})'.format(self.cname))
|
||||
|
||||
|
||||
class Paragraph:
|
||||
def __init__(self):
|
||||
self.parts = []
|
||||
class Paragraph(MultiChildTreeNode):
|
||||
@property
|
||||
def parts(self):
|
||||
return self.children
|
||||
|
||||
@parts.setter
|
||||
def parts(self, parts):
|
||||
self.children = parts
|
||||
|
||||
def resolve_all_references(self, api):
|
||||
for part in self.parts:
|
||||
if isinstance(part, Reference):
|
||||
part.resolve(api)
|
||||
elif isinstance(part, (Section, ParameterList)):
|
||||
part.resolve_all_references(api)
|
||||
|
||||
def translate(self, docTranslator, **kargs):
|
||||
return docTranslator._translate_paragraph(self, **kargs)
|
||||
|
||||
|
||||
class Description:
|
||||
class Section(SingleChildTreeNode):
|
||||
def __init__(self, kind):
|
||||
SingleChildTreeNode.__init__(self)
|
||||
self.kind = kind
|
||||
|
||||
@property
|
||||
def paragraph(self):
|
||||
return self.child
|
||||
|
||||
@paragraph.setter
|
||||
def paragraph(self, paragraph):
|
||||
self.child = paragraph
|
||||
|
||||
def resolve_all_references(self, api):
|
||||
if self.paragraph is not None:
|
||||
self.paragraph.resolve_all_references(api)
|
||||
|
||||
def translate(self, docTranslator, **kargs):
|
||||
return docTranslator._translate_section(self, **kargs)
|
||||
|
||||
|
||||
class ParameterDescription(SingleChildTreeNode):
|
||||
def __init__(self, name, desc):
|
||||
SingleChildTreeNode.__init__(self)
|
||||
self.name = name
|
||||
self.child = desc
|
||||
|
||||
@property
|
||||
def desc(self):
|
||||
return self.child
|
||||
|
||||
@desc.setter
|
||||
def desc(self, desc):
|
||||
self.child = desc
|
||||
|
||||
def is_self_parameter(self):
|
||||
method = self.find_ancestor(Description).relatedObject
|
||||
return method.type == abstractapi.Method.Type.Instance and self.name not in [arg.name for arg in method.args]
|
||||
|
||||
|
||||
class ParameterList(MultiChildTreeNode):
|
||||
@property
|
||||
def parameters(self):
|
||||
return self.children
|
||||
|
||||
@parameters.setter
|
||||
def parameters(self, parameters):
|
||||
self.children = parameters
|
||||
|
||||
def resolve_all_references(self, api):
|
||||
for parameter in self.parameters:
|
||||
if parameter.desc is not None:
|
||||
parameter.desc.resolve_all_references(api)
|
||||
|
||||
def translate(self, docTranslator, **kargs):
|
||||
return docTranslator._translate_parameter_list(self, **kargs)
|
||||
|
||||
|
||||
class Description(MultiChildTreeNode):
|
||||
def __init__(self):
|
||||
self.paragraphs = []
|
||||
MultiChildTreeNode.__init__(self)
|
||||
self.relatedObject = None
|
||||
|
||||
@property
|
||||
def paragraphs(self):
|
||||
return self.children
|
||||
|
||||
@paragraphs.setter
|
||||
def paragraphs(self, paragraphs):
|
||||
self.children = paragraphs
|
||||
|
||||
def resolve_all_references(self, api):
|
||||
for paragraph in self.paragraphs:
|
||||
paragraph.resolve_all_references(api)
|
||||
|
||||
def translate(self, translator, **kargs):
|
||||
return translator.translate_description(self, **kargs)
|
||||
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.constants_regex = re.compile('(?:^|\W)(TRUE|FALSE|NULL)(?:\W|$)')
|
||||
|
||||
def parse_description(self, node):
|
||||
if node is None:
|
||||
return None
|
||||
|
||||
desc = Description()
|
||||
for paraNode in node.findall('./para'):
|
||||
desc.paragraphs.append(self._parse_paragraph(paraNode))
|
||||
desc.paragraphs += self._parse_paragraph(paraNode)
|
||||
return desc
|
||||
|
||||
def _parse_paragraph(self, node):
|
||||
paragraphs = []
|
||||
paragraph = Paragraph()
|
||||
for partNode in node.iter():
|
||||
if partNode is node:
|
||||
|
||||
text = node.text
|
||||
if text is not None:
|
||||
paragraph.parts += self._parse_text(text)
|
||||
|
||||
for partNode in node.findall('*'):
|
||||
if partNode.tag == 'ref':
|
||||
ref = self._parse_reference(partNode)
|
||||
if ref is not None:
|
||||
paragraph.parts.append(ref)
|
||||
elif partNode.tag == 'simplesect':
|
||||
paragraphs.append(paragraph)
|
||||
paragraph.parts.append(self._parse_simple_section(partNode))
|
||||
paragraph = Paragraph()
|
||||
elif partNode.tag == 'xrefsect':
|
||||
paragraphs.append(paragraph)
|
||||
paragraph.parts.append(self._parse_xref_section(partNode))
|
||||
paragraph = Paragraph()
|
||||
elif partNode.tag == 'parameterlist' and partNode.get('kind') == 'param':
|
||||
paragraphs.append(paragraph)
|
||||
paragraphs.append(self._parse_parameter_list(partNode))
|
||||
paragraph = Paragraph()
|
||||
else:
|
||||
text = partNode.text
|
||||
if text is not None:
|
||||
paragraph.parts.append(text)
|
||||
else:
|
||||
if partNode.tag == 'ref':
|
||||
ref = self._parse_reference(partNode)
|
||||
if ref is not None:
|
||||
paragraph.parts.append(ref)
|
||||
else:
|
||||
text = partNode.text
|
||||
if text is not None:
|
||||
paragraph.parts.append(text)
|
||||
|
||||
tail = partNode.tail
|
||||
if tail is not None:
|
||||
paragraph.parts.append(tail)
|
||||
paragraph.parts += self._parse_text(text)
|
||||
|
||||
text = partNode.tail
|
||||
if text is not None:
|
||||
text = text.strip('\n')
|
||||
if len(text) > 0:
|
||||
paragraph.parts += self._parse_text(text)
|
||||
|
||||
return paragraph
|
||||
paragraphs.append(paragraph)
|
||||
return [x for x in paragraphs if type(x) is not Paragraph or len(x.parts) > 0]
|
||||
|
||||
def _parse_text(self, text):
|
||||
parts = []
|
||||
lastIndex = 0
|
||||
|
||||
match = self.constants_regex.search(text)
|
||||
while match is not None:
|
||||
if match.start(1)-lastIndex > 0:
|
||||
parts.append(TextPart(text[lastIndex:match.start(1)]))
|
||||
parts.append(self._parse_constant(text[match.start(1):match.end(1)]))
|
||||
lastIndex = match.end(1)
|
||||
match = self.constants_regex.search(text, lastIndex)
|
||||
|
||||
if lastIndex < len(text):
|
||||
parts.append(TextPart(text[lastIndex:]))
|
||||
|
||||
return parts
|
||||
|
||||
def _parse_constant(self, token):
|
||||
if token == 'TRUE':
|
||||
return LanguageKeyword(abstractapi.Boolean(True))
|
||||
elif token == 'FALSE':
|
||||
return LanguageKeyword(abstractapi.Boolean(False))
|
||||
elif token == 'NULL':
|
||||
return LanguageKeyword(abstractapi.Nil())
|
||||
else:
|
||||
raise ValueError("invalid C constant token '{0}'".format(token))
|
||||
|
||||
def _parse_simple_section(self, sectionNode):
|
||||
section = Section(sectionNode.get('kind'))
|
||||
para = sectionNode.find('./para')
|
||||
paragraphs = self._parse_paragraph(para)
|
||||
section.paragraph = paragraphs[0] if len(paragraphs) > 0 else None
|
||||
return section
|
||||
|
||||
def _parse_parameter_list(self, paramListNode):
|
||||
paramList = ParameterList()
|
||||
for paramItemNode in paramListNode.findall('./parameteritem'):
|
||||
name = metaname.ArgName()
|
||||
name.from_snake_case(paramItemNode.find('./parameternamelist/parametername').text)
|
||||
desc = self.parse_description(paramItemNode.find('parameterdescription'))
|
||||
paramList.parameters.append(ParameterDescription(name, desc))
|
||||
return paramList
|
||||
|
||||
def _parse_xref_section(self, sectionNode):
|
||||
sectionId = sectionNode.get('id')
|
||||
if sectionId.startswith('deprecated_'):
|
||||
section = Section('deprecated')
|
||||
description = self.parse_description(sectionNode.find('./xrefdescription'))
|
||||
paras = description.paragraphs.removeall()
|
||||
section.paragraph = paras[0] if len(paras) > 0 else None
|
||||
return section
|
||||
else:
|
||||
raise ParsingError('unknown xrefsect type ({0})'.format(sectionId))
|
||||
|
||||
def _parse_reference(self, node):
|
||||
if node.text.endswith('()'):
|
||||
|
|
@ -101,50 +369,92 @@ class Parser:
|
|||
return ClassReference(node.text)
|
||||
|
||||
|
||||
class Translator:
|
||||
def __init__(self):
|
||||
self.textWidth = 80
|
||||
class TranslationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ReferenceTranslationError(TranslationError):
|
||||
def __init__(self, refName):
|
||||
Exception.__init__(self, refName)
|
||||
|
||||
def translate(self, description):
|
||||
def msg(self):
|
||||
return '{0} reference could not been translated'.format(self.args[0])
|
||||
|
||||
|
||||
class Translator:
|
||||
def __init__(self, langCode):
|
||||
self.textWidth = 80
|
||||
self.nameTranslator = metaname.Translator.get(langCode)
|
||||
self.langTranslator = abstractapi.Translator.get(langCode)
|
||||
self.displaySelfParam = True if langCode == 'C' else False
|
||||
|
||||
def translate_description(self, description, tagAsBrief=False):
|
||||
if description is None:
|
||||
return None
|
||||
|
||||
lines = []
|
||||
for para in description.paragraphs:
|
||||
if para is not description.paragraphs[0]:
|
||||
lines.append('')
|
||||
lines.append(self._translate_paragraph(para))
|
||||
paras = self._translate_description(description)
|
||||
|
||||
lines = self._paragraphs_to_lines(paras)
|
||||
|
||||
if tagAsBrief:
|
||||
self._tag_as_brief(lines)
|
||||
|
||||
self._tag_as_brief(lines)
|
||||
lines = self._crop_text(lines, self.textWidth)
|
||||
|
||||
translatedDoc = {'lines': []}
|
||||
for line in lines:
|
||||
translatedDoc['lines'].append({'line': line})
|
||||
|
||||
|
||||
return translatedDoc
|
||||
|
||||
def translate_reference(self, ref, absName=False, namespace=None):
|
||||
if ref.relatedObject is None:
|
||||
raise ReferenceTranslationError(ref.cname)
|
||||
if absName:
|
||||
commonName = None
|
||||
else:
|
||||
if namespace is None:
|
||||
description = ref.find_root()
|
||||
namespaceObj = description.relatedObject.find_first_ancestor_by_type(abstractapi.Namespace, abstractapi.Class)
|
||||
namespace = namespaceObj.name
|
||||
if namespace.is_prefix_of(ref.relatedObject.name):
|
||||
commonName = namespace
|
||||
else:
|
||||
commonName = metaname.Name.find_common_parent(ref.relatedObject.name, namespace)
|
||||
return ref.relatedObject.name.translate(self.nameTranslator, recursive=True, topAncestor=commonName)
|
||||
|
||||
def translate_keyword(self, keyword):
|
||||
return keyword.keyword.translate(self.langTranslator)
|
||||
|
||||
def translate_text(self, textpart):
|
||||
return textpart.text
|
||||
|
||||
def _translate_description(self, desc):
|
||||
paras = []
|
||||
for para in desc.paragraphs:
|
||||
paras.append(para.translate(self))
|
||||
return [para for para in paras if para != '']
|
||||
|
||||
def _translate_paragraph(self, para):
|
||||
strPara = ''
|
||||
for part in para.parts:
|
||||
if isinstance(part, str):
|
||||
strPara += part
|
||||
elif isinstance(part, Reference):
|
||||
try:
|
||||
strPara += self._translate_reference(part)
|
||||
except ReferenceTranslationError as e:
|
||||
print('could not translate one reference in docstrings ({0})'.format(e.args[0]))
|
||||
strPara += Translator._translate_reference(self, part)
|
||||
else:
|
||||
raise TypeError('untranslatable paragraph element ({0})'.format(part))
|
||||
try:
|
||||
if isinstance(part, str):
|
||||
strPara += part
|
||||
else:
|
||||
strPara += part.translate(self)
|
||||
except TranslationError as e:
|
||||
print('error: {0}'.format(e.msg()))
|
||||
|
||||
return strPara
|
||||
|
||||
def _translate_reference(self, ref):
|
||||
if isinstance(ref, FunctionReference):
|
||||
return ref.cname + '()'
|
||||
else:
|
||||
return ref.cname
|
||||
def _paragraphs_to_lines(self, paragraphs):
|
||||
lines = []
|
||||
for para in paragraphs:
|
||||
if para is not paragraphs[0]:
|
||||
lines.append('')
|
||||
lines += para.split('\n')
|
||||
return lines
|
||||
|
||||
def _crop_text(self, inputLines, width):
|
||||
outputLines = []
|
||||
|
|
@ -152,7 +462,12 @@ class Translator:
|
|||
outputLines += self._split_line(line, width)
|
||||
return outputLines
|
||||
|
||||
def _split_line(self, line, width):
|
||||
def _split_line(self, line, width, indent=False):
|
||||
firstNonTab = next((c for c in line if c != '\t'), None)
|
||||
tabCount = line.index(firstNonTab) if firstNonTab is not None else 0
|
||||
linePrefix = ('\t' * tabCount)
|
||||
line = line[tabCount:]
|
||||
|
||||
lines = []
|
||||
while len(line) > width:
|
||||
cutIndex = line.rfind(' ', 0, width)
|
||||
|
|
@ -163,36 +478,170 @@ class Translator:
|
|||
cutIndex = width
|
||||
lines.append(line[0:cutIndex])
|
||||
line = line[cutIndex:]
|
||||
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
if indent:
|
||||
lines = [line if line is lines[0] else '\t' + line for line in lines]
|
||||
|
||||
return [linePrefix + line for line in lines]
|
||||
|
||||
def _tag_as_brief(self, lines):
|
||||
pass
|
||||
|
||||
|
||||
class ReferenceTranslationError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class DoxygenCppTranslator(Translator):
|
||||
class DoxygenTranslator(Translator):
|
||||
def _tag_as_brief(self, lines):
|
||||
if len(lines) > 0:
|
||||
lines[0] = '@brief ' + lines[0]
|
||||
|
||||
def _translate_reference(self, ref):
|
||||
def translate_reference(self, ref):
|
||||
refStr = Translator.translate_reference(self, ref)
|
||||
if isinstance(ref.relatedObject, (abstractapi.Class, abstractapi.Enum)):
|
||||
return '#' + ref.relatedObject.name.to_c()
|
||||
return '#' + refStr
|
||||
elif isinstance(ref.relatedObject, abstractapi.Method):
|
||||
return ref.relatedObject.name.to_c() + '()'
|
||||
return refStr + '()'
|
||||
else:
|
||||
raise ReferenceTranslationError(ref.cname)
|
||||
|
||||
def _translate_section(self, section):
|
||||
return '@{0} {1}'.format(
|
||||
section.kind,
|
||||
self._translate_paragraph(section.paragraph)
|
||||
)
|
||||
|
||||
def _translate_parameter_list(self, parameterList):
|
||||
text = ''
|
||||
for paramDesc in parameterList.parameters:
|
||||
if self.displaySelfParam or not paramDesc.is_self_parameter():
|
||||
desc = self._translate_description(paramDesc.desc)
|
||||
desc = desc[0] if len(desc) > 0 else ''
|
||||
text = ('@param {0} {1}'.format(paramDesc.name.translate(self.nameTranslator), desc))
|
||||
return text
|
||||
|
||||
|
||||
class SandcastleCSharpTranslator(Translator):
|
||||
class JavaDocTranslator(DoxygenTranslator):
|
||||
def __init__(self):
|
||||
DoxygenTranslator.__init__(self, 'C')
|
||||
|
||||
def _tag_as_brief(self, lines):
|
||||
pass
|
||||
|
||||
|
||||
class SphinxTranslator(Translator):
|
||||
def __init__(self, langCode):
|
||||
Translator.__init__(self, langCode)
|
||||
if langCode == 'C':
|
||||
self.domain = 'c'
|
||||
self.classDeclarator = 'type'
|
||||
self.methodDeclarator = 'function'
|
||||
self.enumDeclarator = 'type'
|
||||
self.enumeratorDeclarator = 'var'
|
||||
self.enumeratorReferencer = 'data'
|
||||
self.methodReferencer = 'func'
|
||||
elif langCode == 'Cpp':
|
||||
self.domain = 'cpp'
|
||||
self.classDeclarator = 'class'
|
||||
self.methodDeclarator = 'function'
|
||||
self.enumDeclarator = 'enum'
|
||||
self.enumeratorDeclarator = 'enumerator'
|
||||
self.namespaceDeclarator = 'namespace'
|
||||
self.methodReferencer = 'func'
|
||||
elif langCode == 'CSharp':
|
||||
self.domain = 'csharp'
|
||||
self.classDeclarator = 'class'
|
||||
self.methodDeclarator = 'method'
|
||||
self.enumDeclarator = 'enum'
|
||||
self.enumeratorDeclarator = 'value'
|
||||
self.namespaceDeclarator = 'namespace'
|
||||
self.classReferencer = 'type'
|
||||
self.enumReferencer = 'type'
|
||||
self.enumeratorReferencer = 'enum'
|
||||
self.methodReferencer = 'meth'
|
||||
else:
|
||||
raise ValueError('invalid language code: {0}'.format(langCode))
|
||||
|
||||
def get_declarator(self, typeName):
|
||||
try:
|
||||
attrName = typeName + 'Declarator'
|
||||
declarator = getattr(self, attrName)
|
||||
return '{0}:{1}'.format(self.domain, declarator)
|
||||
except AttributeError:
|
||||
raise ValueError("'{0}' declarator type not supported".format(typeName))
|
||||
|
||||
def get_referencer(self, typeName):
|
||||
try:
|
||||
attrName = typeName + 'Referencer'
|
||||
if attrName in dir(self):
|
||||
referencer = getattr(self, attrName)
|
||||
return '{0}:{1}'.format(self.domain, referencer)
|
||||
else:
|
||||
return self.get_declarator(typeName)
|
||||
except AttributeError:
|
||||
raise ValueError("'{0}' referencer type not supported".format(typeName))
|
||||
|
||||
def translate_reference(self, ref, label=None, namespace=None):
|
||||
strRef = Translator.translate_reference(self, ref, absName=True)
|
||||
kargs = {
|
||||
'tag' : self._sphinx_ref_tag(ref),
|
||||
'ref' : strRef,
|
||||
}
|
||||
kargs['label'] = label if label is not None else Translator.translate_reference(self, ref, namespace=namespace)
|
||||
if isinstance(ref, FunctionReference):
|
||||
kargs['label'] += '()'
|
||||
|
||||
return ':{tag}:`{label} <{ref}>`'.format(**kargs)
|
||||
|
||||
def translate_keyword(self, keyword):
|
||||
translatedKeyword = Translator.translate_keyword(self, keyword)
|
||||
return '``{0}``'.format(translatedKeyword)
|
||||
|
||||
def _translate_section(self, section):
|
||||
strPara = self._translate_paragraph(section.paragraph)
|
||||
if section.kind == 'deprecated':
|
||||
return '**Deprecated:** {0}\n'.format(strPara)
|
||||
else:
|
||||
if section.kind == 'see':
|
||||
kind = 'seealso'
|
||||
else:
|
||||
kind = section.kind
|
||||
|
||||
if section.kind == 'return':
|
||||
return ':return: {0}'.format(strPara)
|
||||
else:
|
||||
return '.. {0}::\n\t\n\t{1}\n\n'.format(kind, strPara)
|
||||
|
||||
def _translate_parameter_list(self, parameterList):
|
||||
text = ''
|
||||
for paramDesc in parameterList.parameters:
|
||||
if self.displaySelfParam or not paramDesc.is_self_parameter():
|
||||
desc = self._translate_description(paramDesc.desc)
|
||||
desc = desc[0] if len(desc) > 0 else ''
|
||||
text += (':param {0}: {1}\n'.format(paramDesc.name.translate(self.nameTranslator), desc))
|
||||
text += '\n'
|
||||
return text
|
||||
|
||||
def _sphinx_ref_tag(self, ref):
|
||||
typeName = type(ref.relatedObject).__name__.lower()
|
||||
return self.get_referencer(typeName)
|
||||
|
||||
isParamDescRegex = re.compile('\t*:(?:param\s+\w+|return):')
|
||||
|
||||
def _split_line(self, line, width):
|
||||
if SphinxTranslator.isParamDescRegex.match(line) is not None:
|
||||
lines = Translator._split_line(self, line, width, indent=True)
|
||||
return lines
|
||||
else:
|
||||
return Translator._split_line(self, line, width)
|
||||
|
||||
|
||||
class SandCastleTranslator(Translator):
|
||||
def _tag_as_brief(self, lines):
|
||||
if len(lines) > 0:
|
||||
lines.insert(0, '<summary>')
|
||||
lines.append('</summary>')
|
||||
|
||||
|
||||
class SandcastleJavaTranslator(Translator):
|
||||
def _tag_as_brief(self, lines):
|
||||
pass
|
||||
|
||||
def translate_reference(self, ref):
|
||||
refStr = Translator.translate_reference(self, ref, absName=True)
|
||||
if isinstance(ref, FunctionReference):
|
||||
refStr += '()'
|
||||
return '<see cref="{0}" />'.format(refStr)
|
||||
|
|
|
|||
340
tools/metaname.py
Normal file
340
tools/metaname.py
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
# Copyright (C) 2017 Belledonne Communications SARL
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class Name(object):
|
||||
camelCaseParsingRegex = re.compile('[A-Z][a-z0-9]*')
|
||||
lowerCamelCaseSplitingRegex = re.compile('([a-z][a-z0-9]*)([A-Z][a-z0-9]*)')
|
||||
|
||||
def __init__(self):
|
||||
self.words = []
|
||||
self.prev = None
|
||||
|
||||
def __eq__(self, other):
|
||||
return (other is not None and self.words == other.words) and (self.prev == other.prev)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.to_camel_case() < other.to_camel_case()
|
||||
|
||||
def copy(self):
|
||||
nameType = type(self)
|
||||
name = nameType()
|
||||
name.words = list(self.words)
|
||||
name.prev = None if self.prev is None else self.prev.copy()
|
||||
return name
|
||||
|
||||
def delete_prefix(self, prefix):
|
||||
it = self
|
||||
_next = None
|
||||
while it is not None and it.words != prefix.words:
|
||||
_next = it
|
||||
it = it.prev
|
||||
|
||||
if it is None or it != prefix:
|
||||
raise Error('no common prefix')
|
||||
elif _next is not None:
|
||||
_next.prev = None
|
||||
|
||||
def _set_namespace(self, namespace):
|
||||
self.prev = namespace
|
||||
if self.prev is not None:
|
||||
prefix = namespace.to_word_list()
|
||||
i = 0
|
||||
while i<len(self.words) and i<len(prefix) and self.words[i] == prefix[i]:
|
||||
i += 1
|
||||
if i == len(self.words):
|
||||
raise Error('name equal to namespace \'{0}\'', self.words)
|
||||
else:
|
||||
self.words = self.words[i:]
|
||||
|
||||
def _lower_all_words(self):
|
||||
i = 0
|
||||
while i<len(self.words):
|
||||
self.words[i] = self.words[i].lower()
|
||||
i += 1
|
||||
|
||||
def from_snake_case(self, name, namespace=None):
|
||||
self.words = name.split('_')
|
||||
Name._set_namespace(self, namespace)
|
||||
|
||||
def from_camel_case(self, name, islowercased=False, namespace=None):
|
||||
if not islowercased:
|
||||
self.words = Name.camelCaseParsingRegex.findall(name)
|
||||
else:
|
||||
match = Name.lowerCamelCaseSplitingRegex.match(name)
|
||||
self.words = [match.group(1)]
|
||||
self.words += Name.camelCaseParsingRegex.findall(match.group(2))
|
||||
|
||||
Name._lower_all_words(self)
|
||||
Name._set_namespace(self, namespace)
|
||||
|
||||
def to_snake_case(self, fullName=False, upper=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = '_'.join(self.words)
|
||||
if upper:
|
||||
res = res.upper()
|
||||
return res
|
||||
else:
|
||||
return Name.to_snake_case(self.prev, fullName=True, upper=upper) + '_' + Name.to_snake_case(self, upper=upper)
|
||||
|
||||
def to_camel_case(self, lower=False, fullName=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = ''
|
||||
for elem in self.words:
|
||||
if elem is self.words[0] and lower:
|
||||
res += elem
|
||||
else:
|
||||
res += elem.title()
|
||||
return res
|
||||
else:
|
||||
return Name.to_camel_case(self.prev, fullName=True, lower=lower) + Name.to_camel_case(self)
|
||||
|
||||
def concatenate(self, upper=False, fullName=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = ''
|
||||
for elem in self.words:
|
||||
if upper:
|
||||
res += elem.upper()
|
||||
else:
|
||||
res += elem
|
||||
return res
|
||||
else:
|
||||
return Name.concatenate(self.prev, upper=upper, fullName=True) + Name.concatenate(self, upper=upper)
|
||||
|
||||
def to_word_list(self):
|
||||
if self.prev is None:
|
||||
return list(self.words)
|
||||
else:
|
||||
return Name.to_word_list(self.prev) + self.words
|
||||
|
||||
def is_prefix_of(self, other):
|
||||
node = other
|
||||
while node is not None and node != self:
|
||||
node = node.prev
|
||||
return (node is not None)
|
||||
|
||||
@staticmethod
|
||||
def find_common_parent(name1, name2):
|
||||
if name1.prev is None or name2.prev is None:
|
||||
return None
|
||||
elif name1.prev is name2.prev:
|
||||
return name1.prev
|
||||
else:
|
||||
commonParent = Name.find_common_parent(name1.prev, name2)
|
||||
if commonParent is not None:
|
||||
return commonParent
|
||||
else:
|
||||
return Name.find_common_parent(name1, name2.prev)
|
||||
|
||||
|
||||
class ClassName(Name):
|
||||
def to_c(self):
|
||||
return self.to_camel_case(fullName=True)
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_class_name(self, **params)
|
||||
|
||||
|
||||
class InterfaceName(ClassName):
|
||||
def to_c(self):
|
||||
return ClassName.to_c(self)[:-8] + 'Cbs'
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_interface_name(self, **params)
|
||||
|
||||
|
||||
class EnumName(ClassName):
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_enum_name(self, **params)
|
||||
|
||||
|
||||
class EnumeratorName(ClassName):
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_enumerator_name(self, **params)
|
||||
|
||||
|
||||
class MethodName(Name):
|
||||
regex = re.compile('^\d+$')
|
||||
|
||||
def __init__(self):
|
||||
self.overloadRef = 0
|
||||
|
||||
def from_snake_case(self, name, namespace=None):
|
||||
Name.from_snake_case(self, name, namespace=namespace)
|
||||
if len(self.words) > 0:
|
||||
suffix = self.words[-1]
|
||||
if MethodName.regex.match(suffix) is not None:
|
||||
self.overloadRef = int(suffix)
|
||||
del self.words[-1]
|
||||
|
||||
def to_c(self):
|
||||
suffix = ('_' + str(self.overloadRef)) if self.overloadRef > 0 else ''
|
||||
return self.to_snake_case(fullName=True) + suffix
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_method_name(self, **params)
|
||||
|
||||
|
||||
class ArgName(Name):
|
||||
def to_c(self):
|
||||
return self.to_snake_case()
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_argument_name(self, **params)
|
||||
|
||||
|
||||
class PropertyName(ArgName):
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_property_name(self, **params)
|
||||
|
||||
|
||||
class NamespaceName(Name):
|
||||
def __init__(self, *params):
|
||||
Name.__init__(self)
|
||||
if len(params) > 0:
|
||||
self.words = params[0]
|
||||
|
||||
def translate(self, translator, **params):
|
||||
return translator.translate_namespace_name(self, **params)
|
||||
|
||||
|
||||
class Translator:
|
||||
instances = {}
|
||||
|
||||
@staticmethod
|
||||
def get(langCode):
|
||||
try:
|
||||
if langCode == '':
|
||||
raise ValueError('Empty language code')
|
||||
if langCode not in Translator.instances:
|
||||
className = langCode + 'Translator'
|
||||
_class = globals()[className]
|
||||
Translator.instances[langCode] = _class()
|
||||
|
||||
return Translator.instances[langCode]
|
||||
except KeyError:
|
||||
raise ValueError("Invalid language code: '{0}'".format(langCode))
|
||||
|
||||
|
||||
class CTranslator(Translator):
|
||||
def translate_class_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
def translate_interface_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
def translate_enum_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
def translate_enumerator_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
def translate_method_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
def translate_namespace_name(self, name, **params):
|
||||
return None
|
||||
|
||||
def translate_argument_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
def translate_property_name(self, name, **params):
|
||||
return name.to_c()
|
||||
|
||||
|
||||
class JavaTranslator(Translator):
|
||||
def __init__(self):
|
||||
self.nsSep = '.'
|
||||
self.keyWordEscapes = {}
|
||||
self.lowerMethodNames = True
|
||||
self.lowerNamespaceNames = True
|
||||
|
||||
def translate_class_name(self, name, recursive=False, topAncestor=None):
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return name.to_camel_case()
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return name.prev.translate(self, **params) + self.nsSep + name.to_camel_case()
|
||||
|
||||
def translate_interface_name(self, name, **params):
|
||||
return self.translate_class_name(name, **params)
|
||||
|
||||
def translate_enum_name(self, name, **params):
|
||||
return self.translate_class_name(name, **params)
|
||||
|
||||
def translate_enumerator_name(self, name, **params):
|
||||
return self.translate_class_name(name, **params)
|
||||
|
||||
def translate_method_name(self, name, recursive=False, topAncestor=None):
|
||||
translatedName = name.to_camel_case(lower=self.lowerMethodNames)
|
||||
translatedName = self._escape_keyword(translatedName)
|
||||
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return translatedName
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return name.prev.translate(self, **params) + self.nsSep + translatedName
|
||||
|
||||
def translate_namespace_name(self, name, recursive=False, topAncestor=None):
|
||||
translatedName = name.concatenate() if self.lowerNamespaceNames else name.to_camel_case()
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return translatedName
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return name.prev.translate(self, **params) + self.nsSep + translatedName
|
||||
|
||||
def translate_argument_name(self, name):
|
||||
argname = name.to_camel_case(lower=True)
|
||||
return self._escape_keyword(argname)
|
||||
|
||||
def translate_property_name(self, name):
|
||||
return self.translate_argument_name(name)
|
||||
|
||||
def _escape_keyword(self, keyword):
|
||||
try:
|
||||
return self.keyWordEscapes[keyword]
|
||||
except KeyError:
|
||||
return keyword
|
||||
|
||||
|
||||
class CppTranslator(JavaTranslator):
|
||||
def __init__(self):
|
||||
JavaTranslator.__init__(self)
|
||||
self.nsSep = '::'
|
||||
self.keyWordEscapes = {'new' : '_new'}
|
||||
|
||||
def translate_enumerator_name(self, name, **params):
|
||||
return self.translate_enum_name(name.prev, **params) + name.to_camel_case()
|
||||
|
||||
|
||||
class CSharpTranslator(JavaTranslator):
|
||||
def __init__(self):
|
||||
JavaTranslator.__init__(self)
|
||||
self.keyWordEscapes = {
|
||||
'params' : 'parameters',
|
||||
'event' : 'ev',
|
||||
'ref' : 'reference',
|
||||
'value' : 'val',
|
||||
'new' : '_new'
|
||||
}
|
||||
self.lowerMethodNames = False
|
||||
self.lowerNamespaceNames = False
|
||||
|
||||
def translate_property_name(self, name):
|
||||
return name.to_camel_case()
|
||||
|
|
@ -24,6 +24,7 @@ add_custom_command(OUTPUT include/linphone++/linphone.hh src/linphone++.cc
|
|||
COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genwrapper.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml"
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/tools/genapixml.py
|
||||
${PROJECT_SOURCE_DIR}/tools/metadoc.py
|
||||
${PROJECT_SOURCE_DIR}/tools/metaname.py
|
||||
${PROJECT_SOURCE_DIR}/tools/abstractapi.py
|
||||
genwrapper.py
|
||||
class_header.mustache
|
||||
|
|
|
|||
|
|
@ -54,13 +54,19 @@ namespace linphone {
|
|||
{{/priorDeclarations}}
|
||||
|
||||
{{#_class}}
|
||||
{{#doc}}
|
||||
/**
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
* {{{line}}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
*
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
* {{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
*/
|
||||
{{/doc}}
|
||||
class {{className}}{{#parentClassName}}: public {{{parentClassName}}}{{/parentClassName}} {
|
||||
{{#friendClasses}}
|
||||
friend class {{name}};
|
||||
|
|
@ -102,25 +108,37 @@ namespace linphone {
|
|||
|
||||
|
||||
{{#methods}}
|
||||
{{#doc}}
|
||||
/**
|
||||
{{#lines}}
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
* {{{line}}}
|
||||
{{/lines}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
*
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
* {{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
*/
|
||||
{{/doc}}
|
||||
{{{prototype}}}
|
||||
LINPHONECXX_PUBLIC {{#deprecated}}LINPHONECXX_DEPRECATED {{/deprecated}}{{#isListener}}virtual {{/isListener}}{{{declPrototype}}}{{{suffix}}};
|
||||
|
||||
{{/methods}}
|
||||
{{#staticMethods}}
|
||||
{{#doc}}
|
||||
{{#staticMethods}};
|
||||
/**
|
||||
{{#lines}}
|
||||
{{#briefDoc}}
|
||||
{{#lines}}
|
||||
* {{{line}}}
|
||||
{{/lines}}
|
||||
{{/lines}}
|
||||
{{/briefDoc}}
|
||||
*
|
||||
{{#detailedDoc}}
|
||||
{{#lines}}
|
||||
* {{{line}}}
|
||||
{{/lines}}
|
||||
{{/detailedDoc}}
|
||||
*/
|
||||
{{/doc}}
|
||||
{{{prototype}}}
|
||||
LINPHONECXX_PUBLIC {{#deprecated}}LINPHONECXX_DEPRECATED {{/deprecated}}static {{{declPrototype}}};
|
||||
|
||||
{{/staticMethods}}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include <linphone/linphone_tunnel.h>
|
||||
#include <linphone/linphonecore_utils.h>
|
||||
#include <linphone/wrapper_utils.h>
|
||||
#include <linphone/logging.h>
|
||||
#include "linphone++/linphone.hh"
|
||||
#include "tools.hh"
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace linphone {
|
|||
*/
|
||||
{{/doc}}
|
||||
enum {{name}} {
|
||||
{{#values}}
|
||||
{{#enumerators}}
|
||||
{{#doc}}
|
||||
/**
|
||||
{{#lines}}
|
||||
|
|
@ -40,7 +40,7 @@ namespace linphone {
|
|||
*/
|
||||
{{/doc}}
|
||||
{{name}}{{#value}} = {{{value}}}{{/value}}{{#notLast}},{{/notLast}}
|
||||
{{/values}}
|
||||
{{/enumerators}}
|
||||
};
|
||||
|
||||
{{/enums}}
|
||||
|
|
|
|||
|
|
@ -23,19 +23,23 @@ import argparse
|
|||
import os
|
||||
import sys
|
||||
import errno
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools'))
|
||||
import genapixml as CApi
|
||||
import abstractapi as AbsApi
|
||||
import metadoc
|
||||
import metaname
|
||||
|
||||
|
||||
class CppTranslator(object):
|
||||
sharedPtrTypeExtractor = re.compile('^(const )?std::shared_ptr<(.+)>( &)?$')
|
||||
|
||||
def __init__(self):
|
||||
self.ignore = []
|
||||
self.ambigousTypes = ['LinphonePayloadType']
|
||||
self.docTranslator = metadoc.DoxygenCppTranslator()
|
||||
self.nameTranslator = metaname.Translator.get('Cpp')
|
||||
self.langTranslator = AbsApi.Translator.get('Cpp')
|
||||
self.langTranslator.ambigousTypes.append('LinphonePayloadType')
|
||||
self.docTranslator = metadoc.DoxygenTranslator('Cpp')
|
||||
|
||||
def is_ambigous_type(self, _type):
|
||||
return _type.name in self.ambigousTypes or (_type.name == 'list' and self.is_ambigous_type(_type.containedTypeDesc))
|
||||
|
|
@ -43,32 +47,23 @@ class CppTranslator(object):
|
|||
def translate_enum(self, enum):
|
||||
enumDict = {}
|
||||
enumDict['name'] = enum.name.to_camel_case()
|
||||
enumDict['doc'] = self.docTranslator.translate(enum.briefDescription)
|
||||
enumDict['values'] = []
|
||||
i = 0
|
||||
for enumValue in enum.values:
|
||||
enumValDict = self.translate_enum_value(enumValue)
|
||||
enumValDict['notLast'] = (i != len(enum.values)-1)
|
||||
enumDict['values'].append(enumValDict)
|
||||
i += 1
|
||||
enumDict['doc'] = enum.briefDescription.translate(self.docTranslator)
|
||||
enumDict['enumerators'] = []
|
||||
for enumerator in enum.enumerators:
|
||||
enumeratorDict = self.translate_enumerator(enumerator)
|
||||
enumeratorDict['notLast'] = (enumerator is not enum.enumerators[-1])
|
||||
enumDict['enumerators'].append(enumeratorDict)
|
||||
return enumDict
|
||||
|
||||
def translate_enum_value(self, enumValue):
|
||||
enumValueDict = {}
|
||||
enumValueDict['name'] = CppTranslator.translate_enum_value_name(enumValue.name)
|
||||
enumValueDict['doc'] = self.docTranslator.translate(enumValue.briefDescription)
|
||||
if type(enumValue.value) is int:
|
||||
enumValueDict['value'] = str(enumValue.value)
|
||||
elif type(enumValue.value) is AbsApi.Flag:
|
||||
enumValueDict['value'] = '1<<' + str(enumValue.value.position)
|
||||
else:
|
||||
enumValueDict['value'] = None
|
||||
return enumValueDict
|
||||
def translate_enumerator(self, enumerator):
|
||||
enumeratorDict = {
|
||||
'name' : enumerator.name.translate(self.nameTranslator),
|
||||
'doc' : enumerator.briefDescription.translate(self.docTranslator),
|
||||
'value' : enumerator.translate_value(self.langTranslator)
|
||||
}
|
||||
return enumeratorDict
|
||||
|
||||
def translate_class(self, _class):
|
||||
if _class.name.to_camel_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_camel_case(fullName=True)))
|
||||
|
||||
islistenable = _class.listenerInterface is not None
|
||||
ismonolistenable = (islistenable and not _class.multilistener)
|
||||
ismultilistenable = (islistenable and _class.multilistener)
|
||||
|
|
@ -81,9 +76,10 @@ class CppTranslator(object):
|
|||
'isrefcountable' : _class.refcountable,
|
||||
'isnotrefcountable' : not _class.refcountable,
|
||||
'isNotListener' : True,
|
||||
'isListener' : False,
|
||||
'isfactory' : (_class.name.to_c() == 'LinphoneFactory'),
|
||||
'isVcard' : (_class.name.to_c() == 'LinphoneVcard'),
|
||||
'className' : CppTranslator.translate_class_name(_class.name),
|
||||
'className' : _class.name.translate(self.nameTranslator),
|
||||
'cClassName' : '::' + _class.name.to_c(),
|
||||
'privCClassName' : '_' + _class.name.to_c(),
|
||||
'parentClassName' : 'Object' if _class.refcountable else None,
|
||||
|
|
@ -96,12 +92,13 @@ class CppTranslator(object):
|
|||
if _class.name.to_c() == 'LinphoneCore':
|
||||
classDict['friendClasses'].append({'name': 'Factory'});
|
||||
|
||||
classDict['doc'] = self.docTranslator.translate(_class.briefDescription)
|
||||
classDict['briefDoc'] = _class.briefDescription.translate(self.docTranslator, tagAsBrief=True)
|
||||
classDict['detailedDoc'] = _class.detailedDescription.translate(self.docTranslator)
|
||||
|
||||
if islistenable:
|
||||
classDict['listenerClassName'] = CppTranslator.translate_class_name(_class.listenerInterface.name)
|
||||
classDict['listenerClassName'] = _class.listenerInterface.name.translate(self.nameTranslator)
|
||||
classDict['cListenerName'] = _class.listenerInterface.name.to_c()
|
||||
classDict['cppListenerName'] = CppTranslator.translate_class_name(_class.listenerInterface.name)
|
||||
classDict['cppListenerName'] = _class.listenerInterface.name.translate(self.nameTranslator)
|
||||
for method in _class.listenerInterface.methods:
|
||||
classDict['wrapperCbs'].append(self._generate_wrapper_callback(_class, method))
|
||||
|
||||
|
|
@ -148,10 +145,10 @@ class CppTranslator(object):
|
|||
args = []
|
||||
wrappedArgs = []
|
||||
for arg in method.args:
|
||||
args.append(arg.type.cname + ' ' + arg.name.to_c())
|
||||
args.append(arg.type.cDecl + ' ' + arg.name.to_c())
|
||||
wrappedArgs.append(self._wrap_c_expression_to_cpp(arg.name.to_c(), arg.type, usedNamespace=namespace))
|
||||
params['params'] = ', '.join(args)
|
||||
params['returnType'] = method.returnType.cname
|
||||
params['returnType'] = method.returnType.cDecl
|
||||
|
||||
wrapperCbDict = {}
|
||||
wrapperCbDict['cbName'] = params['name']
|
||||
|
|
@ -168,16 +165,15 @@ class CppTranslator(object):
|
|||
return wrapperCbDict
|
||||
|
||||
def translate_interface(self, interface):
|
||||
if interface.name.to_camel_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_camel_case(fullName=True)))
|
||||
|
||||
intDict = {}
|
||||
intDict['inheritFrom'] = {'name': 'Listener'}
|
||||
intDict['className'] = CppTranslator.translate_class_name(interface.name)
|
||||
intDict['constructor'] = None
|
||||
intDict['parentClassName'] = 'Listener'
|
||||
intDict['isNotListener'] = False
|
||||
intDict['methods'] = []
|
||||
intDict = {
|
||||
'inheritFrom' : {'name': 'Listener'},
|
||||
'className' : interface.name.translate(self.nameTranslator),
|
||||
'constructor' : None,
|
||||
'parentClassName' : 'Listener',
|
||||
'isNotListener' : False,
|
||||
'isListener' : True,
|
||||
'methods' : []
|
||||
}
|
||||
for method in interface.methods:
|
||||
try:
|
||||
methodDict = self.translate_method(method, genImpl=False)
|
||||
|
|
@ -196,57 +192,26 @@ class CppTranslator(object):
|
|||
return res
|
||||
|
||||
def translate_method(self, method, genImpl=True):
|
||||
if method.name.to_snake_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(method.name.to_snake_case(fullName=True)))
|
||||
|
||||
namespace = method.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
|
||||
methodElems = {}
|
||||
methodElems['return'] = self.translate_type(method.returnType)
|
||||
methodElems['name'] = CppTranslator.translate_method_name(method.name)
|
||||
methodDict = {
|
||||
'declPrototype': method.translate_as_prototype(self.langTranslator),
|
||||
'implPrototype': method.translate_as_prototype(self.langTranslator, namespace=namespace),
|
||||
'deprecated': method.deprecated,
|
||||
'suffix': '',
|
||||
'briefDoc': method.briefDescription.translate(self.docTranslator, tagAsBrief=True) if method.briefDescription is not None else None,
|
||||
'detailedDoc': method.detailedDescription.translate(self.docTranslator) if method.detailedDescription is not None else None
|
||||
}
|
||||
|
||||
methodElems['params'] = ''
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0]:
|
||||
methodElems['params'] += ', '
|
||||
methodElems['params'] += self.translate_argument(arg)
|
||||
|
||||
methodElems['const'] = ' const' if method.constMethod else ''
|
||||
methodElems['semicolon'] = ';'
|
||||
if type(method.parent) is AbsApi.Class and method.type == AbsApi.Method.Type.Class:
|
||||
methodElems['methodType'] = 'static '
|
||||
elif type(method.parent) is AbsApi.Interface:
|
||||
methodElems['methodType'] = 'virtual '
|
||||
if type(method.parent) is AbsApi.Interface:
|
||||
if isinstance(method.returnType, AbsApi.BaseType) and method.returnType.name == 'void':
|
||||
methodElems['semicolon'] = ' {}'
|
||||
methodDict['suffix'] = ' {}'
|
||||
else:
|
||||
methodElems['semicolon'] = ' = 0;'
|
||||
else:
|
||||
methodElems['methodType'] = ''
|
||||
|
||||
methodElems['deprecated'] = 'LINPHONECXX_DEPRECATED ' if method.deprecated else ''
|
||||
|
||||
methodDict = {}
|
||||
methodDict['prototype'] = 'LINPHONECXX_PUBLIC {deprecated}{methodType}{return} {name}({params}){const}{semicolon}'.format(**methodElems)
|
||||
methodDict['suffix'] = ' = 0'
|
||||
|
||||
if genImpl:
|
||||
if not self.is_ambigous_type(method.returnType):
|
||||
methodElems['implReturn'] = self.translate_type(method.returnType, namespace=namespace)
|
||||
else:
|
||||
methodElems['implReturn'] = self.translate_type(method.returnType, namespace=None)
|
||||
|
||||
methodElems['longname'] = CppTranslator.translate_method_name(method.name, recursive=True)
|
||||
methodElems['implParams'] = ''
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0]:
|
||||
methodElems['implParams'] += ', '
|
||||
methodElems['implParams'] += self.translate_argument(arg, namespace=namespace)
|
||||
|
||||
methodDict['implPrototype'] = '{implReturn} {longname}({implParams}){const}'.format(**methodElems)
|
||||
methodDict['sourceCode' ] = self._generate_source_code(method, usedNamespace=namespace)
|
||||
|
||||
methodDict['doc'] = self.docTranslator.translate(method.briefDescription) if method.briefDescription is not None else None
|
||||
|
||||
return methodDict
|
||||
|
||||
def _generate_source_code(self, method, usedNamespace=None):
|
||||
|
|
@ -291,7 +256,7 @@ class CppTranslator(object):
|
|||
elif type(exprtype) is AbsApi.ClassType:
|
||||
cPtrType = exprtype.desc.name.to_c()
|
||||
if exprtype.desc.refcountable:
|
||||
ptrType = self.translate_class_type(exprtype, namespace=usedNamespace)
|
||||
ptrType = exprtype.translate(self.langTranslator, namespace=usedNamespace)
|
||||
ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2)
|
||||
param = {
|
||||
'ptrType' : ptrType,
|
||||
|
|
@ -309,7 +274,7 @@ class CppTranslator(object):
|
|||
if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string':
|
||||
cExpr = 'StringBctbxListWrapper({0}).c_list()'.format(cppExpr)
|
||||
elif type(exprtype.containedTypeDesc) is AbsApi.ClassType:
|
||||
ptrType = self.translate_class_type(exprtype.containedTypeDesc, namespace=usedNamespace)
|
||||
ptrType = exprtype.containedTypeDesc.translate(self.langTranslator, namespace=usedNamespace)
|
||||
if exprtype.containedTypeDesc.desc.refcountable:
|
||||
ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2)
|
||||
cExpr = 'ObjectBctbxListWrapper<{0}>({1}).c_list()'.format(ptrType, cppExpr)
|
||||
|
|
@ -335,10 +300,10 @@ class CppTranslator(object):
|
|||
else:
|
||||
return cExpr
|
||||
elif type(exprtype) is AbsApi.EnumType:
|
||||
cppEnumName = self.translate_enum_type(exprtype, namespace=usedNamespace)
|
||||
cppEnumName = exprtype.translate(self.langTranslator, namespace=usedNamespace)
|
||||
return '({0}){1}'.format(cppEnumName, cExpr)
|
||||
elif type(exprtype) is AbsApi.ClassType:
|
||||
cppReturnType = self.translate_class_type(exprtype, namespace=usedNamespace)
|
||||
cppReturnType = exprtype.translate(self.langTranslator, namespace=usedNamespace)
|
||||
if exprtype.desc.refcountable:
|
||||
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
|
||||
|
||||
|
|
@ -358,7 +323,7 @@ class CppTranslator(object):
|
|||
if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string':
|
||||
return 'StringBctbxListWrapper::bctbxListToCppList({0})'.format(cExpr)
|
||||
elif type(exprtype.containedTypeDesc) is AbsApi.ClassType:
|
||||
cppReturnType = self.translate_class_type(exprtype.containedTypeDesc, namespace=usedNamespace)
|
||||
cppReturnType = exprtype.containedTypeDesc.translate(self.langTranslator, namespace=usedNamespace)
|
||||
if exprtype.containedTypeDesc.desc.refcountable:
|
||||
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
|
||||
return 'ObjectBctbxListWrapper<{0}>::bctbxListToCppList({1})'.format(cppReturnType, cExpr)
|
||||
|
|
@ -370,198 +335,6 @@ class CppTranslator(object):
|
|||
else:
|
||||
return cExpr
|
||||
|
||||
def translate_argument(self, arg, **params):
|
||||
return '{0} {1}'.format(self.translate_type(arg.type, **params), CppTranslator.translate_argument_name(arg.name))
|
||||
|
||||
def translate_type(self, aType, **params):
|
||||
if type(aType) is AbsApi.BaseType:
|
||||
return self.translate_base_type(aType)
|
||||
elif type(aType) is AbsApi.EnumType:
|
||||
return self.translate_enum_type(aType, **params)
|
||||
elif type(aType) is AbsApi.ClassType:
|
||||
return self.translate_class_type(aType, **params)
|
||||
elif type(aType) is AbsApi.ListType:
|
||||
return self.translate_list_type(aType, **params)
|
||||
else:
|
||||
CppTranslator.fail(aType)
|
||||
|
||||
def translate_base_type(self, _type):
|
||||
if _type.name == 'void':
|
||||
if _type.isref:
|
||||
return 'void *'
|
||||
else:
|
||||
return 'void'
|
||||
elif _type.name == 'boolean':
|
||||
res = 'bool'
|
||||
elif _type.name == 'character':
|
||||
res = 'char'
|
||||
elif _type.name == 'size':
|
||||
res = 'size_t'
|
||||
elif _type.name == 'time':
|
||||
res = 'time_t'
|
||||
elif _type.name == 'integer':
|
||||
if _type.size is None:
|
||||
res = 'int'
|
||||
elif isinstance(_type.size, str):
|
||||
res = _type.size
|
||||
else:
|
||||
res = 'int{0}_t'.format(_type.size)
|
||||
|
||||
elif _type.name == 'floatant':
|
||||
if _type.size is not None and _type.size == 'double':
|
||||
res = 'double'
|
||||
else:
|
||||
res = 'float'
|
||||
elif _type.name == 'status':
|
||||
res = 'linphone::Status'
|
||||
elif _type.name == 'string':
|
||||
res = 'std::string'
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
res += ' &'
|
||||
elif _type.name == 'string_array':
|
||||
res = 'std::list<std::string>'
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
res += ' &'
|
||||
else:
|
||||
raise AbsApi.Error('\'{0}\' is not a base abstract type'.format(_type.name))
|
||||
|
||||
if _type.isUnsigned:
|
||||
if _type.name == 'integer' and isinstance(_type.size, int):
|
||||
res = 'u' + res
|
||||
else:
|
||||
res = 'unsigned ' + res
|
||||
|
||||
if _type.isconst:
|
||||
if _type.name not in ['string', 'string_array'] or type(_type.parent) is AbsApi.Argument:
|
||||
res = 'const ' + res
|
||||
|
||||
if _type.isref:
|
||||
res += ' *'
|
||||
return res
|
||||
|
||||
def translate_enum_type(self, _type, **params):
|
||||
if _type.name in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_type.name))
|
||||
|
||||
if _type.desc is None:
|
||||
raise AbsApi.Error('{0} has not been fixed'.format(_type.name))
|
||||
|
||||
if 'namespace' in params:
|
||||
nsName = params['namespace'].name if params['namespace'] is not None else None
|
||||
else:
|
||||
method = _type.find_first_ancestor_by_type(AbsApi.Method)
|
||||
nsName = AbsApi.Name.find_common_parent(_type.desc.name, method.name)
|
||||
|
||||
return CppTranslator.translate_enum_name(_type.desc.name, recursive=True, topAncestor=nsName)
|
||||
|
||||
def translate_class_type(self, _type, **params):
|
||||
if _type.name in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_type.name))
|
||||
|
||||
if _type.desc is None:
|
||||
raise AbsApi.Error('{0} has not been fixed'.format(_type.name))
|
||||
|
||||
if 'namespace' in params:
|
||||
nsName = params['namespace'].name if params['namespace'] is not None else None
|
||||
else:
|
||||
method = _type.find_first_ancestor_by_type(AbsApi.Method)
|
||||
nsName = AbsApi.Name.find_common_parent(_type.desc.name, method.name)
|
||||
|
||||
res = CppTranslator.translate_class_name(_type.desc.name, recursive=True, topAncestor=nsName)
|
||||
|
||||
if _type.desc.refcountable:
|
||||
if _type.isconst:
|
||||
res = 'const ' + res
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
return 'const std::shared_ptr<{0}> &'.format(res)
|
||||
else:
|
||||
return 'std::shared_ptr<{0}>'.format(res)
|
||||
else:
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
return 'const {0} &'.format(res)
|
||||
else:
|
||||
return '{0}'.format(res)
|
||||
|
||||
def translate_list_type(self, _type, **params):
|
||||
if _type.containedTypeDesc is None:
|
||||
raise AbsApi.Error('{0} has not been fixed'.format(_type.containedTypeName))
|
||||
elif isinstance(_type.containedTypeDesc, AbsApi.BaseType):
|
||||
res = self.translate_type(_type.containedTypeDesc)
|
||||
else:
|
||||
res = self.translate_type(_type.containedTypeDesc, **params)
|
||||
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
return 'const std::list<{0} > &'.format(res)
|
||||
else:
|
||||
return 'std::list<{0} >'.format(res)
|
||||
|
||||
@staticmethod
|
||||
def translate_name(aName, **params):
|
||||
if type(aName) is AbsApi.ClassName:
|
||||
return CppTranslator.translate_class_name(aName, **params)
|
||||
elif type(aName) is AbsApi.InterfaceName:
|
||||
return CppTranslator.translate_class_name(aName, **params)
|
||||
elif type(aName) is AbsApi.EnumName:
|
||||
return CppTranslator.translate_enum_name(aName, **params)
|
||||
elif type(aName) is AbsApi.EnumValueName:
|
||||
return CppTranslator.translate_enum_value_name(aName, **params)
|
||||
elif type(aName) is AbsApi.MethodName:
|
||||
return CppTranslator.translate_method_name(aName, **params)
|
||||
elif type(aName) is AbsApi.ArgName:
|
||||
return CppTranslator.translate_argument_name(aName, **params)
|
||||
elif type(aName) is AbsApi.NamespaceName:
|
||||
return CppTranslator.translate_namespace_name(aName, **params)
|
||||
elif type(aName) is AbsApi.PropertyName:
|
||||
return CppTranslator.translate_property_name(aName, **params)
|
||||
else:
|
||||
CppTranslator.fail(aName)
|
||||
|
||||
@staticmethod
|
||||
def translate_class_name(name, recursive=False, topAncestor=None):
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return name.to_camel_case()
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_name(name.prev, **params) + '::' + name.to_camel_case()
|
||||
|
||||
@staticmethod
|
||||
def translate_enum_name(name, recursive=False, topAncestor=None):
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_class_name(name, **params)
|
||||
|
||||
@staticmethod
|
||||
def translate_enum_value_name(name, recursive=False, topAncestor=None):
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_enum_name(name.prev, **params) + name.to_camel_case()
|
||||
|
||||
@staticmethod
|
||||
def translate_method_name(name, recursive=False, topAncestor=None):
|
||||
translatedName = name.to_camel_case(lower=True)
|
||||
if translatedName == 'new':
|
||||
translatedName = '_new'
|
||||
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return translatedName
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_name(name.prev, **params) + '::' + translatedName
|
||||
|
||||
@staticmethod
|
||||
def translate_namespace_name(name, recursive=False, topAncestor=None):
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return name.concatenate()
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_namespace_name(name.prev, **params) + '::' + name.concatenate()
|
||||
|
||||
@staticmethod
|
||||
def translate_argument_name(name):
|
||||
return name.to_camel_case(lower=True)
|
||||
|
||||
@staticmethod
|
||||
def translate_property_name(name):
|
||||
CppTranslator.translate_argument_name(name)
|
||||
|
||||
@staticmethod
|
||||
def fail(obj):
|
||||
raise AbsApi.Error('Cannot translate {0} type'.format(type(obj)))
|
||||
|
|
@ -594,7 +367,7 @@ class ClassHeader(object):
|
|||
if include == 'enums':
|
||||
self.includes['internal'].append({'name': include})
|
||||
else:
|
||||
className = AbsApi.ClassName()
|
||||
className = metaname.ClassName()
|
||||
className.from_snake_case(include)
|
||||
self.priorDeclarations.append({'name': className.to_camel_case()})
|
||||
|
||||
|
|
@ -682,7 +455,7 @@ class GenWrapper(object):
|
|||
self.parser = AbsApi.CParser(project)
|
||||
self.parser.parse_all()
|
||||
self.translator = CppTranslator()
|
||||
self.renderer = pystache.Renderer()
|
||||
self.renderer = pystache.Renderer()
|
||||
self.mainHeader = MainHeader()
|
||||
self.impl = ClassImpl()
|
||||
|
||||
|
|
@ -743,14 +516,14 @@ def main():
|
|||
os.makedirs(includedir)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
print("Cannot create '{0}' dircetory: {1}".format(includedir, e.strerror))
|
||||
print("Cannot create '{0}' directory: {1}".format(includedir, e.strerror))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
os.makedirs(srcdir)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
print("Cannot create '{0}' dircetory: {1}".format(srcdir, e.strerror))
|
||||
print("Cannot create '{0}' directory: {1}".format(srcdir, e.strerror))
|
||||
sys.exit(1)
|
||||
|
||||
genwrapper = GenWrapper(includedir, srcdir, args.xmldir)
|
||||
|
|
|
|||
|
|
@ -22,15 +22,17 @@ import sys
|
|||
import pystache
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools'))
|
||||
print(sys.path)
|
||||
import genapixml as CApi
|
||||
import abstractapi as AbsApi
|
||||
import metadoc
|
||||
import metaname
|
||||
|
||||
class CsharpTranslator(object):
|
||||
def __init__(self):
|
||||
self.ignore = []
|
||||
self.docTranslator = metadoc.SandcastleCSharpTranslator()
|
||||
self.docTranslator = metadoc.SandCastleTranslator('CSharp')
|
||||
self.nameTranslator = metaname.Translator.get('CSharp')
|
||||
self.langTranslator = AbsApi.Translator.get('CSharp')
|
||||
|
||||
def init_method_dict(self):
|
||||
methodDict = {}
|
||||
|
|
@ -52,114 +54,16 @@ class CsharpTranslator(object):
|
|||
if length > 11 and name[:11] == 'IEnumerable':
|
||||
return name[12:length-1]
|
||||
return None
|
||||
|
||||
|
||||
def is_generic(self, methodDict):
|
||||
return not methodDict['is_string'] and not methodDict['is_bool'] and not methodDict['is_class'] and not methodDict['is_enum'] and methodDict['list_type'] == None
|
||||
|
||||
def translate_method_name(self, name, recursive=False, topAncestor=None):
|
||||
translatedName = name.to_camel_case(lower=True)
|
||||
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return translatedName
|
||||
|
||||
def translate_argument_name(self, name):
|
||||
argname = name.to_camel_case(lower=True)
|
||||
arg = argname
|
||||
if argname == "params":
|
||||
arg = "parameters"
|
||||
elif argname == "event":
|
||||
arg = "ev"
|
||||
elif argname == "ref":
|
||||
arg = "reference"
|
||||
elif argname == "value":
|
||||
arg = "val"
|
||||
return arg
|
||||
|
||||
def translate_base_type(self, _type, isArg, dllImport=True):
|
||||
if _type.name == 'void':
|
||||
if _type.isref:
|
||||
return 'IntPtr'
|
||||
return 'void'
|
||||
elif _type.name == 'status':
|
||||
if dllImport:
|
||||
return 'int'
|
||||
else:
|
||||
return 'void'
|
||||
elif _type.name == 'boolean':
|
||||
if dllImport:
|
||||
res = 'int' # In C the bool_t is an integer
|
||||
else:
|
||||
res = 'bool'
|
||||
elif _type.name == 'integer':
|
||||
if _type.isUnsigned:
|
||||
res = 'uint'
|
||||
else:
|
||||
res = 'int'
|
||||
elif _type.name == 'string':
|
||||
if dllImport:
|
||||
if isArg:
|
||||
return 'string'
|
||||
else:
|
||||
res = 'IntPtr' # Return as IntPtr and get string with Marshal.PtrToStringAnsi()
|
||||
else:
|
||||
return 'string'
|
||||
elif _type.name == 'character':
|
||||
if _type.isUnsigned:
|
||||
res = 'byte'
|
||||
else:
|
||||
res = 'sbyte'
|
||||
elif _type.name == 'time':
|
||||
res = 'long' #TODO check
|
||||
elif _type.name == 'size':
|
||||
res = 'long' #TODO check
|
||||
elif _type.name == 'floatant':
|
||||
return 'float'
|
||||
elif _type.name == 'string_array':
|
||||
if dllImport or isArg:
|
||||
return 'IntPtr'
|
||||
else:
|
||||
return 'IEnumerable<string>'
|
||||
else:
|
||||
raise AbsApi.Error('\'{0}\' is not a base abstract type'.format(_type.name))
|
||||
|
||||
return res
|
||||
|
||||
def is_linphone_type(self, _type, isArg, dllImport=True):
|
||||
if type(_type) is AbsApi.ClassType:
|
||||
return False if dllImport else True
|
||||
elif type(_type) is AbsApi.EnumType:
|
||||
return False if dllImport else True
|
||||
|
||||
def translate_type(self, _type, isArg, dllImport=True):
|
||||
if type(_type) is AbsApi.EnumType:
|
||||
if dllImport and isArg:
|
||||
return 'int'
|
||||
return _type.desc.name.to_camel_case()
|
||||
elif type(_type) is AbsApi.ClassType:
|
||||
return "IntPtr" if dllImport else _type.desc.name.to_camel_case()
|
||||
elif type(_type) is AbsApi.BaseType:
|
||||
return self.translate_base_type(_type, isArg, dllImport)
|
||||
elif type(_type) is AbsApi.ListType:
|
||||
if dllImport:
|
||||
return 'IntPtr'
|
||||
else:
|
||||
if type(_type.containedTypeDesc) is AbsApi.BaseType:
|
||||
if _type.containedTypeDesc.name == 'string':
|
||||
return 'IEnumerable<string>'
|
||||
else:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of basic C types is not supported')
|
||||
elif type(_type.containedTypeDesc) is AbsApi.ClassType:
|
||||
ptrType = _type.containedTypeDesc.desc.name.to_camel_case()
|
||||
return 'IEnumerable<' + ptrType + '>'
|
||||
else:
|
||||
if _type.containedTypeDesc:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of enums')
|
||||
else:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of unknow type !')
|
||||
|
||||
def translate_argument(self, arg, dllImport=True):
|
||||
return '{0} {1}'.format(self.translate_type(arg.type, True, dllImport), self.translate_argument_name(arg.name))
|
||||
|
||||
def throws_exception(self, return_type):
|
||||
if type(return_type) is AbsApi.BaseType:
|
||||
if return_type.name == 'status':
|
||||
|
|
@ -167,31 +71,31 @@ class CsharpTranslator(object):
|
|||
return False
|
||||
|
||||
def translate_method(self, method, static=False, genImpl=True):
|
||||
if method.name.to_snake_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(method.name.to_snake_case(fullName=True)))
|
||||
if method.name.to_c() in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(method.name.to_c()))
|
||||
|
||||
methodElems = {}
|
||||
methodElems['return'] = self.translate_type(method.returnType, False)
|
||||
methodElems['return'] = method.returnType.translate(self.langTranslator)
|
||||
methodElems['name'] = method.name.to_c()
|
||||
methodElems['params'] = '' if static else 'IntPtr thiz'
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0] or not static:
|
||||
methodElems['params'] += ', '
|
||||
methodElems['params'] += self.translate_argument(arg)
|
||||
methodElems['params'] += arg.translate(self.langTranslator)
|
||||
|
||||
methodDict = {}
|
||||
methodDict['prototype'] = "static extern {return} {name}({params});".format(**methodElems)
|
||||
|
||||
methodDict['doc'] = self.docTranslator.translate(method.briefDescription)
|
||||
methodDict['doc'] = method.briefDescription.translate(self.docTranslator, tagAsBrief=True)
|
||||
|
||||
methodDict['has_impl'] = genImpl
|
||||
if genImpl:
|
||||
methodDict['impl'] = {}
|
||||
methodDict['impl']['static'] = 'static ' if static else ''
|
||||
methodDict['impl']['exception'] = self.throws_exception(method.returnType)
|
||||
methodDict['impl']['type'] = self.translate_type(method.returnType, False, False)
|
||||
methodDict['impl']['name'] = method.name.to_camel_case()
|
||||
methodDict['impl']['override'] = 'override ' if method.name.to_camel_case() == 'ToString' else ''
|
||||
methodDict['impl']['type'] = method.returnType.translate(self.langTranslator, dllImport=False)
|
||||
methodDict['impl']['name'] = method.name.translate(self.nameTranslator)
|
||||
methodDict['impl']['override'] = 'override ' if method.name.translate(self.nameTranslator) == 'ToString' else ''
|
||||
methodDict['impl']['return'] = '' if methodDict['impl']['type'] == "void" else 'return '
|
||||
methodDict['impl']['c_name'] = method.name.to_c()
|
||||
methodDict['impl']['nativePtr'] = '' if static else ('nativePtr, ' if len(method.args) > 0 else 'nativePtr')
|
||||
|
|
@ -218,21 +122,21 @@ class CsharpTranslator(object):
|
|||
methodDict['impl']['c_args'] += ', '
|
||||
if self.is_linphone_type(arg.type, False, False):
|
||||
if type(arg.type) is AbsApi.ClassType:
|
||||
argname = self.translate_argument_name(arg.name)
|
||||
argname = arg.name.translate(self.nameTranslator)
|
||||
methodDict['impl']['c_args'] += argname + " != null ? " + argname + ".nativePtr : IntPtr.Zero"
|
||||
else:
|
||||
methodDict['impl']['c_args'] += '(int)' + self.translate_argument_name(arg.name)
|
||||
elif self.translate_type(arg.type, False, False) == "bool":
|
||||
methodDict['impl']['c_args'] += self.translate_argument_name(arg.name) + " ? 1 : 0"
|
||||
elif self.get_class_array_type(self.translate_type(arg.type, False, False)) is not None:
|
||||
listtype = self.get_class_array_type(self.translate_type(arg.type, False, False))
|
||||
methodDict['impl']['c_args'] += '(int)' + arg.name.translate(self.nameTranslator)
|
||||
elif arg.type.translate(self.langTranslator, dllImport=False) == "bool":
|
||||
methodDict['impl']['c_args'] += arg.name.translate(self.nameTranslator) + " ? (char)1 : (char)0"
|
||||
elif self.get_class_array_type(arg.type.translate(self.langTranslator, dllImport=False)) is not None:
|
||||
listtype = self.get_class_array_type(arg.type.translate(self.langTranslator, dllImport=False))
|
||||
if listtype == 'string':
|
||||
methodDict['impl']['c_args'] += "StringArrayToBctbxList(" + self.translate_argument_name(arg.name) + ")"
|
||||
methodDict['impl']['c_args'] += "StringArrayToBctbxList(" + arg.name.translate(self.nameTranslator) + ")"
|
||||
else:
|
||||
methodDict['impl']['c_args'] += "ObjectArrayToBctbxList<" + listtype + ">(" + self.translate_argument_name(arg.name) + ")"
|
||||
methodDict['impl']['c_args'] += "ObjectArrayToBctbxList<" + listtype + ">(" + arg.name.translate(self.nameTranslator) + ")"
|
||||
else:
|
||||
methodDict['impl']['c_args'] += self.translate_argument_name(arg.name)
|
||||
methodDict['impl']['args'] += self.translate_argument(arg, False)
|
||||
methodDict['impl']['c_args'] += arg.name.translate(self.nameTranslator)
|
||||
methodDict['impl']['args'] += arg.translate(self.langTranslator, dllImport=False)
|
||||
|
||||
return methodDict
|
||||
|
||||
|
|
@ -242,7 +146,7 @@ class CsharpTranslator(object):
|
|||
methodDict = self.translate_method(prop, static, False)
|
||||
|
||||
methodDict['property_static'] = 'static ' if static else ''
|
||||
methodDict['property_return'] = self.translate_type(prop.returnType, False, False)
|
||||
methodDict['property_return'] = prop.returnType.translate(self.langTranslator, dllImport=False)
|
||||
methodDict['property_name'] = (name[3:] if len(name) > 3 else 'Instance') if name[:3] == "Get" else name
|
||||
|
||||
methodDict['has_property'] = True
|
||||
|
|
@ -273,7 +177,7 @@ class CsharpTranslator(object):
|
|||
methodDict = self.translate_method(prop, static, False)
|
||||
|
||||
methodDict['property_static'] = 'static ' if static else ''
|
||||
methodDict['property_return'] = self.translate_type(prop.args[0].type, True, False)
|
||||
methodDict['property_return'] = prop.args[0].type.translate(self.langTranslator, dllImport=False)
|
||||
methodDict['property_name'] = (name[3:] if len(name) > 3 else 'Instance') if name[:3] == "Set" else name
|
||||
|
||||
methodDict['has_property'] = True
|
||||
|
|
@ -297,7 +201,7 @@ class CsharpTranslator(object):
|
|||
return methodDict
|
||||
|
||||
def translate_property_getter_setter(self, getter, setter, name, static=False):
|
||||
methodDict = self.translate_property_getter(getter, name, static)
|
||||
methodDict = self.translate_property_getter(getter, name, static=static)
|
||||
methodDictSet = self.translate_property_setter(setter, name, static)
|
||||
|
||||
protoElems = {}
|
||||
|
|
@ -314,7 +218,7 @@ class CsharpTranslator(object):
|
|||
|
||||
def translate_property(self, prop):
|
||||
res = []
|
||||
name = prop.name.to_camel_case()
|
||||
name = prop.name.translate(self.nameTranslator)
|
||||
if prop.getter is not None:
|
||||
if prop.setter is not None:
|
||||
res.append(self.translate_property_getter_setter(prop.getter, prop.setter, name))
|
||||
|
|
@ -331,7 +235,7 @@ class CsharpTranslator(object):
|
|||
|
||||
listenerDict = {}
|
||||
c_name_setter = listenedClass.name.to_snake_case(fullName=True) + '_cbs_set_' + method.name.to_snake_case()[3:]
|
||||
delegate_name_public = method.name.to_camel_case() + "Delegate"
|
||||
delegate_name_public = method.name.translate(self.nameTranslator) + "Delegate"
|
||||
delegate_name_private = delegate_name_public + "Private"
|
||||
listenerDict['cb_setter'] = {}
|
||||
listenerDict['cb_setter']['name'] = c_name_setter
|
||||
|
|
@ -345,9 +249,9 @@ class CsharpTranslator(object):
|
|||
listenerDict['delegate']['var_public'] = var_name_public
|
||||
listenerDict['delegate']['var_private'] = var_name_private
|
||||
listenerDict['delegate']['cb_name'] = method.name.to_snake_case()
|
||||
listenerDict['delegate']['name'] = method.name.to_camel_case()
|
||||
listenerDict['delegate']['name'] = method.name.translate(self.nameTranslator)
|
||||
|
||||
listenerDict['delegate']['interfaceClassName'] = listenedClass.name.to_camel_case()
|
||||
listenerDict['delegate']['interfaceClassName'] = listenedClass.name.translate(self.nameTranslator)
|
||||
listenerDict['delegate']['isSimpleListener'] = not listenedClass.multilistener
|
||||
listenerDict['delegate']['isMultiListener'] = listenedClass.multilistener
|
||||
|
||||
|
|
@ -355,10 +259,10 @@ class CsharpTranslator(object):
|
|||
listenerDict['delegate']['params_private'] = ""
|
||||
listenerDict['delegate']['params'] = ""
|
||||
for arg in method.args:
|
||||
dllImportType = self.translate_type(arg.type, True, True)
|
||||
normalType = self.translate_type(arg.type, True, False)
|
||||
dllImportType = arg.type.translate(self.langTranslator, dllImport=True)
|
||||
normalType = arg.type.translate(self.langTranslator, dllImport=False)
|
||||
|
||||
argName = self.translate_argument_name(arg.name)
|
||||
argName = arg.name.translate(self.nameTranslator)
|
||||
if arg != method.args[0]:
|
||||
listenerDict['delegate']['params_public'] += ', '
|
||||
listenerDict['delegate']['params_private'] += ', '
|
||||
|
|
@ -369,9 +273,9 @@ class CsharpTranslator(object):
|
|||
else:
|
||||
if normalType == "bool":
|
||||
listenerDict['delegate']['params'] += argName + " == 0"
|
||||
elif self.is_linphone_type(arg.type, True, False) and type(arg.type) is AbsApi.ClassType:
|
||||
elif self.is_linphone_type(arg.type, True, dllImport=False) and type(arg.type) is AbsApi.ClassType:
|
||||
listenerDict['delegate']['params'] += "fromNativePtr<" + normalType + ">(" + argName + ")"
|
||||
elif self.is_linphone_type(arg.type, True, False) and type(arg.type) is AbsApi.EnumType:
|
||||
elif self.is_linphone_type(arg.type, True, dllImport=False) and type(arg.type) is AbsApi.EnumType:
|
||||
listenerDict['delegate']['params'] += "(" + normalType + ")" + argName + ""
|
||||
else:
|
||||
raise("Error")
|
||||
|
|
@ -439,15 +343,15 @@ class CsharpTranslator(object):
|
|||
|
||||
def translate_enum(self, enum):
|
||||
enumDict = {}
|
||||
enumDict['enumName'] = enum.name.to_camel_case()
|
||||
enumDict['doc'] = self.docTranslator.translate(enum.briefDescription)
|
||||
enumDict['enumName'] = enum.name.translate(self.nameTranslator)
|
||||
enumDict['doc'] = enum.briefDescription.translate(self.docTranslator, tagAsBrief=True)
|
||||
enumDict['values'] = []
|
||||
i = 0
|
||||
lastValue = None
|
||||
for enumValue in enum.values:
|
||||
for enumValue in enum.enumerators:
|
||||
enumValDict = {}
|
||||
enumValDict['name'] = enumValue.name.to_camel_case()
|
||||
enumValDict['doc'] = self.docTranslator.translate(enumValue.briefDescription)
|
||||
enumValDict['name'] = enumValue.name.translate(self.nameTranslator)
|
||||
enumValDict['doc'] = enumValue.briefDescription.translate(self.docTranslator, tagAsBrief=True)
|
||||
if type(enumValue.value) is int:
|
||||
lastValue = enumValue.value
|
||||
enumValDict['value'] = str(enumValue.value)
|
||||
|
|
@ -464,21 +368,21 @@ class CsharpTranslator(object):
|
|||
return enumDict
|
||||
|
||||
def translate_class(self, _class):
|
||||
if _class.name.to_camel_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_camel_case(fullName=True)))
|
||||
if _class.name.to_c() in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_c()))
|
||||
|
||||
classDict = {}
|
||||
classDict['className'] = _class.name.to_camel_case()
|
||||
classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory"
|
||||
classDict['className'] = _class.name.translate(self.nameTranslator)
|
||||
classDict['isLinphoneFactory'] = classDict['className'] == "Factory"
|
||||
classDict['isLinphoneCall'] = _class.name.to_camel_case() == "Call"
|
||||
classDict['isLinphoneCore'] = _class.name.to_camel_case() == "Core"
|
||||
classDict['doc'] = self.docTranslator.translate(_class.briefDescription)
|
||||
classDict['doc'] = _class.briefDescription.translate(self.docTranslator, tagAsBrief=True)
|
||||
classDict['dllImports'] = []
|
||||
|
||||
islistenable = _class.listenerInterface is not None
|
||||
ismonolistenable = (islistenable and not _class.multilistener)
|
||||
if islistenable:
|
||||
listenerName = _class.listenerInterface.name.to_camel_case()
|
||||
listenerName = _class.listenerInterface.name.translate(self.nameTranslator)
|
||||
if ismonolistenable:
|
||||
classDict['dllImports'].append(self.generate_getter_for_listener_callbacks(_class, listenerName))
|
||||
else:
|
||||
|
|
@ -488,7 +392,7 @@ class CsharpTranslator(object):
|
|||
for method in _class.classMethods:
|
||||
try:
|
||||
if 'get' in method.name.to_word_list():
|
||||
methodDict = self.translate_property_getter(method, method.name.to_camel_case(), True)
|
||||
methodDict = self.translate_property_getter(method, method.name.translate(self.nameTranslator), True)
|
||||
#The following doesn't work because there a at least one method that has both getter and setter,
|
||||
#and because it doesn't do both of them at once, property is declared twice
|
||||
#elif 'set' in method.name.to_word_list():
|
||||
|
|
@ -497,29 +401,29 @@ class CsharpTranslator(object):
|
|||
methodDict = self.translate_method(method, static=True, genImpl=True)
|
||||
classDict['dllImports'].append(methodDict)
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
|
||||
print('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0]))
|
||||
|
||||
for prop in _class.properties:
|
||||
try:
|
||||
classDict['dllImports'] += self.translate_property(prop)
|
||||
except AbsApi.Error as e:
|
||||
print('error while translating {0} property: {1}'.format(prop.name.to_snake_case(), e.args[0]))
|
||||
print('error while translating {0} property: {1}'.format(prop.name.to_c(), e.args[0]))
|
||||
|
||||
for method in _class.instanceMethods:
|
||||
try:
|
||||
methodDict = self.translate_method(method, static=False, genImpl=True)
|
||||
classDict['dllImports'].append(methodDict)
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
|
||||
print('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0]))
|
||||
|
||||
return classDict
|
||||
|
||||
def translate_interface(self, interface):
|
||||
if interface.name.to_camel_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_camel_case(fullName=True)))
|
||||
if interface.name.to_c() in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_c()))
|
||||
|
||||
interfaceDict = {}
|
||||
interfaceDict['interfaceName'] = interface.name.to_camel_case()
|
||||
interfaceDict['interfaceName'] = interface.name.translate(self.nameTranslator)
|
||||
interfaceDict['methods'] = []
|
||||
for method in interface.methods:
|
||||
interfaceDict['methods'].append(self.translate_listener(interface, method))
|
||||
|
|
@ -615,7 +519,7 @@ def main():
|
|||
impl = InterfaceImpl(_class, translator)
|
||||
interfaces.append(impl)
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0]))
|
||||
print('Could not translate {0}: {1}'.format(_class.name.to_c(), e.args[0]))
|
||||
|
||||
wrapper = WrapperImpl(enums, interfaces, classes)
|
||||
render(renderer, wrapper, args.outputdir + "/" + args.outputfile)
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ namespace Linphone
|
|||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_string}}
|
||||
{{#is_bool}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? 1 : 0);
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? (char)1 : (char)0);
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_bool}}
|
||||
{{#is_class}}
|
||||
|
|
@ -525,7 +525,7 @@ namespace Linphone
|
|||
return Marshal.PtrToStringAnsi(stringPtr);
|
||||
{{/is_string}}
|
||||
{{#is_bool}}
|
||||
{{return}}{{c_name}}({{nativePtr}}{{c_args}}) == 0 ? false : true;
|
||||
{{return}}{{c_name}}({{nativePtr}}{{c_args}}) == (char)0 ? false : true;
|
||||
{{/is_bool}}
|
||||
{{#is_class}}
|
||||
IntPtr ptr = {{c_name}}({{nativePtr}}{{c_args}});
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class JavaTranslator(object):
|
|||
self.jni_package += directory + '_'
|
||||
self.jni_path += directory + '/'
|
||||
|
||||
self.docTranslator = metadoc.SandcastleJavaTranslator()
|
||||
self.docTranslator = metadoc.JavaDocTranslator()
|
||||
|
||||
def throws_exception(self, _type):
|
||||
if not self.exceptions:
|
||||
|
|
@ -353,7 +353,7 @@ class JavaTranslator(object):
|
|||
methodDict['native_params_impl'] += self.translate_argument_name(arg.name)
|
||||
|
||||
methodDict['deprecated'] = _method.deprecated
|
||||
methodDict['doc'] = self.docTranslator.translate(_method.briefDescription) if _method.briefDescription is not None else None
|
||||
methodDict['doc'] = _method.briefDescription.translate(self.docTranslator) if _method.briefDescription is not None else None
|
||||
|
||||
return methodDict
|
||||
|
||||
|
|
@ -449,7 +449,7 @@ class JavaTranslator(object):
|
|||
|
||||
classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory"
|
||||
classDict['isLinphoneCore'] = _class.name.to_camel_case() == "Core"
|
||||
classDict['doc'] = self.docTranslator.translate(_class.briefDescription) if _class.briefDescription is not None else None
|
||||
classDict['doc'] = _class.briefDescription.translate(self.docTranslator) if _class.briefDescription is not None else None
|
||||
|
||||
for _property in _class.properties:
|
||||
try:
|
||||
|
|
@ -572,7 +572,7 @@ class JavaTranslator(object):
|
|||
'jniMethods': [],
|
||||
}
|
||||
|
||||
interfaceDict['doc'] = self.docTranslator.translate(_class.briefDescription)
|
||||
interfaceDict['doc'] = _class.briefDescription.translate(self.docTranslator)
|
||||
|
||||
for method in _class.methods:
|
||||
interfaceDict['methods'].append(self.translate_method(method))
|
||||
|
|
@ -580,23 +580,23 @@ class JavaTranslator(object):
|
|||
|
||||
return interfaceDict
|
||||
|
||||
def translate_enum(self, _class):
|
||||
def translate_enum(self, enum):
|
||||
enumDict = {
|
||||
'jniMethods': [],
|
||||
}
|
||||
|
||||
enumDict['name'] = _class.name.to_camel_case()
|
||||
enumDict['doc'] = self.docTranslator.translate(_class.briefDescription)
|
||||
enumDict['name'] = enum.name.to_camel_case()
|
||||
enumDict['doc'] = enum.briefDescription.translate(self.docTranslator)
|
||||
enumDict['values'] = []
|
||||
i = 0
|
||||
lastValue = None
|
||||
|
||||
enumDict['jniPath'] = self.jni_path
|
||||
|
||||
for enumValue in _class.values:
|
||||
for enumValue in enum.enumerators:
|
||||
enumValDict = {}
|
||||
enumValDict['name'] = enumValue.name.to_camel_case()
|
||||
enumValDict['doc'] = self.docTranslator.translate(enumValue.briefDescription)
|
||||
enumValDict['doc'] = enumValue.briefDescription.translate(self.docTranslator)
|
||||
if type(enumValue.value) is int:
|
||||
lastValue = enumValue.value
|
||||
enumValDict['value'] = str(enumValue.value)
|
||||
|
|
@ -609,7 +609,7 @@ class JavaTranslator(object):
|
|||
else:
|
||||
enumValDict['value'] = i
|
||||
i += 1
|
||||
enumValDict['commarorsemicolon'] = ';' if i == len(_class.values) else ','
|
||||
enumValDict['commarorsemicolon'] = ';' if i == len(enum.enumerators) else ','
|
||||
enumDict['values'].append(enumValDict)
|
||||
|
||||
return enumDict
|
||||
|
|
@ -805,22 +805,22 @@ class GenWrapper(object):
|
|||
if _enum[1] is not None:
|
||||
self.render_java_enum(_enum[1])
|
||||
|
||||
for name, value in self.enums.iteritems():
|
||||
for name, value in self.enums.items():
|
||||
self.jni.add_enum(value)
|
||||
if name in ENUMS_LIST:
|
||||
className = ENUMS_LIST[name]
|
||||
print 'Enum ' + name + ' belongs to class ' + className
|
||||
print('Enum ' + name + ' belongs to class ' + className)
|
||||
self.classes[className].add_enum(value)
|
||||
self.enums_to_remove.append(name)
|
||||
|
||||
for enum in self.enums_to_remove:
|
||||
self.enums.pop(enum, None)
|
||||
|
||||
for name, value in self.enums.iteritems():
|
||||
for name, value in self.enums.items():
|
||||
self.render(value, self.javadir + '/' + value.filename)
|
||||
for name, value in self.interfaces.iteritems():
|
||||
for name, value in self.interfaces.items():
|
||||
self.render(value, self.javadir + '/' + value.filename)
|
||||
for name, value in self.classes.iteritems():
|
||||
for name, value in self.classes.items():
|
||||
self.render(value, self.javadir + '/' + value.filename)
|
||||
self.jni.add_object(value)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue