OLD | NEW |
(Empty) | |
| 1 from Cython.Compiler.Visitor import CythonTransform |
| 2 from Cython.Compiler.StringEncoding import EncodedString |
| 3 from Cython.Compiler import Options |
| 4 from Cython.Compiler import PyrexTypes, ExprNodes |
| 5 |
| 6 class EmbedSignature(CythonTransform): |
| 7 |
| 8 def __init__(self, context): |
| 9 super(EmbedSignature, self).__init__(context) |
| 10 self.denv = None # XXX |
| 11 self.class_name = None |
| 12 self.class_node = None |
| 13 |
| 14 unop_precedence = 11 |
| 15 binop_precedence = { |
| 16 'or': 1, |
| 17 'and': 2, |
| 18 'not': 3, |
| 19 'in': 4, 'not in': 4, 'is': 4, 'is not': 4, '<': 4, '<=': 4, '>': 4, '>=
': 4, '!=': 4, '==': 4, |
| 20 '|': 5, |
| 21 '^': 6, |
| 22 '&': 7, |
| 23 '<<': 8, '>>': 8, |
| 24 '+': 9, '-': 9, |
| 25 '*': 10, '/': 10, '//': 10, '%': 10, |
| 26 # unary: '+': 11, '-': 11, '~': 11 |
| 27 '**': 12} |
| 28 |
| 29 def _fmt_expr_node(self, node, precedence=0): |
| 30 if isinstance(node, ExprNodes.BinopNode) and not node.inplace: |
| 31 new_prec = self.binop_precedence.get(node.operator, 0) |
| 32 result = '%s %s %s' % (self._fmt_expr_node(node.operand1, new_prec), |
| 33 node.operator, |
| 34 self._fmt_expr_node(node.operand2, new_prec)) |
| 35 if precedence > new_prec: |
| 36 result = '(%s)' % result |
| 37 elif isinstance(node, ExprNodes.UnopNode): |
| 38 result = '%s%s' % (node.operator, |
| 39 self._fmt_expr_node(node.operand, self.unop_prece
dence)) |
| 40 if precedence > self.unop_precedence: |
| 41 result = '(%s)' % result |
| 42 elif isinstance(node, ExprNodes.AttributeNode): |
| 43 result = '%s.%s' % (self._fmt_expr_node(node.obj), node.attribute) |
| 44 else: |
| 45 result = node.name |
| 46 return result |
| 47 |
| 48 def _fmt_arg_defv(self, arg): |
| 49 default_val = arg.default |
| 50 if not default_val: |
| 51 return None |
| 52 try: |
| 53 denv = self.denv # XXX |
| 54 ctval = default_val.compile_time_value(self.denv) |
| 55 repr_val = repr(ctval) |
| 56 if isinstance(default_val, ExprNodes.UnicodeNode): |
| 57 if repr_val[:1] != 'u': |
| 58 return u'u%s' % repr_val |
| 59 elif isinstance(default_val, ExprNodes.BytesNode): |
| 60 if repr_val[:1] != 'b': |
| 61 return u'b%s' % repr_val |
| 62 elif isinstance(default_val, ExprNodes.StringNode): |
| 63 if repr_val[:1] in 'ub': |
| 64 return repr_val[1:] |
| 65 return repr_val |
| 66 except Exception: |
| 67 try: |
| 68 return self._fmt_expr_node(default_val) |
| 69 except AttributeError, e: |
| 70 return '<???>' |
| 71 |
| 72 def _fmt_arg(self, arg): |
| 73 if arg.type is PyrexTypes.py_object_type or arg.is_self_arg: |
| 74 doc = arg.name |
| 75 else: |
| 76 doc = arg.type.declaration_code(arg.name, for_display=1) |
| 77 if arg.default: |
| 78 arg_defv = self._fmt_arg_defv(arg) |
| 79 if arg_defv: |
| 80 doc = doc + ('=%s' % arg_defv) |
| 81 return doc |
| 82 |
| 83 def _fmt_arglist(self, args, |
| 84 npargs=0, pargs=None, |
| 85 nkargs=0, kargs=None, |
| 86 hide_self=False): |
| 87 arglist = [] |
| 88 for arg in args: |
| 89 if not hide_self or not arg.entry.is_self_arg: |
| 90 arg_doc = self._fmt_arg(arg) |
| 91 arglist.append(arg_doc) |
| 92 if pargs: |
| 93 arglist.insert(npargs, '*%s' % pargs.name) |
| 94 elif nkargs: |
| 95 arglist.insert(npargs, '*') |
| 96 if kargs: |
| 97 arglist.append('**%s' % kargs.name) |
| 98 return arglist |
| 99 |
| 100 def _fmt_ret_type(self, ret): |
| 101 if ret is PyrexTypes.py_object_type: |
| 102 return None |
| 103 else: |
| 104 return ret.declaration_code("", for_display=1) |
| 105 |
| 106 def _fmt_signature(self, cls_name, func_name, args, |
| 107 npargs=0, pargs=None, |
| 108 nkargs=0, kargs=None, |
| 109 return_type=None, hide_self=False): |
| 110 arglist = self._fmt_arglist(args, |
| 111 npargs, pargs, |
| 112 nkargs, kargs, |
| 113 hide_self=hide_self) |
| 114 arglist_doc = ', '.join(arglist) |
| 115 func_doc = '%s(%s)' % (func_name, arglist_doc) |
| 116 if cls_name: |
| 117 func_doc = '%s.%s' % (cls_name, func_doc) |
| 118 if return_type: |
| 119 ret_doc = self._fmt_ret_type(return_type) |
| 120 if ret_doc: |
| 121 func_doc = '%s -> %s' % (func_doc, ret_doc) |
| 122 return func_doc |
| 123 |
| 124 def _embed_signature(self, signature, node_doc): |
| 125 if node_doc: |
| 126 return "%s\n%s" % (signature, node_doc) |
| 127 else: |
| 128 return signature |
| 129 |
| 130 def __call__(self, node): |
| 131 if not Options.docstrings: |
| 132 return node |
| 133 else: |
| 134 return super(EmbedSignature, self).__call__(node) |
| 135 |
| 136 def visit_ClassDefNode(self, node): |
| 137 oldname = self.class_name |
| 138 oldclass = self.class_node |
| 139 self.class_node = node |
| 140 try: |
| 141 # PyClassDefNode |
| 142 self.class_name = node.name |
| 143 except AttributeError: |
| 144 # CClassDefNode |
| 145 self.class_name = node.class_name |
| 146 self.visitchildren(node) |
| 147 self.class_name = oldname |
| 148 self.class_node = oldclass |
| 149 return node |
| 150 |
| 151 def visit_DefNode(self, node): |
| 152 if not self.current_directives['embedsignature']: |
| 153 return node |
| 154 |
| 155 is_constructor = False |
| 156 hide_self = False |
| 157 if node.entry.is_special: |
| 158 is_constructor = self.class_node and node.name == '__init__' |
| 159 if not is_constructor: |
| 160 return node |
| 161 class_name, func_name = None, self.class_name |
| 162 hide_self = True |
| 163 else: |
| 164 class_name, func_name = self.class_name, node.name |
| 165 |
| 166 nkargs = getattr(node, 'num_kwonly_args', 0) |
| 167 npargs = len(node.args) - nkargs |
| 168 signature = self._fmt_signature( |
| 169 class_name, func_name, node.args, |
| 170 npargs, node.star_arg, |
| 171 nkargs, node.starstar_arg, |
| 172 return_type=None, hide_self=hide_self) |
| 173 if signature: |
| 174 if is_constructor: |
| 175 doc_holder = self.class_node.entry.type.scope |
| 176 else: |
| 177 doc_holder = node.entry |
| 178 |
| 179 if doc_holder.doc is not None: |
| 180 old_doc = doc_holder.doc |
| 181 elif not is_constructor and getattr(node, 'py_func', None) is not No
ne: |
| 182 old_doc = node.py_func.entry.doc |
| 183 else: |
| 184 old_doc = None |
| 185 new_doc = self._embed_signature(signature, old_doc) |
| 186 doc_holder.doc = EncodedString(new_doc) |
| 187 if not is_constructor and getattr(node, 'py_func', None) is not None
: |
| 188 node.py_func.entry.doc = EncodedString(new_doc) |
| 189 return node |
| 190 |
| 191 def visit_CFuncDefNode(self, node): |
| 192 if not self.current_directives['embedsignature']: |
| 193 return node |
| 194 if not node.overridable: # not cpdef FOO(...): |
| 195 return node |
| 196 |
| 197 signature = self._fmt_signature( |
| 198 self.class_name, node.declarator.base.name, |
| 199 node.declarator.args, |
| 200 return_type=node.return_type) |
| 201 if signature: |
| 202 if node.entry.doc is not None: |
| 203 old_doc = node.entry.doc |
| 204 elif getattr(node, 'py_func', None) is not None: |
| 205 old_doc = node.py_func.entry.doc |
| 206 else: |
| 207 old_doc = None |
| 208 new_doc = self._embed_signature(signature, old_doc) |
| 209 node.entry.doc = EncodedString(new_doc) |
| 210 if hasattr(node, 'py_func') and node.py_func is not None: |
| 211 node.py_func.entry.doc = EncodedString(new_doc) |
| 212 return node |
| 213 |
| 214 def visit_PropertyNode(self, node): |
| 215 if not self.current_directives['embedsignature']: |
| 216 return node |
| 217 |
| 218 entry = node.entry |
| 219 if entry.visibility == 'public': |
| 220 # property synthesised from a cdef public attribute |
| 221 type_name = entry.type.declaration_code("", for_display=1) |
| 222 if not entry.type.is_pyobject: |
| 223 type_name = "'%s'" % type_name |
| 224 elif entry.type.is_extension_type: |
| 225 type_name = entry.type.module_name + '.' + type_name |
| 226 signature = '%s: %s' % (entry.name, type_name) |
| 227 new_doc = self._embed_signature(signature, entry.doc) |
| 228 entry.doc = EncodedString(new_doc) |
| 229 return node |
OLD | NEW |