blob: b503932e2624bbacbef5b21e75111ec5d6a78849 [file] [log] [blame]
Larry Hastings31826802013-10-19 00:09:25 -07001#!/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
Larry Hastings31826802013-10-19 00:09:25 -070010import collections
11import contextlib
Larry Hastings7726ac92014-01-31 22:03:12 -080012import copy
13import cpp
Larry Hastings31826802013-10-19 00:09:25 -070014import functools
15import hashlib
16import inspect
17import io
18import itertools
19import os
Larry Hastingsbebf7352014-01-17 17:47:17 -080020import pprint
Larry Hastings31826802013-10-19 00:09:25 -070021import re
22import shlex
Larry Hastings581ee362014-01-28 05:00:08 -080023import string
Larry Hastings31826802013-10-19 00:09:25 -070024import sys
25import tempfile
26import textwrap
Georg Brandlaabebde2014-01-16 06:53:54 +010027import traceback
Larry Hastingsdbfdc382015-05-04 06:59:46 -070028import types
Larry Hastings31826802013-10-19 00:09:25 -070029
Larry Hastingsdbfdc382015-05-04 06:59:46 -070030from types import *
31NoneType = type(None)
32
Larry Hastings31826802013-10-19 00:09:25 -070033# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070034#
35# soon:
36#
37# * allow mixing any two of {positional-only, positional-or-keyword,
38# keyword-only}
39# * dict constructor uses positional-only and keyword-only
40# * max and min use positional only with an optional group
41# and keyword-only
42#
Larry Hastings31826802013-10-19 00:09:25 -070043
Larry Hastingsebdcb502013-11-23 14:54:00 -080044version = '1'
45
Larry Hastings4a55fc52014-01-12 11:09:57 -080046NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070047
48class Unspecified:
49 def __repr__(self):
50 return '<Unspecified>'
51
52unspecified = Unspecified()
53
54
55class Null:
56 def __repr__(self):
57 return '<Null>'
58
59NULL = Null()
60
61
Larry Hastings2a727912014-01-16 11:32:01 -080062class Unknown:
63 def __repr__(self):
64 return '<Unknown>'
65
66unknown = Unknown()
67
Zachary Ware8ef887c2015-04-13 18:22:35 -050068sig_end_marker = '--'
69
Larry Hastings2a727912014-01-16 11:32:01 -080070
Larry Hastings0759f842015-04-03 13:09:02 -070071_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output")
72
Larry Hastings31826802013-10-19 00:09:25 -070073def _text_accumulator():
74 text = []
75 def output():
76 s = ''.join(text)
77 text.clear()
78 return s
Larry Hastings0759f842015-04-03 13:09:02 -070079 return _text_accumulator_nt(text, text.append, output)
Larry Hastings31826802013-10-19 00:09:25 -070080
81
Larry Hastings0759f842015-04-03 13:09:02 -070082text_accumulator_nt = collections.namedtuple("text_accumulator", "text append")
83
Larry Hastings31826802013-10-19 00:09:25 -070084def text_accumulator():
85 """
86 Creates a simple text accumulator / joiner.
87
88 Returns a pair of callables:
89 append, output
90 "append" appends a string to the accumulator.
91 "output" returns the contents of the accumulator
92 joined together (''.join(accumulator)) and
93 empties the accumulator.
94 """
95 text, append, output = _text_accumulator()
Larry Hastings0759f842015-04-03 13:09:02 -070096 return text_accumulator_nt(append, output)
Larry Hastings31826802013-10-19 00:09:25 -070097
98
Larry Hastingsbebf7352014-01-17 17:47:17 -080099def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -0700100 joined = " ".join([str(a) for a in args])
101 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800102 if fail:
103 add("Error")
104 else:
105 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -0700106 if clinic:
107 if filename is None:
108 filename = clinic.filename
Larry Hastings581ee362014-01-28 05:00:08 -0800109 if getattr(clinic, 'block_parser', None) and (line_number is None):
Larry Hastings31826802013-10-19 00:09:25 -0700110 line_number = clinic.block_parser.line_number
111 if filename is not None:
112 add(' in file "' + filename + '"')
113 if line_number is not None:
114 add(" on line " + str(line_number))
115 add(':\n')
116 add(joined)
117 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800118 if fail:
119 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700120
121
Larry Hastingsbebf7352014-01-17 17:47:17 -0800122def warn(*args, filename=None, line_number=None):
123 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
124
125def fail(*args, filename=None, line_number=None):
126 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
127
Larry Hastings31826802013-10-19 00:09:25 -0700128
129def quoted_for_c_string(s):
130 for old, new in (
Zachary Ware9d7849f2014-01-25 03:26:20 -0600131 ('\\', '\\\\'), # must be first!
Larry Hastings31826802013-10-19 00:09:25 -0700132 ('"', '\\"'),
133 ("'", "\\'"),
134 ):
135 s = s.replace(old, new)
136 return s
137
Larry Hastings4903e002014-01-18 00:26:16 -0800138def c_repr(s):
139 return '"' + s + '"'
140
141
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700142is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
143
144def is_legal_py_identifier(s):
145 return all(is_legal_c_identifier(field) for field in s.split('.'))
146
Larry Hastingsbebf7352014-01-17 17:47:17 -0800147# identifiers that are okay in Python but aren't a good idea in C.
148# so if they're used Argument Clinic will add "_value" to the end
149# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700150c_keywords = set("""
Larry Hastings5c661892014-01-24 06:17:25 -0800151asm auto break case char const continue default do double
152else enum extern float for goto if inline int long
153register return short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800154typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700155""".strip().split())
156
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700157def ensure_legal_c_identifier(s):
158 # for now, just complain if what we're given isn't legal
159 if not is_legal_c_identifier(s):
160 fail("Illegal C identifier: {}".format(s))
161 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700162 if s in c_keywords:
163 return s + "_value"
164 return s
165
166def rstrip_lines(s):
167 text, add, output = _text_accumulator()
168 for line in s.split('\n'):
169 add(line.rstrip())
170 add('\n')
171 text.pop()
172 return output()
173
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +0300174def format_escape(s):
175 # double up curly-braces, this string will be used
176 # as part of a format_map() template later
177 s = s.replace('{', '{{')
178 s = s.replace('}', '}}')
179 return s
180
Larry Hastings31826802013-10-19 00:09:25 -0700181def linear_format(s, **kwargs):
182 """
183 Perform str.format-like substitution, except:
184 * The strings substituted must be on lines by
185 themselves. (This line is the "source line".)
186 * If the substitution text is empty, the source line
187 is removed in the output.
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800188 * If the field is not recognized, the original line
189 is passed unmodified through to the output.
Larry Hastings31826802013-10-19 00:09:25 -0700190 * If the substitution text is not empty:
191 * Each line of the substituted text is indented
192 by the indent of the source line.
193 * A newline will be added to the end.
194 """
195
196 add, output = text_accumulator()
197 for line in s.split('\n'):
198 indent, curly, trailing = line.partition('{')
199 if not curly:
200 add(line)
201 add('\n')
202 continue
203
Martin Panter4177e7c2016-02-14 03:23:13 +0000204 name, curly, trailing = trailing.partition('}')
Larry Hastings31826802013-10-19 00:09:25 -0700205 if not curly or name not in kwargs:
206 add(line)
207 add('\n')
208 continue
209
210 if trailing:
211 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
212 if indent.strip():
213 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
214
215 value = kwargs[name]
216 if not value:
217 continue
218
219 value = textwrap.indent(rstrip_lines(value), indent)
220 add(value)
221 add('\n')
222
223 return output()[:-1]
224
Larry Hastingsbebf7352014-01-17 17:47:17 -0800225def indent_all_lines(s, prefix):
226 """
227 Returns 's', with 'prefix' prepended to all lines.
228
229 If the last line is empty, prefix is not prepended
230 to it. (If s is blank, returns s unchanged.)
231
232 (textwrap.indent only adds to non-blank lines.)
233 """
234 split = s.split('\n')
235 last = split.pop()
236 final = []
237 for line in split:
238 final.append(prefix)
239 final.append(line)
240 final.append('\n')
241 if last:
242 final.append(prefix)
243 final.append(last)
244 return ''.join(final)
245
246def suffix_all_lines(s, suffix):
247 """
248 Returns 's', with 'suffix' appended to all lines.
249
250 If the last line is empty, suffix is not appended
251 to it. (If s is blank, returns s unchanged.)
252 """
253 split = s.split('\n')
254 last = split.pop()
255 final = []
256 for line in split:
257 final.append(line)
258 final.append(suffix)
259 final.append('\n')
260 if last:
261 final.append(last)
262 final.append(suffix)
263 return ''.join(final)
264
265
Larry Hastingsebdcb502013-11-23 14:54:00 -0800266def version_splitter(s):
267 """Splits a version string into a tuple of integers.
268
269 The following ASCII characters are allowed, and employ
270 the following conversions:
271 a -> -3
272 b -> -2
273 c -> -1
274 (This permits Python-style version strings such as "1.4b3".)
275 """
276 version = []
277 accumulator = []
278 def flush():
279 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800280 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800281 version.append(int(''.join(accumulator)))
282 accumulator.clear()
283
284 for c in s:
285 if c.isdigit():
286 accumulator.append(c)
287 elif c == '.':
288 flush()
289 elif c in 'abc':
290 flush()
291 version.append('abc'.index(c) - 3)
292 else:
293 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
294 flush()
295 return tuple(version)
296
297def version_comparitor(version1, version2):
298 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
299 for i, (a, b) in enumerate(iterator):
300 if a < b:
301 return -1
302 if a > b:
303 return 1
304 return 0
305
Larry Hastings31826802013-10-19 00:09:25 -0700306
307class CRenderData:
308 def __init__(self):
309
310 # The C statements to declare variables.
311 # Should be full lines with \n eol characters.
312 self.declarations = []
313
314 # The C statements required to initialize the variables before the parse call.
315 # Should be full lines with \n eol characters.
316 self.initializers = []
317
Larry Hastingsc2047262014-01-25 20:43:29 -0800318 # The C statements needed to dynamically modify the values
319 # parsed by the parse call, before calling the impl.
320 self.modifications = []
321
Larry Hastings31826802013-10-19 00:09:25 -0700322 # The entries for the "keywords" array for PyArg_ParseTuple.
323 # Should be individual strings representing the names.
324 self.keywords = []
325
326 # The "format units" for PyArg_ParseTuple.
327 # Should be individual strings that will get
328 self.format_units = []
329
330 # The varargs arguments for PyArg_ParseTuple.
331 self.parse_arguments = []
332
333 # The parameter declarations for the impl function.
334 self.impl_parameters = []
335
336 # The arguments to the impl function at the time it's called.
337 self.impl_arguments = []
338
339 # For return converters: the name of the variable that
340 # should receive the value returned by the impl.
341 self.return_value = "return_value"
342
343 # For return converters: the code to convert the return
344 # value from the parse function. This is also where
345 # you should check the _return_value for errors, and
346 # "goto exit" if there are any.
347 self.return_conversion = []
348
349 # The C statements required to clean up after the impl call.
350 self.cleanup = []
351
352
Larry Hastings581ee362014-01-28 05:00:08 -0800353class FormatCounterFormatter(string.Formatter):
354 """
355 This counts how many instances of each formatter
356 "replacement string" appear in the format string.
357
358 e.g. after evaluating "string {a}, {b}, {c}, {a}"
359 the counts dict would now look like
360 {'a': 2, 'b': 1, 'c': 1}
361 """
362 def __init__(self):
363 self.counts = collections.Counter()
364
365 def get_value(self, key, args, kwargs):
366 self.counts[key] += 1
367 return ''
368
Larry Hastings31826802013-10-19 00:09:25 -0700369class Language(metaclass=abc.ABCMeta):
370
371 start_line = ""
372 body_prefix = ""
373 stop_line = ""
374 checksum_line = ""
375
Larry Hastings7726ac92014-01-31 22:03:12 -0800376 def __init__(self, filename):
377 pass
378
Larry Hastings31826802013-10-19 00:09:25 -0700379 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800380 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700381 pass
382
Larry Hastings7726ac92014-01-31 22:03:12 -0800383 def parse_line(self, line):
384 pass
385
Larry Hastings31826802013-10-19 00:09:25 -0700386 def validate(self):
Larry Hastings581ee362014-01-28 05:00:08 -0800387 def assert_only_one(attr, *additional_fields):
388 """
389 Ensures that the string found at getattr(self, attr)
390 contains exactly one formatter replacement string for
391 each valid field. The list of valid fields is
392 ['dsl_name'] extended by additional_fields.
393
394 e.g.
395 self.fmt = "{dsl_name} {a} {b}"
396
397 # this passes
398 self.assert_only_one('fmt', 'a', 'b')
399
400 # this fails, the format string has a {b} in it
401 self.assert_only_one('fmt', 'a')
402
403 # this fails, the format string doesn't have a {c} in it
404 self.assert_only_one('fmt', 'a', 'b', 'c')
405
406 # this fails, the format string has two {a}s in it,
407 # it must contain exactly one
408 self.fmt2 = '{dsl_name} {a} {a}'
409 self.assert_only_one('fmt2', 'a')
410
411 """
412 fields = ['dsl_name']
413 fields.extend(additional_fields)
414 line = getattr(self, attr)
415 fcf = FormatCounterFormatter()
416 fcf.format(line)
417 def local_fail(should_be_there_but_isnt):
418 if should_be_there_but_isnt:
419 fail("{} {} must contain {{{}}} exactly once!".format(
420 self.__class__.__name__, attr, name))
421 else:
422 fail("{} {} must not contain {{{}}}!".format(
423 self.__class__.__name__, attr, name))
424
425 for name, count in fcf.counts.items():
426 if name in fields:
427 if count > 1:
428 local_fail(True)
429 else:
430 local_fail(False)
431 for name in fields:
432 if fcf.counts.get(name) != 1:
433 local_fail(True)
434
Larry Hastings31826802013-10-19 00:09:25 -0700435 assert_only_one('start_line')
436 assert_only_one('stop_line')
Larry Hastings31826802013-10-19 00:09:25 -0700437
Larry Hastings581ee362014-01-28 05:00:08 -0800438 field = "arguments" if "{arguments}" in self.checksum_line else "checksum"
439 assert_only_one('checksum_line', field)
Larry Hastings31826802013-10-19 00:09:25 -0700440
441
442
443class PythonLanguage(Language):
444
445 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800446 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700447 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800448 stop_line = "#[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800449 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700450
451
452def permute_left_option_groups(l):
453 """
454 Given [1, 2, 3], should yield:
455 ()
456 (3,)
457 (2, 3)
458 (1, 2, 3)
459 """
460 yield tuple()
461 accumulator = []
462 for group in reversed(l):
463 accumulator = list(group) + accumulator
464 yield tuple(accumulator)
465
466
467def permute_right_option_groups(l):
468 """
469 Given [1, 2, 3], should yield:
470 ()
471 (1,)
472 (1, 2)
473 (1, 2, 3)
474 """
475 yield tuple()
476 accumulator = []
477 for group in l:
478 accumulator.extend(group)
479 yield tuple(accumulator)
480
481
482def permute_optional_groups(left, required, right):
483 """
484 Generator function that computes the set of acceptable
485 argument lists for the provided iterables of
486 argument groups. (Actually it generates a tuple of tuples.)
487
488 Algorithm: prefer left options over right options.
489
490 If required is empty, left must also be empty.
491 """
492 required = tuple(required)
493 result = []
494
495 if not required:
496 assert not left
497
498 accumulator = []
499 counts = set()
500 for r in permute_right_option_groups(right):
501 for l in permute_left_option_groups(left):
502 t = l + required + r
503 if len(t) in counts:
504 continue
505 counts.add(len(t))
506 accumulator.append(t)
507
508 accumulator.sort(key=len)
509 return tuple(accumulator)
510
511
Larry Hastings7726ac92014-01-31 22:03:12 -0800512def strip_leading_and_trailing_blank_lines(s):
513 lines = s.rstrip().split('\n')
514 while lines:
515 line = lines[0]
516 if line.strip():
517 break
518 del lines[0]
519 return '\n'.join(lines)
520
521@functools.lru_cache()
522def normalize_snippet(s, *, indent=0):
523 """
524 Reformats s:
525 * removes leading and trailing blank lines
526 * ensures that it does not end with a newline
527 * dedents so the first nonwhite character on any line is at column "indent"
528 """
529 s = strip_leading_and_trailing_blank_lines(s)
530 s = textwrap.dedent(s)
531 if indent:
532 s = textwrap.indent(s, ' ' * indent)
533 return s
534
535
Larry Hastings89964c42015-04-14 18:07:59 -0400536def wrap_declarations(text, length=78):
537 """
538 A simple-minded text wrapper for C function declarations.
539
540 It views a declaration line as looking like this:
541 xxxxxxxx(xxxxxxxxx,xxxxxxxxx)
542 If called with length=30, it would wrap that line into
543 xxxxxxxx(xxxxxxxxx,
544 xxxxxxxxx)
545 (If the declaration has zero or one parameters, this
546 function won't wrap it.)
547
548 If this doesn't work properly, it's probably better to
549 start from scratch with a more sophisticated algorithm,
550 rather than try and improve/debug this dumb little function.
551 """
552 lines = []
553 for line in text.split('\n'):
554 prefix, _, after_l_paren = line.partition('(')
555 if not after_l_paren:
556 lines.append(line)
557 continue
558 parameters, _, after_r_paren = after_l_paren.partition(')')
559 if not _:
560 lines.append(line)
561 continue
562 if ',' not in parameters:
563 lines.append(line)
564 continue
565 parameters = [x.strip() + ", " for x in parameters.split(',')]
566 prefix += "("
567 if len(prefix) < length:
568 spaces = " " * len(prefix)
569 else:
570 spaces = " " * 4
571
572 while parameters:
573 line = prefix
574 first = True
575 while parameters:
576 if (not first and
577 (len(line) + len(parameters[0]) > length)):
578 break
579 line += parameters.pop(0)
580 first = False
581 if not parameters:
582 line = line.rstrip(", ") + ")" + after_r_paren
583 lines.append(line.rstrip())
584 prefix = spaces
585 return "\n".join(lines)
586
587
Larry Hastings31826802013-10-19 00:09:25 -0700588class CLanguage(Language):
589
Larry Hastings61272b72014-01-07 12:41:53 -0800590 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700591 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800592 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700593 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800594 stop_line = "[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800595 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700596
Larry Hastings7726ac92014-01-31 22:03:12 -0800597 def __init__(self, filename):
598 super().__init__(filename)
599 self.cpp = cpp.Monitor(filename)
600 self.cpp.fail = fail
601
602 def parse_line(self, line):
603 self.cpp.writeline(line)
604
Larry Hastingsbebf7352014-01-17 17:47:17 -0800605 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700606 function = None
607 for o in signatures:
608 if isinstance(o, Function):
609 if function:
610 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
611 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800612 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700613
614 def docstring_for_c_string(self, f):
animalize463572c2019-02-25 07:18:48 +0800615 if re.search(r'[^\x00-\x7F]', f.docstring):
616 warn("Non-ascii character appear in docstring.")
617
Larry Hastings31826802013-10-19 00:09:25 -0700618 text, add, output = _text_accumulator()
619 # turn docstring into a properly quoted C string
620 for line in f.docstring.split('\n'):
621 add('"')
622 add(quoted_for_c_string(line))
623 add('\\n"\n')
624
Zachary Ware8ef887c2015-04-13 18:22:35 -0500625 if text[-2] == sig_end_marker:
626 # If we only have a signature, add the blank line that the
627 # __text_signature__ getter expects to be there.
628 add('"\\n"')
629 else:
630 text.pop()
631 add('"')
Larry Hastings31826802013-10-19 00:09:25 -0700632 return ''.join(text)
633
Larry Hastingsbebf7352014-01-17 17:47:17 -0800634 def output_templates(self, f):
635 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800636 assert parameters
637 assert isinstance(parameters[0].converter, self_converter)
638 del parameters[0]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800639 converters = [p.converter for p in parameters]
640
641 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
642 default_return_converter = (not f.return_converter or
643 f.return_converter.type == 'PyObject *')
644
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800645 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
646
Serhiy Storchaka31913912019-03-14 10:32:22 +0200647 pos_only = min_pos = max_pos = min_kw_only = 0
648 for i, p in enumerate(parameters, 1):
649 if p.is_keyword_only():
650 assert not p.is_positional_only()
651 if not p.is_optional():
652 min_kw_only = i - max_pos
653 else:
654 max_pos = i
655 if p.is_positional_only():
656 pos_only = i
657 if not p.is_optional():
658 min_pos = i
659
Larry Hastingsbebf7352014-01-17 17:47:17 -0800660 meth_o = (len(parameters) == 1 and
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300661 parameters[0].is_positional_only() and
Larry Hastingsbebf7352014-01-17 17:47:17 -0800662 not converters[0].is_optional() and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800663 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800664
Larry Hastings7726ac92014-01-31 22:03:12 -0800665 # we have to set these things before we're done:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800666 #
667 # docstring_prototype
668 # docstring_definition
669 # impl_prototype
670 # methoddef_define
671 # parser_prototype
672 # parser_definition
673 # impl_definition
Larry Hastings7726ac92014-01-31 22:03:12 -0800674 # cpp_if
675 # cpp_endif
676 # methoddef_ifndef
Larry Hastingsbebf7352014-01-17 17:47:17 -0800677
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800678 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700679
Larry Hastings7726ac92014-01-31 22:03:12 -0800680 methoddef_define = normalize_snippet("""
681 #define {methoddef_name} \\
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200682 {{"{name}", {methoddef_cast}{c_basename}, {methoddef_flags}, {c_basename}__doc__}},
Larry Hastings7726ac92014-01-31 22:03:12 -0800683 """)
Larry Hastings5c661892014-01-24 06:17:25 -0800684 if new_or_init and not f.docstring:
685 docstring_prototype = docstring_definition = ''
686 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800687 docstring_prototype = normalize_snippet("""
688 PyDoc_VAR({c_basename}__doc__);
689 """)
690 docstring_definition = normalize_snippet("""
691 PyDoc_STRVAR({c_basename}__doc__,
692 {docstring});
693 """)
694 impl_definition = normalize_snippet("""
695 static {impl_return_type}
696 {c_basename}_impl({impl_parameters})
697 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800698 impl_prototype = parser_prototype = parser_definition = None
699
Larry Hastings7726ac92014-01-31 22:03:12 -0800700 parser_prototype_keyword = normalize_snippet("""
701 static PyObject *
702 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
703 """)
704
705 parser_prototype_varargs = normalize_snippet("""
706 static PyObject *
707 {c_basename}({self_type}{self_name}, PyObject *args)
708 """)
709
Victor Stinner0c8c3892017-01-17 01:42:54 +0100710 parser_prototype_fastcall = normalize_snippet("""
711 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200712 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300713 """)
714
715 parser_prototype_fastcall_keywords = normalize_snippet("""
716 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200717 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
Victor Stinner0c8c3892017-01-17 01:42:54 +0100718 """)
719
Larry Hastings7726ac92014-01-31 22:03:12 -0800720 # parser_body_fields remembers the fields passed in to the
721 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800722 parser_body_fields = ()
Serhiy Storchaka31913912019-03-14 10:32:22 +0200723 parser_body_declarations = ''
724 def parser_body(prototype, *fields, declarations=''):
725 nonlocal parser_body_fields, parser_body_declarations
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800726 add, output = text_accumulator()
727 add(prototype)
728 parser_body_fields = fields
Serhiy Storchaka31913912019-03-14 10:32:22 +0200729 parser_body_declarations = declarations
Larry Hastings7726ac92014-01-31 22:03:12 -0800730
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800731 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800732 fields.insert(0, normalize_snippet("""
733 {{
734 {return_value_declaration}
Serhiy Storchaka31913912019-03-14 10:32:22 +0200735 {parser_declarations}
Larry Hastings7726ac92014-01-31 22:03:12 -0800736 {declarations}
737 {initializers}
738 """) + "\n")
739 # just imagine--your code is here in the middle
740 fields.append(normalize_snippet("""
741 {modifications}
742 {return_value} = {c_basename}_impl({impl_arguments});
743 {return_conversion}
744
745 {exit_label}
746 {cleanup}
747 return return_value;
748 }}
749 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800750 for field in fields:
751 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800752 add(field)
Serhiy Storchaka31913912019-03-14 10:32:22 +0200753 return linear_format(output(), parser_declarations=declarations)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800754
755 if not parameters:
756 # no parameters, METH_NOARGS
757
758 flags = "METH_NOARGS"
759
Larry Hastings7726ac92014-01-31 22:03:12 -0800760 parser_prototype = normalize_snippet("""
761 static PyObject *
762 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
763 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800764 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800765
766 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800767 parser_definition = parser_prototype + '\n' + normalize_snippet("""
768 {{
769 return {c_basename}_impl({impl_arguments});
770 }}
771 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800772 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800773 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700774
Larry Hastingsbebf7352014-01-17 17:47:17 -0800775 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800776 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800777
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300778 if (isinstance(converters[0], object_converter) and
779 converters[0].format_unit == 'O'):
780 meth_o_prototype = normalize_snippet("""
781 static PyObject *
782 {c_basename}({impl_parameters})
783 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800784
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300785 if default_return_converter:
786 # maps perfectly to METH_O, doesn't need a return converter.
787 # so we skip making a parse function
788 # and call directly into the impl function.
789 impl_prototype = parser_prototype = parser_definition = ''
790 impl_definition = meth_o_prototype
791 else:
792 # SLIGHT HACK
793 # use impl_parameters for the parser here!
794 parser_prototype = meth_o_prototype
795 parser_definition = parser_body(parser_prototype)
796
Larry Hastingsbebf7352014-01-17 17:47:17 -0800797 else:
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300798 argname = 'arg'
799 if parameters[0].name == argname:
800 argname += '_'
801 parser_prototype = normalize_snippet("""
802 static PyObject *
803 {c_basename}({self_type}{self_name}, PyObject *%s)
804 """ % argname)
805
Rémi Lapeyre4901fe22019-08-29 16:49:08 +0200806 displayname = parameters[0].get_displayname(0)
807 parsearg = converters[0].parse_arg(argname, displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200808 if parsearg is None:
809 parsearg = """
810 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
811 goto exit;
812 }}
813 """ % argname
Serhiy Storchaka32d96a22018-12-25 13:23:47 +0200814 parser_definition = parser_body(parser_prototype,
815 normalize_snippet(parsearg, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700816
Larry Hastingsbebf7352014-01-17 17:47:17 -0800817 elif has_option_groups:
818 # positional parameters with option groups
819 # (we have to generate lots of PyArg_ParseTuple calls
820 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700821
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800822 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800823 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700824
Larry Hastings7726ac92014-01-31 22:03:12 -0800825 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700826
Serhiy Storchaka31913912019-03-14 10:32:22 +0200827 elif pos_only == len(parameters):
Victor Stinner0c8c3892017-01-17 01:42:54 +0100828 if not new_or_init:
829 # positional-only, but no option groups
830 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800831
Victor Stinner0c8c3892017-01-17 01:42:54 +0100832 flags = "METH_FASTCALL"
833 parser_prototype = parser_prototype_fastcall
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200834 nargs = 'nargs'
835 argname_fmt = 'args[%d]'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100836 else:
837 # positional-only, but no option groups
838 # we only need one call to PyArg_ParseTuple
839
840 flags = "METH_VARARGS"
841 parser_prototype = parser_prototype_varargs
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200842 nargs = 'PyTuple_GET_SIZE(args)'
843 argname_fmt = 'PyTuple_GET_ITEM(args, %d)'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100844
Serhiy Storchaka31913912019-03-14 10:32:22 +0200845 parser_code = [normalize_snippet("""
846 if (!_PyArg_CheckPositional("{name}", %s, %d, %d)) {{
847 goto exit;
848 }}
849 """ % (nargs, min_pos, max_pos), indent=4)]
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200850 has_optional = False
Serhiy Storchaka31913912019-03-14 10:32:22 +0200851 for i, p in enumerate(parameters):
Rémi Lapeyre4901fe22019-08-29 16:49:08 +0200852 displayname = p.get_displayname(i+1)
853 parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200854 if parsearg is None:
Serhiy Storchaka31913912019-03-14 10:32:22 +0200855 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200856 parser_code = None
857 break
Serhiy Storchaka31913912019-03-14 10:32:22 +0200858 if has_optional or p.is_optional():
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200859 has_optional = True
860 parser_code.append(normalize_snippet("""
861 if (%s < %d) {{
862 goto skip_optional;
863 }}
864 """, indent=4) % (nargs, i + 1))
865 parser_code.append(normalize_snippet(parsearg, indent=4))
866
867 if parser_code is not None:
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200868 if has_optional:
869 parser_code.append("skip_optional:")
870 else:
871 if not new_or_init:
872 parser_code = [normalize_snippet("""
873 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
874 {parse_arguments})) {{
875 goto exit;
876 }}
877 """, indent=4)]
878 else:
879 parser_code = [normalize_snippet("""
880 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
881 {parse_arguments})) {{
882 goto exit;
883 }}
884 """, indent=4)]
885 parser_definition = parser_body(parser_prototype, *parser_code)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800886
887 else:
Serhiy Storchaka31913912019-03-14 10:32:22 +0200888 has_optional_kw = (max(pos_only, min_pos) + min_kw_only < len(converters))
889 if not new_or_init:
890 flags = "METH_FASTCALL|METH_KEYWORDS"
891 parser_prototype = parser_prototype_fastcall_keywords
892 argname_fmt = 'args[%d]'
893 declarations = normalize_snippet("""
894 static const char * const _keywords[] = {{{keywords}, NULL}};
895 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
896 PyObject *argsbuf[%s];
897 """ % len(converters))
898 if has_optional_kw:
899 declarations += "\nPy_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (min_pos + min_kw_only)
900 parser_code = [normalize_snippet("""
901 args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, %d, %d, %d, argsbuf);
902 if (!args) {{
903 goto exit;
904 }}
905 """ % (min_pos, max_pos, min_kw_only), indent=4)]
906 else:
907 # positional-or-keyword arguments
908 flags = "METH_VARARGS|METH_KEYWORDS"
909 parser_prototype = parser_prototype_keyword
910 argname_fmt = 'fastargs[%d]'
911 declarations = normalize_snippet("""
912 static const char * const _keywords[] = {{{keywords}, NULL}};
913 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
914 PyObject *argsbuf[%s];
915 PyObject * const *fastargs;
916 Py_ssize_t nargs = PyTuple_GET_SIZE(args);
917 """ % len(converters))
918 if has_optional_kw:
919 declarations += "\nPy_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (min_pos + min_kw_only)
920 parser_code = [normalize_snippet("""
921 fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %d, %d, %d, argsbuf);
922 if (!fastargs) {{
923 goto exit;
924 }}
925 """ % (min_pos, max_pos, min_kw_only), indent=4)]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800926
Serhiy Storchaka31913912019-03-14 10:32:22 +0200927 add_label = None
928 for i, p in enumerate(parameters):
Rémi Lapeyre4901fe22019-08-29 16:49:08 +0200929 displayname = p.get_displayname(i+1)
930 parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
Serhiy Storchaka31913912019-03-14 10:32:22 +0200931 if parsearg is None:
932 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr)
933 parser_code = None
934 break
935 if add_label and (i == pos_only or i == max_pos):
936 parser_code.append("%s:" % add_label)
937 add_label = None
938 if not p.is_optional():
939 parser_code.append(normalize_snippet(parsearg, indent=4))
940 elif i < pos_only:
941 add_label = 'skip_optional_posonly'
942 parser_code.append(normalize_snippet("""
943 if (nargs < %d) {{
944 goto %s;
945 }}
946 """ % (i + 1, add_label), indent=4))
947 if has_optional_kw:
948 parser_code.append(normalize_snippet("""
949 noptargs--;
950 """, indent=4))
951 parser_code.append(normalize_snippet(parsearg, indent=4))
952 else:
953 if i < max_pos:
954 label = 'skip_optional_pos'
955 first_opt = max(min_pos, pos_only)
956 else:
957 label = 'skip_optional_kwonly'
958 first_opt = max_pos + min_kw_only
959 if i == first_opt:
960 add_label = label
961 parser_code.append(normalize_snippet("""
962 if (!noptargs) {{
963 goto %s;
964 }}
965 """ % add_label, indent=4))
966 if i + 1 == len(parameters):
967 parser_code.append(normalize_snippet(parsearg, indent=4))
968 else:
969 add_label = label
970 parser_code.append(normalize_snippet("""
971 if (%s) {{
972 """ % (argname_fmt % i), indent=4))
973 parser_code.append(normalize_snippet(parsearg, indent=8))
974 parser_code.append(normalize_snippet("""
975 if (!--noptargs) {{
976 goto %s;
977 }}
978 }}
979 """ % add_label, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800980
Serhiy Storchaka31913912019-03-14 10:32:22 +0200981 if parser_code is not None:
982 if add_label:
983 parser_code.append("%s:" % add_label)
984 else:
985 declarations = (
986 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
987 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};')
988 if not new_or_init:
989 parser_code = [normalize_snippet("""
990 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
991 {parse_arguments})) {{
992 goto exit;
993 }}
994 """, indent=4)]
995 else:
996 parser_code = [normalize_snippet("""
997 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
998 {parse_arguments})) {{
999 goto exit;
1000 }}
1001 """, indent=4)]
1002 parser_definition = parser_body(parser_prototype, *parser_code,
1003 declarations=declarations)
Larry Hastings31826802013-10-19 00:09:25 -07001004
Larry Hastings31826802013-10-19 00:09:25 -07001005
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001006 if new_or_init:
1007 methoddef_define = ''
1008
1009 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -08001010 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001011 else:
1012 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -08001013 parser_prototype = normalize_snippet("""
1014 static int
1015 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
1016 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001017
1018 fields = list(parser_body_fields)
1019 parses_positional = 'METH_NOARGS' not in flags
1020 parses_keywords = 'METH_KEYWORDS' in flags
1021 if parses_keywords:
1022 assert parses_positional
1023
1024 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -08001025 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001026 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -08001027 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001028 }}
Larry Hastings7726ac92014-01-31 22:03:12 -08001029 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001030 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -08001031 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001032 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -08001033 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001034 }}
Larry Hastings7726ac92014-01-31 22:03:12 -08001035 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001036
Serhiy Storchaka31913912019-03-14 10:32:22 +02001037 parser_definition = parser_body(parser_prototype, *fields,
1038 declarations=parser_body_declarations)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001039
Larry Hastings31826802013-10-19 00:09:25 -07001040
Serhiy Storchaka4a934d42018-11-27 11:27:36 +02001041 if flags in ('METH_NOARGS', 'METH_O', 'METH_VARARGS'):
1042 methoddef_cast = "(PyCFunction)"
1043 else:
1044 methoddef_cast = "(PyCFunction)(void(*)(void))"
1045
Larry Hastingsbebf7352014-01-17 17:47:17 -08001046 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001047 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -07001048
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001049 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Serhiy Storchaka4a934d42018-11-27 11:27:36 +02001050 methoddef_define = methoddef_define.replace('{methoddef_cast}', methoddef_cast)
Larry Hastings31826802013-10-19 00:09:25 -07001051
Larry Hastings7726ac92014-01-31 22:03:12 -08001052 methoddef_ifndef = ''
1053 conditional = self.cpp.condition()
1054 if not conditional:
1055 cpp_if = cpp_endif = ''
1056 else:
1057 cpp_if = "#if " + conditional
1058 cpp_endif = "#endif /* " + conditional + " */"
1059
Tal Einat4f574092017-11-03 11:09:00 +02001060 if methoddef_define and f.full_name not in clinic.ifndef_symbols:
1061 clinic.ifndef_symbols.add(f.full_name)
Larry Hastings7726ac92014-01-31 22:03:12 -08001062 methoddef_ifndef = normalize_snippet("""
1063 #ifndef {methoddef_name}
1064 #define {methoddef_name}
1065 #endif /* !defined({methoddef_name}) */
1066 """)
1067
1068
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001069 # add ';' to the end of parser_prototype and impl_prototype
1070 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001071 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001072 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001073 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001074 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -07001075
Larry Hastingsbebf7352014-01-17 17:47:17 -08001076 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001077 impl_prototype = impl_definition
1078 if impl_prototype:
1079 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -07001080
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001081 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001082
1083 d = {
1084 "docstring_prototype" : docstring_prototype,
1085 "docstring_definition" : docstring_definition,
1086 "impl_prototype" : impl_prototype,
1087 "methoddef_define" : methoddef_define,
1088 "parser_prototype" : parser_prototype,
1089 "parser_definition" : parser_definition,
1090 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -08001091 "cpp_if" : cpp_if,
1092 "cpp_endif" : cpp_endif,
1093 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001094 }
1095
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001096 # make sure we didn't forget to assign something,
1097 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001098 d2 = {}
1099 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001100 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001101 if value:
1102 value = '\n' + value + '\n'
1103 d2[name] = value
1104 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001105
1106 @staticmethod
1107 def group_to_variable_name(group):
1108 adjective = "left_" if group < 0 else "right_"
1109 return "group_" + adjective + str(abs(group))
1110
1111 def render_option_group_parsing(self, f, template_dict):
1112 # positional only, grouped, optional arguments!
1113 # can be optional on the left or right.
1114 # here's an example:
1115 #
1116 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1117 #
1118 # Here group D are required, and all other groups are optional.
1119 # (Group D's "group" is actually None.)
1120 # We can figure out which sets of arguments we have based on
1121 # how many arguments are in the tuple.
1122 #
1123 # Note that you need to count up on both sides. For example,
1124 # you could have groups C+D, or C+D+E, or C+D+E+F.
1125 #
1126 # What if the number of arguments leads us to an ambiguous result?
1127 # Clinic prefers groups on the left. So in the above example,
1128 # five arguments would map to B+C, not C+D.
1129
1130 add, output = text_accumulator()
1131 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001132 if isinstance(parameters[0].converter, self_converter):
1133 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001134
1135 groups = []
1136 group = None
1137 left = []
1138 right = []
1139 required = []
1140 last = unspecified
1141
1142 for p in parameters:
1143 group_id = p.group
1144 if group_id != last:
1145 last = group_id
1146 group = []
1147 if group_id < 0:
1148 left.append(group)
1149 elif group_id == 0:
1150 group = required
1151 else:
1152 right.append(group)
1153 group.append(p)
1154
1155 count_min = sys.maxsize
1156 count_max = -1
1157
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001158 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001159 for subset in permute_optional_groups(left, required, right):
1160 count = len(subset)
1161 count_min = min(count_min, count)
1162 count_max = max(count_max, count)
1163
Larry Hastings583baa82014-01-12 08:49:30 -08001164 if count == 0:
1165 add(""" case 0:
1166 break;
1167""")
1168 continue
1169
Larry Hastings31826802013-10-19 00:09:25 -07001170 group_ids = {p.group for p in subset} # eliminate duplicates
1171 d = {}
1172 d['count'] = count
1173 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001174 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1175
1176 parse_arguments = []
1177 for p in subset:
1178 p.converter.parse_argument(parse_arguments)
1179 d['parse_arguments'] = ", ".join(parse_arguments)
1180
1181 group_ids.discard(0)
1182 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1183 lines = "\n".join(lines)
1184
Dong-hee Na5136e722020-01-06 19:46:04 +09001185 s = """\
Larry Hastings31826802013-10-19 00:09:25 -07001186 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001187 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001188 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001189 }}
Larry Hastings31826802013-10-19 00:09:25 -07001190 {group_booleans}
1191 break;
Dong-hee Na5136e722020-01-06 19:46:04 +09001192"""
Larry Hastings31826802013-10-19 00:09:25 -07001193 s = linear_format(s, group_booleans=lines)
1194 s = s.format_map(d)
1195 add(s)
1196
1197 add(" default:\n")
1198 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1199 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001200 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001201 add("}")
1202 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001203
Larry Hastingsbebf7352014-01-17 17:47:17 -08001204 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001205 if not f:
1206 return ""
1207
1208 add, output = text_accumulator()
1209 data = CRenderData()
1210
Larry Hastings7726ac92014-01-31 22:03:12 -08001211 assert f.parameters, "We should always have a 'self' at this point!"
1212 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001213 converters = [p.converter for p in parameters]
1214
Larry Hastings5c661892014-01-24 06:17:25 -08001215 templates = self.output_templates(f)
1216
1217 f_self = parameters[0]
1218 selfless = parameters[1:]
1219 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1220
1221 last_group = 0
1222 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001223 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001224 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1225 default_return_converter = (not f.return_converter or
1226 f.return_converter.type == 'PyObject *')
1227 has_option_groups = False
1228
1229 # offset i by -1 because first_optional needs to ignore self
1230 for i, p in enumerate(parameters, -1):
1231 c = p.converter
1232
1233 if (i != -1) and (p.default is not unspecified):
1234 first_optional = min(first_optional, i)
1235
1236 # insert group variable
1237 group = p.group
1238 if last_group != group:
1239 last_group = group
1240 if group:
1241 group_name = self.group_to_variable_name(group)
1242 data.impl_arguments.append(group_name)
1243 data.declarations.append("int " + group_name + " = 0;")
1244 data.impl_parameters.append("int " + group_name)
1245 has_option_groups = True
1246
1247 c.render(p, data)
1248
1249 if has_option_groups and (not positional):
1250 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1251
1252 # HACK
1253 # when we're METH_O, but have a custom return converter,
1254 # we use "impl_parameters" for the parsing function
1255 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001256 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001257 # as variables in the parsing function. but since it's
1258 # METH_O, we have exactly one anyway, so we know exactly
1259 # where it is.
1260 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001261 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001262 data.declarations.pop(0)
1263
Larry Hastings31826802013-10-19 00:09:25 -07001264 template_dict = {}
1265
1266 full_name = f.full_name
1267 template_dict['full_name'] = full_name
1268
Larry Hastings5c661892014-01-24 06:17:25 -08001269 if new_or_init:
1270 name = f.cls.name
1271 else:
1272 name = f.name
1273
Larry Hastings31826802013-10-19 00:09:25 -07001274 template_dict['name'] = name
1275
Larry Hastings8666e652014-01-12 14:12:59 -08001276 if f.c_basename:
1277 c_basename = f.c_basename
1278 else:
1279 fields = full_name.split(".")
1280 if fields[-1] == '__new__':
1281 fields.pop()
1282 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001283
Larry Hastings31826802013-10-19 00:09:25 -07001284 template_dict['c_basename'] = c_basename
1285
1286 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1287 template_dict['methoddef_name'] = methoddef_name
1288
1289 template_dict['docstring'] = self.docstring_for_c_string(f)
1290
Larry Hastingsc2047262014-01-25 20:43:29 -08001291 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001292 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001293
Larry Hastings31826802013-10-19 00:09:25 -07001294 f.return_converter.render(f, data)
1295 template_dict['impl_return_type'] = f.return_converter.type
1296
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001297 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001298 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001299 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001300 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1301 template_dict['format_units'] = ''.join(data.format_units)
1302 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1303 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1304 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001305 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1306 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001307 template_dict['return_value'] = data.return_value
1308
Larry Hastings5c661892014-01-24 06:17:25 -08001309 # used by unpack tuple code generator
1310 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1311 unpack_min = first_optional
1312 unpack_max = len(selfless)
1313 template_dict['unpack_min'] = str(unpack_min)
1314 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001315
Larry Hastingsbebf7352014-01-17 17:47:17 -08001316 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001317 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001318
Larry Hastings0759f842015-04-03 13:09:02 -07001319 # buffers, not destination
1320 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001321 template = templates[name]
1322 if has_option_groups:
1323 template = linear_format(template,
1324 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001325 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001326 declarations=template_dict['declarations'],
1327 return_conversion=template_dict['return_conversion'],
1328 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001329 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001330 cleanup=template_dict['cleanup'],
1331 )
Larry Hastings31826802013-10-19 00:09:25 -07001332
Larry Hastingsbebf7352014-01-17 17:47:17 -08001333 # Only generate the "exit:" label
1334 # if we have any gotos
1335 need_exit_label = "goto exit;" in template
1336 template = linear_format(template,
1337 exit_label="exit:" if need_exit_label else ''
1338 )
Larry Hastings31826802013-10-19 00:09:25 -07001339
Larry Hastingsbebf7352014-01-17 17:47:17 -08001340 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001341
Larry Hastings89964c42015-04-14 18:07:59 -04001342 # mild hack:
1343 # reflow long impl declarations
1344 if name in {"impl_prototype", "impl_definition"}:
1345 s = wrap_declarations(s)
1346
Larry Hastingsbebf7352014-01-17 17:47:17 -08001347 if clinic.line_prefix:
1348 s = indent_all_lines(s, clinic.line_prefix)
1349 if clinic.line_suffix:
1350 s = suffix_all_lines(s, clinic.line_suffix)
1351
1352 destination.append(s)
1353
1354 return clinic.get_destination('block').dump()
1355
Larry Hastings31826802013-10-19 00:09:25 -07001356
1357
Larry Hastings5c661892014-01-24 06:17:25 -08001358
Larry Hastings31826802013-10-19 00:09:25 -07001359@contextlib.contextmanager
1360def OverrideStdioWith(stdout):
1361 saved_stdout = sys.stdout
1362 sys.stdout = stdout
1363 try:
1364 yield
1365 finally:
1366 assert sys.stdout is stdout
1367 sys.stdout = saved_stdout
1368
1369
Larry Hastings2623c8c2014-02-08 22:15:29 -08001370def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001371 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001372 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001373 pattern = r'{}({}){}'
1374 if whole_line:
1375 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001376 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1377 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001378
1379
1380class Block:
1381 r"""
1382 Represents a single block of text embedded in
1383 another file. If dsl_name is None, the block represents
1384 verbatim text, raw original text from the file, in
1385 which case "input" will be the only non-false member.
1386 If dsl_name is not None, the block represents a Clinic
1387 block.
1388
1389 input is always str, with embedded \n characters.
1390 input represents the original text from the file;
1391 if it's a Clinic block, it is the original text with
1392 the body_prefix and redundant leading whitespace removed.
1393
1394 dsl_name is either str or None. If str, it's the text
1395 found on the start line of the block between the square
1396 brackets.
1397
1398 signatures is either list or None. If it's a list,
1399 it may only contain clinic.Module, clinic.Class, and
1400 clinic.Function objects. At the moment it should
1401 contain at most one of each.
1402
1403 output is either str or None. If str, it's the output
1404 from this block, with embedded '\n' characters.
1405
1406 indent is either str or None. It's the leading whitespace
1407 that was found on every line of input. (If body_prefix is
1408 not empty, this is the indent *after* removing the
1409 body_prefix.)
1410
1411 preindent is either str or None. It's the whitespace that
1412 was found in front of every line of input *before* the
1413 "body_prefix" (see the Language object). If body_prefix
1414 is empty, preindent must always be empty too.
1415
1416 To illustrate indent and preindent: Assume that '_'
1417 represents whitespace. If the block processed was in a
1418 Python file, and looked like this:
1419 ____#/*[python]
1420 ____#__for a in range(20):
1421 ____#____print(a)
1422 ____#[python]*/
1423 "preindent" would be "____" and "indent" would be "__".
1424
1425 """
1426 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1427 assert isinstance(input, str)
1428 self.input = input
1429 self.dsl_name = dsl_name
1430 self.signatures = signatures or []
1431 self.output = output
1432 self.indent = indent
1433 self.preindent = preindent
1434
Larry Hastings581ee362014-01-28 05:00:08 -08001435 def __repr__(self):
1436 dsl_name = self.dsl_name or "text"
1437 def summarize(s):
1438 s = repr(s)
1439 if len(s) > 30:
1440 return s[:26] + "..." + s[0]
1441 return s
1442 return "".join((
1443 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1444
Larry Hastings31826802013-10-19 00:09:25 -07001445
1446class BlockParser:
1447 """
1448 Block-oriented parser for Argument Clinic.
1449 Iterator, yields Block objects.
1450 """
1451
1452 def __init__(self, input, language, *, verify=True):
1453 """
1454 "input" should be a str object
1455 with embedded \n characters.
1456
1457 "language" should be a Language object.
1458 """
1459 language.validate()
1460
1461 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1462 self.block_start_line_number = self.line_number = 0
1463
1464 self.language = language
1465 before, _, after = language.start_line.partition('{dsl_name}')
1466 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001467 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001468 self.start_re = create_regex(before, after)
1469 self.verify = verify
1470 self.last_checksum_re = None
1471 self.last_dsl_name = None
1472 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001473 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001474
1475 def __iter__(self):
1476 return self
1477
1478 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001479 while True:
1480 if not self.input:
1481 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001482
Larry Hastingsbebf7352014-01-17 17:47:17 -08001483 if self.dsl_name:
1484 return_value = self.parse_clinic_block(self.dsl_name)
1485 self.dsl_name = None
1486 self.first_block = False
1487 return return_value
1488 block = self.parse_verbatim_block()
1489 if self.first_block and not block.input:
1490 continue
1491 self.first_block = False
1492 return block
1493
Larry Hastings31826802013-10-19 00:09:25 -07001494
1495 def is_start_line(self, line):
1496 match = self.start_re.match(line.lstrip())
1497 return match.group(1) if match else None
1498
Larry Hastingse1b82532014-07-27 16:22:20 +02001499 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001500 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001501 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001502 if not lookahead:
1503 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001504 return line
Larry Hastings31826802013-10-19 00:09:25 -07001505
1506 def parse_verbatim_block(self):
1507 add, output = text_accumulator()
1508 self.block_start_line_number = self.line_number
1509
1510 while self.input:
1511 line = self._line()
1512 dsl_name = self.is_start_line(line)
1513 if dsl_name:
1514 self.dsl_name = dsl_name
1515 break
1516 add(line)
1517
1518 return Block(output())
1519
1520 def parse_clinic_block(self, dsl_name):
1521 input_add, input_output = text_accumulator()
1522 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001523 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001524 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1525
Larry Hastings90261132014-01-07 12:21:08 -08001526 def is_stop_line(line):
1527 # make sure to recognize stop line even if it
1528 # doesn't end with EOL (it could be the very end of the file)
1529 if not line.startswith(stop_line):
1530 return False
1531 remainder = line[len(stop_line):]
1532 return (not remainder) or remainder.isspace()
1533
Larry Hastings31826802013-10-19 00:09:25 -07001534 # consume body of program
1535 while self.input:
1536 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001537 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001538 break
1539 if body_prefix:
1540 line = line.lstrip()
1541 assert line.startswith(body_prefix)
1542 line = line[len(body_prefix):]
1543 input_add(line)
1544
1545 # consume output and checksum line, if present.
1546 if self.last_dsl_name == dsl_name:
1547 checksum_re = self.last_checksum_re
1548 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001549 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1550 assert _ == '{arguments}'
1551 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001552 self.last_dsl_name = dsl_name
1553 self.last_checksum_re = checksum_re
1554
1555 # scan forward for checksum line
1556 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001557 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001558 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001559 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001560 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001561 arguments = match.group(1) if match else None
1562 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001563 break
1564 output_add(line)
1565 if self.is_start_line(line):
1566 break
1567
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001568 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001569 if arguments:
1570 d = {}
1571 for field in shlex.split(arguments):
1572 name, equals, value = field.partition('=')
1573 if not equals:
1574 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1575 d[name.strip()] = value.strip()
1576
Larry Hastings31826802013-10-19 00:09:25 -07001577 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001578 if 'input' in d:
1579 checksum = d['output']
1580 input_checksum = d['input']
1581 else:
1582 checksum = d['checksum']
1583 input_checksum = None
1584
1585 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001586 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001587 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1588 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001589 "the end marker,\n"
1590 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001591 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001592 else:
1593 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001594 output_lines = output.splitlines(keepends=True)
1595 self.line_number -= len(output_lines)
1596 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001597 output = None
1598
1599 return Block(input_output(), dsl_name, output=output)
1600
1601
1602class BlockPrinter:
1603
1604 def __init__(self, language, f=None):
1605 self.language = language
1606 self.f = f or io.StringIO()
1607
1608 def print_block(self, block):
1609 input = block.input
1610 output = block.output
1611 dsl_name = block.dsl_name
1612 write = self.f.write
1613
Larry Hastings31826802013-10-19 00:09:25 -07001614 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1615
1616 if not dsl_name:
1617 write(input)
1618 return
1619
1620 write(self.language.start_line.format(dsl_name=dsl_name))
1621 write("\n")
1622
1623 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1624 if not body_prefix:
1625 write(input)
1626 else:
1627 for line in input.split('\n'):
1628 write(body_prefix)
1629 write(line)
1630 write("\n")
1631
1632 write(self.language.stop_line.format(dsl_name=dsl_name))
1633 write("\n")
1634
Larry Hastings581ee362014-01-28 05:00:08 -08001635 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001636 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001637 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001638 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001639 output += '\n'
1640 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001641
Larry Hastings581ee362014-01-28 05:00:08 -08001642 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1643 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001644 write("\n")
1645
Larry Hastingsbebf7352014-01-17 17:47:17 -08001646 def write(self, text):
1647 self.f.write(text)
1648
1649
Larry Hastings0759f842015-04-03 13:09:02 -07001650class BufferSeries:
1651 """
1652 Behaves like a "defaultlist".
1653 When you ask for an index that doesn't exist yet,
1654 the object grows the list until that item exists.
1655 So o[n] will always work.
1656
1657 Supports negative indices for actual items.
1658 e.g. o[-1] is an element immediately preceding o[0].
1659 """
1660
1661 def __init__(self):
1662 self._start = 0
1663 self._array = []
1664 self._constructor = _text_accumulator
1665
1666 def __getitem__(self, i):
1667 i -= self._start
1668 if i < 0:
1669 self._start += i
1670 prefix = [self._constructor() for x in range(-i)]
1671 self._array = prefix + self._array
1672 i = 0
1673 while i >= len(self._array):
1674 self._array.append(self._constructor())
1675 return self._array[i]
1676
1677 def clear(self):
1678 for ta in self._array:
1679 ta._text.clear()
1680
1681 def dump(self):
1682 texts = [ta.output() for ta in self._array]
1683 return "".join(texts)
1684
1685
Larry Hastingsbebf7352014-01-17 17:47:17 -08001686class Destination:
1687 def __init__(self, name, type, clinic, *args):
1688 self.name = name
1689 self.type = type
1690 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001691 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001692 if type not in valid_types:
1693 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1694 extra_arguments = 1 if type == "file" else 0
1695 if len(args) < extra_arguments:
1696 fail("Not enough arguments for destination " + name + " new " + type)
1697 if len(args) > extra_arguments:
1698 fail("Too many arguments for destination " + name + " new " + type)
1699 if type =='file':
1700 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001701 filename = clinic.filename
1702 d['path'] = filename
1703 dirname, basename = os.path.split(filename)
1704 if not dirname:
1705 dirname = '.'
1706 d['dirname'] = dirname
1707 d['basename'] = basename
1708 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001709 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001710
Larry Hastings0759f842015-04-03 13:09:02 -07001711 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001712
1713 def __repr__(self):
1714 if self.type == 'file':
1715 file_repr = " " + repr(self.filename)
1716 else:
1717 file_repr = ''
1718 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1719
1720 def clear(self):
1721 if self.type != 'buffer':
1722 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001723 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001724
1725 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001726 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001727
Larry Hastings31826802013-10-19 00:09:25 -07001728
1729# maps strings to Language objects.
1730# "languages" maps the name of the language ("C", "Python").
1731# "extensions" maps the file extension ("c", "py").
1732languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001733extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1734extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001735
1736
1737# maps strings to callables.
1738# these callables must be of the form:
1739# def foo(name, default, *, ...)
1740# The callable may have any number of keyword-only parameters.
1741# The callable must return a CConverter object.
1742# The callable should not call builtins.print.
1743converters = {}
1744
1745# maps strings to callables.
1746# these callables follow the same rules as those for "converters" above.
1747# note however that they will never be called with keyword-only parameters.
1748legacy_converters = {}
1749
1750
1751# maps strings to callables.
1752# these callables must be of the form:
1753# def foo(*, ...)
1754# The callable may have any number of keyword-only parameters.
1755# The callable must return a CConverter object.
1756# The callable should not call builtins.print.
1757return_converters = {}
1758
Larry Hastings7726ac92014-01-31 22:03:12 -08001759clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001760class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001761
1762 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001763preset block
1764everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001765methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001766docstring_prototype suppress
1767parser_prototype suppress
1768cpp_if suppress
1769cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001770
Larry Hastingsbebf7352014-01-17 17:47:17 -08001771preset original
1772everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001773methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001774docstring_prototype suppress
1775parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001776cpp_if suppress
1777cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001778
1779preset file
1780everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001781methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001782docstring_prototype suppress
1783parser_prototype suppress
1784impl_definition block
1785
1786preset buffer
1787everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001788methoddef_ifndef buffer 1
1789impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001790docstring_prototype suppress
1791impl_prototype suppress
1792parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001793
1794preset partial-buffer
1795everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001796methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001797docstring_prototype block
1798impl_prototype suppress
1799methoddef_define block
1800parser_prototype block
1801impl_definition block
1802
Larry Hastingsbebf7352014-01-17 17:47:17 -08001803"""
1804
Larry Hastings581ee362014-01-28 05:00:08 -08001805 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001806 # maps strings to Parser objects.
1807 # (instantiated from the "parsers" global.)
1808 self.parsers = {}
1809 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001810 if printer:
1811 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001812 self.printer = printer or BlockPrinter(language)
1813 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001814 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001815 self.filename = filename
1816 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001817 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001818 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001819
Larry Hastingsbebf7352014-01-17 17:47:17 -08001820 self.line_prefix = self.line_suffix = ''
1821
1822 self.destinations = {}
1823 self.add_destination("block", "buffer")
1824 self.add_destination("suppress", "suppress")
1825 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001826 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001827 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001828
Larry Hastings0759f842015-04-03 13:09:02 -07001829 d = self.get_destination_buffer
1830 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001831 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001832 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001833 ('docstring_definition', d('file')),
1834 ('methoddef_define', d('file')),
1835 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001836 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001837 ('parser_definition', d('file')),
1838 ('cpp_endif', d('file')),
1839 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001840 ('impl_definition', d('block')),
1841 ))
1842
Larry Hastings0759f842015-04-03 13:09:02 -07001843 self.destination_buffers_stack = []
1844 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001845
1846 self.presets = {}
1847 preset = None
1848 for line in self.presets_text.strip().split('\n'):
1849 line = line.strip()
1850 if not line:
1851 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001852 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001853 if name == 'preset':
1854 self.presets[value] = preset = collections.OrderedDict()
1855 continue
1856
Larry Hastings0759f842015-04-03 13:09:02 -07001857 if len(options):
1858 index = int(options[0])
1859 else:
1860 index = 0
1861 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001862
1863 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001864 for name in self.destination_buffers:
1865 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001866 continue
1867
Larry Hastings0759f842015-04-03 13:09:02 -07001868 assert name in self.destination_buffers
1869 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001870
Larry Hastings31826802013-10-19 00:09:25 -07001871 global clinic
1872 clinic = self
1873
Larry Hastingsbebf7352014-01-17 17:47:17 -08001874 def add_destination(self, name, type, *args):
1875 if name in self.destinations:
1876 fail("Destination already exists: " + repr(name))
1877 self.destinations[name] = Destination(name, type, self, *args)
1878
Larry Hastings0759f842015-04-03 13:09:02 -07001879 def get_destination(self, name):
1880 d = self.destinations.get(name)
1881 if not d:
1882 fail("Destination does not exist: " + repr(name))
1883 return d
1884
1885 def get_destination_buffer(self, name, item=0):
1886 d = self.get_destination(name)
1887 return d.buffers[item]
1888
Larry Hastings31826802013-10-19 00:09:25 -07001889 def parse(self, input):
1890 printer = self.printer
1891 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1892 for block in self.block_parser:
1893 dsl_name = block.dsl_name
1894 if dsl_name:
1895 if dsl_name not in self.parsers:
1896 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1897 self.parsers[dsl_name] = parsers[dsl_name](self)
1898 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001899 try:
1900 parser.parse(block)
1901 except Exception:
1902 fail('Exception raised during parsing:\n' +
1903 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001904 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001905
1906 second_pass_replacements = {}
1907
Larry Hastings0759f842015-04-03 13:09:02 -07001908 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001909 for name, destination in self.destinations.items():
1910 if destination.type == 'suppress':
1911 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001912 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001913
1914 if output:
1915
1916 block = Block("", dsl_name="clinic", output=output)
1917
1918 if destination.type == 'buffer':
1919 block.input = "dump " + name + "\n"
1920 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1921 printer.write("\n")
1922 printer.print_block(block)
1923 continue
1924
1925 if destination.type == 'file':
1926 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001927 dirname = os.path.dirname(destination.filename)
1928 try:
1929 os.makedirs(dirname)
1930 except FileExistsError:
1931 if not os.path.isdir(dirname):
1932 fail("Can't write to destination {}, "
1933 "can't make directory {}!".format(
1934 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001935 if self.verify:
1936 with open(destination.filename, "rt") as f:
1937 parser_2 = BlockParser(f.read(), language=self.language)
1938 blocks = list(parser_2)
1939 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1940 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001941 except FileNotFoundError:
1942 pass
1943
1944 block.input = 'preserve\n'
1945 printer_2 = BlockPrinter(self.language)
1946 printer_2.print_block(block)
1947 with open(destination.filename, "wt") as f:
1948 f.write(printer_2.f.getvalue())
1949 continue
1950 text = printer.f.getvalue()
1951
1952 if second_pass_replacements:
1953 printer_2 = BlockPrinter(self.language)
1954 parser_2 = BlockParser(text, self.language)
1955 changed = False
1956 for block in parser_2:
1957 if block.dsl_name:
1958 for id, replacement in second_pass_replacements.items():
1959 if id in block.output:
1960 changed = True
1961 block.output = block.output.replace(id, replacement)
1962 printer_2.print_block(block)
1963 if changed:
1964 text = printer_2.f.getvalue()
1965
1966 return text
1967
Larry Hastings31826802013-10-19 00:09:25 -07001968
1969 def _module_and_class(self, fields):
1970 """
1971 fields should be an iterable of field names.
1972 returns a tuple of (module, class).
1973 the module object could actually be self (a clinic object).
1974 this function is only ever used to find the parent of where
1975 a new class/module should go.
1976 """
1977 in_classes = False
1978 parent = module = self
1979 cls = None
1980 so_far = []
1981
1982 for field in fields:
1983 so_far.append(field)
1984 if not in_classes:
1985 child = parent.modules.get(field)
1986 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001987 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001988 continue
1989 in_classes = True
1990 if not hasattr(parent, 'classes'):
1991 return module, cls
1992 child = parent.classes.get(field)
1993 if not child:
1994 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1995 cls = parent = child
1996
1997 return module, cls
1998
1999
Larry Hastings581ee362014-01-28 05:00:08 -08002000def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07002001 extension = os.path.splitext(filename)[1][1:]
2002 if not extension:
2003 fail("Can't extract file type for file " + repr(filename))
2004
2005 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08002006 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07002007 except KeyError:
2008 fail("Can't identify file type for file " + repr(filename))
2009
Larry Hastings31826802013-10-19 00:09:25 -07002010 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002011 raw = f.read()
2012
Larry Hastings2623c8c2014-02-08 22:15:29 -08002013 # exit quickly if there are no clinic markers in the file
2014 find_start_re = BlockParser("", language).find_start_re
2015 if not find_start_re.search(raw):
2016 return
2017
2018 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002019 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08002020 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002021 return
Larry Hastings31826802013-10-19 00:09:25 -07002022
2023 directory = os.path.dirname(filename) or '.'
2024
2025 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002026 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07002027 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
2028 with open(tmpfilename, "wb") as f:
2029 f.write(bytes)
2030 os.replace(tmpfilename, output or filename)
2031
2032
Larry Hastings581ee362014-01-28 05:00:08 -08002033def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07002034 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08002035 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
2036 if length:
2037 s = s[:length]
2038 return s
Larry Hastings31826802013-10-19 00:09:25 -07002039
2040
2041
2042
2043class PythonParser:
2044 def __init__(self, clinic):
2045 pass
2046
2047 def parse(self, block):
2048 s = io.StringIO()
2049 with OverrideStdioWith(s):
2050 exec(block.input)
2051 block.output = s.getvalue()
2052
2053
2054class Module:
2055 def __init__(self, name, module=None):
2056 self.name = name
2057 self.module = self.parent = module
2058
2059 self.modules = collections.OrderedDict()
2060 self.classes = collections.OrderedDict()
2061 self.functions = []
2062
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002063 def __repr__(self):
2064 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
2065
Larry Hastings31826802013-10-19 00:09:25 -07002066class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08002067 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07002068 self.name = name
2069 self.module = module
2070 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08002071 self.typedef = typedef
2072 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07002073 self.parent = cls or module
2074
2075 self.classes = collections.OrderedDict()
2076 self.functions = []
2077
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002078 def __repr__(self):
2079 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
2080
Larry Hastings8666e652014-01-12 14:12:59 -08002081unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002082
Larry Hastings8666e652014-01-12 14:12:59 -08002083__abs__
2084__add__
2085__and__
2086__bytes__
2087__call__
2088__complex__
2089__delitem__
2090__divmod__
2091__eq__
2092__float__
2093__floordiv__
2094__ge__
2095__getattr__
2096__getattribute__
2097__getitem__
2098__gt__
2099__hash__
2100__iadd__
2101__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002102__ifloordiv__
2103__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002104__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002105__imod__
2106__imul__
2107__index__
2108__int__
2109__invert__
2110__ior__
2111__ipow__
2112__irshift__
2113__isub__
2114__iter__
2115__itruediv__
2116__ixor__
2117__le__
2118__len__
2119__lshift__
2120__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002121__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002122__mod__
2123__mul__
2124__neg__
2125__new__
2126__next__
2127__or__
2128__pos__
2129__pow__
2130__radd__
2131__rand__
2132__rdivmod__
2133__repr__
2134__rfloordiv__
2135__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002136__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002137__rmod__
2138__rmul__
2139__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002140__rpow__
2141__rrshift__
2142__rshift__
2143__rsub__
2144__rtruediv__
2145__rxor__
2146__setattr__
2147__setitem__
2148__str__
2149__sub__
2150__truediv__
2151__xor__
2152
2153""".strip().split())
2154
2155
Larry Hastings5c661892014-01-24 06:17:25 -08002156INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2157INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2158""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002159
2160class Function:
2161 """
2162 Mutable duck type for inspect.Function.
2163
2164 docstring - a str containing
2165 * embedded line breaks
2166 * text outdented to the left margin
2167 * no trailing whitespace.
2168 It will always be true that
2169 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2170 """
2171
2172 def __init__(self, parameters=None, *, name,
2173 module, cls=None, c_basename=None,
2174 full_name=None,
Serhiy Storchaka279f4462019-09-14 12:24:05 +03002175 return_converter, return_annotation=inspect.Signature.empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002176 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002177 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002178 self.parameters = parameters or collections.OrderedDict()
2179 self.return_annotation = return_annotation
2180 self.name = name
2181 self.full_name = full_name
2182 self.module = module
2183 self.cls = cls
2184 self.parent = cls or module
2185 self.c_basename = c_basename
2186 self.return_converter = return_converter
2187 self.docstring = docstring or ''
2188 self.kind = kind
2189 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002190 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002191 # docstring_only means "don't generate a machine-readable
2192 # signature, just a normal docstring". it's True for
2193 # functions with optional groups because we can't represent
2194 # those accurately with inspect.Signature in 3.4.
2195 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002196
Larry Hastings7726ac92014-01-31 22:03:12 -08002197 self.rendered_parameters = None
2198
2199 __render_parameters__ = None
2200 @property
2201 def render_parameters(self):
2202 if not self.__render_parameters__:
2203 self.__render_parameters__ = l = []
2204 for p in self.parameters.values():
2205 p = p.copy()
2206 p.converter.pre_render()
2207 l.append(p)
2208 return self.__render_parameters__
2209
Larry Hastingsebdcb502013-11-23 14:54:00 -08002210 @property
2211 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002212 if self.kind in (METHOD_INIT, METHOD_NEW):
2213 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002214 flags = []
2215 if self.kind == CLASS_METHOD:
2216 flags.append('METH_CLASS')
2217 elif self.kind == STATIC_METHOD:
2218 flags.append('METH_STATIC')
2219 else:
2220 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2221 if self.coexist:
2222 flags.append('METH_COEXIST')
2223 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002224
2225 def __repr__(self):
2226 return '<clinic.Function ' + self.name + '>'
2227
Larry Hastings7726ac92014-01-31 22:03:12 -08002228 def copy(self, **overrides):
2229 kwargs = {
2230 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2231 'cls': self.cls, 'c_basename': self.c_basename,
2232 'full_name': self.full_name,
2233 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2234 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002235 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002236 }
2237 kwargs.update(overrides)
2238 f = Function(**kwargs)
2239
2240 parameters = collections.OrderedDict()
2241 for name, value in f.parameters.items():
2242 value = value.copy(function=f)
2243 parameters[name] = value
2244 f.parameters = parameters
2245 return f
2246
Larry Hastings31826802013-10-19 00:09:25 -07002247
2248class Parameter:
2249 """
2250 Mutable duck type of inspect.Parameter.
2251 """
2252
Serhiy Storchaka279f4462019-09-14 12:24:05 +03002253 def __init__(self, name, kind, *, default=inspect.Parameter.empty,
2254 function, converter, annotation=inspect.Parameter.empty,
Larry Hastings31826802013-10-19 00:09:25 -07002255 docstring=None, group=0):
2256 self.name = name
2257 self.kind = kind
2258 self.default = default
2259 self.function = function
2260 self.converter = converter
2261 self.annotation = annotation
2262 self.docstring = docstring or ''
2263 self.group = group
2264
2265 def __repr__(self):
2266 return '<clinic.Parameter ' + self.name + '>'
2267
2268 def is_keyword_only(self):
2269 return self.kind == inspect.Parameter.KEYWORD_ONLY
2270
Larry Hastings2623c8c2014-02-08 22:15:29 -08002271 def is_positional_only(self):
2272 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2273
Serhiy Storchaka31913912019-03-14 10:32:22 +02002274 def is_optional(self):
2275 return (self.default is not unspecified)
2276
Larry Hastings7726ac92014-01-31 22:03:12 -08002277 def copy(self, **overrides):
2278 kwargs = {
2279 'name': self.name, 'kind': self.kind, 'default':self.default,
2280 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2281 'docstring': self.docstring, 'group': self.group,
2282 }
2283 kwargs.update(overrides)
2284 if 'converter' not in overrides:
2285 converter = copy.copy(self.converter)
2286 converter.function = kwargs['function']
2287 kwargs['converter'] = converter
2288 return Parameter(**kwargs)
2289
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002290 def get_displayname(self, i):
2291 if i == 0:
2292 return '"argument"'
2293 if not self.is_positional_only():
2294 return '''"argument '{}'"'''.format(self.name)
2295 else:
2296 return '"argument {}"'.format(i)
Larry Hastings7726ac92014-01-31 22:03:12 -08002297
2298
2299class LandMine:
2300 # try to access any
2301 def __init__(self, message):
2302 self.__message__ = message
2303
2304 def __repr__(self):
2305 return '<LandMine ' + repr(self.__message__) + ">"
2306
2307 def __getattribute__(self, name):
2308 if name in ('__repr__', '__message__'):
2309 return super().__getattribute__(name)
2310 # raise RuntimeError(repr(name))
2311 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002312
Larry Hastings31826802013-10-19 00:09:25 -07002313
2314def add_c_converter(f, name=None):
2315 if not name:
2316 name = f.__name__
2317 if not name.endswith('_converter'):
2318 return f
2319 name = name[:-len('_converter')]
2320 converters[name] = f
2321 return f
2322
2323def add_default_legacy_c_converter(cls):
2324 # automatically add converter for default format unit
2325 # (but without stomping on the existing one if it's already
2326 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002327 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002328 (cls.format_unit not in legacy_converters)):
2329 legacy_converters[cls.format_unit] = cls
2330 return cls
2331
2332def add_legacy_c_converter(format_unit, **kwargs):
2333 """
2334 Adds a legacy converter.
2335 """
2336 def closure(f):
2337 if not kwargs:
2338 added_f = f
2339 else:
2340 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002341 if format_unit:
2342 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002343 return f
2344 return closure
2345
2346class CConverterAutoRegister(type):
2347 def __init__(cls, name, bases, classdict):
2348 add_c_converter(cls)
2349 add_default_legacy_c_converter(cls)
2350
2351class CConverter(metaclass=CConverterAutoRegister):
2352 """
2353 For the init function, self, name, function, and default
2354 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002355 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002356 """
2357
Larry Hastings7726ac92014-01-31 22:03:12 -08002358 # The C name to use for this variable.
2359 name = None
2360
2361 # The Python name to use for this variable.
2362 py_name = None
2363
Larry Hastings78cf85c2014-01-04 12:44:57 -08002364 # The C type to use for this variable.
2365 # 'type' should be a Python string specifying the type, e.g. "int".
2366 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002367 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002368
2369 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002370 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002371 # Or the magic value "unknown" if this value is a cannot be evaluated
2372 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2373 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002374 default = unspecified
2375
Larry Hastings4a55fc52014-01-12 11:09:57 -08002376 # If not None, default must be isinstance() of this type.
2377 # (You can also specify a tuple of types.)
2378 default_type = None
2379
Larry Hastings31826802013-10-19 00:09:25 -07002380 # "default" converted into a C value, as a string.
2381 # Or None if there is no default.
2382 c_default = None
2383
Larry Hastings2a727912014-01-16 11:32:01 -08002384 # "default" converted into a Python value, as a string.
2385 # Or None if there is no default.
2386 py_default = None
2387
Larry Hastingsabc716b2013-11-20 09:13:52 -08002388 # The default value used to initialize the C variable when
2389 # there is no default, but not specifying a default may
2390 # result in an "uninitialized variable" warning. This can
2391 # easily happen when using option groups--although
2392 # properly-written code won't actually use the variable,
2393 # the variable does get passed in to the _impl. (Ah, if
2394 # only dataflow analysis could inline the static function!)
2395 #
2396 # This value is specified as a string.
2397 # Every non-abstract subclass should supply a valid value.
2398 c_ignored_default = 'NULL'
2399
Larry Hastings31826802013-10-19 00:09:25 -07002400 # The C converter *function* to be used, if any.
2401 # (If this is not None, format_unit must be 'O&'.)
2402 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002403
Larry Hastings78cf85c2014-01-04 12:44:57 -08002404 # Should Argument Clinic add a '&' before the name of
2405 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002406 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002407
2408 # Should Argument Clinic add a '&' before the name of
2409 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002410 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002411
2412 #############################################################
2413 #############################################################
2414 ## You shouldn't need to read anything below this point to ##
2415 ## write your own converter functions. ##
2416 #############################################################
2417 #############################################################
2418
2419 # The "format unit" to specify for this variable when
2420 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2421 # Custom converters should always use the default value of 'O&'.
2422 format_unit = 'O&'
2423
2424 # What encoding do we want for this variable? Only used
2425 # by format units starting with 'e'.
2426 encoding = None
2427
Larry Hastings77561cc2014-01-07 12:13:13 -08002428 # Should this object be required to be a subclass of a specific type?
2429 # If not None, should be a string representing a pointer to a
2430 # PyTypeObject (e.g. "&PyUnicode_Type").
2431 # Only used by the 'O!' format unit (and the "object" converter).
2432 subclass_of = None
2433
Larry Hastings78cf85c2014-01-04 12:44:57 -08002434 # Do we want an adjacent '_length' variable for this variable?
2435 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002436 length = False
2437
Larry Hastings5c661892014-01-24 06:17:25 -08002438 # Should we show this parameter in the generated
2439 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002440 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002441 show_in_signature = True
2442
2443 # Overrides the name used in a text signature.
2444 # The name used for a "self" parameter must be one of
2445 # self, type, or module; however users can set their own.
2446 # This lets the self_converter overrule the user-settable
2447 # name, *just* for the text signature.
2448 # Only set by self_converter.
2449 signature_name = None
2450
2451 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002452 def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002453 self.name = ensure_legal_c_identifier(name)
Larry Hastings7726ac92014-01-31 22:03:12 -08002454 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002455
2456 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002457 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002458 if isinstance(self.default_type, type):
2459 types_str = self.default_type.__name__
2460 else:
2461 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2462 fail("{}: default value {!r} for field {} is not of type {}".format(
2463 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002464 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002465
Larry Hastingsb4705752014-01-18 21:54:15 -08002466 if c_default:
2467 self.c_default = c_default
2468 if py_default:
2469 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002470
Larry Hastings31826802013-10-19 00:09:25 -07002471 if annotation != unspecified:
2472 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002473
2474 # this is deliberate, to prevent you from caching information
2475 # about the function in the init.
2476 # (that breaks if we get cloned.)
2477 # so after this change we will noisily fail.
2478 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002479 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002480 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002481
2482 def converter_init(self):
2483 pass
2484
2485 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002486 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002487
Larry Hastings5c661892014-01-24 06:17:25 -08002488 def _render_self(self, parameter, data):
2489 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002490 name = self.name
Larry Hastings5c661892014-01-24 06:17:25 -08002491
2492 # impl_arguments
2493 s = ("&" if self.impl_by_reference else "") + name
2494 data.impl_arguments.append(s)
2495 if self.length:
2496 data.impl_arguments.append(self.length_name())
2497
2498 # impl_parameters
2499 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2500 if self.length:
2501 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2502
2503 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002504 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002505 name = self.name
Larry Hastings31826802013-10-19 00:09:25 -07002506
2507 # declarations
2508 d = self.declaration()
2509 data.declarations.append(d)
2510
2511 # initializers
2512 initializers = self.initialize()
2513 if initializers:
2514 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2515
Larry Hastingsc2047262014-01-25 20:43:29 -08002516 # modifications
2517 modifications = self.modify()
2518 if modifications:
2519 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2520
Larry Hastings31826802013-10-19 00:09:25 -07002521 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002522 if parameter.is_positional_only():
2523 data.keywords.append('')
2524 else:
2525 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002526
2527 # format_units
2528 if self.is_optional() and '|' not in data.format_units:
2529 data.format_units.append('|')
2530 if parameter.is_keyword_only() and '$' not in data.format_units:
2531 data.format_units.append('$')
2532 data.format_units.append(self.format_unit)
2533
2534 # parse_arguments
2535 self.parse_argument(data.parse_arguments)
2536
Larry Hastings31826802013-10-19 00:09:25 -07002537 # cleanup
2538 cleanup = self.cleanup()
2539 if cleanup:
2540 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2541
Larry Hastings5c661892014-01-24 06:17:25 -08002542 def render(self, parameter, data):
2543 """
2544 parameter is a clinic.Parameter instance.
2545 data is a CRenderData instance.
2546 """
2547 self._render_self(parameter, data)
2548 self._render_non_self(parameter, data)
2549
Larry Hastingsebdcb502013-11-23 14:54:00 -08002550 def length_name(self):
2551 """Computes the name of the associated "length" variable."""
2552 if not self.length:
2553 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002554 return self.name + "_length"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002555
Larry Hastings31826802013-10-19 00:09:25 -07002556 # Why is this one broken out separately?
2557 # For "positional-only" function parsing,
2558 # which generates a bunch of PyArg_ParseTuple calls.
2559 def parse_argument(self, list):
2560 assert not (self.converter and self.encoding)
2561 if self.format_unit == 'O&':
2562 assert self.converter
2563 list.append(self.converter)
2564
2565 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002566 list.append(c_repr(self.encoding))
2567 elif self.subclass_of:
2568 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002569
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002570 s = ("&" if self.parse_by_reference else "") + self.name
Larry Hastings31826802013-10-19 00:09:25 -07002571 list.append(s)
2572
Larry Hastingsebdcb502013-11-23 14:54:00 -08002573 if self.length:
2574 list.append("&" + self.length_name())
2575
Larry Hastings31826802013-10-19 00:09:25 -07002576 #
2577 # All the functions after here are intended as extension points.
2578 #
2579
2580 def simple_declaration(self, by_reference=False):
2581 """
2582 Computes the basic declaration of the variable.
2583 Used in computing the prototype declaration and the
2584 variable declaration.
2585 """
2586 prototype = [self.type]
2587 if by_reference or not self.type.endswith('*'):
2588 prototype.append(" ")
2589 if by_reference:
2590 prototype.append('*')
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002591 prototype.append(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07002592 return "".join(prototype)
2593
2594 def declaration(self):
2595 """
2596 The C statement to declare this variable.
2597 """
2598 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002599 default = self.c_default
2600 if not default and self.parameter.group:
2601 default = self.c_ignored_default
2602 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002603 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002604 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002605 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002606 if self.length:
2607 declaration.append('\nPy_ssize_clean_t ')
2608 declaration.append(self.length_name())
2609 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002610 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002611
2612 def initialize(self):
2613 """
2614 The C statements required to set up this variable before parsing.
2615 Returns a string containing this code indented at column 0.
2616 If no initialization is necessary, returns an empty string.
2617 """
2618 return ""
2619
Larry Hastingsc2047262014-01-25 20:43:29 -08002620 def modify(self):
2621 """
2622 The C statements required to modify this variable after parsing.
2623 Returns a string containing this code indented at column 0.
2624 If no initialization is necessary, returns an empty string.
2625 """
2626 return ""
2627
Larry Hastings31826802013-10-19 00:09:25 -07002628 def cleanup(self):
2629 """
2630 The C statements required to clean up after this variable.
2631 Returns a string containing this code indented at column 0.
2632 If no cleanup is necessary, returns an empty string.
2633 """
2634 return ""
2635
Larry Hastings7726ac92014-01-31 22:03:12 -08002636 def pre_render(self):
2637 """
2638 A second initialization function, like converter_init,
2639 called just before rendering.
2640 You are permitted to examine self.function here.
2641 """
2642 pass
2643
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002644 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002645 if self.format_unit == 'O&':
2646 return """
2647 if (!{converter}({argname}, &{paramname})) {{{{
2648 goto exit;
2649 }}}}
2650 """.format(argname=argname, paramname=self.name,
2651 converter=self.converter)
2652 if self.format_unit == 'O!':
2653 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2654 if self.subclass_of in type_checks:
2655 typecheck, typename = type_checks[self.subclass_of]
2656 return """
2657 if (!{typecheck}({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002658 _PyArg_BadArgument("{{name}}", {displayname}, "{typename}", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002659 goto exit;
2660 }}}}
2661 {paramname} = {cast}{argname};
2662 """.format(argname=argname, paramname=self.name,
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002663 displayname=displayname, typecheck=typecheck,
2664 typename=typename, cast=cast)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002665 return """
2666 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002667 _PyArg_BadArgument("{{name}}", {displayname}, ({subclass_of})->tp_name, {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002668 goto exit;
2669 }}}}
2670 {paramname} = {cast}{argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002671 """.format(argname=argname, paramname=self.name,
2672 subclass_of=self.subclass_of, cast=cast,
2673 displayname=displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002674 if self.format_unit == 'O':
2675 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2676 return """
2677 {paramname} = {cast}{argname};
2678 """.format(argname=argname, paramname=self.name, cast=cast)
2679 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002680
2681type_checks = {
2682 '&PyLong_Type': ('PyLong_Check', 'int'),
2683 '&PyTuple_Type': ('PyTuple_Check', 'tuple'),
2684 '&PyList_Type': ('PyList_Check', 'list'),
2685 '&PySet_Type': ('PySet_Check', 'set'),
2686 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'),
2687 '&PyDict_Type': ('PyDict_Check', 'dict'),
2688 '&PyUnicode_Type': ('PyUnicode_Check', 'str'),
2689 '&PyBytes_Type': ('PyBytes_Check', 'bytes'),
2690 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'),
2691}
2692
Larry Hastings31826802013-10-19 00:09:25 -07002693
2694class bool_converter(CConverter):
2695 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002696 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002697 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002698 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002699
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002700 def converter_init(self, *, accept={object}):
2701 if accept == {int}:
2702 self.format_unit = 'i'
2703 elif accept != {object}:
2704 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002705 if self.default is not unspecified:
2706 self.default = bool(self.default)
2707 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002708
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002709 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002710 if self.format_unit == 'i':
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +02002711 # XXX PyFloat_Check can be removed after the end of the
2712 # deprecation in _PyLong_FromNbIndexOrNbInt.
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002713 return """
2714 if (PyFloat_Check({argname})) {{{{
2715 PyErr_SetString(PyExc_TypeError,
2716 "integer argument expected, got float" );
2717 goto exit;
2718 }}}}
2719 {paramname} = _PyLong_AsInt({argname});
2720 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2721 goto exit;
2722 }}}}
2723 """.format(argname=argname, paramname=self.name)
2724 elif self.format_unit == 'p':
2725 return """
2726 {paramname} = PyObject_IsTrue({argname});
2727 if ({paramname} < 0) {{{{
2728 goto exit;
2729 }}}}
2730 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002731 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002732
Larry Hastings31826802013-10-19 00:09:25 -07002733class char_converter(CConverter):
2734 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002735 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002736 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002737 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002738
Larry Hastings4a55fc52014-01-12 11:09:57 -08002739 def converter_init(self):
Tal Einatc929df32018-07-06 13:17:38 +03002740 if isinstance(self.default, self.default_type):
2741 if len(self.default) != 1:
2742 fail("char_converter: illegal default value " + repr(self.default))
2743
Serhiy Storchaka65ce60a2018-12-25 11:10:05 +02002744 self.c_default = repr(bytes(self.default))[1:]
2745 if self.c_default == '"\'"':
2746 self.c_default = r"'\''"
Larry Hastings4a55fc52014-01-12 11:09:57 -08002747
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002748 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002749 if self.format_unit == 'c':
2750 return """
2751 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
2752 {paramname} = PyBytes_AS_STRING({argname})[0];
2753 }}}}
2754 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{
2755 {paramname} = PyByteArray_AS_STRING({argname})[0];
2756 }}}}
2757 else {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002758 _PyArg_BadArgument("{{name}}", {displayname}, "a byte string of length 1", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002759 goto exit;
2760 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002761 """.format(argname=argname, paramname=self.name,
2762 displayname=displayname)
2763 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002764
Larry Hastings4a55fc52014-01-12 11:09:57 -08002765
Larry Hastings31826802013-10-19 00:09:25 -07002766@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002767class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002768 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002769 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002770 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002771 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002772
2773 def converter_init(self, *, bitwise=False):
2774 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002775 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002776
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002777 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002778 if self.format_unit == 'b':
2779 return """
2780 if (PyFloat_Check({argname})) {{{{
2781 PyErr_SetString(PyExc_TypeError,
2782 "integer argument expected, got float" );
2783 goto exit;
2784 }}}}
2785 {{{{
2786 long ival = PyLong_AsLong({argname});
2787 if (ival == -1 && PyErr_Occurred()) {{{{
2788 goto exit;
2789 }}}}
2790 else if (ival < 0) {{{{
2791 PyErr_SetString(PyExc_OverflowError,
2792 "unsigned byte integer is less than minimum");
2793 goto exit;
2794 }}}}
2795 else if (ival > UCHAR_MAX) {{{{
2796 PyErr_SetString(PyExc_OverflowError,
2797 "unsigned byte integer is greater than maximum");
2798 goto exit;
2799 }}}}
2800 else {{{{
2801 {paramname} = (unsigned char) ival;
2802 }}}}
2803 }}}}
2804 """.format(argname=argname, paramname=self.name)
2805 elif self.format_unit == 'B':
2806 return """
2807 if (PyFloat_Check({argname})) {{{{
2808 PyErr_SetString(PyExc_TypeError,
2809 "integer argument expected, got float" );
2810 goto exit;
2811 }}}}
2812 {{{{
2813 long ival = PyLong_AsUnsignedLongMask({argname});
2814 if (ival == -1 && PyErr_Occurred()) {{{{
2815 goto exit;
2816 }}}}
2817 else {{{{
2818 {paramname} = (unsigned char) ival;
2819 }}}}
2820 }}}}
2821 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002822 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002823
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002824class byte_converter(unsigned_char_converter): pass
2825
Larry Hastings31826802013-10-19 00:09:25 -07002826class short_converter(CConverter):
2827 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002828 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002829 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002830 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002831
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002832 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002833 if self.format_unit == 'h':
2834 return """
2835 if (PyFloat_Check({argname})) {{{{
2836 PyErr_SetString(PyExc_TypeError,
2837 "integer argument expected, got float" );
2838 goto exit;
2839 }}}}
2840 {{{{
2841 long ival = PyLong_AsLong({argname});
2842 if (ival == -1 && PyErr_Occurred()) {{{{
2843 goto exit;
2844 }}}}
2845 else if (ival < SHRT_MIN) {{{{
2846 PyErr_SetString(PyExc_OverflowError,
2847 "signed short integer is less than minimum");
2848 goto exit;
2849 }}}}
2850 else if (ival > SHRT_MAX) {{{{
2851 PyErr_SetString(PyExc_OverflowError,
2852 "signed short integer is greater than maximum");
2853 goto exit;
2854 }}}}
2855 else {{{{
2856 {paramname} = (short) ival;
2857 }}}}
2858 }}}}
2859 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002860 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002861
Larry Hastings31826802013-10-19 00:09:25 -07002862class unsigned_short_converter(CConverter):
2863 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002864 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002865 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002866
2867 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002868 if bitwise:
2869 self.format_unit = 'H'
2870 else:
2871 self.converter = '_PyLong_UnsignedShort_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002872
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002873 def parse_arg(self, argname, displayname):
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002874 if self.format_unit == 'H':
2875 return """
2876 if (PyFloat_Check({argname})) {{{{
2877 PyErr_SetString(PyExc_TypeError,
2878 "integer argument expected, got float" );
2879 goto exit;
2880 }}}}
2881 {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname});
2882 if ({paramname} == (unsigned short)-1 && PyErr_Occurred()) {{{{
2883 goto exit;
2884 }}}}
2885 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002886 return super().parse_arg(argname, displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002887
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002888@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002889class int_converter(CConverter):
2890 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002891 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002892 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002893 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002894
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002895 def converter_init(self, *, accept={int}, type=None):
2896 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002897 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002898 elif accept != {int}:
2899 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002900 if type != None:
2901 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002902
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002903 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002904 if self.format_unit == 'i':
2905 return """
2906 if (PyFloat_Check({argname})) {{{{
2907 PyErr_SetString(PyExc_TypeError,
2908 "integer argument expected, got float" );
2909 goto exit;
2910 }}}}
2911 {paramname} = _PyLong_AsInt({argname});
2912 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2913 goto exit;
2914 }}}}
2915 """.format(argname=argname, paramname=self.name)
2916 elif self.format_unit == 'C':
2917 return """
2918 if (!PyUnicode_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002919 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002920 goto exit;
2921 }}}}
2922 if (PyUnicode_READY({argname})) {{{{
2923 goto exit;
2924 }}}}
2925 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002926 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002927 goto exit;
2928 }}}}
2929 {paramname} = PyUnicode_READ_CHAR({argname}, 0);
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002930 """.format(argname=argname, paramname=self.name,
2931 displayname=displayname)
2932 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002933
Larry Hastings31826802013-10-19 00:09:25 -07002934class unsigned_int_converter(CConverter):
2935 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002936 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002937 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002938
2939 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002940 if bitwise:
2941 self.format_unit = 'I'
2942 else:
2943 self.converter = '_PyLong_UnsignedInt_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002944
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002945 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002946 if self.format_unit == 'I':
2947 return """
2948 if (PyFloat_Check({argname})) {{{{
2949 PyErr_SetString(PyExc_TypeError,
2950 "integer argument expected, got float" );
2951 goto exit;
2952 }}}}
2953 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
2954 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{
2955 goto exit;
2956 }}}}
2957 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002958 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002959
Larry Hastings31826802013-10-19 00:09:25 -07002960class long_converter(CConverter):
2961 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002962 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002963 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002964 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002965
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002966 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002967 if self.format_unit == 'l':
2968 return """
2969 if (PyFloat_Check({argname})) {{{{
2970 PyErr_SetString(PyExc_TypeError,
2971 "integer argument expected, got float" );
2972 goto exit;
2973 }}}}
2974 {paramname} = PyLong_AsLong({argname});
2975 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2976 goto exit;
2977 }}}}
2978 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002979 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002980
Larry Hastings31826802013-10-19 00:09:25 -07002981class unsigned_long_converter(CConverter):
2982 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002983 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002984 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002985
2986 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002987 if bitwise:
2988 self.format_unit = 'k'
2989 else:
2990 self.converter = '_PyLong_UnsignedLong_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002991
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002992 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002993 if self.format_unit == 'k':
2994 return """
2995 if (!PyLong_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002996 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002997 goto exit;
2998 }}}}
2999 {paramname} = PyLong_AsUnsignedLongMask({argname});
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003000 """.format(argname=argname, paramname=self.name,
3001 displayname=displayname)
3002 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003003
Benjamin Petersoncc854492016-09-08 09:29:11 -07003004class long_long_converter(CConverter):
3005 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003006 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07003007 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003008 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003009
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003010 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003011 if self.format_unit == 'L':
3012 return """
3013 if (PyFloat_Check({argname})) {{{{
3014 PyErr_SetString(PyExc_TypeError,
3015 "integer argument expected, got float" );
3016 goto exit;
3017 }}}}
3018 {paramname} = PyLong_AsLongLong({argname});
Sergey Fedoseeva9ed91e2019-10-21 11:49:48 +05003019 if ({paramname} == -1 && PyErr_Occurred()) {{{{
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003020 goto exit;
3021 }}}}
3022 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003023 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003024
Benjamin Petersoncc854492016-09-08 09:29:11 -07003025class unsigned_long_long_converter(CConverter):
3026 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003027 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08003028 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003029
3030 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03003031 if bitwise:
3032 self.format_unit = 'K'
3033 else:
3034 self.converter = '_PyLong_UnsignedLongLong_Converter'
Serhiy Storchaka762bf402017-03-30 09:15:31 +03003035
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003036 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003037 if self.format_unit == 'K':
3038 return """
3039 if (!PyLong_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003040 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003041 goto exit;
3042 }}}}
3043 {paramname} = PyLong_AsUnsignedLongLongMask({argname});
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003044 """.format(argname=argname, paramname=self.name,
3045 displayname=displayname)
3046 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003047
Larry Hastings31826802013-10-19 00:09:25 -07003048class Py_ssize_t_converter(CConverter):
3049 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003050 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003051
Serhiy Storchaka762bf402017-03-30 09:15:31 +03003052 def converter_init(self, *, accept={int}):
3053 if accept == {int}:
3054 self.format_unit = 'n'
3055 self.default_type = int
3056 elif accept == {int, NoneType}:
3057 self.converter = '_Py_convert_optional_to_ssize_t'
3058 else:
3059 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
3060
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003061 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003062 if self.format_unit == 'n':
3063 return """
3064 if (PyFloat_Check({argname})) {{{{
3065 PyErr_SetString(PyExc_TypeError,
3066 "integer argument expected, got float" );
3067 goto exit;
3068 }}}}
3069 {{{{
3070 Py_ssize_t ival = -1;
3071 PyObject *iobj = PyNumber_Index({argname});
3072 if (iobj != NULL) {{{{
3073 ival = PyLong_AsSsize_t(iobj);
3074 Py_DECREF(iobj);
3075 }}}}
3076 if (ival == -1 && PyErr_Occurred()) {{{{
3077 goto exit;
3078 }}}}
3079 {paramname} = ival;
3080 }}}}
3081 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003082 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003083
Larry Hastings31826802013-10-19 00:09:25 -07003084
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003085class slice_index_converter(CConverter):
3086 type = 'Py_ssize_t'
3087
3088 def converter_init(self, *, accept={int, NoneType}):
3089 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03003090 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003091 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03003092 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003093 else:
3094 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
3095
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03003096class size_t_converter(CConverter):
3097 type = 'size_t'
3098 converter = '_PyLong_Size_t_Converter'
3099 c_ignored_default = "0"
3100
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003101 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003102 if self.format_unit == 'n':
3103 return """
3104 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
3105 if ({paramname} == -1 && PyErr_Occurred()) {{{{
3106 goto exit;
3107 }}}}
3108 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003109 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003110
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003111
Larry Hastings31826802013-10-19 00:09:25 -07003112class float_converter(CConverter):
3113 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003114 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003115 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003116 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003117
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003118 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003119 if self.format_unit == 'f':
3120 return """
Raymond Hettingeraef9ad82019-08-24 19:10:39 -07003121 if (PyFloat_CheckExact({argname})) {{{{
3122 {paramname} = (float) (PyFloat_AS_DOUBLE({argname}));
3123 }}}}
3124 else
3125 {{{{
3126 {paramname} = (float) PyFloat_AsDouble({argname});
3127 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{
3128 goto exit;
3129 }}}}
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003130 }}}}
3131 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003132 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003133
Larry Hastings31826802013-10-19 00:09:25 -07003134class double_converter(CConverter):
3135 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003136 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003137 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003138 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003139
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003140 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003141 if self.format_unit == 'd':
3142 return """
Raymond Hettingeraef9ad82019-08-24 19:10:39 -07003143 if (PyFloat_CheckExact({argname})) {{{{
3144 {paramname} = PyFloat_AS_DOUBLE({argname});
3145 }}}}
3146 else
3147 {{{{
3148 {paramname} = PyFloat_AsDouble({argname});
3149 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{
3150 goto exit;
3151 }}}}
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003152 }}}}
3153 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003154 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003155
Larry Hastings31826802013-10-19 00:09:25 -07003156
3157class Py_complex_converter(CConverter):
3158 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003159 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07003160 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003161 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07003162
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003163 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003164 if self.format_unit == 'D':
3165 return """
3166 {paramname} = PyComplex_AsCComplex({argname});
3167 if (PyErr_Occurred()) {{{{
3168 goto exit;
3169 }}}}
3170 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003171 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003172
Larry Hastings31826802013-10-19 00:09:25 -07003173
3174class object_converter(CConverter):
3175 type = 'PyObject *'
3176 format_unit = 'O'
3177
Larry Hastings4a55fc52014-01-12 11:09:57 -08003178 def converter_init(self, *, converter=None, type=None, subclass_of=None):
3179 if converter:
3180 if subclass_of:
3181 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
3182 self.format_unit = 'O&'
3183 self.converter = converter
3184 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07003185 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08003186 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08003187
Larry Hastings77561cc2014-01-07 12:13:13 -08003188 if type is not None:
3189 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07003190
3191
Larry Hastings7f90cba2015-04-15 23:02:12 -04003192#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003193# We define three conventions for buffer types in the 'accept' argument:
3194#
3195# buffer : any object supporting the buffer interface
3196# rwbuffer: any object supporting the buffer interface, but must be writeable
3197# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04003198#
3199
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003200class buffer: pass
3201class rwbuffer: pass
3202class robuffer: pass
3203
Larry Hastings38337d12015-05-07 23:30:09 -07003204def str_converter_key(types, encoding, zeroes):
3205 return (frozenset(types), bool(encoding), bool(zeroes))
3206
3207str_converter_argument_map = {}
3208
Larry Hastings31826802013-10-19 00:09:25 -07003209class str_converter(CConverter):
3210 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003211 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003212 format_unit = 's'
3213
Larry Hastings38337d12015-05-07 23:30:09 -07003214 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003215
Larry Hastings38337d12015-05-07 23:30:09 -07003216 key = str_converter_key(accept, encoding, zeroes)
3217 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003218 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07003219 fail("str_converter: illegal combination of arguments", key)
3220
Larry Hastingsebdcb502013-11-23 14:54:00 -08003221 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07003222 self.length = bool(zeroes)
3223 if encoding:
3224 if self.default not in (Null, None, unspecified):
3225 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
3226 self.encoding = encoding
3227 self.type = 'char *'
3228 # sorry, clinic can't support preallocated buffers
3229 # for es# and et#
3230 self.c_default = "NULL"
Serhiy Storchaka279f4462019-09-14 12:24:05 +03003231 if NoneType in accept and self.c_default == "Py_None":
3232 self.c_default = "NULL"
Larry Hastings38337d12015-05-07 23:30:09 -07003233
3234 def cleanup(self):
3235 if self.encoding:
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003236 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003237 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07003238
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003239 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003240 if self.format_unit == 's':
3241 return """
3242 if (!PyUnicode_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003243 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003244 goto exit;
3245 }}}}
3246 Py_ssize_t {paramname}_length;
3247 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3248 if ({paramname} == NULL) {{{{
3249 goto exit;
3250 }}}}
3251 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3252 PyErr_SetString(PyExc_ValueError, "embedded null character");
3253 goto exit;
3254 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003255 """.format(argname=argname, paramname=self.name,
3256 displayname=displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003257 if self.format_unit == 'z':
3258 return """
3259 if ({argname} == Py_None) {{{{
3260 {paramname} = NULL;
3261 }}}}
3262 else if (PyUnicode_Check({argname})) {{{{
3263 Py_ssize_t {paramname}_length;
3264 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3265 if ({paramname} == NULL) {{{{
3266 goto exit;
3267 }}}}
3268 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3269 PyErr_SetString(PyExc_ValueError, "embedded null character");
3270 goto exit;
3271 }}}}
3272 }}}}
3273 else {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003274 _PyArg_BadArgument("{{name}}", {displayname}, "str or None", {argname});
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003275 goto exit;
3276 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003277 """.format(argname=argname, paramname=self.name,
3278 displayname=displayname)
3279 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003280
Larry Hastings38337d12015-05-07 23:30:09 -07003281#
3282# This is the fourth or fifth rewrite of registering all the
Raymond Hettinger14010182018-09-13 21:17:40 -07003283# string converter format units. Previous approaches hid
Larry Hastings38337d12015-05-07 23:30:09 -07003284# bugs--generally mismatches between the semantics of the format
3285# unit and the arguments necessary to represent those semantics
3286# properly. Hopefully with this approach we'll get it 100% right.
3287#
3288# The r() function (short for "register") both registers the
3289# mapping from arguments to format unit *and* registers the
3290# legacy C converter for that format unit.
3291#
3292def r(format_unit, *, accept, encoding=False, zeroes=False):
3293 if not encoding and format_unit != 's':
3294 # add the legacy c converters here too.
3295 #
3296 # note: add_legacy_c_converter can't work for
3297 # es, es#, et, or et#
3298 # because of their extra encoding argument
3299 #
3300 # also don't add the converter for 's' because
3301 # the metaclass for CConverter adds it for us.
3302 kwargs = {}
3303 if accept != {str}:
3304 kwargs['accept'] = accept
3305 if zeroes:
3306 kwargs['zeroes'] = True
3307 added_f = functools.partial(str_converter, **kwargs)
3308 legacy_converters[format_unit] = added_f
3309
3310 d = str_converter_argument_map
3311 key = str_converter_key(accept, encoding, zeroes)
3312 if key in d:
3313 sys.exit("Duplicate keys specified for str_converter_argument_map!")
3314 d[key] = format_unit
3315
3316r('es', encoding=True, accept={str})
3317r('es#', encoding=True, zeroes=True, accept={str})
3318r('et', encoding=True, accept={bytes, bytearray, str})
3319r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
3320r('s', accept={str})
3321r('s#', zeroes=True, accept={robuffer, str})
3322r('y', accept={robuffer})
3323r('y#', zeroes=True, accept={robuffer})
3324r('z', accept={str, NoneType})
3325r('z#', zeroes=True, accept={robuffer, str, NoneType})
3326del r
Larry Hastings31826802013-10-19 00:09:25 -07003327
3328
3329class PyBytesObject_converter(CConverter):
3330 type = 'PyBytesObject *'
3331 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003332 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07003333
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003334 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003335 if self.format_unit == 'S':
3336 return """
3337 if (!PyBytes_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003338 _PyArg_BadArgument("{{name}}", {displayname}, "bytes", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003339 goto exit;
3340 }}}}
3341 {paramname} = ({type}){argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003342 """.format(argname=argname, paramname=self.name,
3343 type=self.type, displayname=displayname)
3344 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003345
Larry Hastings31826802013-10-19 00:09:25 -07003346class PyByteArrayObject_converter(CConverter):
3347 type = 'PyByteArrayObject *'
3348 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003349 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07003350
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003351 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003352 if self.format_unit == 'Y':
3353 return """
3354 if (!PyByteArray_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003355 _PyArg_BadArgument("{{name}}", {displayname}, "bytearray", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003356 goto exit;
3357 }}}}
3358 {paramname} = ({type}){argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003359 """.format(argname=argname, paramname=self.name,
3360 type=self.type, displayname=displayname)
3361 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003362
Larry Hastings31826802013-10-19 00:09:25 -07003363class unicode_converter(CConverter):
3364 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003365 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003366 format_unit = 'U'
3367
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003368 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003369 if self.format_unit == 'U':
3370 return """
3371 if (!PyUnicode_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003372 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003373 goto exit;
3374 }}}}
3375 if (PyUnicode_READY({argname}) == -1) {{{{
3376 goto exit;
3377 }}}}
3378 {paramname} = {argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003379 """.format(argname=argname, paramname=self.name,
3380 displayname=displayname)
3381 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003382
Larry Hastings38337d12015-05-07 23:30:09 -07003383@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003384@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07003385@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07003386class Py_UNICODE_converter(CConverter):
Serhiy Storchakaafb3e712018-12-14 11:19:51 +02003387 type = 'const Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003388 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003389 format_unit = 'u'
3390
Larry Hastings38337d12015-05-07 23:30:09 -07003391 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003392 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07003393 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003394 format_unit += '#'
3395 self.length = True
3396 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003397
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003398@add_legacy_c_converter('s*', accept={str, buffer})
3399@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
3400@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07003401class Py_buffer_converter(CConverter):
3402 type = 'Py_buffer'
3403 format_unit = 'y*'
3404 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08003405 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07003406
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003407 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08003408 if self.default not in (unspecified, None):
3409 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003410
Larry Hastings3f144c22014-01-06 10:34:00 -08003411 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08003412
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003413 if accept == {str, buffer, NoneType}:
3414 format_unit = 'z*'
3415 elif accept == {str, buffer}:
3416 format_unit = 's*'
3417 elif accept == {buffer}:
3418 format_unit = 'y*'
3419 elif accept == {rwbuffer}:
3420 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07003421 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003422 fail("Py_buffer_converter: illegal combination of arguments")
3423
3424 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003425
3426 def cleanup(self):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003427 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003428 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08003429
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003430 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003431 if self.format_unit == 'y*':
3432 return """
3433 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3434 goto exit;
3435 }}}}
3436 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003437 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003438 goto exit;
3439 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003440 """.format(argname=argname, paramname=self.name,
3441 displayname=displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003442 elif self.format_unit == 's*':
3443 return """
3444 if (PyUnicode_Check({argname})) {{{{
3445 Py_ssize_t len;
3446 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
3447 if (ptr == NULL) {{{{
3448 goto exit;
3449 }}}}
3450 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
3451 }}}}
3452 else {{{{ /* any bytes-like object */
3453 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3454 goto exit;
3455 }}}}
3456 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003457 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003458 goto exit;
3459 }}}}
3460 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003461 """.format(argname=argname, paramname=self.name,
3462 displayname=displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003463 elif self.format_unit == 'w*':
3464 return """
3465 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
3466 PyErr_Clear();
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003467 _PyArg_BadArgument("{{name}}", {displayname}, "read-write bytes-like object", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003468 goto exit;
3469 }}}}
3470 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003471 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003472 goto exit;
3473 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003474 """.format(argname=argname, paramname=self.name,
3475 displayname=displayname)
3476 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003477
Larry Hastingsebdcb502013-11-23 14:54:00 -08003478
Larry Hastings5c661892014-01-24 06:17:25 -08003479def correct_name_for_self(f):
3480 if f.kind in (CALLABLE, METHOD_INIT):
3481 if f.cls:
3482 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03003483 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08003484 if f.kind == STATIC_METHOD:
3485 return "void *", "null"
3486 if f.kind in (CLASS_METHOD, METHOD_NEW):
3487 return "PyTypeObject *", "type"
3488 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
3489
Larry Hastingsc2047262014-01-25 20:43:29 -08003490def required_type_for_self_for_parser(f):
3491 type, _ = correct_name_for_self(f)
3492 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
3493 return type
3494 return None
3495
Larry Hastings5c661892014-01-24 06:17:25 -08003496
Larry Hastingsebdcb502013-11-23 14:54:00 -08003497class self_converter(CConverter):
3498 """
3499 A special-case converter:
3500 this is the default converter used for "self".
3501 """
Larry Hastings5c661892014-01-24 06:17:25 -08003502 type = None
3503 format_unit = ''
3504
Larry Hastings78cf85c2014-01-04 12:44:57 -08003505 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08003506 self.specified_type = type
3507
3508 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003509 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08003510 default_type, default_name = correct_name_for_self(f)
3511 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08003512 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08003513
Larry Hastings5c661892014-01-24 06:17:25 -08003514 kind = self.function.kind
3515 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
3516
3517 if (kind == STATIC_METHOD) or new_or_init:
3518 self.show_in_signature = False
3519
3520 # tp_new (METHOD_NEW) functions are of type newfunc:
3521 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
3522 # PyTypeObject is a typedef for struct _typeobject.
3523 #
3524 # tp_init (METHOD_INIT) functions are of type initproc:
3525 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
3526 #
3527 # All other functions generated by Argument Clinic are stored in
3528 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
3529 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
3530 # However! We habitually cast these functions to PyCFunction,
3531 # since functions that accept keyword arguments don't fit this signature
3532 # but are stored there anyway. So strict type equality isn't important
3533 # for these functions.
3534 #
3535 # So:
3536 #
3537 # * The name of the first parameter to the impl and the parsing function will always
3538 # be self.name.
3539 #
3540 # * The type of the first parameter to the impl will always be of self.type.
3541 #
3542 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
3543 # * The type of the first parameter to the parsing function is also self.type.
3544 # This means that if you step into the parsing function, your "self" parameter
3545 # is of the correct type, which may make debugging more pleasant.
3546 #
3547 # * Else if the function is tp_new (METHOD_NEW):
3548 # * The type of the first parameter to the parsing function is "PyTypeObject *",
3549 # so the type signature of the function call is an exact match.
3550 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
3551 # in the impl call.
3552 #
3553 # * Else if the function is tp_init (METHOD_INIT):
3554 # * The type of the first parameter to the parsing function is "PyObject *",
3555 # so the type signature of the function call is an exact match.
3556 # * If self.type != "PyObject *", we cast the first parameter to self.type
3557 # in the impl call.
3558
3559 @property
3560 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08003561 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08003562
Larry Hastingsebdcb502013-11-23 14:54:00 -08003563 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08003564 """
3565 parameter is a clinic.Parameter instance.
3566 data is a CRenderData instance.
3567 """
3568 if self.function.kind == STATIC_METHOD:
3569 return
3570
3571 self._render_self(parameter, data)
3572
3573 if self.type != self.parser_type:
3574 # insert cast to impl_argument[0], aka self.
3575 # we know we're in the first slot in all the CRenderData lists,
3576 # because we render parameters in order, and self is always first.
3577 assert len(data.impl_arguments) == 1
3578 assert data.impl_arguments[0] == self.name
3579 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3580
3581 def set_template_dict(self, template_dict):
3582 template_dict['self_name'] = self.name
3583 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003584 kind = self.function.kind
3585 cls = self.function.cls
3586
3587 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3588 if kind == METHOD_NEW:
3589 passed_in_type = self.name
3590 else:
3591 passed_in_type = 'Py_TYPE({})'.format(self.name)
3592
3593 line = '({passed_in_type} == {type_object}) &&\n '
3594 d = {
3595 'type_object': self.function.cls.type_object,
3596 'passed_in_type': passed_in_type
3597 }
3598 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003599
Larry Hastings31826802013-10-19 00:09:25 -07003600
3601
3602def add_c_return_converter(f, name=None):
3603 if not name:
3604 name = f.__name__
3605 if not name.endswith('_return_converter'):
3606 return f
3607 name = name[:-len('_return_converter')]
3608 return_converters[name] = f
3609 return f
3610
3611
3612class CReturnConverterAutoRegister(type):
3613 def __init__(cls, name, bases, classdict):
3614 add_c_return_converter(cls)
3615
3616class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3617
Larry Hastings78cf85c2014-01-04 12:44:57 -08003618 # The C type to use for this variable.
3619 # 'type' should be a Python string specifying the type, e.g. "int".
3620 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003621 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003622
3623 # The Python default value for this parameter, as a Python value.
3624 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003625 default = None
3626
Larry Hastings2a727912014-01-16 11:32:01 -08003627 def __init__(self, *, py_default=None, **kwargs):
3628 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003629 try:
3630 self.return_converter_init(**kwargs)
3631 except TypeError as e:
3632 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3633 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3634
3635 def return_converter_init(self):
3636 pass
3637
3638 def declare(self, data, name="_return_value"):
3639 line = []
3640 add = line.append
3641 add(self.type)
3642 if not self.type.endswith('*'):
3643 add(' ')
3644 add(name + ';')
3645 data.declarations.append(''.join(line))
3646 data.return_value = name
3647
3648 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003649 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003650
3651 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003652 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003653
3654 def render(self, function, data):
3655 """
3656 function is a clinic.Function instance.
3657 data is a CRenderData instance.
3658 """
3659 pass
3660
3661add_c_return_converter(CReturnConverter, 'object')
3662
Larry Hastings78cf85c2014-01-04 12:44:57 -08003663class NoneType_return_converter(CReturnConverter):
3664 def render(self, function, data):
3665 self.declare(data)
3666 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003667if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003668 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003669}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003670return_value = Py_None;
3671Py_INCREF(Py_None);
3672'''.strip())
3673
Larry Hastings4a55fc52014-01-12 11:09:57 -08003674class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003675 type = 'int'
3676
3677 def render(self, function, data):
3678 self.declare(data)
3679 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003680 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003681
3682class long_return_converter(CReturnConverter):
3683 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003684 conversion_fn = 'PyLong_FromLong'
3685 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003686 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003687
3688 def render(self, function, data):
3689 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003690 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003691 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003692 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003693
Larry Hastings4a55fc52014-01-12 11:09:57 -08003694class int_return_converter(long_return_converter):
3695 type = 'int'
3696 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003697
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003698class init_return_converter(long_return_converter):
3699 """
3700 Special return converter for __init__ functions.
3701 """
3702 type = 'int'
3703 cast = '(long)'
3704
3705 def render(self, function, data):
3706 pass
3707
Larry Hastings4a55fc52014-01-12 11:09:57 -08003708class unsigned_long_return_converter(long_return_converter):
3709 type = 'unsigned long'
3710 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003711 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003712
3713class unsigned_int_return_converter(unsigned_long_return_converter):
3714 type = 'unsigned int'
3715 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003716 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003717
3718class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003719 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003720 conversion_fn = 'PyLong_FromSsize_t'
3721
3722class size_t_return_converter(long_return_converter):
3723 type = 'size_t'
3724 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003725 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003726
3727
3728class double_return_converter(CReturnConverter):
3729 type = 'double'
3730 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003731
3732 def render(self, function, data):
3733 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003734 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003735 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003736 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3737
3738class float_return_converter(double_return_converter):
3739 type = 'float'
3740 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003741
3742
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003743def eval_ast_expr(node, globals, *, filename='-'):
3744 """
3745 Takes an ast.Expr node. Compiles and evaluates it.
3746 Returns the result of the expression.
3747
3748 globals represents the globals dict the expression
3749 should see. (There's no equivalent for "locals" here.)
3750 """
3751
3752 if isinstance(node, ast.Expr):
3753 node = node.value
3754
3755 node = ast.Expression(node)
3756 co = compile(node, filename, 'eval')
3757 fn = types.FunctionType(co, globals)
3758 return fn()
3759
3760
Larry Hastings31826802013-10-19 00:09:25 -07003761class IndentStack:
3762 def __init__(self):
3763 self.indents = []
3764 self.margin = None
3765
3766 def _ensure(self):
3767 if not self.indents:
3768 fail('IndentStack expected indents, but none are defined.')
3769
3770 def measure(self, line):
3771 """
3772 Returns the length of the line's margin.
3773 """
3774 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003775 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003776 stripped = line.lstrip()
3777 if not len(stripped):
3778 # we can't tell anything from an empty line
3779 # so just pretend it's indented like our current indent
3780 self._ensure()
3781 return self.indents[-1]
3782 return len(line) - len(stripped)
3783
3784 def infer(self, line):
3785 """
3786 Infer what is now the current margin based on this line.
3787 Returns:
3788 1 if we have indented (or this is the first margin)
3789 0 if the margin has not changed
3790 -N if we have dedented N times
3791 """
3792 indent = self.measure(line)
3793 margin = ' ' * indent
3794 if not self.indents:
3795 self.indents.append(indent)
3796 self.margin = margin
3797 return 1
3798 current = self.indents[-1]
3799 if indent == current:
3800 return 0
3801 if indent > current:
3802 self.indents.append(indent)
3803 self.margin = margin
3804 return 1
3805 # indent < current
3806 if indent not in self.indents:
3807 fail("Illegal outdent.")
3808 outdent_count = 0
3809 while indent != current:
3810 self.indents.pop()
3811 current = self.indents[-1]
3812 outdent_count -= 1
3813 self.margin = margin
3814 return outdent_count
3815
3816 @property
3817 def depth(self):
3818 """
3819 Returns how many margins are currently defined.
3820 """
3821 return len(self.indents)
3822
3823 def indent(self, line):
3824 """
3825 Indents a line by the currently defined margin.
3826 """
3827 return self.margin + line
3828
3829 def dedent(self, line):
3830 """
3831 Dedents a line by the currently defined margin.
3832 (The inverse of 'indent'.)
3833 """
3834 margin = self.margin
3835 indent = self.indents[-1]
3836 if not line.startswith(margin):
3837 fail('Cannot dedent, line does not start with the previous margin:')
3838 return line[indent:]
3839
3840
3841class DSLParser:
3842 def __init__(self, clinic):
3843 self.clinic = clinic
3844
3845 self.directives = {}
3846 for name in dir(self):
3847 # functions that start with directive_ are added to directives
3848 _, s, key = name.partition("directive_")
3849 if s:
3850 self.directives[key] = getattr(self, name)
3851
3852 # functions that start with at_ are too, with an @ in front
3853 _, s, key = name.partition("at_")
3854 if s:
3855 self.directives['@' + key] = getattr(self, name)
3856
3857 self.reset()
3858
3859 def reset(self):
3860 self.function = None
3861 self.state = self.state_dsl_start
3862 self.parameter_indent = None
3863 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003864 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003865 self.group = 0
3866 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003867 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003868 self.indent = IndentStack()
3869 self.kind = CALLABLE
3870 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003871 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003872 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003873
Larry Hastingsebdcb502013-11-23 14:54:00 -08003874 def directive_version(self, required):
3875 global version
3876 if version_comparitor(version, required) < 0:
3877 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3878
Larry Hastings31826802013-10-19 00:09:25 -07003879 def directive_module(self, name):
3880 fields = name.split('.')
3881 new = fields.pop()
3882 module, cls = self.clinic._module_and_class(fields)
3883 if cls:
3884 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003885
3886 if name in module.classes:
3887 fail("Already defined module " + repr(name) + "!")
3888
Larry Hastings31826802013-10-19 00:09:25 -07003889 m = Module(name, module)
3890 module.modules[name] = m
3891 self.block.signatures.append(m)
3892
Larry Hastingsc2047262014-01-25 20:43:29 -08003893 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003894 fields = name.split('.')
3895 in_classes = False
3896 parent = self
3897 name = fields.pop()
3898 so_far = []
3899 module, cls = self.clinic._module_and_class(fields)
3900
Larry Hastingsc2047262014-01-25 20:43:29 -08003901 parent = cls or module
3902 if name in parent.classes:
3903 fail("Already defined class " + repr(name) + "!")
3904
3905 c = Class(name, module, cls, typedef, type_object)
3906 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003907 self.block.signatures.append(c)
3908
Larry Hastingsbebf7352014-01-17 17:47:17 -08003909 def directive_set(self, name, value):
3910 if name not in ("line_prefix", "line_suffix"):
3911 fail("unknown variable", repr(name))
3912
3913 value = value.format_map({
3914 'block comment start': '/*',
3915 'block comment end': '*/',
3916 })
3917
3918 self.clinic.__dict__[name] = value
3919
3920 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003921 if command == 'new':
3922 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003923 return
3924
Zachary Ware071baa62014-01-21 23:07:12 -06003925 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003926 self.clinic.get_destination(name).clear()
3927 fail("unknown destination command", repr(command))
3928
3929
Larry Hastings0759f842015-04-03 13:09:02 -07003930 def directive_output(self, command_or_name, destination=''):
3931 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003932
Larry Hastings0759f842015-04-03 13:09:02 -07003933 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003934 preset = self.clinic.presets.get(destination)
3935 if not preset:
3936 fail("Unknown preset " + repr(destination) + "!")
3937 fd.update(preset)
3938 return
3939
Larry Hastings0759f842015-04-03 13:09:02 -07003940 if command_or_name == "push":
3941 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003942 return
3943
Larry Hastings0759f842015-04-03 13:09:02 -07003944 if command_or_name == "pop":
3945 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003946 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003947 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003948 fd.update(previous_fd)
3949 return
3950
3951 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003952 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003953 self.block.output.append(pprint.pformat(fd))
3954 self.block.output.append('\n')
3955 return
3956
3957 d = self.clinic.get_destination(destination)
3958
Larry Hastings0759f842015-04-03 13:09:02 -07003959 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003960 for name in list(fd):
3961 fd[name] = d
3962 return
3963
Larry Hastings0759f842015-04-03 13:09:02 -07003964 if command_or_name not in fd:
3965 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3966 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003967
3968 def directive_dump(self, name):
3969 self.block.output.append(self.clinic.get_destination(name).dump())
3970
3971 def directive_print(self, *args):
3972 self.block.output.append(' '.join(args))
3973 self.block.output.append('\n')
3974
3975 def directive_preserve(self):
3976 if self.preserve_output:
3977 fail("Can't have preserve twice in one block!")
3978 self.preserve_output = True
3979
Larry Hastings31826802013-10-19 00:09:25 -07003980 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003981 if self.kind is not CALLABLE:
3982 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003983 self.kind = CLASS_METHOD
3984
3985 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003986 if self.kind is not CALLABLE:
3987 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003988 self.kind = STATIC_METHOD
3989
3990 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003991 if self.coexist:
3992 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003993 self.coexist = True
3994
3995 def parse(self, block):
3996 self.reset()
3997 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003998 self.saved_output = self.block.output
3999 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07004000 block_start = self.clinic.block_parser.line_number
4001 lines = block.input.split('\n')
4002 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
4003 if '\t' in line:
4004 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
4005 self.state(line)
4006
4007 self.next(self.state_terminal)
4008 self.state(None)
4009
Larry Hastingsbebf7352014-01-17 17:47:17 -08004010 block.output.extend(self.clinic.language.render(clinic, block.signatures))
4011
4012 if self.preserve_output:
4013 if block.output:
4014 fail("'preserve' only works for blocks that don't produce any output!")
4015 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07004016
4017 @staticmethod
4018 def ignore_line(line):
4019 # ignore comment-only lines
4020 if line.lstrip().startswith('#'):
4021 return True
4022
4023 # Ignore empty lines too
4024 # (but not in docstring sections!)
4025 if not line.strip():
4026 return True
4027
4028 return False
4029
4030 @staticmethod
4031 def calculate_indent(line):
4032 return len(line) - len(line.strip())
4033
4034 def next(self, state, line=None):
4035 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
4036 self.state = state
4037 if line is not None:
4038 self.state(line)
4039
4040 def state_dsl_start(self, line):
4041 # self.block = self.ClinicOutputBlock(self)
4042 if self.ignore_line(line):
4043 return
Larry Hastings7726ac92014-01-31 22:03:12 -08004044
4045 # is it a directive?
4046 fields = shlex.split(line)
4047 directive_name = fields[0]
4048 directive = self.directives.get(directive_name, None)
4049 if directive:
4050 try:
4051 directive(*fields[1:])
4052 except TypeError as e:
4053 fail(str(e))
4054 return
4055
Larry Hastings31826802013-10-19 00:09:25 -07004056 self.next(self.state_modulename_name, line)
4057
4058 def state_modulename_name(self, line):
4059 # looking for declaration, which establishes the leftmost column
4060 # line should be
4061 # modulename.fnname [as c_basename] [-> return annotation]
4062 # square brackets denote optional syntax.
4063 #
Larry Hastings4a714d42014-01-14 22:22:41 -08004064 # alternatively:
4065 # modulename.fnname [as c_basename] = modulename.existing_fn_name
4066 # clones the parameters and return converter from that
4067 # function. you can't modify them. you must enter a
4068 # new docstring.
4069 #
Larry Hastings31826802013-10-19 00:09:25 -07004070 # (but we might find a directive first!)
4071 #
4072 # this line is permitted to start with whitespace.
4073 # we'll call this number of spaces F (for "function").
4074
4075 if not line.strip():
4076 return
4077
4078 self.indent.infer(line)
4079
Larry Hastings4a714d42014-01-14 22:22:41 -08004080 # are we cloning?
4081 before, equals, existing = line.rpartition('=')
4082 if equals:
4083 full_name, _, c_basename = before.partition(' as ')
4084 full_name = full_name.strip()
4085 c_basename = c_basename.strip()
4086 existing = existing.strip()
4087 if (is_legal_py_identifier(full_name) and
4088 (not c_basename or is_legal_c_identifier(c_basename)) and
4089 is_legal_py_identifier(existing)):
4090 # we're cloning!
4091 fields = [x.strip() for x in existing.split('.')]
4092 function_name = fields.pop()
4093 module, cls = self.clinic._module_and_class(fields)
4094
4095 for existing_function in (cls or module).functions:
4096 if existing_function.name == function_name:
4097 break
4098 else:
4099 existing_function = None
4100 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08004101 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08004102 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08004103 fail("Couldn't find existing function " + repr(existing) + "!")
4104
4105 fields = [x.strip() for x in full_name.split('.')]
4106 function_name = fields.pop()
4107 module, cls = self.clinic._module_and_class(fields)
4108
4109 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
4110 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08004111 self.function = existing_function.copy(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, docstring='')
Larry Hastings4a714d42014-01-14 22:22:41 -08004112
4113 self.block.signatures.append(self.function)
4114 (cls or module).functions.append(self.function)
4115 self.next(self.state_function_docstring)
4116 return
4117
Larry Hastings31826802013-10-19 00:09:25 -07004118 line, _, returns = line.partition('->')
4119
4120 full_name, _, c_basename = line.partition(' as ')
4121 full_name = full_name.strip()
4122 c_basename = c_basename.strip() or None
4123
Larry Hastingsdfcd4672013-10-27 02:49:39 -07004124 if not is_legal_py_identifier(full_name):
4125 fail("Illegal function name: {}".format(full_name))
4126 if c_basename and not is_legal_c_identifier(c_basename):
4127 fail("Illegal C basename: {}".format(c_basename))
4128
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004129 return_converter = None
4130 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07004131 ast_input = "def x() -> {}: pass".format(returns)
4132 module = None
4133 try:
4134 module = ast.parse(ast_input)
4135 except SyntaxError:
4136 pass
4137 if not module:
4138 fail("Badly-formed annotation for " + full_name + ": " + returns)
4139 try:
4140 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004141 if legacy:
4142 fail("Legacy converter {!r} not allowed as a return converter"
4143 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07004144 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004145 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07004146 return_converter = return_converters[name](**kwargs)
4147 except ValueError:
4148 fail("Badly-formed annotation for " + full_name + ": " + returns)
4149
4150 fields = [x.strip() for x in full_name.split('.')]
4151 function_name = fields.pop()
4152 module, cls = self.clinic._module_and_class(fields)
4153
Larry Hastings8666e652014-01-12 14:12:59 -08004154 fields = full_name.split('.')
4155 if fields[-1] == '__new__':
4156 if (self.kind != CLASS_METHOD) or (not cls):
4157 fail("__new__ must be a class method!")
4158 self.kind = METHOD_NEW
4159 elif fields[-1] == '__init__':
4160 if (self.kind != CALLABLE) or (not cls):
4161 fail("__init__ must be a normal method, not a class or static method!")
4162 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004163 if not return_converter:
4164 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08004165 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08004166 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08004167
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004168 if not return_converter:
4169 return_converter = CReturnConverter()
4170
Larry Hastings31826802013-10-19 00:09:25 -07004171 if not module:
4172 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
4173 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
4174 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
4175 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08004176
4177 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08004178 type, name = correct_name_for_self(self.function)
4179 kwargs = {}
4180 if cls and type == "PyObject *":
4181 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08004182 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08004183 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
4184 self.function.parameters[sc.name] = p_self
4185
Larry Hastings4a714d42014-01-14 22:22:41 -08004186 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07004187 self.next(self.state_parameters_start)
4188
4189 # Now entering the parameters section. The rules, formally stated:
4190 #
4191 # * All lines must be indented with spaces only.
4192 # * The first line must be a parameter declaration.
4193 # * The first line must be indented.
4194 # * This first line establishes the indent for parameters.
4195 # * We'll call this number of spaces P (for "parameter").
4196 # * Thenceforth:
4197 # * Lines indented with P spaces specify a parameter.
4198 # * Lines indented with > P spaces are docstrings for the previous
4199 # parameter.
4200 # * We'll call this number of spaces D (for "docstring").
4201 # * All subsequent lines indented with >= D spaces are stored as
4202 # part of the per-parameter docstring.
4203 # * All lines will have the first D spaces of the indent stripped
4204 # before they are stored.
4205 # * It's illegal to have a line starting with a number of spaces X
4206 # such that P < X < D.
4207 # * A line with < P spaces is the first line of the function
4208 # docstring, which ends processing for parameters and per-parameter
4209 # docstrings.
4210 # * The first line of the function docstring must be at the same
4211 # indent as the function declaration.
4212 # * It's illegal to have any line in the parameters section starting
4213 # with X spaces such that F < X < P. (As before, F is the indent
4214 # of the function declaration.)
4215 #
Larry Hastings31826802013-10-19 00:09:25 -07004216 # Also, currently Argument Clinic places the following restrictions on groups:
4217 # * Each group must contain at least one parameter.
4218 # * Each group may contain at most one group, which must be the furthest
4219 # thing in the group from the required parameters. (The nested group
4220 # must be the first in the group when it's before the required
4221 # parameters, and the last thing in the group when after the required
4222 # parameters.)
4223 # * There may be at most one (top-level) group to the left or right of
4224 # the required parameters.
4225 # * You must specify a slash, and it must be after all parameters.
4226 # (In other words: either all parameters are positional-only,
4227 # or none are.)
4228 #
4229 # Said another way:
4230 # * Each group must contain at least one parameter.
4231 # * All left square brackets before the required parameters must be
4232 # consecutive. (You can't have a left square bracket followed
4233 # by a parameter, then another left square bracket. You can't
4234 # have a left square bracket, a parameter, a right square bracket,
4235 # and then a left square bracket.)
4236 # * All right square brackets after the required parameters must be
4237 # consecutive.
4238 #
4239 # These rules are enforced with a single state variable:
4240 # "parameter_state". (Previously the code was a miasma of ifs and
4241 # separate boolean state variables.) The states are:
4242 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004243 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4244 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07004245 #
4246 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4247 # 1: ps_left_square_before. left square brackets before required parameters.
4248 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08004249 # 3: ps_required. required parameters, positional-or-keyword or positional-only
4250 # (we don't know yet). (renumber left groups!)
4251 # 4: ps_optional. positional-or-keyword or positional-only parameters that
4252 # now must have default values.
4253 # 5: ps_group_after. in a group, after required parameters.
4254 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07004255 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004256 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07004257
4258 def state_parameters_start(self, line):
4259 if self.ignore_line(line):
4260 return
4261
4262 # if this line is not indented, we have no parameters
4263 if not self.indent.infer(line):
4264 return self.next(self.state_function_docstring, line)
4265
Larry Hastings2a727912014-01-16 11:32:01 -08004266 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07004267 return self.next(self.state_parameter, line)
4268
4269
4270 def to_required(self):
4271 """
4272 Transition to the "required" parameter state.
4273 """
4274 if self.parameter_state != self.ps_required:
4275 self.parameter_state = self.ps_required
4276 for p in self.function.parameters.values():
4277 p.group = -p.group
4278
4279 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08004280 if self.parameter_continuation:
4281 line = self.parameter_continuation + ' ' + line.lstrip()
4282 self.parameter_continuation = ''
4283
Larry Hastings31826802013-10-19 00:09:25 -07004284 if self.ignore_line(line):
4285 return
4286
4287 assert self.indent.depth == 2
4288 indent = self.indent.infer(line)
4289 if indent == -1:
4290 # we outdented, must be to definition column
4291 return self.next(self.state_function_docstring, line)
4292
4293 if indent == 1:
4294 # we indented, must be to new parameter docstring column
4295 return self.next(self.state_parameter_docstring_start, line)
4296
Larry Hastings2a727912014-01-16 11:32:01 -08004297 line = line.rstrip()
4298 if line.endswith('\\'):
4299 self.parameter_continuation = line[:-1]
4300 return
4301
Larry Hastings31826802013-10-19 00:09:25 -07004302 line = line.lstrip()
4303
4304 if line in ('*', '/', '[', ']'):
4305 self.parse_special_symbol(line)
4306 return
4307
4308 if self.parameter_state in (self.ps_start, self.ps_required):
4309 self.to_required()
4310 elif self.parameter_state == self.ps_left_square_before:
4311 self.parameter_state = self.ps_group_before
4312 elif self.parameter_state == self.ps_group_before:
4313 if not self.group:
4314 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08004315 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07004316 pass
4317 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004318 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07004319
Larry Hastings7726ac92014-01-31 22:03:12 -08004320 # handle "as" for parameters too
4321 c_name = None
4322 name, have_as_token, trailing = line.partition(' as ')
4323 if have_as_token:
4324 name = name.strip()
4325 if ' ' not in name:
4326 fields = trailing.strip().split(' ')
4327 if not fields:
4328 fail("Invalid 'as' clause!")
4329 c_name = fields[0]
4330 if c_name.endswith(':'):
4331 name += ':'
4332 c_name = c_name[:-1]
4333 fields[0] = name
4334 line = ' '.join(fields)
4335
Larry Hastings2a727912014-01-16 11:32:01 -08004336 base, equals, default = line.rpartition('=')
4337 if not equals:
4338 base = default
4339 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08004340
Larry Hastings31826802013-10-19 00:09:25 -07004341 module = None
4342 try:
Larry Hastings2a727912014-01-16 11:32:01 -08004343 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07004344 module = ast.parse(ast_input)
4345 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08004346 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08004347 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004348 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08004349 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08004350 default = None
4351 ast_input = "def x({}): pass".format(line)
4352 module = ast.parse(ast_input)
4353 except SyntaxError:
4354 pass
Larry Hastings31826802013-10-19 00:09:25 -07004355 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07004356 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07004357
4358 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004359
4360 if len(function_args.args) > 1:
4361 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
4362 if function_args.defaults or function_args.kw_defaults:
4363 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
4364 if function_args.vararg or function_args.kwarg:
4365 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
4366
Larry Hastings31826802013-10-19 00:09:25 -07004367 parameter = function_args.args[0]
4368
Larry Hastings16c51912014-01-07 11:53:01 -08004369 parameter_name = parameter.arg
4370 name, legacy, kwargs = self.parse_converter(parameter.annotation)
4371
Larry Hastings2a727912014-01-16 11:32:01 -08004372 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08004373 if self.parameter_state == self.ps_optional:
4374 fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!")
Larry Hastings2a727912014-01-16 11:32:01 -08004375 value = unspecified
4376 if 'py_default' in kwargs:
4377 fail("You can't specify py_default without specifying a default value!")
4378 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004379 if self.parameter_state == self.ps_required:
4380 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08004381 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06004382 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004383 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08004384 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004385 try:
4386 module = ast.parse(ast_input)
4387
Larry Hastings5c661892014-01-24 06:17:25 -08004388 if 'c_default' not in kwargs:
4389 # we can only represent very simple data values in C.
4390 # detect whether default is okay, via a blacklist
4391 # of disallowed ast nodes.
4392 class DetectBadNodes(ast.NodeVisitor):
4393 bad = False
4394 def bad_node(self, node):
4395 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08004396
Larry Hastings5c661892014-01-24 06:17:25 -08004397 # inline function call
4398 visit_Call = bad_node
4399 # inline if statement ("x = 3 if y else z")
4400 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004401
Larry Hastings5c661892014-01-24 06:17:25 -08004402 # comprehensions and generator expressions
4403 visit_ListComp = visit_SetComp = bad_node
4404 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004405
Larry Hastings5c661892014-01-24 06:17:25 -08004406 # literals for advanced types
4407 visit_Dict = visit_Set = bad_node
4408 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004409
Larry Hastings5c661892014-01-24 06:17:25 -08004410 # "starred": "a = [1, 2, 3]; *a"
4411 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004412
Larry Hastings5c661892014-01-24 06:17:25 -08004413 blacklist = DetectBadNodes()
4414 blacklist.visit(module)
4415 bad = blacklist.bad
4416 else:
4417 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06004418 # but at least make an attempt at ensuring it's a valid expression.
4419 try:
4420 value = eval(default)
4421 if value == unspecified:
4422 fail("'unspecified' is not a legal default value!")
4423 except NameError:
4424 pass # probably a named constant
4425 except Exception as e:
4426 fail("Malformed expression given as default value\n"
4427 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08004428 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08004429 fail("Unsupported expression as default value: " + repr(default))
4430
4431 expr = module.body[0].value
4432 # mild hack: explicitly support NULL as a default value
4433 if isinstance(expr, ast.Name) and expr.id == 'NULL':
4434 value = NULL
Serhiy Storchaka279f4462019-09-14 12:24:05 +03004435 py_default = '<unrepresentable>'
Larry Hastings2a727912014-01-16 11:32:01 -08004436 c_default = "NULL"
4437 elif (isinstance(expr, ast.BinOp) or
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004438 (isinstance(expr, ast.UnaryOp) and
4439 not (isinstance(expr.operand, ast.Num) or
4440 (hasattr(ast, 'Constant') and
4441 isinstance(expr.operand, ast.Constant) and
4442 type(expr.operand.value) in (int, float, complex)))
4443 )):
Larry Hastings2a727912014-01-16 11:32:01 -08004444 c_default = kwargs.get("c_default")
4445 if not (isinstance(c_default, str) and c_default):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004446 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default." + ast.dump(expr))
Larry Hastings2a727912014-01-16 11:32:01 -08004447 py_default = default
4448 value = unknown
4449 elif isinstance(expr, ast.Attribute):
4450 a = []
4451 n = expr
4452 while isinstance(n, ast.Attribute):
4453 a.append(n.attr)
4454 n = n.value
4455 if not isinstance(n, ast.Name):
4456 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
4457 a.append(n.id)
4458 py_default = ".".join(reversed(a))
4459
4460 c_default = kwargs.get("c_default")
4461 if not (isinstance(c_default, str) and c_default):
4462 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4463
4464 try:
4465 value = eval(py_default)
4466 except NameError:
4467 value = unknown
4468 else:
4469 value = ast.literal_eval(expr)
4470 py_default = repr(value)
4471 if isinstance(value, (bool, None.__class__)):
4472 c_default = "Py_" + py_default
4473 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08004474 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08004475 else:
4476 c_default = py_default
4477
4478 except SyntaxError as e:
4479 fail("Syntax error: " + repr(e.text))
4480 except (ValueError, AttributeError):
4481 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08004482 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08004483 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08004484 if not (isinstance(c_default, str) and c_default):
4485 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4486
Larry Hastings2a727912014-01-16 11:32:01 -08004487 kwargs.setdefault('c_default', c_default)
4488 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004489
Larry Hastings31826802013-10-19 00:09:25 -07004490 dict = legacy_converters if legacy else converters
4491 legacy_str = "legacy " if legacy else ""
4492 if name not in dict:
4493 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08004494 # if you use a c_name for the parameter, we just give that name to the converter
4495 # but the parameter object gets the python name
4496 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07004497
4498 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08004499
4500 if isinstance(converter, self_converter):
4501 if len(self.function.parameters) == 1:
4502 if (self.parameter_state != self.ps_required):
4503 fail("A 'self' parameter cannot be marked optional.")
4504 if value is not unspecified:
4505 fail("A 'self' parameter cannot have a default value.")
4506 if self.group:
4507 fail("A 'self' parameter cannot be in an optional group.")
4508 kind = inspect.Parameter.POSITIONAL_ONLY
4509 self.parameter_state = self.ps_start
4510 self.function.parameters.clear()
4511 else:
4512 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
4513
Larry Hastings31826802013-10-19 00:09:25 -07004514 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08004515
4516 if parameter_name in self.function.parameters:
4517 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07004518 self.function.parameters[parameter_name] = p
4519
4520 def parse_converter(self, annotation):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004521 if (hasattr(ast, 'Constant') and
4522 isinstance(annotation, ast.Constant) and
4523 type(annotation.value) is str):
4524 return annotation.value, True, {}
4525
Larry Hastings31826802013-10-19 00:09:25 -07004526 if isinstance(annotation, ast.Str):
4527 return annotation.s, True, {}
4528
4529 if isinstance(annotation, ast.Name):
4530 return annotation.id, False, {}
4531
Larry Hastings4a55fc52014-01-12 11:09:57 -08004532 if not isinstance(annotation, ast.Call):
4533 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07004534
4535 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004536 symbols = globals()
4537
4538 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07004539 return name, False, kwargs
4540
4541 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07004542 if symbol == '*':
4543 if self.keyword_only:
4544 fail("Function " + self.function.name + " uses '*' more than once.")
4545 self.keyword_only = True
4546 elif symbol == '[':
4547 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
4548 self.parameter_state = self.ps_left_square_before
4549 elif self.parameter_state in (self.ps_required, self.ps_group_after):
4550 self.parameter_state = self.ps_group_after
4551 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004552 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07004553 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08004554 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07004555 elif symbol == ']':
4556 if not self.group:
4557 fail("Function " + self.function.name + " has a ] without a matching [.")
4558 if not any(p.group == self.group for p in self.function.parameters.values()):
4559 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
4560 self.group -= 1
4561 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
4562 self.parameter_state = self.ps_group_before
4563 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
4564 self.parameter_state = self.ps_right_square_after
4565 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004566 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07004567 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004568 if self.positional_only:
4569 fail("Function " + self.function.name + " uses '/' more than once.")
4570 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08004571 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07004572 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08004573 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
4574 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07004575 if self.keyword_only:
4576 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004577 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004578 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004579 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004580 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4581 p.kind = inspect.Parameter.POSITIONAL_ONLY
4582
4583 def state_parameter_docstring_start(self, line):
4584 self.parameter_docstring_indent = len(self.indent.margin)
4585 assert self.indent.depth == 3
4586 return self.next(self.state_parameter_docstring, line)
4587
4588 # every line of the docstring must start with at least F spaces,
4589 # where F > P.
4590 # these F spaces will be stripped.
4591 def state_parameter_docstring(self, line):
4592 stripped = line.strip()
4593 if stripped.startswith('#'):
4594 return
4595
4596 indent = self.indent.measure(line)
4597 if indent < self.parameter_docstring_indent:
4598 self.indent.infer(line)
4599 assert self.indent.depth < 3
4600 if self.indent.depth == 2:
4601 # back to a parameter
4602 return self.next(self.state_parameter, line)
4603 assert self.indent.depth == 1
4604 return self.next(self.state_function_docstring, line)
4605
4606 assert self.function.parameters
4607 last_parameter = next(reversed(list(self.function.parameters.values())))
4608
4609 new_docstring = last_parameter.docstring
4610
4611 if new_docstring:
4612 new_docstring += '\n'
4613 if stripped:
4614 new_docstring += self.indent.dedent(line)
4615
4616 last_parameter.docstring = new_docstring
4617
4618 # the final stanza of the DSL is the docstring.
4619 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004620 if self.group:
4621 fail("Function " + self.function.name + " has a ] without a matching [.")
4622
4623 stripped = line.strip()
4624 if stripped.startswith('#'):
4625 return
4626
4627 new_docstring = self.function.docstring
4628 if new_docstring:
4629 new_docstring += "\n"
4630 if stripped:
4631 line = self.indent.dedent(line).rstrip()
4632 else:
4633 line = ''
4634 new_docstring += line
4635 self.function.docstring = new_docstring
4636
4637 def format_docstring(self):
4638 f = self.function
4639
Larry Hastings5c661892014-01-24 06:17:25 -08004640 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4641 if new_or_init and not f.docstring:
4642 # don't render a docstring at all, no signature, nothing.
4643 return f.docstring
4644
Larry Hastings2623c8c2014-02-08 22:15:29 -08004645 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004646 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004647
4648 ##
4649 ## docstring first line
4650 ##
4651
Larry Hastings2623c8c2014-02-08 22:15:29 -08004652 if new_or_init:
4653 # classes get *just* the name of the class
4654 # not __new__, not __init__, and not module.classname
4655 assert f.cls
4656 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004657 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004658 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004659 add('(')
4660
4661 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004662 assert parameters, "We should always have a self parameter. " + repr(f)
4663 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004664 # self is always positional-only.
4665 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004666 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004667 positional_only = True
4668 for p in parameters[1:]:
4669 if not p.is_positional_only():
4670 positional_only = False
4671 else:
4672 assert positional_only
4673 if positional_only:
4674 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004675 else:
4676 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004677 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004678
4679 right_bracket_count = 0
4680
4681 def fix_right_bracket_count(desired):
4682 nonlocal right_bracket_count
4683 s = ''
4684 while right_bracket_count < desired:
4685 s += '['
4686 right_bracket_count += 1
4687 while right_bracket_count > desired:
4688 s += ']'
4689 right_bracket_count -= 1
4690 return s
4691
Larry Hastings2623c8c2014-02-08 22:15:29 -08004692 need_slash = False
4693 added_slash = False
4694 need_a_trailing_slash = False
4695
4696 # we only need a trailing slash:
4697 # * if this is not a "docstring_only" signature
4698 # * and if the last *shown* parameter is
4699 # positional only
4700 if not f.docstring_only:
4701 for p in reversed(parameters):
4702 if not p.converter.show_in_signature:
4703 continue
4704 if p.is_positional_only():
4705 need_a_trailing_slash = True
4706 break
4707
4708
Larry Hastings31826802013-10-19 00:09:25 -07004709 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004710
4711 first_parameter = True
4712 last_p = parameters[-1]
4713 line_length = len(''.join(text))
4714 indent = " " * line_length
4715 def add_parameter(text):
4716 nonlocal line_length
4717 nonlocal first_parameter
4718 if first_parameter:
4719 s = text
4720 first_parameter = False
4721 else:
4722 s = ' ' + text
4723 if line_length + len(s) >= 72:
4724 add('\n')
4725 add(indent)
4726 line_length = len(indent)
4727 s = text
4728 line_length += len(s)
4729 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004730
4731 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004732 if not p.converter.show_in_signature:
4733 continue
Larry Hastings31826802013-10-19 00:09:25 -07004734 assert p.name
4735
Larry Hastings2623c8c2014-02-08 22:15:29 -08004736 is_self = isinstance(p.converter, self_converter)
4737 if is_self and f.docstring_only:
4738 # this isn't a real machine-parsable signature,
4739 # so let's not print the "self" parameter
4740 continue
4741
4742 if p.is_positional_only():
4743 need_slash = not f.docstring_only
4744 elif need_slash and not (added_slash or p.is_positional_only()):
4745 added_slash = True
4746 add_parameter('/,')
4747
Larry Hastings31826802013-10-19 00:09:25 -07004748 if p.is_keyword_only() and not added_star:
4749 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004750 add_parameter('*,')
4751
4752 p_add, p_output = text_accumulator()
4753 p_add(fix_right_bracket_count(p.right_bracket_count))
4754
4755 if isinstance(p.converter, self_converter):
4756 # annotate first parameter as being a "self".
4757 #
4758 # if inspect.Signature gets this function,
4759 # and it's already bound, the self parameter
4760 # will be stripped off.
4761 #
4762 # if it's not bound, it should be marked
4763 # as positional-only.
4764 #
4765 # note: we don't print "self" for __init__,
4766 # because this isn't actually the signature
4767 # for __init__. (it can't be, __init__ doesn't
4768 # have a docstring.) if this is an __init__
4769 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004770 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004771 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004772
Larry Hastings5c661892014-01-24 06:17:25 -08004773 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004774 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004775
Larry Hastings31826802013-10-19 00:09:25 -07004776 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004777 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004778 value = p.converter.py_default
4779 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004780 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004781 p_add(value)
4782
4783 if (p != last_p) or need_a_trailing_slash:
4784 p_add(',')
4785
4786 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004787
4788 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004789 if need_a_trailing_slash:
4790 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004791 add(')')
4792
Larry Hastings2a727912014-01-16 11:32:01 -08004793 # PEP 8 says:
4794 #
4795 # The Python standard library will not use function annotations
4796 # as that would result in a premature commitment to a particular
4797 # annotation style. Instead, the annotations are left for users
4798 # to discover and experiment with useful annotation styles.
4799 #
4800 # therefore this is commented out:
4801 #
4802 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004803 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004804 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004805
Larry Hastings2623c8c2014-02-08 22:15:29 -08004806 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004807 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004808
Larry Hastings31826802013-10-19 00:09:25 -07004809 docstring_first_line = output()
4810
4811 # now fix up the places where the brackets look wrong
4812 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4813
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004814 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004815 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004816 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004817 for p in parameters:
4818 if not p.docstring.strip():
4819 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004820 if spacer_line:
4821 add('\n')
4822 else:
4823 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004824 add(" ")
4825 add(p.name)
4826 add('\n')
4827 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004828 parameters = output()
4829 if parameters:
4830 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004831
4832 ##
4833 ## docstring body
4834 ##
4835
4836 docstring = f.docstring.rstrip()
4837 lines = [line.rstrip() for line in docstring.split('\n')]
4838
4839 # Enforce the summary line!
4840 # The first line of a docstring should be a summary of the function.
4841 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4842 # by itself.
4843 #
4844 # Argument Clinic enforces the following rule:
4845 # * either the docstring is empty,
4846 # * or it must have a summary line.
4847 #
4848 # Guido said Clinic should enforce this:
4849 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4850
4851 if len(lines) >= 2:
4852 if lines[1]:
4853 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4854 "Every non-blank function docstring must start with\n" +
4855 "a single line summary followed by an empty line.")
4856 elif len(lines) == 1:
4857 # the docstring is only one line right now--the summary line.
4858 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004859 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004860 lines.append('')
4861
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004862 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4863 if parameters_marker_count > 1:
4864 fail('You may not specify {parameters} more than once in a docstring!')
4865
4866 if not parameters_marker_count:
4867 # insert after summary line
4868 lines.insert(2, '{parameters}')
4869
4870 # insert at front of docstring
4871 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004872
4873 docstring = "\n".join(lines)
4874
4875 add(docstring)
4876 docstring = output()
4877
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004878 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004879 docstring = docstring.rstrip()
4880
4881 return docstring
4882
4883 def state_terminal(self, line):
4884 """
4885 Called when processing the block is done.
4886 """
4887 assert not line
4888
4889 if not self.function:
4890 return
4891
4892 if self.keyword_only:
4893 values = self.function.parameters.values()
4894 if not values:
4895 no_parameter_after_star = True
4896 else:
4897 last_parameter = next(reversed(list(values)))
4898 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4899 if no_parameter_after_star:
4900 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4901
4902 # remove trailing whitespace from all parameter docstrings
4903 for name, value in self.function.parameters.items():
4904 if not value:
4905 continue
4906 value.docstring = value.docstring.rstrip()
4907
4908 self.function.docstring = self.format_docstring()
4909
4910
Larry Hastings5c661892014-01-24 06:17:25 -08004911
4912
Larry Hastings31826802013-10-19 00:09:25 -07004913# maps strings to callables.
4914# the callable should return an object
4915# that implements the clinic parser
4916# interface (__init__ and parse).
4917#
4918# example parsers:
4919# "clinic", handles the Clinic DSL
4920# "python", handles running Python code
4921#
4922parsers = {'clinic' : DSLParser, 'python': PythonParser}
4923
4924
4925clinic = None
4926
4927
4928def main(argv):
4929 import sys
4930
4931 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4932 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4933
4934 import argparse
Tim Hoffmann5df40252019-06-02 18:58:10 +02004935 cmdline = argparse.ArgumentParser(
4936 description="""Preprocessor for CPython C files.
4937
4938The purpose of the Argument Clinic is automating all the boilerplate involved
4939with writing argument parsing code for builtins and providing introspection
4940signatures ("docstrings") for CPython builtins.
4941
4942For more information see https://docs.python.org/3/howto/clinic.html""")
Larry Hastings31826802013-10-19 00:09:25 -07004943 cmdline.add_argument("-f", "--force", action='store_true')
4944 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004945 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004946 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004947 cmdline.add_argument("--make", action='store_true',
4948 help="Walk --srcdir to run over all relevant files.")
4949 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4950 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004951 cmdline.add_argument("filename", type=str, nargs="*")
4952 ns = cmdline.parse_args(argv)
4953
4954 if ns.converters:
4955 if ns.filename:
4956 print("Usage error: can't specify --converters and a filename at the same time.")
4957 print()
4958 cmdline.print_usage()
4959 sys.exit(-1)
4960 converters = []
4961 return_converters = []
4962 ignored = set("""
4963 add_c_converter
4964 add_c_return_converter
4965 add_default_legacy_c_converter
4966 add_legacy_c_converter
4967 """.strip().split())
4968 module = globals()
4969 for name in module:
4970 for suffix, ids in (
4971 ("_return_converter", return_converters),
4972 ("_converter", converters),
4973 ):
4974 if name in ignored:
4975 continue
4976 if name.endswith(suffix):
4977 ids.append((name, name[:-len(suffix)]))
4978 break
4979 print()
4980
4981 print("Legacy converters:")
4982 legacy = sorted(legacy_converters)
4983 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4984 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4985 print()
4986
4987 for title, attribute, ids in (
4988 ("Converters", 'converter_init', converters),
4989 ("Return converters", 'return_converter_init', return_converters),
4990 ):
4991 print(title + ":")
4992 longest = -1
4993 for name, short_name in ids:
4994 longest = max(longest, len(short_name))
4995 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4996 cls = module[name]
4997 callable = getattr(cls, attribute, None)
4998 if not callable:
4999 continue
5000 signature = inspect.signature(callable)
5001 parameters = []
5002 for parameter_name, parameter in signature.parameters.items():
5003 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
5004 if parameter.default != inspect.Parameter.empty:
5005 s = '{}={!r}'.format(parameter_name, parameter.default)
5006 else:
5007 s = parameter_name
5008 parameters.append(s)
5009 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07005010 print()
Larry Hastings2a727912014-01-16 11:32:01 -08005011 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
5012 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07005013 sys.exit(0)
5014
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005015 if ns.make:
5016 if ns.output or ns.filename:
5017 print("Usage error: can't use -o or filenames with --make.")
5018 print()
5019 cmdline.print_usage()
5020 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07005021 if not ns.srcdir:
5022 print("Usage error: --srcdir must not be empty with --make.")
5023 print()
5024 cmdline.print_usage()
5025 sys.exit(-1)
5026 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05005027 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005028 if rcs_dir in dirs:
5029 dirs.remove(rcs_dir)
5030 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08005031 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005032 continue
5033 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08005034 if ns.verbose:
5035 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08005036 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005037 return
5038
Larry Hastings31826802013-10-19 00:09:25 -07005039 if not ns.filename:
5040 cmdline.print_usage()
5041 sys.exit(-1)
5042
5043 if ns.output and len(ns.filename) > 1:
5044 print("Usage error: can't use -o with multiple filenames.")
5045 print()
5046 cmdline.print_usage()
5047 sys.exit(-1)
5048
5049 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08005050 if ns.verbose:
5051 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08005052 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07005053
5054
5055if __name__ == "__main__":
5056 sys.exit(main(sys.argv[1:]))