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