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