cython

Форк
0
/
CodeWriter.py 
811 строк · 23.5 Кб
1
"""
2
Serializes a Cython code tree to Cython code. This is primarily useful for
3
debugging and testing purposes.
4
The output is in a strict format, no whitespace or comments from the input
5
is preserved (and it could not be as it is not present in the code tree).
6
"""
7

8

9
from .Compiler.Visitor import TreeVisitor
10
from .Compiler.ExprNodes import *
11
from .Compiler.Nodes import CSimpleBaseTypeNode
12

13

14
class LinesResult:
15
    def __init__(self):
16
        self.lines = []
17
        self.s = ""
18

19
    def put(self, s):
20
        self.s += s
21

22
    def newline(self):
23
        self.lines.append(self.s)
24
        self.s = ""
25

26
    def putline(self, s):
27
        self.put(s)
28
        self.newline()
29

30

31
class DeclarationWriter(TreeVisitor):
32
    """
33
    A Cython code writer that is limited to declarations nodes.
34
    """
35

36
    indent_string = "    "
37

38
    def __init__(self, result=None):
39
        super().__init__()
40
        if result is None:
41
            result = LinesResult()
42
        self.result = result
43
        self.numindents = 0
44
        self.tempnames = {}
45
        self.tempblockindex = 0
46

47
    def write(self, tree):
48
        self.visit(tree)
49
        return self.result
50

51
    def indent(self):
52
        self.numindents += 1
53

54
    def dedent(self):
55
        self.numindents -= 1
56

57
    def startline(self, s=""):
58
        self.result.put(self.indent_string * self.numindents + s)
59

60
    def put(self, s):
61
        self.result.put(s)
62

63
    def putline(self, s):
64
        self.result.putline(self.indent_string * self.numindents + s)
65

66
    def endline(self, s=""):
67
        self.result.putline(s)
68

69
    def line(self, s):
70
        self.startline(s)
71
        self.endline()
72

73
    def comma_separated_list(self, items, output_rhs=False):
74
        if len(items) > 0:
75
            for item in items[:-1]:
76
                self.visit(item)
77
                if output_rhs and item.default is not None:
78
                    self.put(" = ")
79
                    self.visit(item.default)
80
                self.put(", ")
81
            self.visit(items[-1])
82
            if output_rhs and items[-1].default is not None:
83
                self.put(" = ")
84
                self.visit(items[-1].default)
85

86
    def _visit_indented(self, node):
87
        self.indent()
88
        self.visit(node)
89
        self.dedent()
90

91
    def visit_Node(self, node):
92
        raise AssertionError("Node not handled by serializer: %r" % node)
93

94
    def visit_ModuleNode(self, node):
95
        self.visitchildren(node)
96

97
    def visit_StatListNode(self, node):
98
        self.visitchildren(node)
99

100
    def visit_CDefExternNode(self, node):
101
        if node.include_file is None:
102
            file = '*'
103
        else:
104
            file = '"%s"' % node.include_file
105
        self.putline("cdef extern from %s:" % file)
106
        self._visit_indented(node.body)
107

108
    def visit_CPtrDeclaratorNode(self, node):
109
        self.put('*')
110
        self.visit(node.base)
111

112
    def visit_CReferenceDeclaratorNode(self, node):
113
        self.put('&')
114
        self.visit(node.base)
115

116
    def visit_CArrayDeclaratorNode(self, node):
117
        self.visit(node.base)
118
        self.put('[')
119
        if node.dimension is not None:
120
            self.visit(node.dimension)
121
        self.put(']')
122

123
    def visit_CFuncDeclaratorNode(self, node):
124
        # TODO: except, gil, etc.
125
        self.visit(node.base)
126
        self.put('(')
127
        self.comma_separated_list(node.args)
128
        self.endline(')')
129

130
    def visit_CNameDeclaratorNode(self, node):
131
        self.put(node.name)
132

133
    def visit_CSimpleBaseTypeNode(self, node):
134
        # See Parsing.p_sign_and_longness
135
        if node.is_basic_c_type:
136
            self.put(("unsigned ", "", "signed ")[node.signed])
137
            if node.longness < 0:
138
                self.put("short " * -node.longness)
139
            elif node.longness > 0:
140
                self.put("long " * node.longness)
141
        if node.name is not None:
142
            self.put(node.name)
143

144
    def visit_CComplexBaseTypeNode(self, node):
145
        self.visit(node.base_type)
146
        self.visit(node.declarator)
147

148
    def visit_CNestedBaseTypeNode(self, node):
149
        self.visit(node.base_type)
150
        self.put('.')
151
        self.put(node.name)
152

153
    def visit_TemplatedTypeNode(self, node):
154
        self.visit(node.base_type_node)
155
        self.put('[')
156
        self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs)
157
        self.put(']')
158

159
    def visit_CVarDefNode(self, node):
160
        self.startline("cdef ")
161
        self.visit(node.base_type)
162
        self.put(" ")
163
        self.comma_separated_list(node.declarators, output_rhs=True)
164
        self.endline()
165

166
    def _visit_container_node(self, node, decl, extras, attributes):
167
        # TODO: visibility
168
        self.startline(decl)
169
        if node.name:
170
            self.put(' ')
171
            self.put(node.name)
172
            if node.cname is not None:
173
                self.put(' "%s"' % node.cname)
174
        if extras:
175
            self.put(extras)
176
        self.endline(':')
177
        self.indent()
178
        if not attributes:
179
            self.putline('pass')
180
        else:
181
            for attribute in attributes:
182
                self.visit(attribute)
183
        self.dedent()
184

185
    def visit_CStructOrUnionDefNode(self, node):
186
        if node.typedef_flag:
187
            decl = 'ctypedef '
188
        else:
189
            decl = 'cdef '
190
        if node.visibility == 'public':
191
            decl += 'public '
192
        if node.packed:
193
            decl += 'packed '
194
        decl += node.kind
195
        self._visit_container_node(node, decl, None, node.attributes)
196

197
    def visit_CppClassNode(self, node):
198
        extras = ""
199
        if node.templates:
200
            extras = "[%s]" % ", ".join(node.templates)
201
        if node.base_classes:
202
            extras += "(%s)" % ", ".join(node.base_classes)
203
        self._visit_container_node(node, "cdef cppclass", extras, node.attributes)
204

205
    def visit_CEnumDefNode(self, node):
206
        self._visit_container_node(node, "cdef enum", None, node.items)
207

208
    def visit_CEnumDefItemNode(self, node):
209
        self.startline(node.name)
210
        if node.cname:
211
            self.put(' "%s"' % node.cname)
212
        if node.value:
213
            self.put(" = ")
214
            self.visit(node.value)
215
        self.endline()
216

217
    def visit_CClassDefNode(self, node):
218
        assert not node.module_name
219
        if node.decorators:
220
            for decorator in node.decorators:
221
                self.visit(decorator)
222
        self.startline("cdef class ")
223
        self.put(node.class_name)
224
        if node.base_class_name:
225
            self.put("(")
226
            if node.base_class_module:
227
                self.put(node.base_class_module)
228
                self.put(".")
229
            self.put(node.base_class_name)
230
            self.put(")")
231
        self.endline(":")
232
        self._visit_indented(node.body)
233

234
    def visit_CTypeDefNode(self, node):
235
        self.startline("ctypedef ")
236
        self.visit(node.base_type)
237
        self.put(" ")
238
        self.visit(node.declarator)
239
        self.endline()
240

241
    def visit_FuncDefNode(self, node):
242
        # TODO: support cdef + cpdef functions
243
        self.startline("def %s(" % node.name)
244
        self.comma_separated_list(node.args)
245
        self.endline("):")
246
        self._visit_indented(node.body)
247

248
    def visit_CFuncDefNode(self, node):
249
        self.startline('cpdef ' if node.overridable else 'cdef ')
250
        if node.modifiers:
251
            self.put(' '.join(node.modifiers))
252
            self.put(' ')
253
        if node.visibility != 'private':
254
            self.put(node.visibility)
255
            self.put(' ')
256
        if node.api:
257
            self.put('api ')
258

259
        if node.base_type:
260
            self.visit(node.base_type)
261
            if node.base_type.name is not None:
262
                self.put(' ')
263

264
        # visit the CFuncDeclaratorNode, but put a `:` at the end of line
265
        self.visit(node.declarator.base)
266
        self.put('(')
267
        self.comma_separated_list(node.declarator.args)
268
        self.endline('):')
269

270
        self._visit_indented(node.body)
271

272
    def visit_CArgDeclNode(self, node):
273
        # For "CSimpleBaseTypeNode", the variable type may have been parsed as type.
274
        # For other node types, the "name" is always None.
275
        if not isinstance(node.base_type, CSimpleBaseTypeNode) or \
276
                node.base_type.name is not None:
277
            self.visit(node.base_type)
278

279
            # If we printed something for "node.base_type", we may need to print an extra ' '.
280
            #
281
            # Special case: if "node.declarator" is a "CNameDeclaratorNode",
282
            # its "name" might be an empty string, for example, for "cdef f(x)".
283
            if node.declarator.declared_name():
284
                self.put(" ")
285
        self.visit(node.declarator)
286
        if node.default is not None:
287
            self.put(" = ")
288
            self.visit(node.default)
289

290
    def visit_CImportStatNode(self, node):
291
        self.startline("cimport ")
292
        self.put(node.module_name)
293
        if node.as_name:
294
            self.put(" as ")
295
            self.put(node.as_name)
296
        self.endline()
297

298
    def visit_FromCImportStatNode(self, node):
299
        self.startline("from ")
300
        self.put(node.module_name)
301
        self.put(" cimport ")
302
        first = True
303
        for pos, name, as_name, kind in node.imported_names:
304
            assert kind is None
305
            if first:
306
                first = False
307
            else:
308
                self.put(", ")
309
            self.put(name)
310
            if as_name:
311
                self.put(" as ")
312
                self.put(as_name)
313
        self.endline()
314

315
    def visit_NameNode(self, node):
316
        self.put(node.name)
317

318
    def visit_DecoratorNode(self, node):
319
        self.startline("@")
320
        self.visit(node.decorator)
321
        self.endline()
322

323
    def visit_PassStatNode(self, node):
324
        self.startline("pass")
325
        self.endline()
326

327

328
class StatementWriter(DeclarationWriter):
329
    """
330
    A Cython code writer for most language statement features.
331
    """
332

333
    def visit_SingleAssignmentNode(self, node):
334
        self.startline()
335
        self.visit(node.lhs)
336
        self.put(" = ")
337
        self.visit(node.rhs)
338
        self.endline()
339

340
    def visit_CascadedAssignmentNode(self, node):
341
        self.startline()
342
        for lhs in node.lhs_list:
343
            self.visit(lhs)
344
            self.put(" = ")
345
        self.visit(node.rhs)
346
        self.endline()
347

348
    def visit_PrintStatNode(self, node):
349
        self.startline("print ")
350
        self.comma_separated_list(node.arg_tuple.args)
351
        if not node.append_newline:
352
            self.put(",")
353
        self.endline()
354

355
    def visit_ForInStatNode(self, node):
356
        self.startline("for ")
357
        if node.target.is_sequence_constructor:
358
            self.comma_separated_list(node.target.args)
359
        else:
360
            self.visit(node.target)
361
        self.put(" in ")
362
        self.visit(node.iterator.sequence)
363
        self.endline(":")
364
        self._visit_indented(node.body)
365
        if node.else_clause is not None:
366
            self.line("else:")
367
            self._visit_indented(node.else_clause)
368

369
    def visit_IfStatNode(self, node):
370
        # The IfClauseNode is handled directly without a separate match
371
        # for clariy.
372
        self.startline("if ")
373
        self.visit(node.if_clauses[0].condition)
374
        self.endline(":")
375
        self._visit_indented(node.if_clauses[0].body)
376
        for clause in node.if_clauses[1:]:
377
            self.startline("elif ")
378
            self.visit(clause.condition)
379
            self.endline(":")
380
            self._visit_indented(clause.body)
381
        if node.else_clause is not None:
382
            self.line("else:")
383
            self._visit_indented(node.else_clause)
384

385
    def visit_WhileStatNode(self, node):
386
        self.startline("while ")
387
        self.visit(node.condition)
388
        self.endline(":")
389
        self._visit_indented(node.body)
390
        if node.else_clause is not None:
391
            self.line("else:")
392
            self._visit_indented(node.else_clause)
393

394
    def visit_ContinueStatNode(self, node):
395
        self.line("continue")
396

397
    def visit_BreakStatNode(self, node):
398
        self.line("break")
399

400
    def visit_SequenceNode(self, node):
401
        self.comma_separated_list(node.args)  # Might need to discover whether we need () around tuples...hmm...
402

403
    def visit_ExprStatNode(self, node):
404
        self.startline()
405
        self.visit(node.expr)
406
        self.endline()
407

408
    def visit_InPlaceAssignmentNode(self, node):
409
        self.startline()
410
        self.visit(node.lhs)
411
        self.put(" %s= " % node.operator)
412
        self.visit(node.rhs)
413
        self.endline()
414

415
    def visit_WithStatNode(self, node):
416
        self.startline()
417
        self.put("with ")
418
        self.visit(node.manager)
419
        if node.target is not None:
420
            self.put(" as ")
421
            self.visit(node.target)
422
        self.endline(":")
423
        self._visit_indented(node.body)
424

425
    def visit_TryFinallyStatNode(self, node):
426
        self.line("try:")
427
        self._visit_indented(node.body)
428
        self.line("finally:")
429
        self._visit_indented(node.finally_clause)
430

431
    def visit_TryExceptStatNode(self, node):
432
        self.line("try:")
433
        self._visit_indented(node.body)
434
        for x in node.except_clauses:
435
            self.visit(x)
436
        if node.else_clause is not None:
437
            self.visit(node.else_clause)
438

439
    def visit_ExceptClauseNode(self, node):
440
        self.startline("except")
441
        if node.pattern is not None:
442
            self.put(" ")
443
            self.visit(node.pattern)
444
        if node.target is not None:
445
            self.put(", ")
446
            self.visit(node.target)
447
        self.endline(":")
448
        self._visit_indented(node.body)
449

450
    def visit_ReturnStatNode(self, node):
451
        self.startline("return")
452
        if node.value is not None:
453
            self.put(" ")
454
            self.visit(node.value)
455
        self.endline()
456

457
    def visit_ReraiseStatNode(self, node):
458
        self.line("raise")
459

460
    def visit_ImportNode(self, node):
461
        self.put("(import %s)" % node.module_name.value)
462

463
    def visit_TempsBlockNode(self, node):
464
        """
465
        Temporaries are output like $1_1', where the first number is
466
        an index of the TempsBlockNode and the second number is an index
467
        of the temporary which that block allocates.
468
        """
469
        idx = 0
470
        for handle in node.temps:
471
            self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
472
            idx += 1
473
        self.tempblockindex += 1
474
        self.visit(node.body)
475

476
    def visit_TempRefNode(self, node):
477
        self.put(self.tempnames[node.handle])
478

479

480
class ExpressionWriter(TreeVisitor):
481
    """
482
    A Cython code writer that is intentionally limited to expressions.
483
    """
484

485
    def __init__(self, result=None):
486
        super().__init__()
487
        if result is None:
488
            result = ""
489
        self.result = result
490
        self.precedence = [0]
491

492
    def write(self, tree):
493
        self.visit(tree)
494
        return self.result
495

496
    def put(self, s):
497
        self.result += s
498

499
    def remove(self, s):
500
        if self.result.endswith(s):
501
            self.result = self.result[:-len(s)]
502

503
    def comma_separated_list(self, items):
504
        if len(items) > 0:
505
            for item in items[:-1]:
506
                self.visit(item)
507
                self.put(", ")
508
            self.visit(items[-1])
509

510
    def visit_Node(self, node):
511
        raise AssertionError("Node not handled by serializer: %r" % node)
512

513
    # TODO: Remove redundancy below. Most constants serialise fine as just "repr(node.value)".
514

515
    def visit_IntNode(self, node):
516
        self.put(node.value)
517

518
    def visit_FloatNode(self, node):
519
        self.put(node.value)
520

521
    def visit_NoneNode(self, node):
522
        self.put("None")
523

524
    def visit_NameNode(self, node):
525
        self.put(node.name)
526

527
    def visit_EllipsisNode(self, node):
528
        self.put("...")
529

530
    def visit_BoolNode(self, node):
531
        self.put(str(node.value))
532

533
    def visit_ConstNode(self, node):
534
        self.put(str(node.value))
535

536
    def visit_ImagNode(self, node):
537
        self.put(f"{node.value}j")
538

539
    def visit_BytesNode(self, node):
540
        self.put(repr(node.value))
541

542
    def visit_UnicodeNode(self, node):
543
        self.put(repr(node.value))
544

545
    def emit_sequence(self, node, parens=("", "")):
546
        open_paren, close_paren = parens
547
        items = node.subexpr_nodes()
548
        self.put(open_paren)
549
        self.comma_separated_list(items)
550
        self.put(close_paren)
551

552
    def visit_ListNode(self, node):
553
        self.emit_sequence(node, "[]")
554

555
    def visit_TupleNode(self, node):
556
        self.emit_sequence(node, "()")
557

558
    def visit_SetNode(self, node):
559
        if len(node.subexpr_nodes()) > 0:
560
            self.emit_sequence(node, "{}")
561
        else:
562
            self.put("set()")
563

564
    def visit_DictNode(self, node):
565
        self.emit_sequence(node, "{}")
566

567
    def visit_DictItemNode(self, node):
568
        self.visit(node.key)
569
        self.put(": ")
570
        self.visit(node.value)
571

572
    unop_precedence = {
573
        'not': 3, '!': 3,
574
        '+': 11, '-': 11, '~': 11,
575
    }
576
    binop_precedence = {
577
        'or': 1,
578
        'and': 2,
579
        # unary: 'not': 3, '!': 3,
580
        'in': 4, 'not_in': 4, 'is': 4, 'is_not': 4, '<': 4, '<=': 4, '>': 4, '>=': 4, '!=': 4, '==': 4,
581
        '|': 5,
582
        '^': 6,
583
        '&': 7,
584
        '<<': 8, '>>': 8,
585
        '+': 9, '-': 9,
586
        '*': 10, '@': 10, '/': 10, '//': 10, '%': 10,
587
        # unary: '+': 11, '-': 11, '~': 11
588
        '**': 12,
589
    }
590

591
    def operator_enter(self, new_prec):
592
        old_prec = self.precedence[-1]
593
        if old_prec > new_prec:
594
            self.put("(")
595
        self.precedence.append(new_prec)
596

597
    def operator_exit(self):
598
        old_prec, new_prec = self.precedence[-2:]
599
        if old_prec > new_prec:
600
            self.put(")")
601
        self.precedence.pop()
602

603
    def visit_NotNode(self, node):
604
        op = 'not'
605
        prec = self.unop_precedence[op]
606
        self.operator_enter(prec)
607
        self.put("not ")
608
        self.visit(node.operand)
609
        self.operator_exit()
610

611
    def visit_UnopNode(self, node):
612
        op = node.operator
613
        prec = self.unop_precedence[op]
614
        self.operator_enter(prec)
615
        self.put("%s" % node.operator)
616
        self.visit(node.operand)
617
        self.operator_exit()
618

619
    def visit_BinopNode(self, node):
620
        op = node.operator
621
        prec = self.binop_precedence.get(op, 0)
622
        self.operator_enter(prec)
623
        self.visit(node.operand1)
624
        self.put(" %s " % op.replace('_', ' '))
625
        self.visit(node.operand2)
626
        self.operator_exit()
627

628
    def visit_BoolBinopNode(self, node):
629
        self.visit_BinopNode(node)
630

631
    def visit_PrimaryCmpNode(self, node):
632
        self.visit_BinopNode(node)
633

634
    def visit_IndexNode(self, node):
635
        self.visit(node.base)
636
        self.put("[")
637
        if isinstance(node.index, TupleNode):
638
            if node.index.subexpr_nodes():
639
                self.emit_sequence(node.index)
640
            else:
641
                self.put("()")
642
        else:
643
            self.visit(node.index)
644
        self.put("]")
645

646
    def visit_SliceIndexNode(self, node):
647
        self.visit(node.base)
648
        self.put("[")
649
        if node.start:
650
            self.visit(node.start)
651
        self.put(":")
652
        if node.stop:
653
            self.visit(node.stop)
654
        if node.slice:
655
            self.put(":")
656
            self.visit(node.slice)
657
        self.put("]")
658

659
    def visit_SliceNode(self, node):
660
        if not node.start.is_none:
661
            self.visit(node.start)
662
        self.put(":")
663
        if not node.stop.is_none:
664
            self.visit(node.stop)
665
        if not node.step.is_none:
666
            self.put(":")
667
            self.visit(node.step)
668

669
    def visit_CondExprNode(self, node):
670
        self.visit(node.true_val)
671
        self.put(" if ")
672
        self.visit(node.test)
673
        self.put(" else ")
674
        self.visit(node.false_val)
675

676
    def visit_AttributeNode(self, node):
677
        self.visit(node.obj)
678
        self.put(".%s" % node.attribute)
679

680
    def visit_SimpleCallNode(self, node):
681
        self.visit(node.function)
682
        self.put("(")
683
        self.comma_separated_list(node.args)
684
        self.put(")")
685

686
    def emit_pos_args(self, node):
687
        if node is None:
688
            return
689
        if isinstance(node, AddNode):
690
            self.emit_pos_args(node.operand1)
691
            self.emit_pos_args(node.operand2)
692
        elif isinstance(node, TupleNode):
693
            for expr in node.subexpr_nodes():
694
                self.visit(expr)
695
                self.put(", ")
696
        elif isinstance(node, AsTupleNode):
697
            self.put("*")
698
            self.visit(node.arg)
699
            self.put(", ")
700
        else:
701
            self.visit(node)
702
            self.put(", ")
703

704
    def emit_kwd_args(self, node):
705
        if node is None:
706
            return
707
        if isinstance(node, MergedDictNode):
708
            for expr in node.subexpr_nodes():
709
                self.emit_kwd_args(expr)
710
        elif isinstance(node, DictNode):
711
            for expr in node.subexpr_nodes():
712
                self.put("%s=" % expr.key.value)
713
                self.visit(expr.value)
714
                self.put(", ")
715
        else:
716
            self.put("**")
717
            self.visit(node)
718
            self.put(", ")
719

720
    def visit_GeneralCallNode(self, node):
721
        self.visit(node.function)
722
        self.put("(")
723
        self.emit_pos_args(node.positional_args)
724
        self.emit_kwd_args(node.keyword_args)
725
        self.remove(", ")
726
        self.put(")")
727

728
    def emit_comprehension(self, body, target,
729
                           sequence, condition,
730
                           parens=("", "")):
731
        open_paren, close_paren = parens
732
        self.put(open_paren)
733
        self.visit(body)
734
        self.put(" for ")
735
        self.visit(target)
736
        self.put(" in ")
737
        self.visit(sequence)
738
        if condition:
739
            self.put(" if ")
740
            self.visit(condition)
741
        self.put(close_paren)
742

743
    def visit_ComprehensionAppendNode(self, node):
744
        self.visit(node.expr)
745

746
    def visit_DictComprehensionAppendNode(self, node):
747
        self.visit(node.key_expr)
748
        self.put(": ")
749
        self.visit(node.value_expr)
750

751
    def visit_ComprehensionNode(self, node):
752
        tpmap = {'list': "[]", 'dict': "{}", 'set': "{}"}
753
        parens = tpmap[node.type.py_type_name()]
754
        body = node.loop.body
755
        target = node.loop.target
756
        sequence = node.loop.iterator.sequence
757
        condition = None
758
        if hasattr(body, 'if_clauses'):
759
            # type(body) is Nodes.IfStatNode
760
            condition = body.if_clauses[0].condition
761
            body = body.if_clauses[0].body
762
        self.emit_comprehension(body, target, sequence, condition, parens)
763

764
    def visit_GeneratorExpressionNode(self, node):
765
        body = node.loop.body
766
        target = node.loop.target
767
        sequence = node.loop.iterator.sequence
768
        condition = None
769
        if hasattr(body, 'if_clauses'):
770
            # type(body) is Nodes.IfStatNode
771
            condition = body.if_clauses[0].condition
772
            body = body.if_clauses[0].body.expr.arg
773
        elif hasattr(body, 'expr'):
774
            # type(body) is Nodes.ExprStatNode
775
            body = body.expr.arg
776
        self.emit_comprehension(body, target, sequence, condition, "()")
777

778

779
class PxdWriter(DeclarationWriter, ExpressionWriter):
780
    """
781
    A Cython code writer for everything supported in pxd files.
782
    (currently unused)
783
    """
784

785
    def __call__(self, node):
786
        print('\n'.join(self.write(node).lines))
787
        return node
788

789
    def visit_CFuncDefNode(self, node):
790
        if node.overridable:
791
            self.startline('cpdef ')
792
        else:
793
            self.startline('cdef ')
794
        if node.modifiers:
795
            self.put(' '.join(node.modifiers))
796
            self.put(' ')
797
        if node.visibility != 'private':
798
            self.put(node.visibility)
799
            self.put(' ')
800
        if node.api:
801
            self.put('api ')
802
        self.visit(node.declarator)
803

804
    def visit_StatNode(self, node):
805
        pass
806

807

808
class CodeWriter(StatementWriter, ExpressionWriter):
809
    """
810
    A complete Cython code writer.
811
    """
812

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.