mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1624 lines
55 KiB
1624 lines
55 KiB
#!/usr/bin/env python |
|
# -*- coding: utf-8 -*- |
|
""" |
|
ocv domain, a modified copy of sphinx.domains.cpp + shpinx.domains.python. |
|
The original copyright is below |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
The OpenCV C/C++/Python/Java/... language domain. |
|
|
|
:copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. |
|
:license: BSD, see LICENSE for details. |
|
""" |
|
|
|
import re |
|
from copy import deepcopy |
|
|
|
from docutils import nodes |
|
from docutils.parsers.rst import directives |
|
|
|
from sphinx import addnodes |
|
from sphinx.roles import XRefRole |
|
from sphinx.locale import l_, _ |
|
from sphinx.domains import Domain, ObjType |
|
from sphinx.directives import ObjectDescription |
|
from sphinx.util.nodes import make_refnode |
|
from sphinx.util.compat import Directive |
|
from sphinx.util.docfields import Field, GroupedField, TypedField |
|
|
|
########################### Python Part ########################### |
|
|
|
# REs for Python signatures |
|
py_sig_re = re.compile( |
|
r'''^ ([\w.]*\.)? # class name(s) |
|
(\w+) \s* # thing name |
|
(?: \((.*)\) # optional: arguments |
|
(?:\s* -> \s* (.*))? # return annotation |
|
)? $ # and nothing more |
|
''', re.VERBOSE) |
|
|
|
|
|
def _pseudo_parse_arglist(signode, arglist): |
|
""""Parse" a list of arguments separated by commas. |
|
|
|
Arguments can have "optional" annotations given by enclosing them in |
|
brackets. Currently, this will split at any comma, even if it's inside a |
|
string literal (e.g. default argument value). |
|
""" |
|
paramlist = addnodes.desc_parameterlist() |
|
stack = [paramlist] |
|
try: |
|
for argument in arglist.split(','): |
|
argument = argument.strip() |
|
ends_open = ends_close = 0 |
|
while argument.startswith('['): |
|
stack.append(addnodes.desc_optional()) |
|
stack[-2] += stack[-1] |
|
argument = argument[1:].strip() |
|
while argument.startswith(']'): |
|
stack.pop() |
|
argument = argument[1:].strip() |
|
while argument.endswith(']'): |
|
ends_close += 1 |
|
argument = argument[:-1].strip() |
|
while argument.endswith('['): |
|
ends_open += 1 |
|
argument = argument[:-1].strip() |
|
if argument: |
|
stack[-1] += addnodes.desc_parameter(argument, argument, noemph=True) |
|
while ends_open: |
|
stack.append(addnodes.desc_optional()) |
|
stack[-2] += stack[-1] |
|
ends_open -= 1 |
|
while ends_close: |
|
stack.pop() |
|
ends_close -= 1 |
|
if len(stack) != 1: |
|
raise IndexError |
|
except IndexError: |
|
# if there are too few or too many elements on the stack, just give up |
|
# and treat the whole argument list as one argument, discarding the |
|
# already partially populated paramlist node |
|
signode += addnodes.desc_parameterlist() |
|
signode[-1] += addnodes.desc_parameter(arglist, arglist) |
|
else: |
|
signode += paramlist |
|
|
|
|
|
class OCVPyObject(ObjectDescription): |
|
""" |
|
Description of a general Python object. |
|
""" |
|
option_spec = { |
|
'noindex': directives.flag, |
|
'module': directives.unchanged, |
|
} |
|
|
|
doc_field_types = [ |
|
TypedField('parameter', label=l_('Parameters'), |
|
names=('param', 'parameter', 'arg', 'argument', |
|
'keyword', 'kwarg', 'kwparam'), |
|
typerolename='obj', typenames=('paramtype', 'type'), |
|
can_collapse=True), |
|
TypedField('variable', label=l_('Variables'), rolename='obj', |
|
names=('var', 'ivar', 'cvar'), |
|
typerolename='obj', typenames=('vartype',), |
|
can_collapse=True), |
|
GroupedField('exceptions', label=l_('Raises'), rolename='exc', |
|
names=('raises', 'raise', 'exception', 'except'), |
|
can_collapse=True), |
|
Field('returnvalue', label=l_('Returns'), has_arg=False, |
|
names=('returns', 'return')), |
|
Field('returntype', label=l_('Return type'), has_arg=False, |
|
names=('rtype',)), |
|
] |
|
|
|
def get_signature_prefix(self, sig): |
|
""" |
|
May return a prefix to put before the object name in the signature. |
|
""" |
|
return '' |
|
|
|
def needs_arglist(self): |
|
""" |
|
May return true if an empty argument list is to be generated even if |
|
the document contains none. |
|
""" |
|
return False |
|
|
|
def handle_signature(self, sig, signode): |
|
""" |
|
Transform a Python signature into RST nodes. |
|
Returns (fully qualified name of the thing, classname if any). |
|
|
|
If inside a class, the current class name is handled intelligently: |
|
* it is stripped from the displayed name if present |
|
* it is added to the full name (return value) if not present |
|
""" |
|
signode += nodes.strong("Python:", "Python:") |
|
signode += addnodes.desc_name(" ", " ") |
|
m = py_sig_re.match(sig) |
|
if m is None: |
|
raise ValueError |
|
name_prefix, name, arglist, retann = m.groups() |
|
|
|
# determine module and class name (if applicable), as well as full name |
|
modname = self.options.get( |
|
'module', self.env.temp_data.get('py:module')) |
|
classname = self.env.temp_data.get('py:class') |
|
if classname: |
|
add_module = False |
|
if name_prefix and name_prefix.startswith(classname): |
|
fullname = name_prefix + name |
|
# class name is given again in the signature |
|
name_prefix = name_prefix[len(classname):].lstrip('.') |
|
elif name_prefix: |
|
# class name is given in the signature, but different |
|
# (shouldn't happen) |
|
fullname = classname + '.' + name_prefix + name |
|
else: |
|
# class name is not given in the signature |
|
fullname = classname + '.' + name |
|
else: |
|
add_module = True |
|
if name_prefix: |
|
classname = name_prefix.rstrip('.') |
|
fullname = name_prefix + name |
|
else: |
|
classname = '' |
|
fullname = name |
|
|
|
signode['module'] = modname |
|
signode['class'] = classname |
|
signode['fullname'] = fullname |
|
|
|
sig_prefix = self.get_signature_prefix(sig) |
|
if sig_prefix: |
|
signode += addnodes.desc_annotation(sig_prefix, sig_prefix) |
|
|
|
if name_prefix: |
|
signode += addnodes.desc_addname(name_prefix, name_prefix) |
|
# exceptions are a special case, since they are documented in the |
|
# 'exceptions' module. |
|
elif add_module and self.env.config.add_module_names: |
|
modname = self.options.get( |
|
'module', self.env.temp_data.get('py:module')) |
|
if modname and modname != 'exceptions': |
|
nodetext = modname + '.' |
|
signode += addnodes.desc_addname(nodetext, nodetext) |
|
|
|
signode += addnodes.desc_name(name, name) |
|
if not arglist: |
|
if self.needs_arglist(): |
|
# for callables, add an empty parameter list |
|
signode += addnodes.desc_parameterlist() |
|
if retann: |
|
signode += addnodes.desc_returns(retann, retann) |
|
return fullname, name_prefix |
|
_pseudo_parse_arglist(signode, arglist) |
|
if retann: |
|
signode += addnodes.desc_returns(retann, retann) |
|
return fullname, name_prefix |
|
|
|
def get_index_text(self, modname, name): |
|
""" |
|
Return the text for the index entry of the object. |
|
""" |
|
raise NotImplementedError('must be implemented in subclasses') |
|
|
|
def add_target_and_index(self, name_cls, sig, signode): |
|
modname = self.options.get( |
|
'module', self.env.temp_data.get('py:module')) |
|
fullname = (modname and modname + '.' or '') + name_cls[0] |
|
# note target |
|
if fullname not in self.state.document.ids: |
|
signode['names'].append(fullname) |
|
signode['ids'].append(fullname) |
|
signode['first'] = (not self.names) |
|
self.state.document.note_explicit_target(signode) |
|
objects = self.env.domaindata['ocv']['objects'] |
|
if fullname in objects: |
|
self.env.warn( |
|
self.env.docname, |
|
'duplicate object description of %s, ' % fullname + |
|
'other instance in ' + |
|
self.env.doc2path(objects[fullname][0]) + |
|
', use :noindex: for one of them', |
|
self.lineno) |
|
objects.setdefault(fullname, (self.env.docname, self.objtype, name_cls[0])) |
|
|
|
indextext = self.get_index_text(modname, name_cls) |
|
if indextext: |
|
self.indexnode['entries'].append(('single', indextext, |
|
fullname, fullname)) |
|
|
|
def before_content(self): |
|
# needed for automatic qualification of members (reset in subclasses) |
|
self.clsname_set = False |
|
|
|
def after_content(self): |
|
if self.clsname_set: |
|
self.env.temp_data['py:class'] = None |
|
|
|
class OCVPyModulelevel(OCVPyObject): |
|
""" |
|
Description of an object on module level (functions, data). |
|
""" |
|
directive_prefix = 'py' |
|
|
|
def needs_arglist(self): |
|
return self.objtype == self.__class__.directive_prefix + 'function' |
|
|
|
def get_index_text(self, modname, name_cls): |
|
if self.objtype == self.__class__.directive_prefix + 'function': |
|
if not modname: |
|
fname = name_cls[0] |
|
if not fname.startswith("cv") and not fname.startswith("cv2"): |
|
return _('%s() (Python function)') % fname |
|
pos = fname.find(".") |
|
modname = fname[:pos] |
|
fname = fname[pos+1:] |
|
return _('%s() (Python function in %s)') % (fname, modname) |
|
return _('%s() (Python function in %s)') % (name_cls[0], modname) |
|
elif self.objtype == 'pydata': |
|
if not modname: |
|
return _('%s (Python variable)') % name_cls[0] |
|
return _('%s (in module %s)') % (name_cls[0], modname) |
|
else: |
|
return '' |
|
|
|
class OCVPyOldModulelevel(OCVPyModulelevel): |
|
directive_prefix = 'pyold' |
|
pass |
|
|
|
class OCVPyXRefRole(XRefRole): |
|
def process_link(self, env, refnode, has_explicit_title, title, target): |
|
refnode['ocv:module'] = env.temp_data.get('ocv:module') |
|
refnode['ocv:class'] = env.temp_data.get('ocv:class') |
|
if not has_explicit_title: |
|
title = title.lstrip('.') # only has a meaning for the target |
|
target = target.lstrip('~') # only has a meaning for the title |
|
# if the first character is a tilde, don't display the module/class |
|
# parts of the contents |
|
if title[0:1] == '~': |
|
title = title[1:] |
|
dot = title.rfind('.') |
|
if dot != -1: |
|
title = title[dot+1:] |
|
# if the first character is a dot, search more specific namespaces first |
|
# else search builtins first |
|
if target[0:1] == '.': |
|
target = target[1:] |
|
refnode['refspecific'] = True |
|
return title, target |
|
|
|
|
|
########################### C/C++/Java Part ########################### |
|
|
|
_identifier_re = re.compile(r'(~?\b[a-zA-Z_][a-zA-Z0-9_]*\b)') |
|
_argument_name_re = re.compile(r'(~?\b[a-zA-Z_][a-zA-Z0-9_]*\b(?:\[\d*\])?|\.\.\.)') |
|
_whitespace_re = re.compile(r'\s+(?u)') |
|
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'" |
|
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S) |
|
_visibility_re = re.compile(r'\b(public|private|protected)\b') |
|
_operator_re = re.compile(r'''(?x) |
|
\[\s*\] |
|
| \(\s*\) |
|
| (<<|>>)=? |
|
| \+\+ | -- | ->\*? |
|
| [!<>=/*%+|&^-]=? |
|
| ~ | && | \| | \|\| |
|
| \, |
|
''') |
|
|
|
_id_shortwords = { |
|
'char': 'c', |
|
'signed char': 'c', |
|
'unsigned char': 'C', |
|
'int': 'i', |
|
'signed int': 'i', |
|
'unsigned int': 'U', |
|
'long': 'l', |
|
'signed long': 'l', |
|
'unsigned long': 'L', |
|
'bool': 'b', |
|
'size_t': 's', |
|
'std::string': 'ss', |
|
'std::ostream': 'os', |
|
'std::istream': 'is', |
|
'std::iostream': 'ios', |
|
'std::vector': 'v', |
|
'std::map': 'm', |
|
'operator[]': 'subscript-operator', |
|
'operator()': 'call-operator', |
|
'operator!': 'not-operator', |
|
'operator<': 'lt-operator', |
|
'operator<=': 'lte-operator', |
|
'operator>': 'gt-operator', |
|
'operator>=': 'gte-operator', |
|
'operator=': 'assign-operator', |
|
'operator/': 'div-operator', |
|
'operator*': 'mul-operator', |
|
'operator%': 'mod-operator', |
|
'operator+': 'add-operator', |
|
'operator-': 'sub-operator', |
|
'operator|': 'or-operator', |
|
'operator&': 'and-operator', |
|
'operator^': 'xor-operator', |
|
'operator&&': 'sand-operator', |
|
'operator||': 'sor-operator', |
|
'operator==': 'eq-operator', |
|
'operator!=': 'neq-operator', |
|
'operator<<': 'lshift-operator', |
|
'operator>>': 'rshift-operator', |
|
'operator-=': 'sub-assign-operator', |
|
'operator+=': 'add-assign-operator', |
|
'operator*-': 'mul-assign-operator', |
|
'operator/=': 'div-assign-operator', |
|
'operator%=': 'mod-assign-operator', |
|
'operator&=': 'and-assign-operator', |
|
'operator|=': 'or-assign-operator', |
|
'operator<<=': 'lshift-assign-operator', |
|
'operator>>=': 'rshift-assign-operator', |
|
'operator^=': 'xor-assign-operator', |
|
'operator,': 'comma-operator', |
|
'operator->': 'pointer-operator', |
|
'operator->*': 'pointer-by-pointer-operator', |
|
'operator~': 'inv-operator', |
|
'operator++': 'inc-operator', |
|
'operator--': 'dec-operator', |
|
'operator new': 'new-operator', |
|
'operator new[]': 'new-array-operator', |
|
'operator delete': 'delete-operator', |
|
'operator delete[]': 'delete-array-operator' |
|
} |
|
|
|
|
|
class DefinitionError(Exception): |
|
|
|
def __init__(self, description): |
|
self.description = description |
|
|
|
def __unicode__(self): |
|
return self.description |
|
|
|
def __str__(self): |
|
return unicode(self.encode('utf-8')) |
|
|
|
|
|
class DefExpr(object): |
|
|
|
def __unicode__(self): |
|
raise NotImplementedError() |
|
|
|
def __eq__(self, other): |
|
if type(self) is not type(other): |
|
return False |
|
try: |
|
for key, value in self.__dict__.iteritems(): |
|
if value != getattr(other, value): |
|
return False |
|
except AttributeError: |
|
return False |
|
return True |
|
|
|
def __ne__(self, other): |
|
return not self.__eq__(other) |
|
|
|
def clone(self): |
|
"""Close a definition expression node""" |
|
return deepcopy(self) |
|
|
|
def get_id(self): |
|
"""Returns the id for the node""" |
|
return u'' |
|
|
|
def get_name(self): |
|
"""Returns the name. Returns either `None` or a node with |
|
a name you might call :meth:`split_owner` on. |
|
""" |
|
return None |
|
|
|
def split_owner(self): |
|
"""Nodes returned by :meth:`get_name` can split off their |
|
owning parent. This function returns the owner and the |
|
name as a tuple of two items. If a node does not support |
|
it, it returns None as owner and self as name. |
|
""" |
|
return None, self |
|
|
|
def prefix(self, prefix): |
|
"""Prefixes a name node (a node returned by :meth:`get_name`).""" |
|
raise NotImplementedError() |
|
|
|
def __str__(self): |
|
return unicode(self).encode('utf-8') |
|
|
|
def __repr__(self): |
|
return '<%s %s>' % (self.__class__.__name__, self) |
|
|
|
|
|
class PrimaryDefExpr(DefExpr): |
|
|
|
def get_name(self): |
|
return self |
|
|
|
def prefix(self, prefix): |
|
if isinstance(prefix, PathDefExpr): |
|
prefix = prefix.clone() |
|
prefix.path.append(self) |
|
return prefix |
|
return PathDefExpr([prefix, self]) |
|
|
|
|
|
class NameDefExpr(PrimaryDefExpr): |
|
|
|
def __init__(self, name): |
|
self.name = name |
|
|
|
def get_id(self): |
|
name = _id_shortwords.get(self.name) |
|
if name is not None: |
|
return name |
|
return self.name.replace(u' ', u'-') |
|
|
|
def __unicode__(self): |
|
return unicode(self.name) |
|
|
|
|
|
class PathDefExpr(PrimaryDefExpr): |
|
|
|
def __init__(self, parts): |
|
self.path = parts |
|
|
|
def get_id(self): |
|
rv = u'::'.join(x.get_id() for x in self.path) |
|
return _id_shortwords.get(rv, rv) |
|
|
|
def split_owner(self): |
|
if len(self.path) > 1: |
|
return PathDefExpr(self.path[:-1]), self.path[-1] |
|
return None, self |
|
|
|
def prefix(self, prefix): |
|
if isinstance(prefix, PathDefExpr): |
|
prefix = prefix.clone() |
|
prefix.path.extend(self.path) |
|
return prefix |
|
return PathDefExpr([prefix] + self.path) |
|
|
|
def __unicode__(self): |
|
return u'::'.join(map(unicode, self.path)) |
|
|
|
|
|
class TemplateDefExpr(PrimaryDefExpr): |
|
|
|
def __init__(self, typename, args): |
|
self.typename = typename |
|
self.args = args |
|
|
|
def split_owner(self): |
|
owner, typename = self.typename.split_owner() |
|
return owner, TemplateDefExpr(typename, self.args) |
|
|
|
def get_id(self): |
|
return u'%s:%s:' % (self.typename.get_id(), |
|
u'.'.join(x.get_id() for x in self.args)) |
|
|
|
def __unicode__(self): |
|
return u'%s<%s>' % (self.typename, u', '.join(map(unicode, self.args))) |
|
|
|
|
|
class WrappingDefExpr(DefExpr): |
|
|
|
def __init__(self, typename): |
|
self.typename = typename |
|
|
|
def get_name(self): |
|
return self.typename.get_name() |
|
|
|
|
|
class ModifierDefExpr(WrappingDefExpr): |
|
|
|
def __init__(self, typename, modifiers): |
|
WrappingDefExpr.__init__(self, typename) |
|
self.modifiers = modifiers |
|
|
|
def get_id(self): |
|
pieces = [_id_shortwords.get(unicode(x), unicode(x)) |
|
for x in self.modifiers] |
|
pieces.append(self.typename.get_id()) |
|
return u'-'.join(pieces) |
|
|
|
def __unicode__(self): |
|
return u' '.join(map(unicode, list(self.modifiers) + [self.typename])) |
|
|
|
|
|
class PtrDefExpr(WrappingDefExpr): |
|
|
|
def get_id(self): |
|
return self.typename.get_id() + u'P' |
|
|
|
def __unicode__(self): |
|
return u'%s*' % self.typename |
|
|
|
|
|
class RefDefExpr(WrappingDefExpr): |
|
|
|
def get_id(self): |
|
return self.typename.get_id() + u'R' |
|
|
|
def __unicode__(self): |
|
return u'%s&' % self.typename |
|
|
|
|
|
class ConstDefExpr(WrappingDefExpr): |
|
|
|
def __init__(self, typename, prefix=False): |
|
WrappingDefExpr.__init__(self, typename) |
|
self.prefix = prefix |
|
|
|
def get_id(self): |
|
return self.typename.get_id() + u'C' |
|
|
|
def __unicode__(self): |
|
return (self.prefix and u'const %s' or u'%s const') % self.typename |
|
|
|
class ConstTemplateDefExpr(WrappingDefExpr): |
|
|
|
def __init__(self, typename, prefix=False): |
|
WrappingDefExpr.__init__(self, typename) |
|
self.prefix = prefix |
|
|
|
def get_id(self): |
|
return self.typename.get_id() + u'C' |
|
|
|
def __unicode__(self): |
|
return (self.prefix and u'const %s' or u'%s const') % self.typename |
|
|
|
|
|
class CastOpDefExpr(PrimaryDefExpr): |
|
|
|
def __init__(self, typename): |
|
self.typename = typename |
|
|
|
def get_id(self): |
|
return u'castto-%s-operator' % self.typename.get_id() |
|
|
|
def __unicode__(self): |
|
return u'operator %s' % self.typename |
|
|
|
|
|
class ArgumentDefExpr(DefExpr): |
|
|
|
def __init__(self, type, name, default=None): |
|
self.name = name |
|
self.type = type |
|
self.default = default |
|
|
|
def get_name(self): |
|
return self.name.get_name() |
|
|
|
def get_id(self): |
|
if self.type is None: |
|
return 'X' |
|
return self.type.get_id() |
|
|
|
def __unicode__(self): |
|
return (u'%s %s' % (self.type or u'', self.name or u'')).strip() + \ |
|
(self.default is not None and u'=%s' % self.default or u'') |
|
|
|
|
|
class NamedDefExpr(DefExpr): |
|
|
|
def __init__(self, name, visibility, static): |
|
self.name = name |
|
self.visibility = visibility |
|
self.static = static |
|
|
|
def get_name(self): |
|
return self.name.get_name() |
|
|
|
def get_modifiers(self): |
|
rv = [] |
|
if self.visibility != 'public': |
|
rv.append(self.visibility) |
|
if self.static: |
|
rv.append(u'static') |
|
return rv |
|
|
|
|
|
class TypeObjDefExpr(NamedDefExpr): |
|
|
|
def __init__(self, name, visibility, static, typename): |
|
NamedDefExpr.__init__(self, name, visibility, static) |
|
self.typename = typename |
|
|
|
def get_id(self): |
|
if self.typename is None: |
|
return self.name.get_id() |
|
return u'%s__%s' % (self.name.get_id(), self.typename.get_id()) |
|
|
|
def __unicode__(self): |
|
buf = self.get_modifiers() |
|
if self.typename is None: |
|
buf.append(unicode(self.name)) |
|
else: |
|
buf.extend(map(unicode, (self.typename, self.name))) |
|
return u' '.join(buf) |
|
|
|
|
|
class MemberObjDefExpr(NamedDefExpr): |
|
|
|
def __init__(self, name, visibility, static, typename, value): |
|
NamedDefExpr.__init__(self, name, visibility, static) |
|
self.typename = typename |
|
self.value = value |
|
|
|
def get_id(self): |
|
return u'%s__%s' % (self.name.get_id(), self.typename.get_id()) |
|
|
|
def __unicode__(self): |
|
buf = self.get_modifiers() |
|
buf.append(u'%s %s' % (self.typename, self.name)) |
|
if self.value is not None: |
|
buf.append(u'= %s' % self.value) |
|
return u' '.join(buf) |
|
|
|
|
|
class FuncDefExpr(NamedDefExpr): |
|
|
|
def __init__(self, name, visibility, static, explicit, rv, |
|
signature, const, pure_virtual, virtual): |
|
NamedDefExpr.__init__(self, name, visibility, static) |
|
self.rv = rv |
|
self.signature = signature |
|
self.explicit = explicit |
|
self.const = const |
|
self.pure_virtual = pure_virtual |
|
self.virtual = virtual |
|
|
|
def get_id(self): |
|
return u'%s%s%s' % ( |
|
self.name.get_id(), |
|
self.signature and u'__' + |
|
u'.'.join(x.get_id() for x in self.signature) or u'', |
|
self.const and u'C' or u'' |
|
) |
|
|
|
def __unicode__(self): |
|
buf = self.get_modifiers() |
|
if self.explicit: |
|
buf.append(u'explicit') |
|
if self.virtual: |
|
buf.append(u'virtual') |
|
if self.rv is not None: |
|
buf.append(unicode(self.rv)) |
|
buf.append(u'%s(%s)' % (self.name, u', '.join( |
|
map(unicode, self.signature)))) |
|
if self.const: |
|
buf.append(u'const') |
|
if self.pure_virtual: |
|
buf.append(u'= 0') |
|
return u' '.join(buf) |
|
|
|
|
|
class ClassDefExpr(NamedDefExpr): |
|
|
|
def __init__(self, name, visibility, static, parents = None): |
|
NamedDefExpr.__init__(self, name, visibility, static) |
|
self.parents = parents |
|
|
|
def get_id(self): |
|
return self.name.get_id() |
|
|
|
def __unicode__(self): |
|
buf = self.get_modifiers() |
|
buf.append(unicode(self.name)) |
|
return u' '.join(buf) |
|
|
|
|
|
class DefinitionParser(object): |
|
|
|
# mapping of valid type modifiers. if the set is None it means |
|
# the modifier can prefix all types, otherwise only the types |
|
# (actually more keywords) in the set. Also check |
|
# _guess_typename when changing this. |
|
_modifiers = { |
|
'volatile': None, |
|
'register': None, |
|
'mutable': None, |
|
'const': None, |
|
'typename': None, |
|
'unsigned': set(('char', 'short', 'int', 'long')), |
|
'signed': set(('char', 'short', 'int', 'long')), |
|
'short': set(('int',)), |
|
'long': set(('int', 'long', 'double')) |
|
} |
|
|
|
def __init__(self, definition): |
|
self.definition = definition.strip() |
|
self.pos = 0 |
|
self.end = len(self.definition) |
|
self.last_match = None |
|
self._previous_state = (0, None) |
|
|
|
def fail(self, msg): |
|
raise DefinitionError('Invalid definition: %s [error at %d]\n %s' % |
|
(msg, self.pos, self.definition)) |
|
|
|
def match(self, regex): |
|
match = regex.match(self.definition, self.pos) |
|
if match is not None: |
|
self._previous_state = (self.pos, self.last_match) |
|
self.pos = match.end() |
|
self.last_match = match |
|
return True |
|
return False |
|
|
|
def backout(self): |
|
self.pos, self.last_match = self._previous_state |
|
|
|
def skip_string(self, string): |
|
strlen = len(string) |
|
if self.definition[self.pos:self.pos + strlen] == string: |
|
self.pos += strlen |
|
return True |
|
return False |
|
|
|
def skip_word(self, word): |
|
return self.match(re.compile(r'\b%s\b' % re.escape(word))) |
|
|
|
def skip_ws(self): |
|
return self.match(_whitespace_re) |
|
|
|
@property |
|
def eof(self): |
|
return self.pos >= self.end |
|
|
|
@property |
|
def current_char(self): |
|
try: |
|
return self.definition[self.pos] |
|
except IndexError: |
|
return 'EOF' |
|
|
|
@property |
|
def matched_text(self): |
|
if self.last_match is not None: |
|
return self.last_match.group() |
|
|
|
def _parse_operator(self): |
|
self.skip_ws() |
|
# thank god, a regular operator definition |
|
if self.match(_operator_re): |
|
return NameDefExpr('operator' + |
|
_whitespace_re.sub('', self.matched_text)) |
|
# new/delete operator? |
|
for allocop in 'new', 'delete': |
|
if not self.skip_word(allocop): |
|
continue |
|
self.skip_ws() |
|
if self.skip_string('['): |
|
self.skip_ws() |
|
if not self.skip_string(']'): |
|
self.fail('expected "]" for ' + allocop) |
|
allocop += '[]' |
|
return NameDefExpr('operator ' + allocop) |
|
|
|
# oh well, looks like a cast operator definition. |
|
# In that case, eat another type. |
|
type = self._parse_type() |
|
return CastOpDefExpr(type) |
|
|
|
def _parse_name(self): |
|
if not self.match(_argument_name_re): |
|
self.fail('expected name') |
|
identifier = self.matched_text |
|
|
|
# strictly speaking, operators are not regular identifiers |
|
# but because operator is a keyword, it might not be used |
|
# for variable names anyways, so we can safely parse the |
|
# operator here as identifier |
|
if identifier == 'operator': |
|
return self._parse_operator() |
|
|
|
return NameDefExpr(identifier) |
|
|
|
def _guess_typename(self, path): |
|
if not path: |
|
return [], 'int' |
|
# for the long type, we don't want the int in there |
|
if 'long' in path: |
|
path = [x for x in path if x != 'int'] |
|
# remove one long |
|
path.remove('long') |
|
return path, 'long' |
|
if path[-1] in ('int', 'char'): |
|
return path[:-1], path[-1] |
|
return path, 'int' |
|
|
|
def _attach_crefptr(self, expr, is_const=False): |
|
if is_const: |
|
expr = ConstDefExpr(expr, prefix=True) |
|
while 1: |
|
self.skip_ws() |
|
if self.skip_word('const'): |
|
expr = ConstDefExpr(expr) |
|
elif self.skip_string('*'): |
|
expr = PtrDefExpr(expr) |
|
elif self.skip_string('&'): |
|
expr = RefDefExpr(expr) |
|
else: |
|
return expr |
|
|
|
def _peek_const(self, path): |
|
try: |
|
path.remove('const') |
|
return True |
|
except ValueError: |
|
return False |
|
|
|
def _parse_builtin(self, modifier): |
|
path = [modifier] |
|
following = self._modifiers[modifier] |
|
while 1: |
|
self.skip_ws() |
|
if not self.match(_identifier_re): |
|
break |
|
identifier = self.matched_text |
|
if identifier in following: |
|
path.append(identifier) |
|
following = self._modifiers[modifier] |
|
assert following |
|
else: |
|
self.backout() |
|
break |
|
|
|
is_const = self._peek_const(path) |
|
modifiers, typename = self._guess_typename(path) |
|
rv = ModifierDefExpr(NameDefExpr(typename), modifiers) |
|
return self._attach_crefptr(rv, is_const) |
|
|
|
def _parse_type_expr(self): |
|
typename = self._parse_name() |
|
if typename and self.skip_string('['): |
|
typename.name += '[' |
|
if self.match(re.compile(r'\d*')): |
|
typename.name += self.last_match.group(0) |
|
typename.name += ']' |
|
if not self.skip_string(']'): |
|
self.fail('expected type') |
|
self.skip_ws() |
|
if not self.skip_string('<'): |
|
return typename |
|
|
|
args = [] |
|
while 1: |
|
self.skip_ws() |
|
if self.skip_string('>'): |
|
break |
|
if args: |
|
if not self.skip_string(','): |
|
self.fail('"," or ">" in template expected') |
|
self.skip_ws() |
|
args.append(self._parse_type(True)) |
|
return TemplateDefExpr(typename, args) |
|
|
|
def _parse_type(self, in_template=False): |
|
self.skip_ws() |
|
result = [] |
|
modifiers = [] |
|
|
|
if self.match(re.compile(r'template\w*<([^>]*)>')): |
|
args = self.last_match.group(1).split(',') |
|
args = [a.strip() for a in args] |
|
modifiers.append(TemplateDefExpr('template', args)) |
|
|
|
# if there is a leading :: or not, we don't care because we |
|
# treat them exactly the same. Buf *if* there is one, we |
|
# don't have to check for type modifiers |
|
if not self.skip_string('::'): |
|
self.skip_ws() |
|
while self.match(_identifier_re): |
|
modifier = self.matched_text |
|
if modifier in self._modifiers: |
|
following = self._modifiers[modifier] |
|
# if the set is not none, there is a limited set |
|
# of types that might follow. It is technically |
|
# impossible for a template to follow, so what |
|
# we do is go to a different function that just |
|
# eats types |
|
if following is not None: |
|
return self._parse_builtin(modifier) |
|
modifiers.append(modifier) |
|
else: |
|
self.backout() |
|
break |
|
|
|
while 1: |
|
self.skip_ws() |
|
if (in_template and self.current_char in ',>') or \ |
|
(result and not self.skip_string('::')) or \ |
|
self.eof: |
|
break |
|
result.append(self._parse_type_expr()) |
|
|
|
if not result: |
|
self.fail('expected type') |
|
if len(result) == 1: |
|
rv = result[0] |
|
else: |
|
rv = PathDefExpr(result) |
|
is_const = self._peek_const(modifiers) |
|
if is_const: |
|
rv = ConstDefExpr(rv, prefix=True) |
|
if modifiers: |
|
rv = ModifierDefExpr(rv, modifiers) |
|
return self._attach_crefptr(rv, False) |
|
|
|
def _parse_default_expr(self): |
|
self.skip_ws() |
|
if self.match(_string_re): |
|
return self.matched_text |
|
paren_stack_depth = 0 |
|
max_pos = len(self.definition) |
|
rv_start = self.pos |
|
while 1: |
|
idx0 = self.definition.find('(', self.pos) |
|
idx1 = self.definition.find(',', self.pos) |
|
idx2 = self.definition.find(')', self.pos) |
|
if idx0 < 0: |
|
idx0 = max_pos |
|
if idx1 < 0: |
|
idx1 = max_pos |
|
if idx2 < 0: |
|
idx2 = max_pos |
|
idx = min(idx0, idx1, idx2) |
|
if idx >= max_pos: |
|
self.fail('unexpected end in default expression') |
|
if idx == idx0: |
|
paren_stack_depth += 1 |
|
elif idx == idx2: |
|
paren_stack_depth -= 1 |
|
if paren_stack_depth < 0: |
|
break |
|
elif paren_stack_depth == 0: |
|
break |
|
self.pos = idx+1 |
|
|
|
rv = self.definition[rv_start:idx] |
|
self.pos = idx |
|
return rv |
|
|
|
def _parse_signature(self): |
|
if r'CvStatModel::train' in self.definition: |
|
# hack to skip parsing of problematic definition |
|
self.pos = self.end |
|
return [ArgumentDefExpr("const Mat&", "train_data", None), ArgumentDefExpr(None, self.definition[self.definition.find("["):-1], None)], False, True |
|
|
|
self.skip_ws() |
|
if not self.skip_string('('): |
|
self.fail('expected parentheses for function') |
|
|
|
args = [] |
|
while 1: |
|
self.skip_ws() |
|
if self.eof: |
|
self.fail('missing closing parentheses') |
|
if self.skip_string(')'): |
|
break |
|
if args: |
|
if not self.skip_string(','): |
|
self.fail('expected comma between arguments') |
|
self.skip_ws() |
|
|
|
argtype = self._parse_type() |
|
self.skip_ws() |
|
if unicode(argtype) == u"...": |
|
if not self.skip_string(')'): |
|
self.fail("var arg must be the last argument") |
|
args.append(ArgumentDefExpr(None, argtype, None)) |
|
break |
|
argname = default = None |
|
if self.skip_string('='): |
|
self.pos += 1 |
|
default = self._parse_default_expr() |
|
elif self.current_char not in ',)': |
|
argname = self._parse_name() |
|
self.skip_ws() |
|
if self.skip_string('='): |
|
default = self._parse_default_expr() |
|
|
|
args.append(ArgumentDefExpr(argtype, argname, default)) |
|
self.skip_ws() |
|
const = self.skip_word('const') |
|
if const: |
|
self.skip_ws() |
|
if self.skip_string('='): |
|
self.skip_ws() |
|
if not (self.skip_string('0') or \ |
|
self.skip_word('NULL') or \ |
|
self.skip_word('nullptr')): |
|
self.fail('pure virtual functions must be defined with ' |
|
'either 0, NULL or nullptr, other macros are ' |
|
'not allowed') |
|
pure_virtual = True |
|
else: |
|
pure_virtual = False |
|
return args, const, pure_virtual |
|
|
|
def _parse_visibility_static(self): |
|
visibility = 'public' |
|
if self.match(_visibility_re): |
|
visibility = self.matched_text |
|
static = self.skip_word('static') |
|
return visibility, static |
|
|
|
def parse_type(self): |
|
return self._parse_type() |
|
|
|
def parse_type_object(self): |
|
visibility, static = self._parse_visibility_static() |
|
typename = self._parse_type() |
|
self.skip_ws() |
|
if not self.eof: |
|
name = self._parse_type() |
|
else: |
|
name = typename |
|
typename = None |
|
return TypeObjDefExpr(name, visibility, static, typename) |
|
|
|
def parse_member_object(self): |
|
visibility, static = self._parse_visibility_static() |
|
typename = self._parse_type() |
|
name = self._parse_type() |
|
self.skip_ws() |
|
if self.skip_string('='): |
|
value = self.read_rest().strip() |
|
else: |
|
value = None |
|
return MemberObjDefExpr(name, visibility, static, typename, value) |
|
|
|
def parse_enum_member_object(self): |
|
visibility, static = self._parse_visibility_static() |
|
typename = None |
|
name = self._parse_type() |
|
self.skip_ws() |
|
if self.skip_string('='): |
|
value = self.read_rest().strip() |
|
else: |
|
value = None |
|
return MemberObjDefExpr(name, visibility, static, typename, value) |
|
|
|
def parse_function(self): |
|
visibility, static = self._parse_visibility_static() |
|
if self.skip_word('explicit'): |
|
explicit = True |
|
self.skip_ws() |
|
else: |
|
explicit = False |
|
if self.skip_word('virtual'): |
|
virtual = True |
|
self.skip_ws() |
|
else: |
|
virtual = False |
|
rv = self._parse_type() |
|
self.skip_ws() |
|
# some things just don't have return values |
|
if self.current_char == '(': |
|
name = rv |
|
rv = None |
|
else: |
|
name = self._parse_type() |
|
return FuncDefExpr(name, visibility, static, explicit, rv, |
|
*self._parse_signature(), virtual = virtual) |
|
|
|
def parse_class(self): |
|
visibility, static = self._parse_visibility_static() |
|
typename = self._parse_type() |
|
parent = None |
|
self.skip_ws() |
|
parents = [] |
|
if self.skip_string(':'): |
|
while not self.eof: |
|
self.skip_ws() |
|
classname_pos = self.pos |
|
pvisibility, pstatic = self._parse_visibility_static() |
|
if pstatic: |
|
self.fail('unsepected static keyword, got %r' % |
|
self.definition[self.classname_pos:]) |
|
parents.append(ClassDefExpr(self._parse_type(), pvisibility, pstatic)) |
|
if not self.skip_string(','): |
|
break |
|
return ClassDefExpr(typename, visibility, static, parents) |
|
|
|
def read_rest(self): |
|
rv = self.definition[self.pos:] |
|
self.pos = self.end |
|
return rv |
|
|
|
def assert_end(self): |
|
self.skip_ws() |
|
if not self.eof: |
|
self.fail('expected end of definition, got %r' % |
|
self.definition[self.pos:]) |
|
|
|
|
|
class OCVObject(ObjectDescription): |
|
"""Description of a C++ language object.""" |
|
|
|
langname = "C++" |
|
ismember = False |
|
|
|
doc_field_types = [ |
|
TypedField('parameter', label=l_('Parameters'), |
|
names=('param', 'parameter', 'arg', 'argument'), |
|
typerolename='type', typenames=('type',)), |
|
Field('returnvalue', label=l_('Returns'), has_arg=False, |
|
names=('returns', 'return')), |
|
Field('returntype', label=l_('Return type'), has_arg=False, |
|
names=('rtype',)), |
|
] |
|
|
|
def attach_name(self, node, name): |
|
owner, name = name.split_owner() |
|
varname = unicode(name) |
|
if owner is not None: |
|
owner = unicode(owner) + '::' |
|
node += addnodes.desc_addname(owner, owner) |
|
node += addnodes.desc_name(varname, varname) |
|
|
|
def attach_type(self, node, type): |
|
# XXX: link to c? |
|
text = unicode(type) |
|
pnode = addnodes.pending_xref( |
|
'', refdomain='ocv', reftype='type', |
|
reftarget=text, modname=None, classname=None) |
|
pnode['ocv:parent'] = self.env.temp_data.get('ocv:parent') |
|
pnode += nodes.Text(text) |
|
node += pnode |
|
|
|
def attach_modifiers(self, node, obj): |
|
if not self.__class__.ismember: |
|
lname = self.__class__.langname |
|
node += nodes.strong(lname + ":", lname + ":") |
|
node += addnodes.desc_name(" ", " ") |
|
|
|
if obj.visibility != 'public': |
|
node += addnodes.desc_annotation(obj.visibility, |
|
obj.visibility) |
|
node += nodes.Text(' ') |
|
if obj.static: |
|
node += addnodes.desc_annotation('static', 'static') |
|
node += nodes.Text(' ') |
|
|
|
def add_target_and_index(self, sigobj, sig, signode): |
|
theid = sig#obj.get_id() |
|
theid = re.sub(r" +", " ", theid) |
|
if self.objtype == 'emember': |
|
theid = re.sub(r" ?=.*", "", theid) |
|
theid = re.sub(r"=[^,()]+\([^)]*?\)[^,)]*(,|\))", "\\1", theid) |
|
theid = re.sub(r"=\w*[^,)(]+(,|\))", "\\1", theid) |
|
theid = theid.replace("( ", "(").replace(" )", ")") |
|
name = unicode(sigobj.name) |
|
if theid not in self.state.document.ids: |
|
signode['names'].append(theid) |
|
signode['ids'].append(theid) |
|
signode['first'] = (not self.names) |
|
self.state.document.note_explicit_target(signode) |
|
|
|
#self.env.domaindata['ocv']['objects'].setdefault(name, |
|
#(self.env.docname, self.objtype, theid)) |
|
self.env.domaindata['ocv']['objects'].setdefault(theid, |
|
(self.env.docname, self.objtype, theid)) |
|
self.env.domaindata['ocv']['objects2'].setdefault(name, |
|
(self.env.docname, self.objtype, theid)) |
|
|
|
indextext = self.get_index_text(name) |
|
if indextext: |
|
self.indexnode['entries'].append(('single', indextext, theid, name)) |
|
|
|
def before_content(self): |
|
lastname = self.names and self.names[-1] |
|
if lastname and not self.env.temp_data.get('ocv:parent'): |
|
assert isinstance(lastname, NamedDefExpr) |
|
self.env.temp_data['ocv:parent'] = lastname.name |
|
self.parentname_set = True |
|
else: |
|
self.parentname_set = False |
|
|
|
def after_content(self): |
|
if self.parentname_set: |
|
self.env.temp_data['ocv:parent'] = None |
|
|
|
def parse_definition(self, parser): |
|
raise NotImplementedError() |
|
|
|
def describe_signature(self, signode, arg): |
|
raise NotImplementedError() |
|
|
|
def handle_signature(self, sig, signode): |
|
parser = DefinitionParser(sig) |
|
try: |
|
rv = self.parse_definition(parser) |
|
parser.assert_end() |
|
except DefinitionError, e: |
|
self.env.warn(self.env.docname, |
|
e.description, self.lineno) |
|
raise ValueError |
|
self.describe_signature(signode, rv) |
|
|
|
parent = self.env.temp_data.get('ocv:parent') |
|
if parent is not None: |
|
rv = rv.clone() |
|
rv.name = rv.name.prefix(parent) |
|
return rv |
|
|
|
|
|
class OCVClassObject(OCVObject): |
|
object_annotation = "class " |
|
object_long_name = "class" |
|
|
|
def attach_modifiers(self, node, obj, skip_visibility = 'public'): |
|
if obj.visibility != skip_visibility: |
|
node += addnodes.desc_annotation(obj.visibility, |
|
obj.visibility) |
|
node += nodes.Text(' ') |
|
if obj.static: |
|
node += addnodes.desc_annotation('static', 'static') |
|
node += nodes.Text(' ') |
|
|
|
def get_index_text(self, name): |
|
return _('%s (C++ %s)') % (name, self.__class__.object_long_name) |
|
|
|
def parse_definition(self, parser): |
|
return parser.parse_class() |
|
|
|
def describe_signature(self, signode, cls): |
|
self.attach_modifiers(signode, cls) |
|
signode += addnodes.desc_annotation(self.__class__.object_annotation, self.__class__.object_annotation) |
|
self.attach_name(signode, cls.name) |
|
first_parent = True |
|
for p in cls.parents: |
|
if first_parent: |
|
signode += nodes.Text(' : ') |
|
first_parent = False |
|
else: |
|
signode += nodes.Text(', ') |
|
self.attach_modifiers(signode, p, None) |
|
self.attach_name(signode, p.name) |
|
|
|
class OCVStructObject(OCVClassObject): |
|
object_annotation = "struct " |
|
object_long_name = "structure" |
|
|
|
class OCVTypeObject(OCVObject): |
|
|
|
def get_index_text(self, name): |
|
if self.objtype == 'type': |
|
return _('%s (C++ type)') % name |
|
return '' |
|
|
|
def parse_definition(self, parser): |
|
return parser.parse_type_object() |
|
|
|
def describe_signature(self, signode, obj): |
|
self.attach_modifiers(signode, obj) |
|
signode += addnodes.desc_annotation('type ', 'type ') |
|
if obj.typename is not None: |
|
self.attach_type(signode, obj.typename) |
|
signode += nodes.Text(' ') |
|
self.attach_name(signode, obj.name) |
|
|
|
class OCVEnumObject(OCVObject): |
|
|
|
def get_index_text(self, name): |
|
if self.objtype == 'enum': |
|
return _('%s (enum)') % name |
|
return '' |
|
|
|
def parse_definition(self, parser): |
|
return parser.parse_type_object() |
|
|
|
def describe_signature(self, signode, obj): |
|
self.attach_modifiers(signode, obj) |
|
signode += addnodes.desc_annotation('enum ', 'enum ') |
|
if obj.typename is not None: |
|
self.attach_type(signode, obj.typename) |
|
signode += nodes.Text(' ') |
|
self.attach_name(signode, obj.name) |
|
|
|
|
|
class OCVMemberObject(OCVObject): |
|
ismember = True |
|
|
|
def get_index_text(self, name): |
|
if self.objtype == 'member': |
|
return _('%s (C++ member)') % name |
|
return '' |
|
|
|
def parse_definition(self, parser): |
|
parent_class = self.env.temp_data.get('ocv:parent') |
|
if parent_class is None: |
|
parser.fail("missing parent structure/class") |
|
return parser.parse_member_object() |
|
|
|
def describe_signature(self, signode, obj): |
|
self.attach_modifiers(signode, obj) |
|
if obj.typename: |
|
self.attach_type(signode, obj.typename) |
|
signode += nodes.Text(' ') |
|
self.attach_name(signode, obj.name) |
|
if obj.value is not None: |
|
signode += nodes.Text(u' = ' + obj.value) |
|
|
|
class OCVEnumMemberObject(OCVMemberObject): |
|
def parse_definition(self, parser): |
|
# parent_class = self.env.temp_data.get('ocv:parent') |
|
# if parent_class is None: |
|
# parser.fail("missing parent structure/class") |
|
return parser.parse_enum_member_object() |
|
|
|
class OCVFunctionObject(OCVObject): |
|
|
|
def attach_function(self, node, func): |
|
owner, name = func.name.split_owner() |
|
if owner is not None: |
|
owner = unicode(owner) + '::' |
|
node += addnodes.desc_addname(owner, owner) |
|
|
|
# cast operator is special. in this case the return value |
|
# is reversed. |
|
if isinstance(name, CastOpDefExpr): |
|
node += addnodes.desc_name('operator', 'operator') |
|
node += nodes.Text(u' ') |
|
self.attach_type(node, name.typename) |
|
else: |
|
funcname = unicode(name) |
|
node += addnodes.desc_name(funcname, funcname) |
|
|
|
paramlist = addnodes.desc_parameterlist() |
|
for arg in func.signature: |
|
param = addnodes.desc_parameter('', '', noemph=True) |
|
if arg.type is not None: |
|
self.attach_type(param, arg.type) |
|
param += nodes.Text(u' ') |
|
#param += nodes.emphasis(unicode(arg.name), unicode(arg.name)) |
|
sbrIdx = unicode(arg.name).find("[") |
|
if sbrIdx < 0: |
|
param += nodes.strong(unicode(arg.name), unicode(arg.name)) |
|
else: |
|
param += nodes.strong(unicode(arg.name)[:sbrIdx], unicode(arg.name)[:sbrIdx]) |
|
param += nodes.Text(unicode(arg.name)[sbrIdx:]) |
|
if arg.default is not None: |
|
def_ = u'=' + unicode(arg.default) |
|
#param += nodes.emphasis(def_, def_) |
|
param += nodes.Text(def_) |
|
paramlist += param |
|
|
|
node += paramlist |
|
if func.const: |
|
node += addnodes.desc_addname(' const', ' const') |
|
if func.pure_virtual: |
|
node += addnodes.desc_addname(' = 0', ' = 0') |
|
|
|
def get_index_text(self, name): |
|
lname = self.__class__.langname |
|
if lname == "C" and name.startswith("cv"): |
|
name = name[2:] |
|
return _('%s (%s function)') % (name, lname) |
|
|
|
def parse_definition(self, parser): |
|
return parser.parse_function() |
|
|
|
def describe_signature(self, signode, func): |
|
self.attach_modifiers(signode, func) |
|
if func.explicit: |
|
signode += addnodes.desc_annotation('explicit', 'explicit') |
|
signode += nodes.Text(' ') |
|
if func.virtual: |
|
signode += addnodes.desc_annotation('virtual', 'virtual') |
|
signode += nodes.Text(' ') |
|
# return value is None for things with a reverse return value |
|
# such as casting operator definitions or constructors |
|
# and destructors. |
|
if func.rv is not None: |
|
self.attach_type(signode, func.rv) |
|
signode += nodes.Text(u' ') |
|
self.attach_function(signode, func) |
|
|
|
|
|
class OCVCurrentNamespace(Directive): |
|
"""This directive is just to tell Sphinx that we're documenting |
|
stuff in namespace foo. |
|
""" |
|
|
|
has_content = False |
|
required_arguments = 1 |
|
optional_arguments = 0 |
|
final_argument_whitespace = True |
|
option_spec = {} |
|
|
|
def run(self): |
|
env = self.state.document.settings.env |
|
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): |
|
env.temp_data['ocv:prefix'] = None |
|
else: |
|
parser = DefinitionParser(self.arguments[0]) |
|
try: |
|
prefix = parser.parse_type() |
|
parser.assert_end() |
|
except DefinitionError, e: |
|
self.env.warn(self.env.docname, |
|
e.description, self.lineno) |
|
else: |
|
env.temp_data['ocv:prefix'] = prefix |
|
return [] |
|
|
|
|
|
class OCVXRefRole(XRefRole): |
|
|
|
def process_link(self, env, refnode, has_explicit_title, title, target): |
|
refnode['ocv:parent'] = env.temp_data.get('ocv:parent') |
|
if not has_explicit_title: |
|
target = target.lstrip('~') # only has a meaning for the title |
|
# if the first character is a tilde, don't display the module/class |
|
# parts of the contents |
|
if title[:1] == '~': |
|
title = title[1:] |
|
dcolon = title.rfind('::') |
|
if dcolon != -1: |
|
title = title[dcolon + 2:] |
|
return title, target |
|
|
|
|
|
class OCVCFunctionObject(OCVFunctionObject): |
|
langname = "C" |
|
|
|
class OCVJavaFunctionObject(OCVFunctionObject): |
|
langname = "Java" |
|
|
|
|
|
class OCVDomain(Domain): |
|
"""OpenCV C++ language domain.""" |
|
name = 'ocv' |
|
label = 'C++' |
|
object_types = { |
|
'class': ObjType(l_('class'), 'class'), |
|
'struct': ObjType(l_('struct'), 'struct'), |
|
'function': ObjType(l_('function'), 'func', 'funcx'), |
|
'cfunction': ObjType(l_('cfunction'), 'cfunc', 'cfuncx'), |
|
'jfunction': ObjType(l_('jfunction'), 'jfunc', 'jfuncx'), |
|
'pyfunction': ObjType(l_('pyfunction'), 'pyfunc'), |
|
'pyoldfunction': ObjType(l_('pyoldfunction'), 'pyoldfunc'), |
|
'member': ObjType(l_('member'), 'member'), |
|
'emember': ObjType(l_('emember'), 'emember'), |
|
'type': ObjType(l_('type'), 'type'), |
|
'enum': ObjType(l_('enum'), 'enum') |
|
} |
|
|
|
directives = { |
|
'class': OCVClassObject, |
|
'struct': OCVStructObject, |
|
'function': OCVFunctionObject, |
|
'cfunction': OCVCFunctionObject, |
|
'jfunction': OCVJavaFunctionObject, |
|
'pyfunction': OCVPyModulelevel, |
|
'pyoldfunction': OCVPyOldModulelevel, |
|
'member': OCVMemberObject, |
|
'emember': OCVEnumMemberObject, |
|
'type': OCVTypeObject, |
|
'enum': OCVEnumObject, |
|
'namespace': OCVCurrentNamespace |
|
} |
|
roles = { |
|
'class': OCVXRefRole(), |
|
'struct': OCVXRefRole(), |
|
'func' : OCVXRefRole(fix_parens=True), |
|
'funcx' : OCVXRefRole(), |
|
'cfunc' : OCVXRefRole(fix_parens=True), |
|
'cfuncx' : OCVXRefRole(), |
|
'jfunc' : OCVXRefRole(fix_parens=True), |
|
'jfuncx' : OCVXRefRole(), |
|
'pyfunc' : OCVPyXRefRole(), |
|
'pyoldfunc' : OCVPyXRefRole(), |
|
'member': OCVXRefRole(), |
|
'emember': OCVXRefRole(), |
|
'type': OCVXRefRole(), |
|
'enum': OCVXRefRole() |
|
} |
|
initial_data = { |
|
'objects': {}, # fullname -> docname, objtype |
|
} |
|
|
|
def __init__(self, env): |
|
Domain.__init__(self, env) |
|
self.data['objects2'] = {} |
|
|
|
def clear_doc(self, docname): |
|
for fullname, (fn, _, _) in self.data['objects'].items(): |
|
if fn == docname: |
|
del self.data['objects'][fullname] |
|
|
|
def resolve_xref(self, env, fromdocname, builder, |
|
typ, target, node, contnode): |
|
def _create_refnode(expr): |
|
name = unicode(expr) |
|
if "type" in self.objtypes_for_role(typ): |
|
return None |
|
if "cfunction" in self.objtypes_for_role(typ): |
|
if not name.startswith(u'cv'): |
|
name = u'cv' + name |
|
dict = self.data['objects'] |
|
if name not in dict: |
|
dict = self.data['objects2'] |
|
if name not in dict: |
|
refdoc = node.get('refdoc', fromdocname) |
|
env.warn(refdoc, 'unresolved reference: %r - %r' % (target, typ), node.line) |
|
return None |
|
obj = dict[name] |
|
if obj[1] not in self.objtypes_for_role(typ): |
|
return None |
|
title = obj[2] |
|
if "class" in self.objtypes_for_role(typ): |
|
title = u"class " + title |
|
elif "struct" in self.objtypes_for_role(typ): |
|
title = u"struct " + title |
|
return make_refnode(builder, fromdocname, obj[0], obj[2], |
|
contnode, title) |
|
|
|
parser = DefinitionParser(target) |
|
try: |
|
expr = parser.parse_type().get_name() |
|
parser.skip_ws() |
|
if not parser.eof or expr is None: |
|
raise DefinitionError('') |
|
except DefinitionError: |
|
refdoc = node.get('refdoc', fromdocname) |
|
env.warn(refdoc, 'unparseable C++ definition: %r' % target, |
|
node.line) |
|
return None |
|
|
|
parent = node['ocv:parent'] |
|
|
|
rv = _create_refnode(expr) |
|
if rv is not None or parent is None: |
|
return rv |
|
parent = parent.get_name() |
|
|
|
rv = _create_refnode(expr.prefix(parent)) |
|
if rv is not None: |
|
return rv |
|
|
|
parent, name = parent.split_owner() |
|
return _create_refnode(expr.prefix(parent)) |
|
|
|
def get_objects(self): |
|
for refname, (docname, type, theid) in self.data['objects'].iteritems(): |
|
yield (refname, refname, type, docname, refname, 1) |
|
|
|
def get_type_name(self, type, primary=False): |
|
""" |
|
Return full name for given ObjType. |
|
""" |
|
if primary: |
|
return type.lname |
|
|
|
return { |
|
'class': _('C++ class'), |
|
'struct': _('C/C++ struct'), |
|
'function': _('C++ function'), |
|
'cfunction': _('C function'), |
|
'jfunction': _('Java method'), |
|
'pyfunction': _('Python function'), |
|
'pyoldfunction': _('Legacy Python function'), |
|
'member': _('C++ member'), |
|
'emember': _('enum member'), |
|
'type': _('C/C++ type'), |
|
'enum': _('C/C++ enum'), |
|
'namespace': _('C++ namespace'), |
|
}.get(type.lname, _('%s %s') % (self.label, type.lname)) |
|
|
|
def setup(app): |
|
app.add_domain(OCVDomain)
|
|
|