1 #!/usr/bin/env python3 2 # 3 # Argument Clinic 4 # Copyright 2012-2013 by Larry Hastings. 5 # Licensed to the PSF under a contributor agreement. 6 # 7 8 import abc 9 import ast 10 import collections 11 import contextlib 12 import copy 13 import cpp 14 import functools 15 import hashlib 16 import inspect 17 import io 18 import itertools 19 import os 20 import pprint 21 import re 22 import shlex 23 import string 24 import sys 25 import tempfile 26 import textwrap 27 import traceback 28 import types 29 30 from types import * 31 NoneType = type(None) 32 33 # TODO: 34 # 35 # soon: 36 # 37 # * allow mixing any two of {positional-only, positional-or-keyword, 38 # keyword-only} 39 # * dict constructor uses positional-only and keyword-only 40 # * max and min use positional only with an optional group 41 # and keyword-only 42 # 43 44 version = '1' 45 46 _empty = inspect._empty 47 _void = inspect._void 48 49 NoneType = type(None) 50 51 class Unspecified: 52 def __repr__(self): 53 return '<Unspecified>' 54 55 unspecified = Unspecified() 56 57 58 class Null: 59 def __repr__(self): 60 return '<Null>' 61 62 NULL = Null() 63 64 65 class Unknown: 66 def __repr__(self): 67 return '<Unknown>' 68 69 unknown = Unknown() 70 71 sig_end_marker = '--' 72 73 74 _text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output") 75 76 def _text_accumulator(): 77 text = [] 78 def output(): 79 s = ''.join(text) 80 text.clear() 81 return s 82 return _text_accumulator_nt(text, text.append, output) 83 84 85 text_accumulator_nt = collections.namedtuple("text_accumulator", "text append") 86 87 def text_accumulator(): 88 """ 89 Creates a simple text accumulator / joiner. 90 91 Returns a pair of callables: 92 append, output 93 "append" appends a string to the accumulator. 94 "output" returns the contents of the accumulator 95 joined together (''.join(accumulator)) and 96 empties the accumulator. 97 """ 98 text, append, output = _text_accumulator() 99 return text_accumulator_nt(append, output) 100 101 102 def warn_or_fail(fail=False, *args, filename=None, line_number=None): 103 joined = " ".join([str(a) for a in args]) 104 add, output = text_accumulator() 105 if fail: 106 add("Error") 107 else: 108 add("Warning") 109 if clinic: 110 if filename is None: 111 filename = clinic.filename 112 if getattr(clinic, 'block_parser', None) and (line_number is None): 113 line_number = clinic.block_parser.line_number 114 if filename is not None: 115 add(' in file "' + filename + '"') 116 if line_number is not None: 117 add(" on line " + str(line_number)) 118 add(':\n') 119 add(joined) 120 print(output()) 121 if fail: 122 sys.exit(-1) 123 124 125 def warn(*args, filename=None, line_number=None): 126 return warn_or_fail(False, *args, filename=filename, line_number=line_number) 127 128 def fail(*args, filename=None, line_number=None): 129 return warn_or_fail(True, *args, filename=filename, line_number=line_number) 130 131 132 def quoted_for_c_string(s): 133 for old, new in ( 134 ('\\', '\\\\'), # must be first! 135 ('"', '\\"'), 136 ("'", "\\'"), 137 ): 138 s = s.replace(old, new) 139 return s 140 141 def c_repr(s): 142 return '"' + s + '"' 143 144 145 is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match 146 147 def is_legal_py_identifier(s): 148 return all(is_legal_c_identifier(field) for field in s.split('.')) 149 150 # identifiers that are okay in Python but aren't a good idea in C. 151 # so if they're used Argument Clinic will add "_value" to the end 152 # of the name in C. 153 c_keywords = set(""" 154 asm auto break case char const continue default do double 155 else enum extern float for goto if inline int long 156 register return short signed sizeof static struct switch 157 typedef typeof union unsigned void volatile while 158 """.strip().split()) 159 160 def ensure_legal_c_identifier(s): 161 # for now, just complain if what we're given isn't legal 162 if not is_legal_c_identifier(s): 163 fail("Illegal C identifier: {}".format(s)) 164 # but if we picked a C keyword, pick something else 165 if s in c_keywords: 166 return s + "_value" 167 return s 168 169 def rstrip_lines(s): 170 text, add, output = _text_accumulator() 171 for line in s.split('\n'): 172 add(line.rstrip()) 173 add('\n') 174 text.pop() 175 return output() 176 177 def format_escape(s): 178 # double up curly-braces, this string will be used 179 # as part of a format_map() template later 180 s = s.replace('{', '{{') 181 s = s.replace('}', '}}') 182 return s 183 184 def linear_format(s, **kwargs): 185 """ 186 Perform str.format-like substitution, except: 187 * The strings substituted must be on lines by 188 themselves. (This line is the "source line".) 189 * If the substitution text is empty, the source line 190 is removed in the output. 191 * If the field is not recognized, the original line 192 is passed unmodified through to the output. 193 * If the substitution text is not empty: 194 * Each line of the substituted text is indented 195 by the indent of the source line. 196 * A newline will be added to the end. 197 """ 198 199 add, output = text_accumulator() 200 for line in s.split('\n'): 201 indent, curly, trailing = line.partition('{') 202 if not curly: 203 add(line) 204 add('\n') 205 continue 206 207 name, curly, trailing = trailing.partition('}') 208 if not curly or name not in kwargs: 209 add(line) 210 add('\n') 211 continue 212 213 if trailing: 214 fail("Text found after {" + name + "} block marker! It must be on a line by itself.") 215 if indent.strip(): 216 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.") 217 218 value = kwargs[name] 219 if not value: 220 continue 221 222 value = textwrap.indent(rstrip_lines(value), indent) 223 add(value) 224 add('\n') 225 226 return output()[:-1] 227 228 def indent_all_lines(s, prefix): 229 """ 230 Returns 's', with 'prefix' prepended to all lines. 231 232 If the last line is empty, prefix is not prepended 233 to it. (If s is blank, returns s unchanged.) 234 235 (textwrap.indent only adds to non-blank lines.) 236 """ 237 split = s.split('\n') 238 last = split.pop() 239 final = [] 240 for line in split: 241 final.append(prefix) 242 final.append(line) 243 final.append('\n') 244 if last: 245 final.append(prefix) 246 final.append(last) 247 return ''.join(final) 248 249 def suffix_all_lines(s, suffix): 250 """ 251 Returns 's', with 'suffix' appended to all lines. 252 253 If the last line is empty, suffix is not appended 254 to it. (If s is blank, returns s unchanged.) 255 """ 256 split = s.split('\n') 257 last = split.pop() 258 final = [] 259 for line in split: 260 final.append(line) 261 final.append(suffix) 262 final.append('\n') 263 if last: 264 final.append(last) 265 final.append(suffix) 266 return ''.join(final) 267 268 269 def version_splitter(s): 270 """Splits a version string into a tuple of integers. 271 272 The following ASCII characters are allowed, and employ 273 the following conversions: 274 a -> -3 275 b -> -2 276 c -> -1 277 (This permits Python-style version strings such as "1.4b3".) 278 """ 279 version = [] 280 accumulator = [] 281 def flush(): 282 if not accumulator: 283 raise ValueError('Unsupported version string: ' + repr(s)) 284 version.append(int(''.join(accumulator))) 285 accumulator.clear() 286 287 for c in s: 288 if c.isdigit(): 289 accumulator.append(c) 290 elif c == '.': 291 flush() 292 elif c in 'abc': 293 flush() 294 version.append('abc'.index(c) - 3) 295 else: 296 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s)) 297 flush() 298 return tuple(version) 299 300 def version_comparitor(version1, version2): 301 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0) 302 for i, (a, b) in enumerate(iterator): 303 if a < b: 304 return -1 305 if a > b: 306 return 1 307 return 0 308 309 310 class CRenderData: 311 def __init__(self): 312 313 # The C statements to declare variables. 314 # Should be full lines with \n eol characters. 315 self.declarations = [] 316 317 # The C statements required to initialize the variables before the parse call. 318 # Should be full lines with \n eol characters. 319 self.initializers = [] 320 321 # The C statements needed to dynamically modify the values 322 # parsed by the parse call, before calling the impl. 323 self.modifications = [] 324 325 # The entries for the "keywords" array for PyArg_ParseTuple. 326 # Should be individual strings representing the names. 327 self.keywords = [] 328 329 # The "format units" for PyArg_ParseTuple. 330 # Should be individual strings that will get 331 self.format_units = [] 332 333 # The varargs arguments for PyArg_ParseTuple. 334 self.parse_arguments = [] 335 336 # The parameter declarations for the impl function. 337 self.impl_parameters = [] 338 339 # The arguments to the impl function at the time it's called. 340 self.impl_arguments = [] 341 342 # For return converters: the name of the variable that 343 # should receive the value returned by the impl. 344 self.return_value = "return_value" 345 346 # For return converters: the code to convert the return 347 # value from the parse function. This is also where 348 # you should check the _return_value for errors, and 349 # "goto exit" if there are any. 350 self.return_conversion = [] 351 352 # The C statements required to clean up after the impl call. 353 self.cleanup = [] 354 355 356 class FormatCounterFormatter(string.Formatter): 357 """ 358 This counts how many instances of each formatter 359 "replacement string" appear in the format string. 360 361 e.g. after evaluating "string {a}, {b}, {c}, {a}" 362 the counts dict would now look like 363 {'a': 2, 'b': 1, 'c': 1} 364 """ 365 def __init__(self): 366 self.counts = collections.Counter() 367 368 def get_value(self, key, args, kwargs): 369 self.counts[key] += 1 370 return '' 371 372 class Language(metaclass=abc.ABCMeta): 373 374 start_line = "" 375 body_prefix = "" 376 stop_line = "" 377 checksum_line = "" 378 379 def __init__(self, filename): 380 pass 381 382 @abc.abstractmethod 383 def render(self, clinic, signatures): 384 pass 385 386 def parse_line(self, line): 387 pass 388 389 def validate(self): 390 def assert_only_one(attr, *additional_fields): 391 """ 392 Ensures that the string found at getattr(self, attr) 393 contains exactly one formatter replacement string for 394 each valid field. The list of valid fields is 395 ['dsl_name'] extended by additional_fields. 396 397 e.g. 398 self.fmt = "{dsl_name} {a} {b}" 399 400 # this passes 401 self.assert_only_one('fmt', 'a', 'b') 402 403 # this fails, the format string has a {b} in it 404 self.assert_only_one('fmt', 'a') 405 406 # this fails, the format string doesn't have a {c} in it 407 self.assert_only_one('fmt', 'a', 'b', 'c') 408 409 # this fails, the format string has two {a}s in it, 410 # it must contain exactly one 411 self.fmt2 = '{dsl_name} {a} {a}' 412 self.assert_only_one('fmt2', 'a') 413 414 """ 415 fields = ['dsl_name'] 416 fields.extend(additional_fields) 417 line = getattr(self, attr) 418 fcf = FormatCounterFormatter() 419 fcf.format(line) 420 def local_fail(should_be_there_but_isnt): 421 if should_be_there_but_isnt: 422 fail("{} {} must contain {{{}}} exactly once!".format( 423 self.__class__.__name__, attr, name)) 424 else: 425 fail("{} {} must not contain {{{}}}!".format( 426 self.__class__.__name__, attr, name)) 427 428 for name, count in fcf.counts.items(): 429 if name in fields: 430 if count > 1: 431 local_fail(True) 432 else: 433 local_fail(False) 434 for name in fields: 435 if fcf.counts.get(name) != 1: 436 local_fail(True) 437 438 assert_only_one('start_line') 439 assert_only_one('stop_line') 440 441 field = "arguments" if "{arguments}" in self.checksum_line else "checksum" 442 assert_only_one('checksum_line', field) 443 444 445 446 class PythonLanguage(Language): 447 448 language = 'Python' 449 start_line = "#/*[{dsl_name} input]" 450 body_prefix = "#" 451 stop_line = "#[{dsl_name} start generated code]*/" 452 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/" 453 454 455 def permute_left_option_groups(l): 456 """ 457 Given [1, 2, 3], should yield: 458 () 459 (3,) 460 (2, 3) 461 (1, 2, 3) 462 """ 463 yield tuple() 464 accumulator = [] 465 for group in reversed(l): 466 accumulator = list(group) + accumulator 467 yield tuple(accumulator) 468 469 470 def permute_right_option_groups(l): 471 """ 472 Given [1, 2, 3], should yield: 473 () 474 (1,) 475 (1, 2) 476 (1, 2, 3) 477 """ 478 yield tuple() 479 accumulator = [] 480 for group in l: 481 accumulator.extend(group) 482 yield tuple(accumulator) 483 484 485 def permute_optional_groups(left, required, right): 486 """ 487 Generator function that computes the set of acceptable 488 argument lists for the provided iterables of 489 argument groups. (Actually it generates a tuple of tuples.) 490 491 Algorithm: prefer left options over right options. 492 493 If required is empty, left must also be empty. 494 """ 495 required = tuple(required) 496 result = [] 497 498 if not required: 499 assert not left 500 501 accumulator = [] 502 counts = set() 503 for r in permute_right_option_groups(right): 504 for l in permute_left_option_groups(left): 505 t = l + required + r 506 if len(t) in counts: 507 continue 508 counts.add(len(t)) 509 accumulator.append(t) 510 511 accumulator.sort(key=len) 512 return tuple(accumulator) 513 514 515 def strip_leading_and_trailing_blank_lines(s): 516 lines = s.rstrip().split('\n') 517 while lines: 518 line = lines[0] 519 if line.strip(): 520 break 521 del lines[0] 522 return '\n'.join(lines) 523 524 @functools.lru_cache() 525 def normalize_snippet(s, *, indent=0): 526 """ 527 Reformats s: 528 * removes leading and trailing blank lines 529 * ensures that it does not end with a newline 530 * dedents so the first nonwhite character on any line is at column "indent" 531 """ 532 s = strip_leading_and_trailing_blank_lines(s) 533 s = textwrap.dedent(s) 534 if indent: 535 s = textwrap.indent(s, ' ' * indent) 536 return s 537 538 539 def wrap_declarations(text, length=78): 540 """ 541 A simple-minded text wrapper for C function declarations. 542 543 It views a declaration line as looking like this: 544 xxxxxxxx(xxxxxxxxx,xxxxxxxxx) 545 If called with length=30, it would wrap that line into 546 xxxxxxxx(xxxxxxxxx, 547 xxxxxxxxx) 548 (If the declaration has zero or one parameters, this 549 function won't wrap it.) 550 551 If this doesn't work properly, it's probably better to 552 start from scratch with a more sophisticated algorithm, 553 rather than try and improve/debug this dumb little function. 554 """ 555 lines = [] 556 for line in text.split('\n'): 557 prefix, _, after_l_paren = line.partition('(') 558 if not after_l_paren: 559 lines.append(line) 560 continue 561 parameters, _, after_r_paren = after_l_paren.partition(')') 562 if not _: 563 lines.append(line) 564 continue 565 if ',' not in parameters: 566 lines.append(line) 567 continue 568 parameters = [x.strip() + ", " for x in parameters.split(',')] 569 prefix += "(" 570 if len(prefix) < length: 571 spaces = " " * len(prefix) 572 else: 573 spaces = " " * 4 574 575 while parameters: 576 line = prefix 577 first = True 578 while parameters: 579 if (not first and 580 (len(line) + len(parameters[0]) > length)): 581 break 582 line += parameters.pop(0) 583 first = False 584 if not parameters: 585 line = line.rstrip(", ") + ")" + after_r_paren 586 lines.append(line.rstrip()) 587 prefix = spaces 588 return "\n".join(lines) 589 590 591 class CLanguage(Language): 592 593 body_prefix = "#" 594 language = 'C' 595 start_line = "/*[{dsl_name} input]" 596 body_prefix = "" 597 stop_line = "[{dsl_name} start generated code]*/" 598 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/" 599 600 def __init__(self, filename): 601 super().__init__(filename) 602 self.cpp = cpp.Monitor(filename) 603 self.cpp.fail = fail 604 605 def parse_line(self, line): 606 self.cpp.writeline(line) 607 608 def render(self, clinic, signatures): 609 function = None 610 for o in signatures: 611 if isinstance(o, Function): 612 if function: 613 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o)) 614 function = o 615 return self.render_function(clinic, function) 616 617 def docstring_for_c_string(self, f): 618 text, add, output = _text_accumulator() 619 # turn docstring into a properly quoted C string 620 for line in f.docstring.split('\n'): 621 add('"') 622 add(quoted_for_c_string(line)) 623 add('\\n"\n') 624 625 if text[-2] == sig_end_marker: 626 # If we only have a signature, add the blank line that the 627 # __text_signature__ getter expects to be there. 628 add('"\\n"') 629 else: 630 text.pop() 631 add('"') 632 return ''.join(text) 633 634 def output_templates(self, f): 635 parameters = list(f.parameters.values()) 636 assert parameters 637 assert isinstance(parameters[0].converter, self_converter) 638 del parameters[0] 639 converters = [p.converter for p in parameters] 640 641 has_option_groups = parameters and (parameters[0].group or parameters[-1].group) 642 default_return_converter = (not f.return_converter or 643 f.return_converter.type == 'PyObject *') 644 645 positional = parameters and parameters[-1].is_positional_only() 646 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine 647 first_optional = len(parameters) 648 for i, p in enumerate(parameters): 649 c = p.converter 650 if type(c) != object_converter: 651 break 652 if c.format_unit != 'O': 653 break 654 if p.default is not unspecified: 655 first_optional = min(first_optional, i) 656 else: 657 all_boring_objects = True 658 659 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 660 661 meth_o = (len(parameters) == 1 and 662 parameters[0].is_positional_only() and 663 not converters[0].is_optional() and 664 not new_or_init) 665 666 # we have to set these things before we're done: 667 # 668 # docstring_prototype 669 # docstring_definition 670 # impl_prototype 671 # methoddef_define 672 # parser_prototype 673 # parser_definition 674 # impl_definition 675 # cpp_if 676 # cpp_endif 677 # methoddef_ifndef 678 679 return_value_declaration = "PyObject *return_value = NULL;" 680 681 methoddef_define = normalize_snippet(""" 682 #define {methoddef_name} \\ 683 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, 684 """) 685 if new_or_init and not f.docstring: 686 docstring_prototype = docstring_definition = '' 687 else: 688 docstring_prototype = normalize_snippet(""" 689 PyDoc_VAR({c_basename}__doc__); 690 """) 691 docstring_definition = normalize_snippet(""" 692 PyDoc_STRVAR({c_basename}__doc__, 693 {docstring}); 694 """) 695 impl_definition = normalize_snippet(""" 696 static {impl_return_type} 697 {c_basename}_impl({impl_parameters}) 698 """) 699 impl_prototype = parser_prototype = parser_definition = None 700 701 parser_prototype_keyword = normalize_snippet(""" 702 static PyObject * 703 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) 704 """) 705 706 parser_prototype_varargs = normalize_snippet(""" 707 static PyObject * 708 {c_basename}({self_type}{self_name}, PyObject *args) 709 """) 710 711 parser_prototype_fastcall = normalize_snippet(""" 712 static PyObject * 713 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs) 714 """) 715 716 parser_prototype_fastcall_keywords = normalize_snippet(""" 717 static PyObject * 718 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) 719 """) 720 721 # parser_body_fields remembers the fields passed in to the 722 # previous call to parser_body. this is used for an awful hack. 723 parser_body_fields = () 724 def parser_body(prototype, *fields): 725 nonlocal parser_body_fields 726 add, output = text_accumulator() 727 add(prototype) 728 parser_body_fields = fields 729 730 fields = list(fields) 731 fields.insert(0, normalize_snippet(""" 732 {{ 733 {return_value_declaration} 734 {declarations} 735 {initializers} 736 """) + "\n") 737 # just imagine--your code is here in the middle 738 fields.append(normalize_snippet(""" 739 {modifications} 740 {return_value} = {c_basename}_impl({impl_arguments}); 741 {return_conversion} 742 743 {exit_label} 744 {cleanup} 745 return return_value; 746 }} 747 """)) 748 for field in fields: 749 add('\n') 750 add(field) 751 return output() 752 753 def insert_keywords(s): 754 return linear_format(s, declarations= 755 'static const char * const _keywords[] = {{{keywords}, NULL}};\n' 756 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};\n' 757 '{declarations}') 758 759 if not parameters: 760 # no parameters, METH_NOARGS 761 762 flags = "METH_NOARGS" 763 764 parser_prototype = normalize_snippet(""" 765 static PyObject * 766 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) 767 """) 768 parser_definition = parser_prototype 769 770 if default_return_converter: 771 parser_definition = parser_prototype + '\n' + normalize_snippet(""" 772 {{ 773 return {c_basename}_impl({impl_arguments}); 774 }} 775 """) 776 else: 777 parser_definition = parser_body(parser_prototype) 778 779 elif meth_o: 780 flags = "METH_O" 781 782 if (isinstance(converters[0], object_converter) and 783 converters[0].format_unit == 'O'): 784 meth_o_prototype = normalize_snippet(""" 785 static PyObject * 786 {c_basename}({impl_parameters}) 787 """) 788 789 if default_return_converter: 790 # maps perfectly to METH_O, doesn't need a return converter. 791 # so we skip making a parse function 792 # and call directly into the impl function. 793 impl_prototype = parser_prototype = parser_definition = '' 794 impl_definition = meth_o_prototype 795 else: 796 # SLIGHT HACK 797 # use impl_parameters for the parser here! 798 parser_prototype = meth_o_prototype 799 parser_definition = parser_body(parser_prototype) 800 801 else: 802 argname = 'arg' 803 if parameters[0].name == argname: 804 argname += '_' 805 parser_prototype = normalize_snippet(""" 806 static PyObject * 807 {c_basename}({self_type}{self_name}, PyObject *%s) 808 """ % argname) 809 810 parser_definition = parser_body(parser_prototype, normalize_snippet(""" 811 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{ 812 goto exit; 813 }} 814 """ % argname, indent=4)) 815 816 elif has_option_groups: 817 # positional parameters with option groups 818 # (we have to generate lots of PyArg_ParseTuple calls 819 # in a big switch statement) 820 821 flags = "METH_VARARGS" 822 parser_prototype = parser_prototype_varargs 823 824 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}') 825 826 elif positional and all_boring_objects: 827 # positional-only, but no option groups, 828 # and nothing but normal objects: 829 # PyArg_UnpackTuple! 830 831 if not new_or_init: 832 flags = "METH_FASTCALL" 833 parser_prototype = parser_prototype_fastcall 834 835 parser_definition = parser_body(parser_prototype, normalize_snippet(""" 836 if (!_PyArg_UnpackStack(args, nargs, "{name}", 837 {unpack_min}, {unpack_max}, 838 {parse_arguments})) {{ 839 goto exit; 840 }} 841 """, indent=4)) 842 else: 843 flags = "METH_VARARGS" 844 parser_prototype = parser_prototype_varargs 845 846 parser_definition = parser_body(parser_prototype, normalize_snippet(""" 847 if (!PyArg_UnpackTuple(args, "{name}", 848 {unpack_min}, {unpack_max}, 849 {parse_arguments})) {{ 850 goto exit; 851 }} 852 """, indent=4)) 853 854 elif positional: 855 if not new_or_init: 856 # positional-only, but no option groups 857 # we only need one call to _PyArg_ParseStack 858 859 flags = "METH_FASTCALL" 860 parser_prototype = parser_prototype_fastcall 861 862 parser_definition = parser_body(parser_prototype, normalize_snippet(""" 863 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}", 864 {parse_arguments})) {{ 865 goto exit; 866 }} 867 """, indent=4)) 868 else: 869 # positional-only, but no option groups 870 # we only need one call to PyArg_ParseTuple 871 872 flags = "METH_VARARGS" 873 parser_prototype = parser_prototype_varargs 874 875 parser_definition = parser_body(parser_prototype, normalize_snippet(""" 876 if (!PyArg_ParseTuple(args, "{format_units}:{name}", 877 {parse_arguments})) {{ 878 goto exit; 879 }} 880 """, indent=4)) 881 882 elif not new_or_init: 883 flags = "METH_FASTCALL|METH_KEYWORDS" 884 885 parser_prototype = parser_prototype_fastcall_keywords 886 887 body = normalize_snippet(""" 888 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, 889 {parse_arguments})) {{ 890 goto exit; 891 }} 892 """, indent=4) 893 parser_definition = parser_body(parser_prototype, body) 894 parser_definition = insert_keywords(parser_definition) 895 else: 896 # positional-or-keyword arguments 897 flags = "METH_VARARGS|METH_KEYWORDS" 898 899 parser_prototype = parser_prototype_keyword 900 901 body = normalize_snippet(""" 902 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, 903 {parse_arguments})) {{ 904 goto exit; 905 }} 906 """, indent=4) 907 parser_definition = parser_body(parser_prototype, body) 908 parser_definition = insert_keywords(parser_definition) 909 910 911 if new_or_init: 912 methoddef_define = '' 913 914 if f.kind == METHOD_NEW: 915 parser_prototype = parser_prototype_keyword 916 else: 917 return_value_declaration = "int return_value = -1;" 918 parser_prototype = normalize_snippet(""" 919 static int 920 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) 921 """) 922 923 fields = list(parser_body_fields) 924 parses_positional = 'METH_NOARGS' not in flags 925 parses_keywords = 'METH_KEYWORDS' in flags 926 if parses_keywords: 927 assert parses_positional 928 929 if not parses_keywords: 930 fields.insert(0, normalize_snippet(""" 931 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{ 932 goto exit; 933 }} 934 """, indent=4)) 935 if not parses_positional: 936 fields.insert(0, normalize_snippet(""" 937 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{ 938 goto exit; 939 }} 940 """, indent=4)) 941 942 parser_definition = parser_body(parser_prototype, *fields) 943 if parses_keywords: 944 parser_definition = insert_keywords(parser_definition) 945 946 947 if f.methoddef_flags: 948 flags += '|' + f.methoddef_flags 949 950 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags) 951 952 methoddef_ifndef = '' 953 conditional = self.cpp.condition() 954 if not conditional: 955 cpp_if = cpp_endif = '' 956 else: 957 cpp_if = "#if " + conditional 958 cpp_endif = "#endif /* " + conditional + " */" 959 960 if methoddef_define and f.full_name not in clinic.ifndef_symbols: 961 clinic.ifndef_symbols.add(f.full_name) 962 methoddef_ifndef = normalize_snippet(""" 963 #ifndef {methoddef_name} 964 #define {methoddef_name} 965 #endif /* !defined({methoddef_name}) */ 966 """) 967 968 969 # add ';' to the end of parser_prototype and impl_prototype 970 # (they mustn't be None, but they could be an empty string.) 971 assert parser_prototype is not None 972 if parser_prototype: 973 assert not parser_prototype.endswith(';') 974 parser_prototype += ';' 975 976 if impl_prototype is None: 977 impl_prototype = impl_definition 978 if impl_prototype: 979 impl_prototype += ";" 980 981 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration) 982 983 d = { 984 "docstring_prototype" : docstring_prototype, 985 "docstring_definition" : docstring_definition, 986 "impl_prototype" : impl_prototype, 987 "methoddef_define" : methoddef_define, 988 "parser_prototype" : parser_prototype, 989 "parser_definition" : parser_definition, 990 "impl_definition" : impl_definition, 991 "cpp_if" : cpp_if, 992 "cpp_endif" : cpp_endif, 993 "methoddef_ifndef" : methoddef_ifndef, 994 } 995 996 # make sure we didn't forget to assign something, 997 # and wrap each non-empty value in \n's 998 d2 = {} 999 for name, value in d.items(): 1000 assert value is not None, "got a None value for template " + repr(name) 1001 if value: 1002 value = '\n' + value + '\n' 1003 d2[name] = value 1004 return d2 1005 1006 @staticmethod 1007 def group_to_variable_name(group): 1008 adjective = "left_" if group < 0 else "right_" 1009 return "group_" + adjective + str(abs(group)) 1010 1011 def render_option_group_parsing(self, f, template_dict): 1012 # positional only, grouped, optional arguments! 1013 # can be optional on the left or right. 1014 # here's an example: 1015 # 1016 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ] 1017 # 1018 # Here group D are required, and all other groups are optional. 1019 # (Group D's "group" is actually None.) 1020 # We can figure out which sets of arguments we have based on 1021 # how many arguments are in the tuple. 1022 # 1023 # Note that you need to count up on both sides. For example, 1024 # you could have groups C+D, or C+D+E, or C+D+E+F. 1025 # 1026 # What if the number of arguments leads us to an ambiguous result? 1027 # Clinic prefers groups on the left. So in the above example, 1028 # five arguments would map to B+C, not C+D. 1029 1030 add, output = text_accumulator() 1031 parameters = list(f.parameters.values()) 1032 if isinstance(parameters[0].converter, self_converter): 1033 del parameters[0] 1034 1035 groups = [] 1036 group = None 1037 left = [] 1038 right = [] 1039 required = [] 1040 last = unspecified 1041 1042 for p in parameters: 1043 group_id = p.group 1044 if group_id != last: 1045 last = group_id 1046 group = [] 1047 if group_id < 0: 1048 left.append(group) 1049 elif group_id == 0: 1050 group = required 1051 else: 1052 right.append(group) 1053 group.append(p) 1054 1055 count_min = sys.maxsize 1056 count_max = -1 1057 1058 add("switch (PyTuple_GET_SIZE(args)) {\n") 1059 for subset in permute_optional_groups(left, required, right): 1060 count = len(subset) 1061 count_min = min(count_min, count) 1062 count_max = max(count_max, count) 1063 1064 if count == 0: 1065 add(""" case 0: 1066 break; 1067 """) 1068 continue 1069 1070 group_ids = {p.group for p in subset} # eliminate duplicates 1071 d = {} 1072 d['count'] = count 1073 d['name'] = f.name 1074 d['format_units'] = "".join(p.converter.format_unit for p in subset) 1075 1076 parse_arguments = [] 1077 for p in subset: 1078 p.converter.parse_argument(parse_arguments) 1079 d['parse_arguments'] = ", ".join(parse_arguments) 1080 1081 group_ids.discard(0) 1082 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids] 1083 lines = "\n".join(lines) 1084 1085 s = """ 1086 case {count}: 1087 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{ 1088 goto exit; 1089 }} 1090 {group_booleans} 1091 break; 1092 """[1:] 1093 s = linear_format(s, group_booleans=lines) 1094 s = s.format_map(d) 1095 add(s) 1096 1097 add(" default:\n") 1098 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n' 1099 add(s.format(f.full_name, count_min, count_max)) 1100 add(' goto exit;\n') 1101 add("}") 1102 template_dict['option_group_parsing'] = format_escape(output()) 1103 1104 def render_function(self, clinic, f): 1105 if not f: 1106 return "" 1107 1108 add, output = text_accumulator() 1109 data = CRenderData() 1110 1111 assert f.parameters, "We should always have a 'self' at this point!" 1112 parameters = f.render_parameters 1113 converters = [p.converter for p in parameters] 1114 1115 templates = self.output_templates(f) 1116 1117 f_self = parameters[0] 1118 selfless = parameters[1:] 1119 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!" 1120 1121 last_group = 0 1122 first_optional = len(selfless) 1123 positional = selfless and selfless[-1].is_positional_only() 1124 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 1125 default_return_converter = (not f.return_converter or 1126 f.return_converter.type == 'PyObject *') 1127 has_option_groups = False 1128 1129 # offset i by -1 because first_optional needs to ignore self 1130 for i, p in enumerate(parameters, -1): 1131 c = p.converter 1132 1133 if (i != -1) and (p.default is not unspecified): 1134 first_optional = min(first_optional, i) 1135 1136 # insert group variable 1137 group = p.group 1138 if last_group != group: 1139 last_group = group 1140 if group: 1141 group_name = self.group_to_variable_name(group) 1142 data.impl_arguments.append(group_name) 1143 data.declarations.append("int " + group_name + " = 0;") 1144 data.impl_parameters.append("int " + group_name) 1145 has_option_groups = True 1146 1147 c.render(p, data) 1148 1149 if has_option_groups and (not positional): 1150 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').") 1151 1152 # HACK 1153 # when we're METH_O, but have a custom return converter, 1154 # we use "impl_parameters" for the parsing function 1155 # because that works better. but that means we must 1156 # suppress actually declaring the impl's parameters 1157 # as variables in the parsing function. but since it's 1158 # METH_O, we have exactly one anyway, so we know exactly 1159 # where it is. 1160 if ("METH_O" in templates['methoddef_define'] and 1161 '{impl_parameters}' in templates['parser_prototype']): 1162 data.declarations.pop(0) 1163 1164 template_dict = {} 1165 1166 full_name = f.full_name 1167 template_dict['full_name'] = full_name 1168 1169 if new_or_init: 1170 name = f.cls.name 1171 else: 1172 name = f.name 1173 1174 template_dict['name'] = name 1175 1176 if f.c_basename: 1177 c_basename = f.c_basename 1178 else: 1179 fields = full_name.split(".") 1180 if fields[-1] == '__new__': 1181 fields.pop() 1182 c_basename = "_".join(fields) 1183 1184 template_dict['c_basename'] = c_basename 1185 1186 methoddef_name = "{}_METHODDEF".format(c_basename.upper()) 1187 template_dict['methoddef_name'] = methoddef_name 1188 1189 template_dict['docstring'] = self.docstring_for_c_string(f) 1190 1191 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = '' 1192 f_self.converter.set_template_dict(template_dict) 1193 1194 f.return_converter.render(f, data) 1195 template_dict['impl_return_type'] = f.return_converter.type 1196 1197 template_dict['declarations'] = format_escape("\n".join(data.declarations)) 1198 template_dict['initializers'] = "\n\n".join(data.initializers) 1199 template_dict['modifications'] = '\n\n'.join(data.modifications) 1200 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"' 1201 template_dict['format_units'] = ''.join(data.format_units) 1202 template_dict['parse_arguments'] = ', '.join(data.parse_arguments) 1203 template_dict['impl_parameters'] = ", ".join(data.impl_parameters) 1204 template_dict['impl_arguments'] = ", ".join(data.impl_arguments) 1205 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip()) 1206 template_dict['cleanup'] = format_escape("".join(data.cleanup)) 1207 template_dict['return_value'] = data.return_value 1208 1209 # used by unpack tuple code generator 1210 ignore_self = -1 if isinstance(converters[0], self_converter) else 0 1211 unpack_min = first_optional 1212 unpack_max = len(selfless) 1213 template_dict['unpack_min'] = str(unpack_min) 1214 template_dict['unpack_max'] = str(unpack_max) 1215 1216 if has_option_groups: 1217 self.render_option_group_parsing(f, template_dict) 1218 1219 # buffers, not destination 1220 for name, destination in clinic.destination_buffers.items(): 1221 template = templates[name] 1222 if has_option_groups: 1223 template = linear_format(template, 1224 option_group_parsing=template_dict['option_group_parsing']) 1225 template = linear_format(template, 1226 declarations=template_dict['declarations'], 1227 return_conversion=template_dict['return_conversion'], 1228 initializers=template_dict['initializers'], 1229 modifications=template_dict['modifications'], 1230 cleanup=template_dict['cleanup'], 1231 ) 1232 1233 # Only generate the "exit:" label 1234 # if we have any gotos 1235 need_exit_label = "goto exit;" in template 1236 template = linear_format(template, 1237 exit_label="exit:" if need_exit_label else '' 1238 ) 1239 1240 s = template.format_map(template_dict) 1241 1242 # mild hack: 1243 # reflow long impl declarations 1244 if name in {"impl_prototype", "impl_definition"}: 1245 s = wrap_declarations(s) 1246 1247 if clinic.line_prefix: 1248 s = indent_all_lines(s, clinic.line_prefix) 1249 if clinic.line_suffix: 1250 s = suffix_all_lines(s, clinic.line_suffix) 1251 1252 destination.append(s) 1253 1254 return clinic.get_destination('block').dump() 1255 1256 1257 1258 1259 @contextlib.contextmanager 1260 def OverrideStdioWith(stdout): 1261 saved_stdout = sys.stdout 1262 sys.stdout = stdout 1263 try: 1264 yield 1265 finally: 1266 assert sys.stdout is stdout 1267 sys.stdout = saved_stdout 1268 1269 1270 def create_regex(before, after, word=True, whole_line=True): 1271 """Create an re object for matching marker lines.""" 1272 group_re = r"\w+" if word else ".+" 1273 pattern = r'{}({}){}' 1274 if whole_line: 1275 pattern = '^' + pattern + '$' 1276 pattern = pattern.format(re.escape(before), group_re, re.escape(after)) 1277 return re.compile(pattern) 1278 1279 1280 class Block: 1281 r""" 1282 Represents a single block of text embedded in 1283 another file. If dsl_name is None, the block represents 1284 verbatim text, raw original text from the file, in 1285 which case "input" will be the only non-false member. 1286 If dsl_name is not None, the block represents a Clinic 1287 block. 1288 1289 input is always str, with embedded \n characters. 1290 input represents the original text from the file; 1291 if it's a Clinic block, it is the original text with 1292 the body_prefix and redundant leading whitespace removed. 1293 1294 dsl_name is either str or None. If str, it's the text 1295 found on the start line of the block between the square 1296 brackets. 1297 1298 signatures is either list or None. If it's a list, 1299 it may only contain clinic.Module, clinic.Class, and 1300 clinic.Function objects. At the moment it should 1301 contain at most one of each. 1302 1303 output is either str or None. If str, it's the output 1304 from this block, with embedded '\n' characters. 1305 1306 indent is either str or None. It's the leading whitespace 1307 that was found on every line of input. (If body_prefix is 1308 not empty, this is the indent *after* removing the 1309 body_prefix.) 1310 1311 preindent is either str or None. It's the whitespace that 1312 was found in front of every line of input *before* the 1313 "body_prefix" (see the Language object). If body_prefix 1314 is empty, preindent must always be empty too. 1315 1316 To illustrate indent and preindent: Assume that '_' 1317 represents whitespace. If the block processed was in a 1318 Python file, and looked like this: 1319 ____#/*[python] 1320 ____#__for a in range(20): 1321 ____#____print(a) 1322 ____#[python]*/ 1323 "preindent" would be "____" and "indent" would be "__". 1324 1325 """ 1326 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''): 1327 assert isinstance(input, str) 1328 self.input = input 1329 self.dsl_name = dsl_name 1330 self.signatures = signatures or [] 1331 self.output = output 1332 self.indent = indent 1333 self.preindent = preindent 1334 1335 def __repr__(self): 1336 dsl_name = self.dsl_name or "text" 1337 def summarize(s): 1338 s = repr(s) 1339 if len(s) > 30: 1340 return s[:26] + "..." + s[0] 1341 return s 1342 return "".join(( 1343 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">")) 1344 1345 1346 class BlockParser: 1347 """ 1348 Block-oriented parser for Argument Clinic. 1349 Iterator, yields Block objects. 1350 """ 1351 1352 def __init__(self, input, language, *, verify=True): 1353 """ 1354 "input" should be a str object 1355 with embedded \n characters. 1356 1357 "language" should be a Language object. 1358 """ 1359 language.validate() 1360 1361 self.input = collections.deque(reversed(input.splitlines(keepends=True))) 1362 self.block_start_line_number = self.line_number = 0 1363 1364 self.language = language 1365 before, _, after = language.start_line.partition('{dsl_name}') 1366 assert _ == '{dsl_name}' 1367 self.find_start_re = create_regex(before, after, whole_line=False) 1368 self.start_re = create_regex(before, after) 1369 self.verify = verify 1370 self.last_checksum_re = None 1371 self.last_dsl_name = None 1372 self.dsl_name = None 1373 self.first_block = True 1374 1375 def __iter__(self): 1376 return self 1377 1378 def __next__(self): 1379 while True: 1380 if not self.input: 1381 raise StopIteration 1382 1383 if self.dsl_name: 1384 return_value = self.parse_clinic_block(self.dsl_name) 1385 self.dsl_name = None 1386 self.first_block = False 1387 return return_value 1388 block = self.parse_verbatim_block() 1389 if self.first_block and not block.input: 1390 continue 1391 self.first_block = False 1392 return block 1393 1394 1395 def is_start_line(self, line): 1396 match = self.start_re.match(line.lstrip()) 1397 return match.group(1) if match else None 1398 1399 def _line(self, lookahead=False): 1400 self.line_number += 1 1401 line = self.input.pop() 1402 if not lookahead: 1403 self.language.parse_line(line) 1404 return line 1405 1406 def parse_verbatim_block(self): 1407 add, output = text_accumulator() 1408 self.block_start_line_number = self.line_number 1409 1410 while self.input: 1411 line = self._line() 1412 dsl_name = self.is_start_line(line) 1413 if dsl_name: 1414 self.dsl_name = dsl_name 1415 break 1416 add(line) 1417 1418 return Block(output()) 1419 1420 def parse_clinic_block(self, dsl_name): 1421 input_add, input_output = text_accumulator() 1422 self.block_start_line_number = self.line_number + 1 1423 stop_line = self.language.stop_line.format(dsl_name=dsl_name) 1424 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name) 1425 1426 def is_stop_line(line): 1427 # make sure to recognize stop line even if it 1428 # doesn't end with EOL (it could be the very end of the file) 1429 if not line.startswith(stop_line): 1430 return False 1431 remainder = line[len(stop_line):] 1432 return (not remainder) or remainder.isspace() 1433 1434 # consume body of program 1435 while self.input: 1436 line = self._line() 1437 if is_stop_line(line) or self.is_start_line(line): 1438 break 1439 if body_prefix: 1440 line = line.lstrip() 1441 assert line.startswith(body_prefix) 1442 line = line[len(body_prefix):] 1443 input_add(line) 1444 1445 # consume output and checksum line, if present. 1446 if self.last_dsl_name == dsl_name: 1447 checksum_re = self.last_checksum_re 1448 else: 1449 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}') 1450 assert _ == '{arguments}' 1451 checksum_re = create_regex(before, after, word=False) 1452 self.last_dsl_name = dsl_name 1453 self.last_checksum_re = checksum_re 1454 1455 # scan forward for checksum line 1456 output_add, output_output = text_accumulator() 1457 arguments = None 1458 while self.input: 1459 line = self._line(lookahead=True) 1460 match = checksum_re.match(line.lstrip()) 1461 arguments = match.group(1) if match else None 1462 if arguments: 1463 break 1464 output_add(line) 1465 if self.is_start_line(line): 1466 break 1467 1468 output = output_output() 1469 if arguments: 1470 d = {} 1471 for field in shlex.split(arguments): 1472 name, equals, value = field.partition('=') 1473 if not equals: 1474 fail("Mangled Argument Clinic marker line: {!r}".format(line)) 1475 d[name.strip()] = value.strip() 1476 1477 if self.verify: 1478 if 'input' in d: 1479 checksum = d['output'] 1480 input_checksum = d['input'] 1481 else: 1482 checksum = d['checksum'] 1483 input_checksum = None 1484 1485 computed = compute_checksum(output, len(checksum)) 1486 if checksum != computed: 1487 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n" 1488 "Suggested fix: remove all generated code including " 1489 "the end marker,\n" 1490 "or use the '-f' option." 1491 .format(checksum, computed)) 1492 else: 1493 # put back output 1494 output_lines = output.splitlines(keepends=True) 1495 self.line_number -= len(output_lines) 1496 self.input.extend(reversed(output_lines)) 1497 output = None 1498 1499 return Block(input_output(), dsl_name, output=output) 1500 1501 1502 class BlockPrinter: 1503 1504 def __init__(self, language, f=None): 1505 self.language = language 1506 self.f = f or io.StringIO() 1507 1508 def print_block(self, block): 1509 input = block.input 1510 output = block.output 1511 dsl_name = block.dsl_name 1512 write = self.f.write 1513 1514 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name) 1515 1516 if not dsl_name: 1517 write(input) 1518 return 1519 1520 write(self.language.start_line.format(dsl_name=dsl_name)) 1521 write("\n") 1522 1523 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name) 1524 if not body_prefix: 1525 write(input) 1526 else: 1527 for line in input.split('\n'): 1528 write(body_prefix) 1529 write(line) 1530 write("\n") 1531 1532 write(self.language.stop_line.format(dsl_name=dsl_name)) 1533 write("\n") 1534 1535 input = ''.join(block.input) 1536 output = ''.join(block.output) 1537 if output: 1538 if not output.endswith('\n'): 1539 output += '\n' 1540 write(output) 1541 1542 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16)) 1543 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments)) 1544 write("\n") 1545 1546 def write(self, text): 1547 self.f.write(text) 1548 1549 1550 class BufferSeries: 1551 """ 1552 Behaves like a "defaultlist". 1553 When you ask for an index that doesn't exist yet, 1554 the object grows the list until that item exists. 1555 So o[n] will always work. 1556 1557 Supports negative indices for actual items. 1558 e.g. o[-1] is an element immediately preceding o[0]. 1559 """ 1560 1561 def __init__(self): 1562 self._start = 0 1563 self._array = [] 1564 self._constructor = _text_accumulator 1565 1566 def __getitem__(self, i): 1567 i -= self._start 1568 if i < 0: 1569 self._start += i 1570 prefix = [self._constructor() for x in range(-i)] 1571 self._array = prefix + self._array 1572 i = 0 1573 while i >= len(self._array): 1574 self._array.append(self._constructor()) 1575 return self._array[i] 1576 1577 def clear(self): 1578 for ta in self._array: 1579 ta._text.clear() 1580 1581 def dump(self): 1582 texts = [ta.output() for ta in self._array] 1583 return "".join(texts) 1584 1585 1586 class Destination: 1587 def __init__(self, name, type, clinic, *args): 1588 self.name = name 1589 self.type = type 1590 self.clinic = clinic 1591 valid_types = ('buffer', 'file', 'suppress') 1592 if type not in valid_types: 1593 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types)) 1594 extra_arguments = 1 if type == "file" else 0 1595 if len(args) < extra_arguments: 1596 fail("Not enough arguments for destination " + name + " new " + type) 1597 if len(args) > extra_arguments: 1598 fail("Too many arguments for destination " + name + " new " + type) 1599 if type =='file': 1600 d = {} 1601 filename = clinic.filename 1602 d['path'] = filename 1603 dirname, basename = os.path.split(filename) 1604 if not dirname: 1605 dirname = '.' 1606 d['dirname'] = dirname 1607 d['basename'] = basename 1608 d['basename_root'], d['basename_extension'] = os.path.splitext(filename) 1609 self.filename = args[0].format_map(d) 1610 1611 self.buffers = BufferSeries() 1612 1613 def __repr__(self): 1614 if self.type == 'file': 1615 file_repr = " " + repr(self.filename) 1616 else: 1617 file_repr = '' 1618 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">")) 1619 1620 def clear(self): 1621 if self.type != 'buffer': 1622 fail("Can't clear destination" + self.name + " , it's not of type buffer") 1623 self.buffers.clear() 1624 1625 def dump(self): 1626 return self.buffers.dump() 1627 1628 1629 # maps strings to Language objects. 1630 # "languages" maps the name of the language ("C", "Python"). 1631 # "extensions" maps the file extension ("c", "py"). 1632 languages = { 'C': CLanguage, 'Python': PythonLanguage } 1633 extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } 1634 extensions['py'] = PythonLanguage 1635 1636 1637 # maps strings to callables. 1638 # these callables must be of the form: 1639 # def foo(name, default, *, ...) 1640 # The callable may have any number of keyword-only parameters. 1641 # The callable must return a CConverter object. 1642 # The callable should not call builtins.print. 1643 converters = {} 1644 1645 # maps strings to callables. 1646 # these callables follow the same rules as those for "converters" above. 1647 # note however that they will never be called with keyword-only parameters. 1648 legacy_converters = {} 1649 1650 1651 # maps strings to callables. 1652 # these callables must be of the form: 1653 # def foo(*, ...) 1654 # The callable may have any number of keyword-only parameters. 1655 # The callable must return a CConverter object. 1656 # The callable should not call builtins.print. 1657 return_converters = {} 1658 1659 clinic = None 1660 class Clinic: 1661 1662 presets_text = """ 1663 preset block 1664 everything block 1665 methoddef_ifndef buffer 1 1666 docstring_prototype suppress 1667 parser_prototype suppress 1668 cpp_if suppress 1669 cpp_endif suppress 1670 1671 preset original 1672 everything block 1673 methoddef_ifndef buffer 1 1674 docstring_prototype suppress 1675 parser_prototype suppress 1676 cpp_if suppress 1677 cpp_endif suppress 1678 1679 preset file 1680 everything file 1681 methoddef_ifndef file 1 1682 docstring_prototype suppress 1683 parser_prototype suppress 1684 impl_definition block 1685 1686 preset buffer 1687 everything buffer 1688 methoddef_ifndef buffer 1 1689 impl_definition block 1690 docstring_prototype suppress 1691 impl_prototype suppress 1692 parser_prototype suppress 1693 1694 preset partial-buffer 1695 everything buffer 1696 methoddef_ifndef buffer 1 1697 docstring_prototype block 1698 impl_prototype suppress 1699 methoddef_define block 1700 parser_prototype block 1701 impl_definition block 1702 1703 """ 1704 1705 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None): 1706 # maps strings to Parser objects. 1707 # (instantiated from the "parsers" global.) 1708 self.parsers = {} 1709 self.language = language 1710 if printer: 1711 fail("Custom printers are broken right now") 1712 self.printer = printer or BlockPrinter(language) 1713 self.verify = verify 1714 self.force = force 1715 self.filename = filename 1716 self.modules = collections.OrderedDict() 1717 self.classes = collections.OrderedDict() 1718 self.functions = [] 1719 1720 self.line_prefix = self.line_suffix = '' 1721 1722 self.destinations = {} 1723 self.add_destination("block", "buffer") 1724 self.add_destination("suppress", "suppress") 1725 self.add_destination("buffer", "buffer") 1726 if filename: 1727 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h") 1728 1729 d = self.get_destination_buffer 1730 self.destination_buffers = collections.OrderedDict(( 1731 ('cpp_if', d('file')), 1732 ('docstring_prototype', d('suppress')), 1733 ('docstring_definition', d('file')), 1734 ('methoddef_define', d('file')), 1735 ('impl_prototype', d('file')), 1736 ('parser_prototype', d('suppress')), 1737 ('parser_definition', d('file')), 1738 ('cpp_endif', d('file')), 1739 ('methoddef_ifndef', d('file', 1)), 1740 ('impl_definition', d('block')), 1741 )) 1742 1743 self.destination_buffers_stack = [] 1744 self.ifndef_symbols = set() 1745 1746 self.presets = {} 1747 preset = None 1748 for line in self.presets_text.strip().split('\n'): 1749 line = line.strip() 1750 if not line: 1751 continue 1752 name, value, *options = line.split() 1753 if name == 'preset': 1754 self.presets[value] = preset = collections.OrderedDict() 1755 continue 1756 1757 if len(options): 1758 index = int(options[0]) 1759 else: 1760 index = 0 1761 buffer = self.get_destination_buffer(value, index) 1762 1763 if name == 'everything': 1764 for name in self.destination_buffers: 1765 preset[name] = buffer 1766 continue 1767 1768 assert name in self.destination_buffers 1769 preset[name] = buffer 1770 1771 global clinic 1772 clinic = self 1773 1774 def add_destination(self, name, type, *args): 1775 if name in self.destinations: 1776 fail("Destination already exists: " + repr(name)) 1777 self.destinations[name] = Destination(name, type, self, *args) 1778 1779 def get_destination(self, name): 1780 d = self.destinations.get(name) 1781 if not d: 1782 fail("Destination does not exist: " + repr(name)) 1783 return d 1784 1785 def get_destination_buffer(self, name, item=0): 1786 d = self.get_destination(name) 1787 return d.buffers[item] 1788 1789 def parse(self, input): 1790 printer = self.printer 1791 self.block_parser = BlockParser(input, self.language, verify=self.verify) 1792 for block in self.block_parser: 1793 dsl_name = block.dsl_name 1794 if dsl_name: 1795 if dsl_name not in self.parsers: 1796 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name) 1797 self.parsers[dsl_name] = parsers[dsl_name](self) 1798 parser = self.parsers[dsl_name] 1799 try: 1800 parser.parse(block) 1801 except Exception: 1802 fail('Exception raised during parsing:\n' + 1803 traceback.format_exc().rstrip()) 1804 printer.print_block(block) 1805 1806 second_pass_replacements = {} 1807 1808 # these are destinations not buffers 1809 for name, destination in self.destinations.items(): 1810 if destination.type == 'suppress': 1811 continue 1812 output = destination.dump() 1813 1814 if output: 1815 1816 block = Block("", dsl_name="clinic", output=output) 1817 1818 if destination.type == 'buffer': 1819 block.input = "dump " + name + "\n" 1820 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.") 1821 printer.write("\n") 1822 printer.print_block(block) 1823 continue 1824 1825 if destination.type == 'file': 1826 try: 1827 dirname = os.path.dirname(destination.filename) 1828 try: 1829 os.makedirs(dirname) 1830 except FileExistsError: 1831 if not os.path.isdir(dirname): 1832 fail("Can't write to destination {}, " 1833 "can't make directory {}!".format( 1834 destination.filename, dirname)) 1835 if self.verify: 1836 with open(destination.filename, "rt") as f: 1837 parser_2 = BlockParser(f.read(), language=self.language) 1838 blocks = list(parser_2) 1839 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'): 1840 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!") 1841 except FileNotFoundError: 1842 pass 1843 1844 block.input = 'preserve\n' 1845 printer_2 = BlockPrinter(self.language) 1846 printer_2.print_block(block) 1847 with open(destination.filename, "wt") as f: 1848 f.write(printer_2.f.getvalue()) 1849 continue 1850 text = printer.f.getvalue() 1851 1852 if second_pass_replacements: 1853 printer_2 = BlockPrinter(self.language) 1854 parser_2 = BlockParser(text, self.language) 1855 changed = False 1856 for block in parser_2: 1857 if block.dsl_name: 1858 for id, replacement in second_pass_replacements.items(): 1859 if id in block.output: 1860 changed = True 1861 block.output = block.output.replace(id, replacement) 1862 printer_2.print_block(block) 1863 if changed: 1864 text = printer_2.f.getvalue() 1865 1866 return text 1867 1868 1869 def _module_and_class(self, fields): 1870 """ 1871 fields should be an iterable of field names. 1872 returns a tuple of (module, class). 1873 the module object could actually be self (a clinic object). 1874 this function is only ever used to find the parent of where 1875 a new class/module should go. 1876 """ 1877 in_classes = False 1878 parent = module = self 1879 cls = None 1880 so_far = [] 1881 1882 for field in fields: 1883 so_far.append(field) 1884 if not in_classes: 1885 child = parent.modules.get(field) 1886 if child: 1887 parent = module = child 1888 continue 1889 in_classes = True 1890 if not hasattr(parent, 'classes'): 1891 return module, cls 1892 child = parent.classes.get(field) 1893 if not child: 1894 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.") 1895 cls = parent = child 1896 1897 return module, cls 1898 1899 1900 def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'): 1901 extension = os.path.splitext(filename)[1][1:] 1902 if not extension: 1903 fail("Can't extract file type for file " + repr(filename)) 1904 1905 try: 1906 language = extensions[extension](filename) 1907 except KeyError: 1908 fail("Can't identify file type for file " + repr(filename)) 1909 1910 with open(filename, 'r', encoding=encoding) as f: 1911 raw = f.read() 1912 1913 # exit quickly if there are no clinic markers in the file 1914 find_start_re = BlockParser("", language).find_start_re 1915 if not find_start_re.search(raw): 1916 return 1917 1918 clinic = Clinic(language, force=force, verify=verify, filename=filename) 1919 cooked = clinic.parse(raw) 1920 if (cooked == raw) and not force: 1921 return 1922 1923 directory = os.path.dirname(filename) or '.' 1924 1925 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir: 1926 bytes = cooked.encode(encoding) 1927 tmpfilename = os.path.join(tmpdir, os.path.basename(filename)) 1928 with open(tmpfilename, "wb") as f: 1929 f.write(bytes) 1930 os.replace(tmpfilename, output or filename) 1931 1932 1933 def compute_checksum(input, length=None): 1934 input = input or '' 1935 s = hashlib.sha1(input.encode('utf-8')).hexdigest() 1936 if length: 1937 s = s[:length] 1938 return s 1939 1940 1941 1942 1943 class PythonParser: 1944 def __init__(self, clinic): 1945 pass 1946 1947 def parse(self, block): 1948 s = io.StringIO() 1949 with OverrideStdioWith(s): 1950 exec(block.input) 1951 block.output = s.getvalue() 1952 1953 1954 class Module: 1955 def __init__(self, name, module=None): 1956 self.name = name 1957 self.module = self.parent = module 1958 1959 self.modules = collections.OrderedDict() 1960 self.classes = collections.OrderedDict() 1961 self.functions = [] 1962 1963 def __repr__(self): 1964 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">" 1965 1966 class Class: 1967 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None): 1968 self.name = name 1969 self.module = module 1970 self.cls = cls 1971 self.typedef = typedef 1972 self.type_object = type_object 1973 self.parent = cls or module 1974 1975 self.classes = collections.OrderedDict() 1976 self.functions = [] 1977 1978 def __repr__(self): 1979 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">" 1980 1981 unsupported_special_methods = set(""" 1982 1983 __abs__ 1984 __add__ 1985 __and__ 1986 __bytes__ 1987 __call__ 1988 __complex__ 1989 __delitem__ 1990 __divmod__ 1991 __eq__ 1992 __float__ 1993 __floordiv__ 1994 __ge__ 1995 __getattr__ 1996 __getattribute__ 1997 __getitem__ 1998 __gt__ 1999 __hash__ 2000 __iadd__ 2001 __iand__ 2002 __ifloordiv__ 2003 __ilshift__ 2004 __imatmul__ 2005 __imod__ 2006 __imul__ 2007 __index__ 2008 __int__ 2009 __invert__ 2010 __ior__ 2011 __ipow__ 2012 __irshift__ 2013 __isub__ 2014 __iter__ 2015 __itruediv__ 2016 __ixor__ 2017 __le__ 2018 __len__ 2019 __lshift__ 2020 __lt__ 2021 __matmul__ 2022 __mod__ 2023 __mul__ 2024 __neg__ 2025 __new__ 2026 __next__ 2027 __or__ 2028 __pos__ 2029 __pow__ 2030 __radd__ 2031 __rand__ 2032 __rdivmod__ 2033 __repr__ 2034 __rfloordiv__ 2035 __rlshift__ 2036 __rmatmul__ 2037 __rmod__ 2038 __rmul__ 2039 __ror__ 2040 __rpow__ 2041 __rrshift__ 2042 __rshift__ 2043 __rsub__ 2044 __rtruediv__ 2045 __rxor__ 2046 __setattr__ 2047 __setitem__ 2048 __str__ 2049 __sub__ 2050 __truediv__ 2051 __xor__ 2052 2053 """.strip().split()) 2054 2055 2056 INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """ 2057 INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW 2058 """.replace(",", "").strip().split() 2059 2060 class Function: 2061 """ 2062 Mutable duck type for inspect.Function. 2063 2064 docstring - a str containing 2065 * embedded line breaks 2066 * text outdented to the left margin 2067 * no trailing whitespace. 2068 It will always be true that 2069 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) 2070 """ 2071 2072 def __init__(self, parameters=None, *, name, 2073 module, cls=None, c_basename=None, 2074 full_name=None, 2075 return_converter, return_annotation=_empty, 2076 docstring=None, kind=CALLABLE, coexist=False, 2077 docstring_only=False): 2078 self.parameters = parameters or collections.OrderedDict() 2079 self.return_annotation = return_annotation 2080 self.name = name 2081 self.full_name = full_name 2082 self.module = module 2083 self.cls = cls 2084 self.parent = cls or module 2085 self.c_basename = c_basename 2086 self.return_converter = return_converter 2087 self.docstring = docstring or '' 2088 self.kind = kind 2089 self.coexist = coexist 2090 self.self_converter = None 2091 # docstring_only means "don't generate a machine-readable 2092 # signature, just a normal docstring". it's True for 2093 # functions with optional groups because we can't represent 2094 # those accurately with inspect.Signature in 3.4. 2095 self.docstring_only = docstring_only 2096 2097 self.rendered_parameters = None 2098 2099 __render_parameters__ = None 2100 @property 2101 def render_parameters(self): 2102 if not self.__render_parameters__: 2103 self.__render_parameters__ = l = [] 2104 for p in self.parameters.values(): 2105 p = p.copy() 2106 p.converter.pre_render() 2107 l.append(p) 2108 return self.__render_parameters__ 2109 2110 @property 2111 def methoddef_flags(self): 2112 if self.kind in (METHOD_INIT, METHOD_NEW): 2113 return None 2114 flags = [] 2115 if self.kind == CLASS_METHOD: 2116 flags.append('METH_CLASS') 2117 elif self.kind == STATIC_METHOD: 2118 flags.append('METH_STATIC') 2119 else: 2120 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind) 2121 if self.coexist: 2122 flags.append('METH_COEXIST') 2123 return '|'.join(flags) 2124 2125 def __repr__(self): 2126 return '<clinic.Function ' + self.name + '>' 2127 2128 def copy(self, **overrides): 2129 kwargs = { 2130 'name': self.name, 'module': self.module, 'parameters': self.parameters, 2131 'cls': self.cls, 'c_basename': self.c_basename, 2132 'full_name': self.full_name, 2133 'return_converter': self.return_converter, 'return_annotation': self.return_annotation, 2134 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist, 2135 'docstring_only': self.docstring_only, 2136 } 2137 kwargs.update(overrides) 2138 f = Function(**kwargs) 2139 2140 parameters = collections.OrderedDict() 2141 for name, value in f.parameters.items(): 2142 value = value.copy(function=f) 2143 parameters[name] = value 2144 f.parameters = parameters 2145 return f 2146 2147 2148 class Parameter: 2149 """ 2150 Mutable duck type of inspect.Parameter. 2151 """ 2152 2153 def __init__(self, name, kind, *, default=_empty, 2154 function, converter, annotation=_empty, 2155 docstring=None, group=0): 2156 self.name = name 2157 self.kind = kind 2158 self.default = default 2159 self.function = function 2160 self.converter = converter 2161 self.annotation = annotation 2162 self.docstring = docstring or '' 2163 self.group = group 2164 2165 def __repr__(self): 2166 return '<clinic.Parameter ' + self.name + '>' 2167 2168 def is_keyword_only(self): 2169 return self.kind == inspect.Parameter.KEYWORD_ONLY 2170 2171 def is_positional_only(self): 2172 return self.kind == inspect.Parameter.POSITIONAL_ONLY 2173 2174 def copy(self, **overrides): 2175 kwargs = { 2176 'name': self.name, 'kind': self.kind, 'default':self.default, 2177 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, 2178 'docstring': self.docstring, 'group': self.group, 2179 } 2180 kwargs.update(overrides) 2181 if 'converter' not in overrides: 2182 converter = copy.copy(self.converter) 2183 converter.function = kwargs['function'] 2184 kwargs['converter'] = converter 2185 return Parameter(**kwargs) 2186 2187 2188 2189 class LandMine: 2190 # try to access any 2191 def __init__(self, message): 2192 self.__message__ = message 2193 2194 def __repr__(self): 2195 return '<LandMine ' + repr(self.__message__) + ">" 2196 2197 def __getattribute__(self, name): 2198 if name in ('__repr__', '__message__'): 2199 return super().__getattribute__(name) 2200 # raise RuntimeError(repr(name)) 2201 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__) 2202 2203 2204 def add_c_converter(f, name=None): 2205 if not name: 2206 name = f.__name__ 2207 if not name.endswith('_converter'): 2208 return f 2209 name = name[:-len('_converter')] 2210 converters[name] = f 2211 return f 2212 2213 def add_default_legacy_c_converter(cls): 2214 # automatically add converter for default format unit 2215 # (but without stomping on the existing one if it's already 2216 # set, in case you subclass) 2217 if ((cls.format_unit not in ('O&', '')) and 2218 (cls.format_unit not in legacy_converters)): 2219 legacy_converters[cls.format_unit] = cls 2220 return cls 2221 2222 def add_legacy_c_converter(format_unit, **kwargs): 2223 """ 2224 Adds a legacy converter. 2225 """ 2226 def closure(f): 2227 if not kwargs: 2228 added_f = f 2229 else: 2230 added_f = functools.partial(f, **kwargs) 2231 if format_unit: 2232 legacy_converters[format_unit] = added_f 2233 return f 2234 return closure 2235 2236 class CConverterAutoRegister(type): 2237 def __init__(cls, name, bases, classdict): 2238 add_c_converter(cls) 2239 add_default_legacy_c_converter(cls) 2240 2241 class CConverter(metaclass=CConverterAutoRegister): 2242 """ 2243 For the init function, self, name, function, and default 2244 must be keyword-or-positional parameters. All other 2245 parameters must be keyword-only. 2246 """ 2247 2248 # The C name to use for this variable. 2249 name = None 2250 2251 # The Python name to use for this variable. 2252 py_name = None 2253 2254 # The C type to use for this variable. 2255 # 'type' should be a Python string specifying the type, e.g. "int". 2256 # If this is a pointer type, the type string should end with ' *'. 2257 type = None 2258 2259 # The Python default value for this parameter, as a Python value. 2260 # Or the magic value "unspecified" if there is no default. 2261 # Or the magic value "unknown" if this value is a cannot be evaluated 2262 # at Argument-Clinic-preprocessing time (but is presumed to be valid 2263 # at runtime). 2264 default = unspecified 2265 2266 # If not None, default must be isinstance() of this type. 2267 # (You can also specify a tuple of types.) 2268 default_type = None 2269 2270 # "default" converted into a C value, as a string. 2271 # Or None if there is no default. 2272 c_default = None 2273 2274 # "default" converted into a Python value, as a string. 2275 # Or None if there is no default. 2276 py_default = None 2277 2278 # The default value used to initialize the C variable when 2279 # there is no default, but not specifying a default may 2280 # result in an "uninitialized variable" warning. This can 2281 # easily happen when using option groups--although 2282 # properly-written code won't actually use the variable, 2283 # the variable does get passed in to the _impl. (Ah, if 2284 # only dataflow analysis could inline the static function!) 2285 # 2286 # This value is specified as a string. 2287 # Every non-abstract subclass should supply a valid value. 2288 c_ignored_default = 'NULL' 2289 2290 # The C converter *function* to be used, if any. 2291 # (If this is not None, format_unit must be 'O&'.) 2292 converter = None 2293 2294 # Should Argument Clinic add a '&' before the name of 2295 # the variable when passing it into the _impl function? 2296 impl_by_reference = False 2297 2298 # Should Argument Clinic add a '&' before the name of 2299 # the variable when passing it into PyArg_ParseTuple (AndKeywords)? 2300 parse_by_reference = True 2301 2302 ############################################################# 2303 ############################################################# 2304 ## You shouldn't need to read anything below this point to ## 2305 ## write your own converter functions. ## 2306 ############################################################# 2307 ############################################################# 2308 2309 # The "format unit" to specify for this variable when 2310 # parsing arguments using PyArg_ParseTuple (AndKeywords). 2311 # Custom converters should always use the default value of 'O&'. 2312 format_unit = 'O&' 2313 2314 # What encoding do we want for this variable? Only used 2315 # by format units starting with 'e'. 2316 encoding = None 2317 2318 # Should this object be required to be a subclass of a specific type? 2319 # If not None, should be a string representing a pointer to a 2320 # PyTypeObject (e.g. "&PyUnicode_Type"). 2321 # Only used by the 'O!' format unit (and the "object" converter). 2322 subclass_of = None 2323 2324 # Do we want an adjacent '_length' variable for this variable? 2325 # Only used by format units ending with '#'. 2326 length = False 2327 2328 # Should we show this parameter in the generated 2329 # __text_signature__? This is *almost* always True. 2330 # (It's only False for __new__, __init__, and METH_STATIC functions.) 2331 show_in_signature = True 2332 2333 # Overrides the name used in a text signature. 2334 # The name used for a "self" parameter must be one of 2335 # self, type, or module; however users can set their own. 2336 # This lets the self_converter overrule the user-settable 2337 # name, *just* for the text signature. 2338 # Only set by self_converter. 2339 signature_name = None 2340 2341 # keep in sync with self_converter.__init__! 2342 def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs): 2343 self.name = name 2344 self.py_name = py_name 2345 2346 if default is not unspecified: 2347 if self.default_type and not isinstance(default, (self.default_type, Unknown)): 2348 if isinstance(self.default_type, type): 2349 types_str = self.default_type.__name__ 2350 else: 2351 types_str = ', '.join((cls.__name__ for cls in self.default_type)) 2352 fail("{}: default value {!r} for field {} is not of type {}".format( 2353 self.__class__.__name__, default, name, types_str)) 2354 self.default = default 2355 2356 if c_default: 2357 self.c_default = c_default 2358 if py_default: 2359 self.py_default = py_default 2360 2361 if annotation != unspecified: 2362 fail("The 'annotation' parameter is not currently permitted.") 2363 2364 # this is deliberate, to prevent you from caching information 2365 # about the function in the init. 2366 # (that breaks if we get cloned.) 2367 # so after this change we will noisily fail. 2368 self.function = LandMine("Don't access members of self.function inside converter_init!") 2369 self.converter_init(**kwargs) 2370 self.function = function 2371 2372 def converter_init(self): 2373 pass 2374 2375 def is_optional(self): 2376 return (self.default is not unspecified) 2377 2378 def _render_self(self, parameter, data): 2379 self.parameter = parameter 2380 original_name = self.name 2381 name = ensure_legal_c_identifier(original_name) 2382 2383 # impl_arguments 2384 s = ("&" if self.impl_by_reference else "") + name 2385 data.impl_arguments.append(s) 2386 if self.length: 2387 data.impl_arguments.append(self.length_name()) 2388 2389 # impl_parameters 2390 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference)) 2391 if self.length: 2392 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name()) 2393 2394 def _render_non_self(self, parameter, data): 2395 self.parameter = parameter 2396 original_name = self.name 2397 name = ensure_legal_c_identifier(original_name) 2398 2399 # declarations 2400 d = self.declaration() 2401 data.declarations.append(d) 2402 2403 # initializers 2404 initializers = self.initialize() 2405 if initializers: 2406 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip()) 2407 2408 # modifications 2409 modifications = self.modify() 2410 if modifications: 2411 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip()) 2412 2413 # keywords 2414 if parameter.is_positional_only(): 2415 data.keywords.append('') 2416 else: 2417 data.keywords.append(parameter.name) 2418 2419 # format_units 2420 if self.is_optional() and '|' not in data.format_units: 2421 data.format_units.append('|') 2422 if parameter.is_keyword_only() and '$' not in data.format_units: 2423 data.format_units.append('$') 2424 data.format_units.append(self.format_unit) 2425 2426 # parse_arguments 2427 self.parse_argument(data.parse_arguments) 2428 2429 # cleanup 2430 cleanup = self.cleanup() 2431 if cleanup: 2432 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") 2433 2434 def render(self, parameter, data): 2435 """ 2436 parameter is a clinic.Parameter instance. 2437 data is a CRenderData instance. 2438 """ 2439 self._render_self(parameter, data) 2440 self._render_non_self(parameter, data) 2441 2442 def length_name(self): 2443 """Computes the name of the associated "length" variable.""" 2444 if not self.length: 2445 return None 2446 return ensure_legal_c_identifier(self.name) + "_length" 2447 2448 # Why is this one broken out separately? 2449 # For "positional-only" function parsing, 2450 # which generates a bunch of PyArg_ParseTuple calls. 2451 def parse_argument(self, list): 2452 assert not (self.converter and self.encoding) 2453 if self.format_unit == 'O&': 2454 assert self.converter 2455 list.append(self.converter) 2456 2457 if self.encoding: 2458 list.append(c_repr(self.encoding)) 2459 elif self.subclass_of: 2460 list.append(self.subclass_of) 2461 2462 legal_name = ensure_legal_c_identifier(self.name) 2463 s = ("&" if self.parse_by_reference else "") + legal_name 2464 list.append(s) 2465 2466 if self.length: 2467 list.append("&" + self.length_name()) 2468 2469 # 2470 # All the functions after here are intended as extension points. 2471 # 2472 2473 def simple_declaration(self, by_reference=False): 2474 """ 2475 Computes the basic declaration of the variable. 2476 Used in computing the prototype declaration and the 2477 variable declaration. 2478 """ 2479 prototype = [self.type] 2480 if by_reference or not self.type.endswith('*'): 2481 prototype.append(" ") 2482 if by_reference: 2483 prototype.append('*') 2484 prototype.append(ensure_legal_c_identifier(self.name)) 2485 return "".join(prototype) 2486 2487 def declaration(self): 2488 """ 2489 The C statement to declare this variable. 2490 """ 2491 declaration = [self.simple_declaration()] 2492 default = self.c_default 2493 if not default and self.parameter.group: 2494 default = self.c_ignored_default 2495 if default: 2496 declaration.append(" = ") 2497 declaration.append(default) 2498 declaration.append(";") 2499 if self.length: 2500 declaration.append('\nPy_ssize_clean_t ') 2501 declaration.append(self.length_name()) 2502 declaration.append(';') 2503 return "".join(declaration) 2504 2505 def initialize(self): 2506 """ 2507 The C statements required to set up this variable before parsing. 2508 Returns a string containing this code indented at column 0. 2509 If no initialization is necessary, returns an empty string. 2510 """ 2511 return "" 2512 2513 def modify(self): 2514 """ 2515 The C statements required to modify this variable after parsing. 2516 Returns a string containing this code indented at column 0. 2517 If no initialization is necessary, returns an empty string. 2518 """ 2519 return "" 2520 2521 def cleanup(self): 2522 """ 2523 The C statements required to clean up after this variable. 2524 Returns a string containing this code indented at column 0. 2525 If no cleanup is necessary, returns an empty string. 2526 """ 2527 return "" 2528 2529 def pre_render(self): 2530 """ 2531 A second initialization function, like converter_init, 2532 called just before rendering. 2533 You are permitted to examine self.function here. 2534 """ 2535 pass 2536 2537 2538 class bool_converter(CConverter): 2539 type = 'int' 2540 default_type = bool 2541 format_unit = 'p' 2542 c_ignored_default = '0' 2543 2544 def converter_init(self, *, accept={object}): 2545 if accept == {int}: 2546 self.format_unit = 'i' 2547 elif accept != {object}: 2548 fail("bool_converter: illegal 'accept' argument " + repr(accept)) 2549 if self.default is not unspecified: 2550 self.default = bool(self.default) 2551 self.c_default = str(int(self.default)) 2552 2553 class char_converter(CConverter): 2554 type = 'char' 2555 default_type = (bytes, bytearray) 2556 format_unit = 'c' 2557 c_ignored_default = "'\0'" 2558 2559 def converter_init(self): 2560 if isinstance(self.default, self.default_type) and (len(self.default) != 1): 2561 fail("char_converter: illegal default value " + repr(self.default)) 2562 2563 2564 @add_legacy_c_converter('B', bitwise=True) 2565 class unsigned_char_converter(CConverter): 2566 type = 'unsigned char' 2567 default_type = int 2568 format_unit = 'b' 2569 c_ignored_default = "'\0'" 2570 2571 def converter_init(self, *, bitwise=False): 2572 if bitwise: 2573 self.format_unit = 'B' 2574 2575 class byte_converter(unsigned_char_converter): pass 2576 2577 class short_converter(CConverter): 2578 type = 'short' 2579 default_type = int 2580 format_unit = 'h' 2581 c_ignored_default = "0" 2582 2583 class unsigned_short_converter(CConverter): 2584 type = 'unsigned short' 2585 default_type = int 2586 format_unit = 'H' 2587 c_ignored_default = "0" 2588 2589 def converter_init(self, *, bitwise=False): 2590 if not bitwise: 2591 fail("Unsigned shorts must be bitwise (for now).") 2592 2593 @add_legacy_c_converter('C', accept={str}) 2594 class int_converter(CConverter): 2595 type = 'int' 2596 default_type = int 2597 format_unit = 'i' 2598 c_ignored_default = "0" 2599 2600 def converter_init(self, *, accept={int}, type=None): 2601 if accept == {str}: 2602 self.format_unit = 'C' 2603 elif accept != {int}: 2604 fail("int_converter: illegal 'accept' argument " + repr(accept)) 2605 if type != None: 2606 self.type = type 2607 2608 class unsigned_int_converter(CConverter): 2609 type = 'unsigned int' 2610 default_type = int 2611 format_unit = 'I' 2612 c_ignored_default = "0" 2613 2614 def converter_init(self, *, bitwise=False): 2615 if not bitwise: 2616 fail("Unsigned ints must be bitwise (for now).") 2617 2618 class long_converter(CConverter): 2619 type = 'long' 2620 default_type = int 2621 format_unit = 'l' 2622 c_ignored_default = "0" 2623 2624 class unsigned_long_converter(CConverter): 2625 type = 'unsigned long' 2626 default_type = int 2627 format_unit = 'k' 2628 c_ignored_default = "0" 2629 2630 def converter_init(self, *, bitwise=False): 2631 if not bitwise: 2632 fail("Unsigned longs must be bitwise (for now).") 2633 2634 class long_long_converter(CConverter): 2635 type = 'long long' 2636 default_type = int 2637 format_unit = 'L' 2638 c_ignored_default = "0" 2639 2640 class unsigned_long_long_converter(CConverter): 2641 type = 'unsigned long long' 2642 default_type = int 2643 format_unit = 'K' 2644 c_ignored_default = "0" 2645 2646 def converter_init(self, *, bitwise=False): 2647 if not bitwise: 2648 fail("Unsigned long long must be bitwise (for now).") 2649 2650 2651 class Py_ssize_t_converter(CConverter): 2652 type = 'Py_ssize_t' 2653 c_ignored_default = "0" 2654 2655 def converter_init(self, *, accept={int}): 2656 if accept == {int}: 2657 self.format_unit = 'n' 2658 self.default_type = int 2659 elif accept == {int, NoneType}: 2660 self.converter = '_Py_convert_optional_to_ssize_t' 2661 else: 2662 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept)) 2663 2664 2665 class slice_index_converter(CConverter): 2666 type = 'Py_ssize_t' 2667 2668 def converter_init(self, *, accept={int, NoneType}): 2669 if accept == {int}: 2670 self.converter = '_PyEval_SliceIndexNotNone' 2671 elif accept == {int, NoneType}: 2672 self.converter = '_PyEval_SliceIndex' 2673 else: 2674 fail("slice_index_converter: illegal 'accept' argument " + repr(accept)) 2675 2676 2677 class float_converter(CConverter): 2678 type = 'float' 2679 default_type = float 2680 format_unit = 'f' 2681 c_ignored_default = "0.0" 2682 2683 class double_converter(CConverter): 2684 type = 'double' 2685 default_type = float 2686 format_unit = 'd' 2687 c_ignored_default = "0.0" 2688 2689 2690 class Py_complex_converter(CConverter): 2691 type = 'Py_complex' 2692 default_type = complex 2693 format_unit = 'D' 2694 c_ignored_default = "{0.0, 0.0}" 2695 2696 2697 class object_converter(CConverter): 2698 type = 'PyObject *' 2699 format_unit = 'O' 2700 2701 def converter_init(self, *, converter=None, type=None, subclass_of=None): 2702 if converter: 2703 if subclass_of: 2704 fail("object: Cannot pass in both 'converter' and 'subclass_of'") 2705 self.format_unit = 'O&' 2706 self.converter = converter 2707 elif subclass_of: 2708 self.format_unit = 'O!' 2709 self.subclass_of = subclass_of 2710 2711 if type is not None: 2712 self.type = type 2713 2714 2715 # 2716 # We define three conventions for buffer types in the 'accept' argument: 2717 # 2718 # buffer : any object supporting the buffer interface 2719 # rwbuffer: any object supporting the buffer interface, but must be writeable 2720 # robuffer: any object supporting the buffer interface, but must not be writeable 2721 # 2722 2723 class buffer: pass 2724 class rwbuffer: pass 2725 class robuffer: pass 2726 2727 def str_converter_key(types, encoding, zeroes): 2728 return (frozenset(types), bool(encoding), bool(zeroes)) 2729 2730 str_converter_argument_map = {} 2731 2732 class str_converter(CConverter): 2733 type = 'const char *' 2734 default_type = (str, Null, NoneType) 2735 format_unit = 's' 2736 2737 def converter_init(self, *, accept={str}, encoding=None, zeroes=False): 2738 2739 key = str_converter_key(accept, encoding, zeroes) 2740 format_unit = str_converter_argument_map.get(key) 2741 if not format_unit: 2742 fail("str_converter: illegal combination of arguments", key) 2743 2744 self.format_unit = format_unit 2745 self.length = bool(zeroes) 2746 if encoding: 2747 if self.default not in (Null, None, unspecified): 2748 fail("str_converter: Argument Clinic doesn't support default values for encoded strings") 2749 self.encoding = encoding 2750 self.type = 'char *' 2751 # sorry, clinic can't support preallocated buffers 2752 # for es# and et# 2753 self.c_default = "NULL" 2754 2755 def cleanup(self): 2756 if self.encoding: 2757 name = ensure_legal_c_identifier(self.name) 2758 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"]) 2759 2760 # 2761 # This is the fourth or fifth rewrite of registering all the 2762 # crazy string converter format units. Previous approaches hid 2763 # bugs--generally mismatches between the semantics of the format 2764 # unit and the arguments necessary to represent those semantics 2765 # properly. Hopefully with this approach we'll get it 100% right. 2766 # 2767 # The r() function (short for "register") both registers the 2768 # mapping from arguments to format unit *and* registers the 2769 # legacy C converter for that format unit. 2770 # 2771 def r(format_unit, *, accept, encoding=False, zeroes=False): 2772 if not encoding and format_unit != 's': 2773 # add the legacy c converters here too. 2774 # 2775 # note: add_legacy_c_converter can't work for 2776 # es, es#, et, or et# 2777 # because of their extra encoding argument 2778 # 2779 # also don't add the converter for 's' because 2780 # the metaclass for CConverter adds it for us. 2781 kwargs = {} 2782 if accept != {str}: 2783 kwargs['accept'] = accept 2784 if zeroes: 2785 kwargs['zeroes'] = True 2786 added_f = functools.partial(str_converter, **kwargs) 2787 legacy_converters[format_unit] = added_f 2788 2789 d = str_converter_argument_map 2790 key = str_converter_key(accept, encoding, zeroes) 2791 if key in d: 2792 sys.exit("Duplicate keys specified for str_converter_argument_map!") 2793 d[key] = format_unit 2794 2795 r('es', encoding=True, accept={str}) 2796 r('es#', encoding=True, zeroes=True, accept={str}) 2797 r('et', encoding=True, accept={bytes, bytearray, str}) 2798 r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str}) 2799 r('s', accept={str}) 2800 r('s#', zeroes=True, accept={robuffer, str}) 2801 r('y', accept={robuffer}) 2802 r('y#', zeroes=True, accept={robuffer}) 2803 r('z', accept={str, NoneType}) 2804 r('z#', zeroes=True, accept={robuffer, str, NoneType}) 2805 del r 2806 2807 2808 class PyBytesObject_converter(CConverter): 2809 type = 'PyBytesObject *' 2810 format_unit = 'S' 2811 # accept = {bytes} 2812 2813 class PyByteArrayObject_converter(CConverter): 2814 type = 'PyByteArrayObject *' 2815 format_unit = 'Y' 2816 # accept = {bytearray} 2817 2818 class unicode_converter(CConverter): 2819 type = 'PyObject *' 2820 default_type = (str, Null, NoneType) 2821 format_unit = 'U' 2822 2823 @add_legacy_c_converter('u#', zeroes=True) 2824 @add_legacy_c_converter('Z', accept={str, NoneType}) 2825 @add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True) 2826 class Py_UNICODE_converter(CConverter): 2827 type = 'const Py_UNICODE *' 2828 default_type = (str, Null, NoneType) 2829 format_unit = 'u' 2830 2831 def converter_init(self, *, accept={str}, zeroes=False): 2832 format_unit = 'Z' if accept=={str, NoneType} else 'u' 2833 if zeroes: 2834 format_unit += '#' 2835 self.length = True 2836 self.format_unit = format_unit 2837 2838 @add_legacy_c_converter('s*', accept={str, buffer}) 2839 @add_legacy_c_converter('z*', accept={str, buffer, NoneType}) 2840 @add_legacy_c_converter('w*', accept={rwbuffer}) 2841 class Py_buffer_converter(CConverter): 2842 type = 'Py_buffer' 2843 format_unit = 'y*' 2844 impl_by_reference = True 2845 c_ignored_default = "{NULL, NULL}" 2846 2847 def converter_init(self, *, accept={buffer}): 2848 if self.default not in (unspecified, None): 2849 fail("The only legal default value for Py_buffer is None.") 2850 2851 self.c_default = self.c_ignored_default 2852 2853 if accept == {str, buffer, NoneType}: 2854 format_unit = 'z*' 2855 elif accept == {str, buffer}: 2856 format_unit = 's*' 2857 elif accept == {buffer}: 2858 format_unit = 'y*' 2859 elif accept == {rwbuffer}: 2860 format_unit = 'w*' 2861 else: 2862 fail("Py_buffer_converter: illegal combination of arguments") 2863 2864 self.format_unit = format_unit 2865 2866 def cleanup(self): 2867 name = ensure_legal_c_identifier(self.name) 2868 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"]) 2869 2870 2871 def correct_name_for_self(f): 2872 if f.kind in (CALLABLE, METHOD_INIT): 2873 if f.cls: 2874 return "PyObject *", "self" 2875 return "PyObject *", "module" 2876 if f.kind == STATIC_METHOD: 2877 return "void *", "null" 2878 if f.kind in (CLASS_METHOD, METHOD_NEW): 2879 return "PyTypeObject *", "type" 2880 raise RuntimeError("Unhandled type of function f: " + repr(f.kind)) 2881 2882 def required_type_for_self_for_parser(f): 2883 type, _ = correct_name_for_self(f) 2884 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD): 2885 return type 2886 return None 2887 2888 2889 class self_converter(CConverter): 2890 """ 2891 A special-case converter: 2892 this is the default converter used for "self". 2893 """ 2894 type = None 2895 format_unit = '' 2896 2897 def converter_init(self, *, type=None): 2898 self.specified_type = type 2899 2900 def pre_render(self): 2901 f = self.function 2902 default_type, default_name = correct_name_for_self(f) 2903 self.signature_name = default_name 2904 self.type = self.specified_type or self.type or default_type 2905 2906 kind = self.function.kind 2907 new_or_init = kind in (METHOD_NEW, METHOD_INIT) 2908 2909 if (kind == STATIC_METHOD) or new_or_init: 2910 self.show_in_signature = False 2911 2912 # tp_new (METHOD_NEW) functions are of type newfunc: 2913 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); 2914 # PyTypeObject is a typedef for struct _typeobject. 2915 # 2916 # tp_init (METHOD_INIT) functions are of type initproc: 2917 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *); 2918 # 2919 # All other functions generated by Argument Clinic are stored in 2920 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction: 2921 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); 2922 # However! We habitually cast these functions to PyCFunction, 2923 # since functions that accept keyword arguments don't fit this signature 2924 # but are stored there anyway. So strict type equality isn't important 2925 # for these functions. 2926 # 2927 # So: 2928 # 2929 # * The name of the first parameter to the impl and the parsing function will always 2930 # be self.name. 2931 # 2932 # * The type of the first parameter to the impl will always be of self.type. 2933 # 2934 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT): 2935 # * The type of the first parameter to the parsing function is also self.type. 2936 # This means that if you step into the parsing function, your "self" parameter 2937 # is of the correct type, which may make debugging more pleasant. 2938 # 2939 # * Else if the function is tp_new (METHOD_NEW): 2940 # * The type of the first parameter to the parsing function is "PyTypeObject *", 2941 # so the type signature of the function call is an exact match. 2942 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type 2943 # in the impl call. 2944 # 2945 # * Else if the function is tp_init (METHOD_INIT): 2946 # * The type of the first parameter to the parsing function is "PyObject *", 2947 # so the type signature of the function call is an exact match. 2948 # * If self.type != "PyObject *", we cast the first parameter to self.type 2949 # in the impl call. 2950 2951 @property 2952 def parser_type(self): 2953 return required_type_for_self_for_parser(self.function) or self.type 2954 2955 def render(self, parameter, data): 2956 """ 2957 parameter is a clinic.Parameter instance. 2958 data is a CRenderData instance. 2959 """ 2960 if self.function.kind == STATIC_METHOD: 2961 return 2962 2963 self._render_self(parameter, data) 2964 2965 if self.type != self.parser_type: 2966 # insert cast to impl_argument[0], aka self. 2967 # we know we're in the first slot in all the CRenderData lists, 2968 # because we render parameters in order, and self is always first. 2969 assert len(data.impl_arguments) == 1 2970 assert data.impl_arguments[0] == self.name 2971 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0] 2972 2973 def set_template_dict(self, template_dict): 2974 template_dict['self_name'] = self.name 2975 template_dict['self_type'] = self.parser_type 2976 kind = self.function.kind 2977 cls = self.function.cls 2978 2979 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef): 2980 if kind == METHOD_NEW: 2981 passed_in_type = self.name 2982 else: 2983 passed_in_type = 'Py_TYPE({})'.format(self.name) 2984 2985 line = '({passed_in_type} == {type_object}) &&\n ' 2986 d = { 2987 'type_object': self.function.cls.type_object, 2988 'passed_in_type': passed_in_type 2989 } 2990 template_dict['self_type_check'] = line.format_map(d) 2991 2992 2993 2994 def add_c_return_converter(f, name=None): 2995 if not name: 2996 name = f.__name__ 2997 if not name.endswith('_return_converter'): 2998 return f 2999 name = name[:-len('_return_converter')] 3000 return_converters[name] = f 3001 return f 3002 3003 3004 class CReturnConverterAutoRegister(type): 3005 def __init__(cls, name, bases, classdict): 3006 add_c_return_converter(cls) 3007 3008 class CReturnConverter(metaclass=CReturnConverterAutoRegister): 3009 3010 # The C type to use for this variable. 3011 # 'type' should be a Python string specifying the type, e.g. "int". 3012 # If this is a pointer type, the type string should end with ' *'. 3013 type = 'PyObject *' 3014 3015 # The Python default value for this parameter, as a Python value. 3016 # Or the magic value "unspecified" if there is no default. 3017 default = None 3018 3019 def __init__(self, *, py_default=None, **kwargs): 3020 self.py_default = py_default 3021 try: 3022 self.return_converter_init(**kwargs) 3023 except TypeError as e: 3024 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items()) 3025 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e)) 3026 3027 def return_converter_init(self): 3028 pass 3029 3030 def declare(self, data, name="_return_value"): 3031 line = [] 3032 add = line.append 3033 add(self.type) 3034 if not self.type.endswith('*'): 3035 add(' ') 3036 add(name + ';') 3037 data.declarations.append(''.join(line)) 3038 data.return_value = name 3039 3040 def err_occurred_if(self, expr, data): 3041 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr)) 3042 3043 def err_occurred_if_null_pointer(self, variable, data): 3044 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable)) 3045 3046 def render(self, function, data): 3047 """ 3048 function is a clinic.Function instance. 3049 data is a CRenderData instance. 3050 """ 3051 pass 3052 3053 add_c_return_converter(CReturnConverter, 'object') 3054 3055 class NoneType_return_converter(CReturnConverter): 3056 def render(self, function, data): 3057 self.declare(data) 3058 data.return_conversion.append(''' 3059 if (_return_value != Py_None) { 3060 goto exit; 3061 } 3062 return_value = Py_None; 3063 Py_INCREF(Py_None); 3064 '''.strip()) 3065 3066 class bool_return_converter(CReturnConverter): 3067 type = 'int' 3068 3069 def render(self, function, data): 3070 self.declare(data) 3071 self.err_occurred_if("_return_value == -1", data) 3072 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n') 3073 3074 class long_return_converter(CReturnConverter): 3075 type = 'long' 3076 conversion_fn = 'PyLong_FromLong' 3077 cast = '' 3078 unsigned_cast = '' 3079 3080 def render(self, function, data): 3081 self.declare(data) 3082 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data) 3083 data.return_conversion.append( 3084 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n'))) 3085 3086 class int_return_converter(long_return_converter): 3087 type = 'int' 3088 cast = '(long)' 3089 3090 class init_return_converter(long_return_converter): 3091 """ 3092 Special return converter for __init__ functions. 3093 """ 3094 type = 'int' 3095 cast = '(long)' 3096 3097 def render(self, function, data): 3098 pass 3099 3100 class unsigned_long_return_converter(long_return_converter): 3101 type = 'unsigned long' 3102 conversion_fn = 'PyLong_FromUnsignedLong' 3103 unsigned_cast = '(unsigned long)' 3104 3105 class unsigned_int_return_converter(unsigned_long_return_converter): 3106 type = 'unsigned int' 3107 cast = '(unsigned long)' 3108 unsigned_cast = '(unsigned int)' 3109 3110 class Py_ssize_t_return_converter(long_return_converter): 3111 type = 'Py_ssize_t' 3112 conversion_fn = 'PyLong_FromSsize_t' 3113 3114 class size_t_return_converter(long_return_converter): 3115 type = 'size_t' 3116 conversion_fn = 'PyLong_FromSize_t' 3117 unsigned_cast = '(size_t)' 3118 3119 3120 class double_return_converter(CReturnConverter): 3121 type = 'double' 3122 cast = '' 3123 3124 def render(self, function, data): 3125 self.declare(data) 3126 self.err_occurred_if("_return_value == -1.0", data) 3127 data.return_conversion.append( 3128 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n') 3129 3130 class float_return_converter(double_return_converter): 3131 type = 'float' 3132 cast = '(double)' 3133 3134 3135 class DecodeFSDefault_return_converter(CReturnConverter): 3136 type = 'char *' 3137 3138 def render(self, function, data): 3139 self.declare(data) 3140 self.err_occurred_if_null_pointer("_return_value", data) 3141 data.return_conversion.append( 3142 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n') 3143 3144 3145 def eval_ast_expr(node, globals, *, filename='-'): 3146 """ 3147 Takes an ast.Expr node. Compiles and evaluates it. 3148 Returns the result of the expression. 3149 3150 globals represents the globals dict the expression 3151 should see. (There's no equivalent for "locals" here.) 3152 """ 3153 3154 if isinstance(node, ast.Expr): 3155 node = node.value 3156 3157 node = ast.Expression(node) 3158 co = compile(node, filename, 'eval') 3159 fn = types.FunctionType(co, globals) 3160 return fn() 3161 3162 3163 class IndentStack: 3164 def __init__(self): 3165 self.indents = [] 3166 self.margin = None 3167 3168 def _ensure(self): 3169 if not self.indents: 3170 fail('IndentStack expected indents, but none are defined.') 3171 3172 def measure(self, line): 3173 """ 3174 Returns the length of the line's margin. 3175 """ 3176 if '\t' in line: 3177 fail('Tab characters are illegal in the Argument Clinic DSL.') 3178 stripped = line.lstrip() 3179 if not len(stripped): 3180 # we can't tell anything from an empty line 3181 # so just pretend it's indented like our current indent 3182 self._ensure() 3183 return self.indents[-1] 3184 return len(line) - len(stripped) 3185 3186 def infer(self, line): 3187 """ 3188 Infer what is now the current margin based on this line. 3189 Returns: 3190 1 if we have indented (or this is the first margin) 3191 0 if the margin has not changed 3192 -N if we have dedented N times 3193 """ 3194 indent = self.measure(line) 3195 margin = ' ' * indent 3196 if not self.indents: 3197 self.indents.append(indent) 3198 self.margin = margin 3199 return 1 3200 current = self.indents[-1] 3201 if indent == current: 3202 return 0 3203 if indent > current: 3204 self.indents.append(indent) 3205 self.margin = margin 3206 return 1 3207 # indent < current 3208 if indent not in self.indents: 3209 fail("Illegal outdent.") 3210 outdent_count = 0 3211 while indent != current: 3212 self.indents.pop() 3213 current = self.indents[-1] 3214 outdent_count -= 1 3215 self.margin = margin 3216 return outdent_count 3217 3218 @property 3219 def depth(self): 3220 """ 3221 Returns how many margins are currently defined. 3222 """ 3223 return len(self.indents) 3224 3225 def indent(self, line): 3226 """ 3227 Indents a line by the currently defined margin. 3228 """ 3229 return self.margin + line 3230 3231 def dedent(self, line): 3232 """ 3233 Dedents a line by the currently defined margin. 3234 (The inverse of 'indent'.) 3235 """ 3236 margin = self.margin 3237 indent = self.indents[-1] 3238 if not line.startswith(margin): 3239 fail('Cannot dedent, line does not start with the previous margin:') 3240 return line[indent:] 3241 3242 3243 class DSLParser: 3244 def __init__(self, clinic): 3245 self.clinic = clinic 3246 3247 self.directives = {} 3248 for name in dir(self): 3249 # functions that start with directive_ are added to directives 3250 _, s, key = name.partition("directive_") 3251 if s: 3252 self.directives[key] = getattr(self, name) 3253 3254 # functions that start with at_ are too, with an @ in front 3255 _, s, key = name.partition("at_") 3256 if s: 3257 self.directives['@' + key] = getattr(self, name) 3258 3259 self.reset() 3260 3261 def reset(self): 3262 self.function = None 3263 self.state = self.state_dsl_start 3264 self.parameter_indent = None 3265 self.keyword_only = False 3266 self.positional_only = False 3267 self.group = 0 3268 self.parameter_state = self.ps_start 3269 self.seen_positional_with_default = False 3270 self.indent = IndentStack() 3271 self.kind = CALLABLE 3272 self.coexist = False 3273 self.parameter_continuation = '' 3274 self.preserve_output = False 3275 3276 def directive_version(self, required): 3277 global version 3278 if version_comparitor(version, required) < 0: 3279 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required) 3280 3281 def directive_module(self, name): 3282 fields = name.split('.') 3283 new = fields.pop() 3284 module, cls = self.clinic._module_and_class(fields) 3285 if cls: 3286 fail("Can't nest a module inside a class!") 3287 3288 if name in module.classes: 3289 fail("Already defined module " + repr(name) + "!") 3290 3291 m = Module(name, module) 3292 module.modules[name] = m 3293 self.block.signatures.append(m) 3294 3295 def directive_class(self, name, typedef, type_object): 3296 fields = name.split('.') 3297 in_classes = False 3298 parent = self 3299 name = fields.pop() 3300 so_far = [] 3301 module, cls = self.clinic._module_and_class(fields) 3302 3303 parent = cls or module 3304 if name in parent.classes: 3305 fail("Already defined class " + repr(name) + "!") 3306 3307 c = Class(name, module, cls, typedef, type_object) 3308 parent.classes[name] = c 3309 self.block.signatures.append(c) 3310 3311 def directive_set(self, name, value): 3312 if name not in ("line_prefix", "line_suffix"): 3313 fail("unknown variable", repr(name)) 3314 3315 value = value.format_map({ 3316 'block comment start': '/*', 3317 'block comment end': '*/', 3318 }) 3319 3320 self.clinic.__dict__[name] = value 3321 3322 def directive_destination(self, name, command, *args): 3323 if command == 'new': 3324 self.clinic.add_destination(name, *args) 3325 return 3326 3327 if command == 'clear': 3328 self.clinic.get_destination(name).clear() 3329 fail("unknown destination command", repr(command)) 3330 3331 3332 def directive_output(self, command_or_name, destination=''): 3333 fd = self.clinic.destination_buffers 3334 3335 if command_or_name == "preset": 3336 preset = self.clinic.presets.get(destination) 3337 if not preset: 3338 fail("Unknown preset " + repr(destination) + "!") 3339 fd.update(preset) 3340 return 3341 3342 if command_or_name == "push": 3343 self.clinic.destination_buffers_stack.append(fd.copy()) 3344 return 3345 3346 if command_or_name == "pop": 3347 if not self.clinic.destination_buffers_stack: 3348 fail("Can't 'output pop', stack is empty!") 3349 previous_fd = self.clinic.destination_buffers_stack.pop() 3350 fd.update(previous_fd) 3351 return 3352 3353 # secret command for debugging! 3354 if command_or_name == "print": 3355 self.block.output.append(pprint.pformat(fd)) 3356 self.block.output.append('\n') 3357 return 3358 3359 d = self.clinic.get_destination(destination) 3360 3361 if command_or_name == "everything": 3362 for name in list(fd): 3363 fd[name] = d 3364 return 3365 3366 if command_or_name not in fd: 3367 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd)) 3368 fd[command_or_name] = d 3369 3370 def directive_dump(self, name): 3371 self.block.output.append(self.clinic.get_destination(name).dump()) 3372 3373 def directive_print(self, *args): 3374 self.block.output.append(' '.join(args)) 3375 self.block.output.append('\n') 3376 3377 def directive_preserve(self): 3378 if self.preserve_output: 3379 fail("Can't have preserve twice in one block!") 3380 self.preserve_output = True 3381 3382 def at_classmethod(self): 3383 if self.kind is not CALLABLE: 3384 fail("Can't set @classmethod, function is not a normal callable") 3385 self.kind = CLASS_METHOD 3386 3387 def at_staticmethod(self): 3388 if self.kind is not CALLABLE: 3389 fail("Can't set @staticmethod, function is not a normal callable") 3390 self.kind = STATIC_METHOD 3391 3392 def at_coexist(self): 3393 if self.coexist: 3394 fail("Called @coexist twice!") 3395 self.coexist = True 3396 3397 def parse(self, block): 3398 self.reset() 3399 self.block = block 3400 self.saved_output = self.block.output 3401 block.output = [] 3402 block_start = self.clinic.block_parser.line_number 3403 lines = block.input.split('\n') 3404 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number): 3405 if '\t' in line: 3406 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start) 3407 self.state(line) 3408 3409 self.next(self.state_terminal) 3410 self.state(None) 3411 3412 block.output.extend(self.clinic.language.render(clinic, block.signatures)) 3413 3414 if self.preserve_output: 3415 if block.output: 3416 fail("'preserve' only works for blocks that don't produce any output!") 3417 block.output = self.saved_output 3418 3419 @staticmethod 3420 def ignore_line(line): 3421 # ignore comment-only lines 3422 if line.lstrip().startswith('#'): 3423 return True 3424 3425 # Ignore empty lines too 3426 # (but not in docstring sections!) 3427 if not line.strip(): 3428 return True 3429 3430 return False 3431 3432 @staticmethod 3433 def calculate_indent(line): 3434 return len(line) - len(line.strip()) 3435 3436 def next(self, state, line=None): 3437 # real_print(self.state.__name__, "->", state.__name__, ", line=", line) 3438 self.state = state 3439 if line is not None: 3440 self.state(line) 3441 3442 def state_dsl_start(self, line): 3443 # self.block = self.ClinicOutputBlock(self) 3444 if self.ignore_line(line): 3445 return 3446 3447 # is it a directive? 3448 fields = shlex.split(line) 3449 directive_name = fields[0] 3450 directive = self.directives.get(directive_name, None) 3451 if directive: 3452 try: 3453 directive(*fields[1:]) 3454 except TypeError as e: 3455 fail(str(e)) 3456 return 3457 3458 self.next(self.state_modulename_name, line) 3459 3460 def state_modulename_name(self, line): 3461 # looking for declaration, which establishes the leftmost column 3462 # line should be 3463 # modulename.fnname [as c_basename] [-> return annotation] 3464 # square brackets denote optional syntax. 3465 # 3466 # alternatively: 3467 # modulename.fnname [as c_basename] = modulename.existing_fn_name 3468 # clones the parameters and return converter from that 3469 # function. you can't modify them. you must enter a 3470 # new docstring. 3471 # 3472 # (but we might find a directive first!) 3473 # 3474 # this line is permitted to start with whitespace. 3475 # we'll call this number of spaces F (for "function"). 3476 3477 if not line.strip(): 3478 return 3479 3480 self.indent.infer(line) 3481 3482 # are we cloning? 3483 before, equals, existing = line.rpartition('=') 3484 if equals: 3485 full_name, _, c_basename = before.partition(' as ') 3486 full_name = full_name.strip() 3487 c_basename = c_basename.strip() 3488 existing = existing.strip() 3489 if (is_legal_py_identifier(full_name) and 3490 (not c_basename or is_legal_c_identifier(c_basename)) and 3491 is_legal_py_identifier(existing)): 3492 # we're cloning! 3493 fields = [x.strip() for x in existing.split('.')] 3494 function_name = fields.pop() 3495 module, cls = self.clinic._module_and_class(fields) 3496 3497 for existing_function in (cls or module).functions: 3498 if existing_function.name == function_name: 3499 break 3500 else: 3501 existing_function = None 3502 if not existing_function: 3503 print("class", cls, "module", module, "existing", existing) 3504 print("cls. functions", cls.functions) 3505 fail("Couldn't find existing function " + repr(existing) + "!") 3506 3507 fields = [x.strip() for x in full_name.split('.')] 3508 function_name = fields.pop() 3509 module, cls = self.clinic._module_and_class(fields) 3510 3511 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist): 3512 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)") 3513 self.function = existing_function.copy(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, docstring='') 3514 3515 self.block.signatures.append(self.function) 3516 (cls or module).functions.append(self.function) 3517 self.next(self.state_function_docstring) 3518 return 3519 3520 line, _, returns = line.partition('->') 3521 3522 full_name, _, c_basename = line.partition(' as ') 3523 full_name = full_name.strip() 3524 c_basename = c_basename.strip() or None 3525 3526 if not is_legal_py_identifier(full_name): 3527 fail("Illegal function name: {}".format(full_name)) 3528 if c_basename and not is_legal_c_identifier(c_basename): 3529 fail("Illegal C basename: {}".format(c_basename)) 3530 3531 return_converter = None 3532 if returns: 3533 ast_input = "def x() -> {}: pass".format(returns) 3534 module = None 3535 try: 3536 module = ast.parse(ast_input) 3537 except SyntaxError: 3538 pass 3539 if not module: 3540 fail("Badly-formed annotation for " + full_name + ": " + returns) 3541 try: 3542 name, legacy, kwargs = self.parse_converter(module.body[0].returns) 3543 if legacy: 3544 fail("Legacy converter {!r} not allowed as a return converter" 3545 .format(name)) 3546 if name not in return_converters: 3547 fail("No available return converter called " + repr(name)) 3548 return_converter = return_converters[name](**kwargs) 3549 except ValueError: 3550 fail("Badly-formed annotation for " + full_name + ": " + returns) 3551 3552 fields = [x.strip() for x in full_name.split('.')] 3553 function_name = fields.pop() 3554 module, cls = self.clinic._module_and_class(fields) 3555 3556 fields = full_name.split('.') 3557 if fields[-1] == '__new__': 3558 if (self.kind != CLASS_METHOD) or (not cls): 3559 fail("__new__ must be a class method!") 3560 self.kind = METHOD_NEW 3561 elif fields[-1] == '__init__': 3562 if (self.kind != CALLABLE) or (not cls): 3563 fail("__init__ must be a normal method, not a class or static method!") 3564 self.kind = METHOD_INIT 3565 if not return_converter: 3566 return_converter = init_return_converter() 3567 elif fields[-1] in unsupported_special_methods: 3568 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)") 3569 3570 if not return_converter: 3571 return_converter = CReturnConverter() 3572 3573 if not module: 3574 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".") 3575 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, 3576 return_converter=return_converter, kind=self.kind, coexist=self.coexist) 3577 self.block.signatures.append(self.function) 3578 3579 # insert a self converter automatically 3580 type, name = correct_name_for_self(self.function) 3581 kwargs = {} 3582 if cls and type == "PyObject *": 3583 kwargs['type'] = cls.typedef 3584 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs) 3585 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc) 3586 self.function.parameters[sc.name] = p_self 3587 3588 (cls or module).functions.append(self.function) 3589 self.next(self.state_parameters_start) 3590 3591 # Now entering the parameters section. The rules, formally stated: 3592 # 3593 # * All lines must be indented with spaces only. 3594 # * The first line must be a parameter declaration. 3595 # * The first line must be indented. 3596 # * This first line establishes the indent for parameters. 3597 # * We'll call this number of spaces P (for "parameter"). 3598 # * Thenceforth: 3599 # * Lines indented with P spaces specify a parameter. 3600 # * Lines indented with > P spaces are docstrings for the previous 3601 # parameter. 3602 # * We'll call this number of spaces D (for "docstring"). 3603 # * All subsequent lines indented with >= D spaces are stored as 3604 # part of the per-parameter docstring. 3605 # * All lines will have the first D spaces of the indent stripped 3606 # before they are stored. 3607 # * It's illegal to have a line starting with a number of spaces X 3608 # such that P < X < D. 3609 # * A line with < P spaces is the first line of the function 3610 # docstring, which ends processing for parameters and per-parameter 3611 # docstrings. 3612 # * The first line of the function docstring must be at the same 3613 # indent as the function declaration. 3614 # * It's illegal to have any line in the parameters section starting 3615 # with X spaces such that F < X < P. (As before, F is the indent 3616 # of the function declaration.) 3617 # 3618 # Also, currently Argument Clinic places the following restrictions on groups: 3619 # * Each group must contain at least one parameter. 3620 # * Each group may contain at most one group, which must be the furthest 3621 # thing in the group from the required parameters. (The nested group 3622 # must be the first in the group when it's before the required 3623 # parameters, and the last thing in the group when after the required 3624 # parameters.) 3625 # * There may be at most one (top-level) group to the left or right of 3626 # the required parameters. 3627 # * You must specify a slash, and it must be after all parameters. 3628 # (In other words: either all parameters are positional-only, 3629 # or none are.) 3630 # 3631 # Said another way: 3632 # * Each group must contain at least one parameter. 3633 # * All left square brackets before the required parameters must be 3634 # consecutive. (You can't have a left square bracket followed 3635 # by a parameter, then another left square bracket. You can't 3636 # have a left square bracket, a parameter, a right square bracket, 3637 # and then a left square bracket.) 3638 # * All right square brackets after the required parameters must be 3639 # consecutive. 3640 # 3641 # These rules are enforced with a single state variable: 3642 # "parameter_state". (Previously the code was a miasma of ifs and 3643 # separate boolean state variables.) The states are: 3644 # 3645 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line 3646 # 01 2 3 4 5 6 <- state transitions 3647 # 3648 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3. 3649 # 1: ps_left_square_before. left square brackets before required parameters. 3650 # 2: ps_group_before. in a group, before required parameters. 3651 # 3: ps_required. required parameters, positional-or-keyword or positional-only 3652 # (we don't know yet). (renumber left groups!) 3653 # 4: ps_optional. positional-or-keyword or positional-only parameters that 3654 # now must have default values. 3655 # 5: ps_group_after. in a group, after required parameters. 3656 # 6: ps_right_square_after. right square brackets after required parameters. 3657 ps_start, ps_left_square_before, ps_group_before, ps_required, \ 3658 ps_optional, ps_group_after, ps_right_square_after = range(7) 3659 3660 def state_parameters_start(self, line): 3661 if self.ignore_line(line): 3662 return 3663 3664 # if this line is not indented, we have no parameters 3665 if not self.indent.infer(line): 3666 return self.next(self.state_function_docstring, line) 3667 3668 self.parameter_continuation = '' 3669 return self.next(self.state_parameter, line) 3670 3671 3672 def to_required(self): 3673 """ 3674 Transition to the "required" parameter state. 3675 """ 3676 if self.parameter_state != self.ps_required: 3677 self.parameter_state = self.ps_required 3678 for p in self.function.parameters.values(): 3679 p.group = -p.group 3680 3681 def state_parameter(self, line): 3682 if self.parameter_continuation: 3683 line = self.parameter_continuation + ' ' + line.lstrip() 3684 self.parameter_continuation = '' 3685 3686 if self.ignore_line(line): 3687 return 3688 3689 assert self.indent.depth == 2 3690 indent = self.indent.infer(line) 3691 if indent == -1: 3692 # we outdented, must be to definition column 3693 return self.next(self.state_function_docstring, line) 3694 3695 if indent == 1: 3696 # we indented, must be to new parameter docstring column 3697 return self.next(self.state_parameter_docstring_start, line) 3698 3699 line = line.rstrip() 3700 if line.endswith('\\'): 3701 self.parameter_continuation = line[:-1] 3702 return 3703 3704 line = line.lstrip() 3705 3706 if line in ('*', '/', '[', ']'): 3707 self.parse_special_symbol(line) 3708 return 3709 3710 if self.parameter_state in (self.ps_start, self.ps_required): 3711 self.to_required() 3712 elif self.parameter_state == self.ps_left_square_before: 3713 self.parameter_state = self.ps_group_before 3714 elif self.parameter_state == self.ps_group_before: 3715 if not self.group: 3716 self.to_required() 3717 elif self.parameter_state in (self.ps_group_after, self.ps_optional): 3718 pass 3719 else: 3720 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)") 3721 3722 # handle "as" for parameters too 3723 c_name = None 3724 name, have_as_token, trailing = line.partition(' as ') 3725 if have_as_token: 3726 name = name.strip() 3727 if ' ' not in name: 3728 fields = trailing.strip().split(' ') 3729 if not fields: 3730 fail("Invalid 'as' clause!") 3731 c_name = fields[0] 3732 if c_name.endswith(':'): 3733 name += ':' 3734 c_name = c_name[:-1] 3735 fields[0] = name 3736 line = ' '.join(fields) 3737 3738 base, equals, default = line.rpartition('=') 3739 if not equals: 3740 base = default 3741 default = None 3742 3743 module = None 3744 try: 3745 ast_input = "def x({}): pass".format(base) 3746 module = ast.parse(ast_input) 3747 except SyntaxError: 3748 try: 3749 # the last = was probably inside a function call, like 3750 # c: int(accept={str}) 3751 # so assume there was no actual default value. 3752 default = None 3753 ast_input = "def x({}): pass".format(line) 3754 module = ast.parse(ast_input) 3755 except SyntaxError: 3756 pass 3757 if not module: 3758 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line) 3759 3760 function_args = module.body[0].args 3761 3762 if len(function_args.args) > 1: 3763 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line) 3764 if function_args.defaults or function_args.kw_defaults: 3765 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line) 3766 if function_args.vararg or function_args.kwarg: 3767 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line) 3768 3769 parameter = function_args.args[0] 3770 3771 parameter_name = parameter.arg 3772 name, legacy, kwargs = self.parse_converter(parameter.annotation) 3773 3774 if not default: 3775 if self.parameter_state == self.ps_optional: 3776 fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!") 3777 value = unspecified 3778 if 'py_default' in kwargs: 3779 fail("You can't specify py_default without specifying a default value!") 3780 else: 3781 if self.parameter_state == self.ps_required: 3782 self.parameter_state = self.ps_optional 3783 default = default.strip() 3784 bad = False 3785 ast_input = "x = {}".format(default) 3786 bad = False 3787 try: 3788 module = ast.parse(ast_input) 3789 3790 if 'c_default' not in kwargs: 3791 # we can only represent very simple data values in C. 3792 # detect whether default is okay, via a blacklist 3793 # of disallowed ast nodes. 3794 class DetectBadNodes(ast.NodeVisitor): 3795 bad = False 3796 def bad_node(self, node): 3797 self.bad = True 3798 3799 # inline function call 3800 visit_Call = bad_node 3801 # inline if statement ("x = 3 if y else z") 3802 visit_IfExp = bad_node 3803 3804 # comprehensions and generator expressions 3805 visit_ListComp = visit_SetComp = bad_node 3806 visit_DictComp = visit_GeneratorExp = bad_node 3807 3808 # literals for advanced types 3809 visit_Dict = visit_Set = bad_node 3810 visit_List = visit_Tuple = bad_node 3811 3812 # "starred": "a = [1, 2, 3]; *a" 3813 visit_Starred = bad_node 3814 3815 # allow ellipsis, for now 3816 # visit_Ellipsis = bad_node 3817 3818 blacklist = DetectBadNodes() 3819 blacklist.visit(module) 3820 bad = blacklist.bad 3821 else: 3822 # if they specify a c_default, we can be more lenient about the default value. 3823 # but at least make an attempt at ensuring it's a valid expression. 3824 try: 3825 value = eval(default) 3826 if value == unspecified: 3827 fail("'unspecified' is not a legal default value!") 3828 except NameError: 3829 pass # probably a named constant 3830 except Exception as e: 3831 fail("Malformed expression given as default value\n" 3832 "{!r} caused {!r}".format(default, e)) 3833 if bad: 3834 fail("Unsupported expression as default value: " + repr(default)) 3835 3836 expr = module.body[0].value 3837 # mild hack: explicitly support NULL as a default value 3838 if isinstance(expr, ast.Name) and expr.id == 'NULL': 3839 value = NULL 3840 py_default = 'None' 3841 c_default = "NULL" 3842 elif (isinstance(expr, ast.BinOp) or 3843 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))): 3844 c_default = kwargs.get("c_default") 3845 if not (isinstance(c_default, str) and c_default): 3846 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.") 3847 py_default = default 3848 value = unknown 3849 elif isinstance(expr, ast.Attribute): 3850 a = [] 3851 n = expr 3852 while isinstance(n, ast.Attribute): 3853 a.append(n.attr) 3854 n = n.value 3855 if not isinstance(n, ast.Name): 3856 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)") 3857 a.append(n.id) 3858 py_default = ".".join(reversed(a)) 3859 3860 c_default = kwargs.get("c_default") 3861 if not (isinstance(c_default, str) and c_default): 3862 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") 3863 3864 try: 3865 value = eval(py_default) 3866 except NameError: 3867 value = unknown 3868 else: 3869 value = ast.literal_eval(expr) 3870 py_default = repr(value) 3871 if isinstance(value, (bool, None.__class__)): 3872 c_default = "Py_" + py_default 3873 elif isinstance(value, str): 3874 c_default = c_repr(value) 3875 else: 3876 c_default = py_default 3877 3878 except SyntaxError as e: 3879 fail("Syntax error: " + repr(e.text)) 3880 except (ValueError, AttributeError): 3881 value = unknown 3882 c_default = kwargs.get("c_default") 3883 py_default = default 3884 if not (isinstance(c_default, str) and c_default): 3885 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") 3886 3887 kwargs.setdefault('c_default', c_default) 3888 kwargs.setdefault('py_default', py_default) 3889 3890 dict = legacy_converters if legacy else converters 3891 legacy_str = "legacy " if legacy else "" 3892 if name not in dict: 3893 fail('{} is not a valid {}converter'.format(name, legacy_str)) 3894 # if you use a c_name for the parameter, we just give that name to the converter 3895 # but the parameter object gets the python name 3896 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs) 3897 3898 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD 3899 3900 if isinstance(converter, self_converter): 3901 if len(self.function.parameters) == 1: 3902 if (self.parameter_state != self.ps_required): 3903 fail("A 'self' parameter cannot be marked optional.") 3904 if value is not unspecified: 3905 fail("A 'self' parameter cannot have a default value.") 3906 if self.group: 3907 fail("A 'self' parameter cannot be in an optional group.") 3908 kind = inspect.Parameter.POSITIONAL_ONLY 3909 self.parameter_state = self.ps_start 3910 self.function.parameters.clear() 3911 else: 3912 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.") 3913 3914 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group) 3915 3916 if parameter_name in self.function.parameters: 3917 fail("You can't have two parameters named " + repr(parameter_name) + "!") 3918 self.function.parameters[parameter_name] = p 3919 3920 def parse_converter(self, annotation): 3921 if isinstance(annotation, ast.Str): 3922 return annotation.s, True, {} 3923 3924 if isinstance(annotation, ast.Name): 3925 return annotation.id, False, {} 3926 3927 if not isinstance(annotation, ast.Call): 3928 fail("Annotations must be either a name, a function call, or a string.") 3929 3930 name = annotation.func.id 3931 symbols = globals() 3932 3933 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords} 3934 return name, False, kwargs 3935 3936 def parse_special_symbol(self, symbol): 3937 if symbol == '*': 3938 if self.keyword_only: 3939 fail("Function " + self.function.name + " uses '*' more than once.") 3940 self.keyword_only = True 3941 elif symbol == '[': 3942 if self.parameter_state in (self.ps_start, self.ps_left_square_before): 3943 self.parameter_state = self.ps_left_square_before 3944 elif self.parameter_state in (self.ps_required, self.ps_group_after): 3945 self.parameter_state = self.ps_group_after 3946 else: 3947 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") 3948 self.group += 1 3949 self.function.docstring_only = True 3950 elif symbol == ']': 3951 if not self.group: 3952 fail("Function " + self.function.name + " has a ] without a matching [.") 3953 if not any(p.group == self.group for p in self.function.parameters.values()): 3954 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.") 3955 self.group -= 1 3956 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before): 3957 self.parameter_state = self.ps_group_before 3958 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after): 3959 self.parameter_state = self.ps_right_square_after 3960 else: 3961 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)") 3962 elif symbol == '/': 3963 if self.positional_only: 3964 fail("Function " + self.function.name + " uses '/' more than once.") 3965 self.positional_only = True 3966 # ps_required and ps_optional are allowed here, that allows positional-only without option groups 3967 # to work (and have default values!) 3968 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group: 3969 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)") 3970 if self.keyword_only: 3971 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") 3972 # fixup preceding parameters 3973 for p in self.function.parameters.values(): 3974 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)): 3975 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") 3976 p.kind = inspect.Parameter.POSITIONAL_ONLY 3977 3978 def state_parameter_docstring_start(self, line): 3979 self.parameter_docstring_indent = len(self.indent.margin) 3980 assert self.indent.depth == 3 3981 return self.next(self.state_parameter_docstring, line) 3982 3983 # every line of the docstring must start with at least F spaces, 3984 # where F > P. 3985 # these F spaces will be stripped. 3986 def state_parameter_docstring(self, line): 3987 stripped = line.strip() 3988 if stripped.startswith('#'): 3989 return 3990 3991 indent = self.indent.measure(line) 3992 if indent < self.parameter_docstring_indent: 3993 self.indent.infer(line) 3994 assert self.indent.depth < 3 3995 if self.indent.depth == 2: 3996 # back to a parameter 3997 return self.next(self.state_parameter, line) 3998 assert self.indent.depth == 1 3999 return self.next(self.state_function_docstring, line) 4000 4001 assert self.function.parameters 4002 last_parameter = next(reversed(list(self.function.parameters.values()))) 4003 4004 new_docstring = last_parameter.docstring 4005 4006 if new_docstring: 4007 new_docstring += '\n' 4008 if stripped: 4009 new_docstring += self.indent.dedent(line) 4010 4011 last_parameter.docstring = new_docstring 4012 4013 # the final stanza of the DSL is the docstring. 4014 def state_function_docstring(self, line): 4015 if self.group: 4016 fail("Function " + self.function.name + " has a ] without a matching [.") 4017 4018 stripped = line.strip() 4019 if stripped.startswith('#'): 4020 return 4021 4022 new_docstring = self.function.docstring 4023 if new_docstring: 4024 new_docstring += "\n" 4025 if stripped: 4026 line = self.indent.dedent(line).rstrip() 4027 else: 4028 line = '' 4029 new_docstring += line 4030 self.function.docstring = new_docstring 4031 4032 def format_docstring(self): 4033 f = self.function 4034 4035 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) 4036 if new_or_init and not f.docstring: 4037 # don't render a docstring at all, no signature, nothing. 4038 return f.docstring 4039 4040 text, add, output = _text_accumulator() 4041 parameters = f.render_parameters 4042 4043 ## 4044 ## docstring first line 4045 ## 4046 4047 if new_or_init: 4048 # classes get *just* the name of the class 4049 # not __new__, not __init__, and not module.classname 4050 assert f.cls 4051 add(f.cls.name) 4052 else: 4053 add(f.name) 4054 add('(') 4055 4056 # populate "right_bracket_count" field for every parameter 4057 assert parameters, "We should always have a self parameter. " + repr(f) 4058 assert isinstance(parameters[0].converter, self_converter) 4059 # self is always positional-only. 4060 assert parameters[0].is_positional_only() 4061 parameters[0].right_bracket_count = 0 4062 positional_only = True 4063 for p in parameters[1:]: 4064 if not p.is_positional_only(): 4065 positional_only = False 4066 else: 4067 assert positional_only 4068 if positional_only: 4069 p.right_bracket_count = abs(p.group) 4070 else: 4071 # don't put any right brackets around non-positional-only parameters, ever. 4072 p.right_bracket_count = 0 4073 4074 right_bracket_count = 0 4075 4076 def fix_right_bracket_count(desired): 4077 nonlocal right_bracket_count 4078 s = '' 4079 while right_bracket_count < desired: 4080 s += '[' 4081 right_bracket_count += 1 4082 while right_bracket_count > desired: 4083 s += ']' 4084 right_bracket_count -= 1 4085 return s 4086 4087 need_slash = False 4088 added_slash = False 4089 need_a_trailing_slash = False 4090 4091 # we only need a trailing slash: 4092 # * if this is not a "docstring_only" signature 4093 # * and if the last *shown* parameter is 4094 # positional only 4095 if not f.docstring_only: 4096 for p in reversed(parameters): 4097 if not p.converter.show_in_signature: 4098 continue 4099 if p.is_positional_only(): 4100 need_a_trailing_slash = True 4101 break 4102 4103 4104 added_star = False 4105 4106 first_parameter = True 4107 last_p = parameters[-1] 4108 line_length = len(''.join(text)) 4109 indent = " " * line_length 4110 def add_parameter(text): 4111 nonlocal line_length 4112 nonlocal first_parameter 4113 if first_parameter: 4114 s = text 4115 first_parameter = False 4116 else: 4117 s = ' ' + text 4118 if line_length + len(s) >= 72: 4119 add('\n') 4120 add(indent) 4121 line_length = len(indent) 4122 s = text 4123 line_length += len(s) 4124 add(s) 4125 4126 for p in parameters: 4127 if not p.converter.show_in_signature: 4128 continue 4129 assert p.name 4130 4131 is_self = isinstance(p.converter, self_converter) 4132 if is_self and f.docstring_only: 4133 # this isn't a real machine-parsable signature, 4134 # so let's not print the "self" parameter 4135 continue 4136 4137 if p.is_positional_only(): 4138 need_slash = not f.docstring_only 4139 elif need_slash and not (added_slash or p.is_positional_only()): 4140 added_slash = True 4141 add_parameter('/,') 4142 4143 if p.is_keyword_only() and not added_star: 4144 added_star = True 4145 add_parameter('*,') 4146 4147 p_add, p_output = text_accumulator() 4148 p_add(fix_right_bracket_count(p.right_bracket_count)) 4149 4150 if isinstance(p.converter, self_converter): 4151 # annotate first parameter as being a "self". 4152 # 4153 # if inspect.Signature gets this function, 4154 # and it's already bound, the self parameter 4155 # will be stripped off. 4156 # 4157 # if it's not bound, it should be marked 4158 # as positional-only. 4159 # 4160 # note: we don't print "self" for __init__, 4161 # because this isn't actually the signature 4162 # for __init__. (it can't be, __init__ doesn't 4163 # have a docstring.) if this is an __init__ 4164 # (or __new__), then this signature is for 4165 # calling the class to construct a new instance. 4166 p_add('$') 4167 4168 name = p.converter.signature_name or p.name 4169 p_add(name) 4170 4171 if p.converter.is_optional(): 4172 p_add('=') 4173 value = p.converter.py_default 4174 if not value: 4175 value = repr(p.converter.default) 4176 p_add(value) 4177 4178 if (p != last_p) or need_a_trailing_slash: 4179 p_add(',') 4180 4181 add_parameter(p_output()) 4182 4183 add(fix_right_bracket_count(0)) 4184 if need_a_trailing_slash: 4185 add_parameter('/') 4186 add(')') 4187 4188 # PEP 8 says: 4189 # 4190 # The Python standard library will not use function annotations 4191 # as that would result in a premature commitment to a particular 4192 # annotation style. Instead, the annotations are left for users 4193 # to discover and experiment with useful annotation styles. 4194 # 4195 # therefore this is commented out: 4196 # 4197 # if f.return_converter.py_default: 4198 # add(' -> ') 4199 # add(f.return_converter.py_default) 4200 4201 if not f.docstring_only: 4202 add("\n" + sig_end_marker + "\n") 4203 4204 docstring_first_line = output() 4205 4206 # now fix up the places where the brackets look wrong 4207 docstring_first_line = docstring_first_line.replace(', ]', ',] ') 4208 4209 # okay. now we're officially building the "parameters" section. 4210 # create substitution text for {parameters} 4211 spacer_line = False 4212 for p in parameters: 4213 if not p.docstring.strip(): 4214 continue 4215 if spacer_line: 4216 add('\n') 4217 else: 4218 spacer_line = True 4219 add(" ") 4220 add(p.name) 4221 add('\n') 4222 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " ")) 4223 parameters = output() 4224 if parameters: 4225 parameters += '\n' 4226 4227 ## 4228 ## docstring body 4229 ## 4230 4231 docstring = f.docstring.rstrip() 4232 lines = [line.rstrip() for line in docstring.split('\n')] 4233 4234 # Enforce the summary line! 4235 # The first line of a docstring should be a summary of the function. 4236 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph 4237 # by itself. 4238 # 4239 # Argument Clinic enforces the following rule: 4240 # * either the docstring is empty, 4241 # * or it must have a summary line. 4242 # 4243 # Guido said Clinic should enforce this: 4244 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html 4245 4246 if len(lines) >= 2: 4247 if lines[1]: 4248 fail("Docstring for " + f.full_name + " does not have a summary line!\n" + 4249 "Every non-blank function docstring must start with\n" + 4250 "a single line summary followed by an empty line.") 4251 elif len(lines) == 1: 4252 # the docstring is only one line right now--the summary line. 4253 # add an empty line after the summary line so we have space 4254 # between it and the {parameters} we're about to add. 4255 lines.append('') 4256 4257 parameters_marker_count = len(docstring.split('{parameters}')) - 1 4258 if parameters_marker_count > 1: 4259 fail('You may not specify {parameters} more than once in a docstring!') 4260 4261 if not parameters_marker_count: 4262 # insert after summary line 4263 lines.insert(2, '{parameters}') 4264 4265 # insert at front of docstring 4266 lines.insert(0, docstring_first_line) 4267 4268 docstring = "\n".join(lines) 4269 4270 add(docstring) 4271 docstring = output() 4272 4273 docstring = linear_format(docstring, parameters=parameters) 4274 docstring = docstring.rstrip() 4275 4276 return docstring 4277 4278 def state_terminal(self, line): 4279 """ 4280 Called when processing the block is done. 4281 """ 4282 assert not line 4283 4284 if not self.function: 4285 return 4286 4287 if self.keyword_only: 4288 values = self.function.parameters.values() 4289 if not values: 4290 no_parameter_after_star = True 4291 else: 4292 last_parameter = next(reversed(list(values))) 4293 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY 4294 if no_parameter_after_star: 4295 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.") 4296 4297 # remove trailing whitespace from all parameter docstrings 4298 for name, value in self.function.parameters.items(): 4299 if not value: 4300 continue 4301 value.docstring = value.docstring.rstrip() 4302 4303 self.function.docstring = self.format_docstring() 4304 4305 4306 4307 4308 # maps strings to callables. 4309 # the callable should return an object 4310 # that implements the clinic parser 4311 # interface (__init__ and parse). 4312 # 4313 # example parsers: 4314 # "clinic", handles the Clinic DSL 4315 # "python", handles running Python code 4316 # 4317 parsers = {'clinic' : DSLParser, 'python': PythonParser} 4318 4319 4320 clinic = None 4321 4322 4323 def main(argv): 4324 import sys 4325 4326 if sys.version_info.major < 3 or sys.version_info.minor < 3: 4327 sys.exit("Error: clinic.py requires Python 3.3 or greater.") 4328 4329 import argparse 4330 cmdline = argparse.ArgumentParser() 4331 cmdline.add_argument("-f", "--force", action='store_true') 4332 cmdline.add_argument("-o", "--output", type=str) 4333 cmdline.add_argument("-v", "--verbose", action='store_true') 4334 cmdline.add_argument("--converters", action='store_true') 4335 cmdline.add_argument("--make", action='store_true', 4336 help="Walk --srcdir to run over all relevant files.") 4337 cmdline.add_argument("--srcdir", type=str, default=os.curdir, 4338 help="The directory tree to walk in --make mode.") 4339 cmdline.add_argument("filename", type=str, nargs="*") 4340 ns = cmdline.parse_args(argv) 4341 4342 if ns.converters: 4343 if ns.filename: 4344 print("Usage error: can't specify --converters and a filename at the same time.") 4345 print() 4346 cmdline.print_usage() 4347 sys.exit(-1) 4348 converters = [] 4349 return_converters = [] 4350 ignored = set(""" 4351 add_c_converter 4352 add_c_return_converter 4353 add_default_legacy_c_converter 4354 add_legacy_c_converter 4355 """.strip().split()) 4356 module = globals() 4357 for name in module: 4358 for suffix, ids in ( 4359 ("_return_converter", return_converters), 4360 ("_converter", converters), 4361 ): 4362 if name in ignored: 4363 continue 4364 if name.endswith(suffix): 4365 ids.append((name, name[:-len(suffix)])) 4366 break 4367 print() 4368 4369 print("Legacy converters:") 4370 legacy = sorted(legacy_converters) 4371 print(' ' + ' '.join(c for c in legacy if c[0].isupper())) 4372 print(' ' + ' '.join(c for c in legacy if c[0].islower())) 4373 print() 4374 4375 for title, attribute, ids in ( 4376 ("Converters", 'converter_init', converters), 4377 ("Return converters", 'return_converter_init', return_converters), 4378 ): 4379 print(title + ":") 4380 longest = -1 4381 for name, short_name in ids: 4382 longest = max(longest, len(short_name)) 4383 for name, short_name in sorted(ids, key=lambda x: x[1].lower()): 4384 cls = module[name] 4385 callable = getattr(cls, attribute, None) 4386 if not callable: 4387 continue 4388 signature = inspect.signature(callable) 4389 parameters = [] 4390 for parameter_name, parameter in signature.parameters.items(): 4391 if parameter.kind == inspect.Parameter.KEYWORD_ONLY: 4392 if parameter.default != inspect.Parameter.empty: 4393 s = '{}={!r}'.format(parameter_name, parameter.default) 4394 else: 4395 s = parameter_name 4396 parameters.append(s) 4397 print(' {}({})'.format(short_name, ', '.join(parameters))) 4398 print() 4399 print("All converters also accept (c_default=None, py_default=None, annotation=None).") 4400 print("All return converters also accept (py_default=None).") 4401 sys.exit(0) 4402 4403 if ns.make: 4404 if ns.output or ns.filename: 4405 print("Usage error: can't use -o or filenames with --make.") 4406 print() 4407 cmdline.print_usage() 4408 sys.exit(-1) 4409 if not ns.srcdir: 4410 print("Usage error: --srcdir must not be empty with --make.") 4411 print() 4412 cmdline.print_usage() 4413 sys.exit(-1) 4414 for root, dirs, files in os.walk(ns.srcdir): 4415 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'): 4416 if rcs_dir in dirs: 4417 dirs.remove(rcs_dir) 4418 for filename in files: 4419 if not (filename.endswith('.c') or filename.endswith('.h')): 4420 continue 4421 path = os.path.join(root, filename) 4422 if ns.verbose: 4423 print(path) 4424 parse_file(path, force=ns.force, verify=not ns.force) 4425 return 4426 4427 if not ns.filename: 4428 cmdline.print_usage() 4429 sys.exit(-1) 4430 4431 if ns.output and len(ns.filename) > 1: 4432 print("Usage error: can't use -o with multiple filenames.") 4433 print() 4434 cmdline.print_usage() 4435 sys.exit(-1) 4436 4437 for filename in ns.filename: 4438 if ns.verbose: 4439 print(filename) 4440 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force) 4441 4442 4443 if __name__ == "__main__": 4444 sys.exit(main(sys.argv[1:])) 4445