blob: 0e7ce965b0f1e3ae790352c9fb270e2280bb4354 [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 Hastings31826802013-10-19 00:09:25 -070046_empty = inspect._empty
47_void = inspect._void
48
Larry Hastings4a55fc52014-01-12 11:09:57 -080049NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070050
51class Unspecified:
52 def __repr__(self):
53 return '<Unspecified>'
54
55unspecified = Unspecified()
56
57
58class Null:
59 def __repr__(self):
60 return '<Null>'
61
62NULL = Null()
63
64
Larry Hastings2a727912014-01-16 11:32:01 -080065class Unknown:
66 def __repr__(self):
67 return '<Unknown>'
68
69unknown = Unknown()
70
Zachary Ware8ef887c2015-04-13 18:22:35 -050071sig_end_marker = '--'
72
Larry Hastings2a727912014-01-16 11:32:01 -080073
Larry Hastings0759f842015-04-03 13:09:02 -070074_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output")
75
Larry Hastings31826802013-10-19 00:09:25 -070076def _text_accumulator():
77 text = []
78 def output():
79 s = ''.join(text)
80 text.clear()
81 return s
Larry Hastings0759f842015-04-03 13:09:02 -070082 return _text_accumulator_nt(text, text.append, output)
Larry Hastings31826802013-10-19 00:09:25 -070083
84
Larry Hastings0759f842015-04-03 13:09:02 -070085text_accumulator_nt = collections.namedtuple("text_accumulator", "text append")
86
Larry Hastings31826802013-10-19 00:09:25 -070087def text_accumulator():
88 """
89 Creates a simple text accumulator / joiner.
90
91 Returns a pair of callables:
92 append, output
93 "append" appends a string to the accumulator.
94 "output" returns the contents of the accumulator
95 joined together (''.join(accumulator)) and
96 empties the accumulator.
97 """
98 text, append, output = _text_accumulator()
Larry Hastings0759f842015-04-03 13:09:02 -070099 return text_accumulator_nt(append, output)
Larry Hastings31826802013-10-19 00:09:25 -0700100
101
Larry Hastingsbebf7352014-01-17 17:47:17 -0800102def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -0700103 joined = " ".join([str(a) for a in args])
104 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800105 if fail:
106 add("Error")
107 else:
108 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -0700109 if clinic:
110 if filename is None:
111 filename = clinic.filename
Larry Hastings581ee362014-01-28 05:00:08 -0800112 if getattr(clinic, 'block_parser', None) and (line_number is None):
Larry Hastings31826802013-10-19 00:09:25 -0700113 line_number = clinic.block_parser.line_number
114 if filename is not None:
115 add(' in file "' + filename + '"')
116 if line_number is not None:
117 add(" on line " + str(line_number))
118 add(':\n')
119 add(joined)
120 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800121 if fail:
122 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700123
124
Larry Hastingsbebf7352014-01-17 17:47:17 -0800125def warn(*args, filename=None, line_number=None):
126 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
127
128def fail(*args, filename=None, line_number=None):
129 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
130
Larry Hastings31826802013-10-19 00:09:25 -0700131
132def quoted_for_c_string(s):
133 for old, new in (
Zachary Ware9d7849f2014-01-25 03:26:20 -0600134 ('\\', '\\\\'), # must be first!
Larry Hastings31826802013-10-19 00:09:25 -0700135 ('"', '\\"'),
136 ("'", "\\'"),
137 ):
138 s = s.replace(old, new)
139 return s
140
Larry Hastings4903e002014-01-18 00:26:16 -0800141def c_repr(s):
142 return '"' + s + '"'
143
144
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700145is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
146
147def is_legal_py_identifier(s):
148 return all(is_legal_c_identifier(field) for field in s.split('.'))
149
Larry Hastingsbebf7352014-01-17 17:47:17 -0800150# identifiers that are okay in Python but aren't a good idea in C.
151# so if they're used Argument Clinic will add "_value" to the end
152# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700153c_keywords = set("""
Larry Hastings5c661892014-01-24 06:17:25 -0800154asm auto break case char const continue default do double
155else enum extern float for goto if inline int long
156register return short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800157typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700158""".strip().split())
159
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700160def ensure_legal_c_identifier(s):
161 # for now, just complain if what we're given isn't legal
162 if not is_legal_c_identifier(s):
163 fail("Illegal C identifier: {}".format(s))
164 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700165 if s in c_keywords:
166 return s + "_value"
167 return s
168
169def rstrip_lines(s):
170 text, add, output = _text_accumulator()
171 for line in s.split('\n'):
172 add(line.rstrip())
173 add('\n')
174 text.pop()
175 return output()
176
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +0300177def format_escape(s):
178 # double up curly-braces, this string will be used
179 # as part of a format_map() template later
180 s = s.replace('{', '{{')
181 s = s.replace('}', '}}')
182 return s
183
Larry Hastings31826802013-10-19 00:09:25 -0700184def linear_format(s, **kwargs):
185 """
186 Perform str.format-like substitution, except:
187 * The strings substituted must be on lines by
188 themselves. (This line is the "source line".)
189 * If the substitution text is empty, the source line
190 is removed in the output.
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800191 * If the field is not recognized, the original line
192 is passed unmodified through to the output.
Larry Hastings31826802013-10-19 00:09:25 -0700193 * If the substitution text is not empty:
194 * Each line of the substituted text is indented
195 by the indent of the source line.
196 * A newline will be added to the end.
197 """
198
199 add, output = text_accumulator()
200 for line in s.split('\n'):
201 indent, curly, trailing = line.partition('{')
202 if not curly:
203 add(line)
204 add('\n')
205 continue
206
Martin Panter4177e7c2016-02-14 03:23:13 +0000207 name, curly, trailing = trailing.partition('}')
Larry Hastings31826802013-10-19 00:09:25 -0700208 if not curly or name not in kwargs:
209 add(line)
210 add('\n')
211 continue
212
213 if trailing:
214 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
215 if indent.strip():
216 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
217
218 value = kwargs[name]
219 if not value:
220 continue
221
222 value = textwrap.indent(rstrip_lines(value), indent)
223 add(value)
224 add('\n')
225
226 return output()[:-1]
227
Larry Hastingsbebf7352014-01-17 17:47:17 -0800228def indent_all_lines(s, prefix):
229 """
230 Returns 's', with 'prefix' prepended to all lines.
231
232 If the last line is empty, prefix is not prepended
233 to it. (If s is blank, returns s unchanged.)
234
235 (textwrap.indent only adds to non-blank lines.)
236 """
237 split = s.split('\n')
238 last = split.pop()
239 final = []
240 for line in split:
241 final.append(prefix)
242 final.append(line)
243 final.append('\n')
244 if last:
245 final.append(prefix)
246 final.append(last)
247 return ''.join(final)
248
249def suffix_all_lines(s, suffix):
250 """
251 Returns 's', with 'suffix' appended to all lines.
252
253 If the last line is empty, suffix is not appended
254 to it. (If s is blank, returns s unchanged.)
255 """
256 split = s.split('\n')
257 last = split.pop()
258 final = []
259 for line in split:
260 final.append(line)
261 final.append(suffix)
262 final.append('\n')
263 if last:
264 final.append(last)
265 final.append(suffix)
266 return ''.join(final)
267
268
Larry Hastingsebdcb502013-11-23 14:54:00 -0800269def version_splitter(s):
270 """Splits a version string into a tuple of integers.
271
272 The following ASCII characters are allowed, and employ
273 the following conversions:
274 a -> -3
275 b -> -2
276 c -> -1
277 (This permits Python-style version strings such as "1.4b3".)
278 """
279 version = []
280 accumulator = []
281 def flush():
282 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800283 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800284 version.append(int(''.join(accumulator)))
285 accumulator.clear()
286
287 for c in s:
288 if c.isdigit():
289 accumulator.append(c)
290 elif c == '.':
291 flush()
292 elif c in 'abc':
293 flush()
294 version.append('abc'.index(c) - 3)
295 else:
296 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
297 flush()
298 return tuple(version)
299
300def version_comparitor(version1, version2):
301 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
302 for i, (a, b) in enumerate(iterator):
303 if a < b:
304 return -1
305 if a > b:
306 return 1
307 return 0
308
Larry Hastings31826802013-10-19 00:09:25 -0700309
310class CRenderData:
311 def __init__(self):
312
313 # The C statements to declare variables.
314 # Should be full lines with \n eol characters.
315 self.declarations = []
316
317 # The C statements required to initialize the variables before the parse call.
318 # Should be full lines with \n eol characters.
319 self.initializers = []
320
Larry Hastingsc2047262014-01-25 20:43:29 -0800321 # The C statements needed to dynamically modify the values
322 # parsed by the parse call, before calling the impl.
323 self.modifications = []
324
Larry Hastings31826802013-10-19 00:09:25 -0700325 # The entries for the "keywords" array for PyArg_ParseTuple.
326 # Should be individual strings representing the names.
327 self.keywords = []
328
329 # The "format units" for PyArg_ParseTuple.
330 # Should be individual strings that will get
331 self.format_units = []
332
333 # The varargs arguments for PyArg_ParseTuple.
334 self.parse_arguments = []
335
336 # The parameter declarations for the impl function.
337 self.impl_parameters = []
338
339 # The arguments to the impl function at the time it's called.
340 self.impl_arguments = []
341
342 # For return converters: the name of the variable that
343 # should receive the value returned by the impl.
344 self.return_value = "return_value"
345
346 # For return converters: the code to convert the return
347 # value from the parse function. This is also where
348 # you should check the _return_value for errors, and
349 # "goto exit" if there are any.
350 self.return_conversion = []
351
352 # The C statements required to clean up after the impl call.
353 self.cleanup = []
354
355
Larry Hastings581ee362014-01-28 05:00:08 -0800356class FormatCounterFormatter(string.Formatter):
357 """
358 This counts how many instances of each formatter
359 "replacement string" appear in the format string.
360
361 e.g. after evaluating "string {a}, {b}, {c}, {a}"
362 the counts dict would now look like
363 {'a': 2, 'b': 1, 'c': 1}
364 """
365 def __init__(self):
366 self.counts = collections.Counter()
367
368 def get_value(self, key, args, kwargs):
369 self.counts[key] += 1
370 return ''
371
Larry Hastings31826802013-10-19 00:09:25 -0700372class Language(metaclass=abc.ABCMeta):
373
374 start_line = ""
375 body_prefix = ""
376 stop_line = ""
377 checksum_line = ""
378
Larry Hastings7726ac92014-01-31 22:03:12 -0800379 def __init__(self, filename):
380 pass
381
Larry Hastings31826802013-10-19 00:09:25 -0700382 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800383 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700384 pass
385
Larry Hastings7726ac92014-01-31 22:03:12 -0800386 def parse_line(self, line):
387 pass
388
Larry Hastings31826802013-10-19 00:09:25 -0700389 def validate(self):
Larry Hastings581ee362014-01-28 05:00:08 -0800390 def assert_only_one(attr, *additional_fields):
391 """
392 Ensures that the string found at getattr(self, attr)
393 contains exactly one formatter replacement string for
394 each valid field. The list of valid fields is
395 ['dsl_name'] extended by additional_fields.
396
397 e.g.
398 self.fmt = "{dsl_name} {a} {b}"
399
400 # this passes
401 self.assert_only_one('fmt', 'a', 'b')
402
403 # this fails, the format string has a {b} in it
404 self.assert_only_one('fmt', 'a')
405
406 # this fails, the format string doesn't have a {c} in it
407 self.assert_only_one('fmt', 'a', 'b', 'c')
408
409 # this fails, the format string has two {a}s in it,
410 # it must contain exactly one
411 self.fmt2 = '{dsl_name} {a} {a}'
412 self.assert_only_one('fmt2', 'a')
413
414 """
415 fields = ['dsl_name']
416 fields.extend(additional_fields)
417 line = getattr(self, attr)
418 fcf = FormatCounterFormatter()
419 fcf.format(line)
420 def local_fail(should_be_there_but_isnt):
421 if should_be_there_but_isnt:
422 fail("{} {} must contain {{{}}} exactly once!".format(
423 self.__class__.__name__, attr, name))
424 else:
425 fail("{} {} must not contain {{{}}}!".format(
426 self.__class__.__name__, attr, name))
427
428 for name, count in fcf.counts.items():
429 if name in fields:
430 if count > 1:
431 local_fail(True)
432 else:
433 local_fail(False)
434 for name in fields:
435 if fcf.counts.get(name) != 1:
436 local_fail(True)
437
Larry Hastings31826802013-10-19 00:09:25 -0700438 assert_only_one('start_line')
439 assert_only_one('stop_line')
Larry Hastings31826802013-10-19 00:09:25 -0700440
Larry Hastings581ee362014-01-28 05:00:08 -0800441 field = "arguments" if "{arguments}" in self.checksum_line else "checksum"
442 assert_only_one('checksum_line', field)
Larry Hastings31826802013-10-19 00:09:25 -0700443
444
445
446class PythonLanguage(Language):
447
448 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800449 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700450 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800451 stop_line = "#[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800452 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700453
454
455def permute_left_option_groups(l):
456 """
457 Given [1, 2, 3], should yield:
458 ()
459 (3,)
460 (2, 3)
461 (1, 2, 3)
462 """
463 yield tuple()
464 accumulator = []
465 for group in reversed(l):
466 accumulator = list(group) + accumulator
467 yield tuple(accumulator)
468
469
470def permute_right_option_groups(l):
471 """
472 Given [1, 2, 3], should yield:
473 ()
474 (1,)
475 (1, 2)
476 (1, 2, 3)
477 """
478 yield tuple()
479 accumulator = []
480 for group in l:
481 accumulator.extend(group)
482 yield tuple(accumulator)
483
484
485def permute_optional_groups(left, required, right):
486 """
487 Generator function that computes the set of acceptable
488 argument lists for the provided iterables of
489 argument groups. (Actually it generates a tuple of tuples.)
490
491 Algorithm: prefer left options over right options.
492
493 If required is empty, left must also be empty.
494 """
495 required = tuple(required)
496 result = []
497
498 if not required:
499 assert not left
500
501 accumulator = []
502 counts = set()
503 for r in permute_right_option_groups(right):
504 for l in permute_left_option_groups(left):
505 t = l + required + r
506 if len(t) in counts:
507 continue
508 counts.add(len(t))
509 accumulator.append(t)
510
511 accumulator.sort(key=len)
512 return tuple(accumulator)
513
514
Larry Hastings7726ac92014-01-31 22:03:12 -0800515def strip_leading_and_trailing_blank_lines(s):
516 lines = s.rstrip().split('\n')
517 while lines:
518 line = lines[0]
519 if line.strip():
520 break
521 del lines[0]
522 return '\n'.join(lines)
523
524@functools.lru_cache()
525def normalize_snippet(s, *, indent=0):
526 """
527 Reformats s:
528 * removes leading and trailing blank lines
529 * ensures that it does not end with a newline
530 * dedents so the first nonwhite character on any line is at column "indent"
531 """
532 s = strip_leading_and_trailing_blank_lines(s)
533 s = textwrap.dedent(s)
534 if indent:
535 s = textwrap.indent(s, ' ' * indent)
536 return s
537
538
Larry Hastings89964c42015-04-14 18:07:59 -0400539def wrap_declarations(text, length=78):
540 """
541 A simple-minded text wrapper for C function declarations.
542
543 It views a declaration line as looking like this:
544 xxxxxxxx(xxxxxxxxx,xxxxxxxxx)
545 If called with length=30, it would wrap that line into
546 xxxxxxxx(xxxxxxxxx,
547 xxxxxxxxx)
548 (If the declaration has zero or one parameters, this
549 function won't wrap it.)
550
551 If this doesn't work properly, it's probably better to
552 start from scratch with a more sophisticated algorithm,
553 rather than try and improve/debug this dumb little function.
554 """
555 lines = []
556 for line in text.split('\n'):
557 prefix, _, after_l_paren = line.partition('(')
558 if not after_l_paren:
559 lines.append(line)
560 continue
561 parameters, _, after_r_paren = after_l_paren.partition(')')
562 if not _:
563 lines.append(line)
564 continue
565 if ',' not in parameters:
566 lines.append(line)
567 continue
568 parameters = [x.strip() + ", " for x in parameters.split(',')]
569 prefix += "("
570 if len(prefix) < length:
571 spaces = " " * len(prefix)
572 else:
573 spaces = " " * 4
574
575 while parameters:
576 line = prefix
577 first = True
578 while parameters:
579 if (not first and
580 (len(line) + len(parameters[0]) > length)):
581 break
582 line += parameters.pop(0)
583 first = False
584 if not parameters:
585 line = line.rstrip(", ") + ")" + after_r_paren
586 lines.append(line.rstrip())
587 prefix = spaces
588 return "\n".join(lines)
589
590
Larry Hastings31826802013-10-19 00:09:25 -0700591class CLanguage(Language):
592
Larry Hastings61272b72014-01-07 12:41:53 -0800593 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700594 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800595 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700596 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800597 stop_line = "[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800598 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700599
Larry Hastings7726ac92014-01-31 22:03:12 -0800600 def __init__(self, filename):
601 super().__init__(filename)
602 self.cpp = cpp.Monitor(filename)
603 self.cpp.fail = fail
604
605 def parse_line(self, line):
606 self.cpp.writeline(line)
607
Larry Hastingsbebf7352014-01-17 17:47:17 -0800608 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700609 function = None
610 for o in signatures:
611 if isinstance(o, Function):
612 if function:
613 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
614 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800615 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700616
617 def docstring_for_c_string(self, f):
animalize463572c2019-02-25 07:18:48 +0800618 if re.search(r'[^\x00-\x7F]', f.docstring):
619 warn("Non-ascii character appear in docstring.")
620
Larry Hastings31826802013-10-19 00:09:25 -0700621 text, add, output = _text_accumulator()
622 # turn docstring into a properly quoted C string
623 for line in f.docstring.split('\n'):
624 add('"')
625 add(quoted_for_c_string(line))
626 add('\\n"\n')
627
Zachary Ware8ef887c2015-04-13 18:22:35 -0500628 if text[-2] == sig_end_marker:
629 # If we only have a signature, add the blank line that the
630 # __text_signature__ getter expects to be there.
631 add('"\\n"')
632 else:
633 text.pop()
634 add('"')
Larry Hastings31826802013-10-19 00:09:25 -0700635 return ''.join(text)
636
Larry Hastingsbebf7352014-01-17 17:47:17 -0800637 def output_templates(self, f):
638 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800639 assert parameters
640 assert isinstance(parameters[0].converter, self_converter)
641 del parameters[0]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800642 converters = [p.converter for p in parameters]
643
644 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
645 default_return_converter = (not f.return_converter or
646 f.return_converter.type == 'PyObject *')
647
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300648 positional = parameters and parameters[-1].is_positional_only()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800649
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800650 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
651
Larry Hastingsbebf7352014-01-17 17:47:17 -0800652 meth_o = (len(parameters) == 1 and
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300653 parameters[0].is_positional_only() and
Larry Hastingsbebf7352014-01-17 17:47:17 -0800654 not converters[0].is_optional() and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800655 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800656
Larry Hastings7726ac92014-01-31 22:03:12 -0800657 # we have to set these things before we're done:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800658 #
659 # docstring_prototype
660 # docstring_definition
661 # impl_prototype
662 # methoddef_define
663 # parser_prototype
664 # parser_definition
665 # impl_definition
Larry Hastings7726ac92014-01-31 22:03:12 -0800666 # cpp_if
667 # cpp_endif
668 # methoddef_ifndef
Larry Hastingsbebf7352014-01-17 17:47:17 -0800669
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800670 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700671
Larry Hastings7726ac92014-01-31 22:03:12 -0800672 methoddef_define = normalize_snippet("""
673 #define {methoddef_name} \\
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200674 {{"{name}", {methoddef_cast}{c_basename}, {methoddef_flags}, {c_basename}__doc__}},
Larry Hastings7726ac92014-01-31 22:03:12 -0800675 """)
Larry Hastings5c661892014-01-24 06:17:25 -0800676 if new_or_init and not f.docstring:
677 docstring_prototype = docstring_definition = ''
678 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800679 docstring_prototype = normalize_snippet("""
680 PyDoc_VAR({c_basename}__doc__);
681 """)
682 docstring_definition = normalize_snippet("""
683 PyDoc_STRVAR({c_basename}__doc__,
684 {docstring});
685 """)
686 impl_definition = normalize_snippet("""
687 static {impl_return_type}
688 {c_basename}_impl({impl_parameters})
689 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800690 impl_prototype = parser_prototype = parser_definition = None
691
Larry Hastings7726ac92014-01-31 22:03:12 -0800692 parser_prototype_keyword = normalize_snippet("""
693 static PyObject *
694 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
695 """)
696
697 parser_prototype_varargs = normalize_snippet("""
698 static PyObject *
699 {c_basename}({self_type}{self_name}, PyObject *args)
700 """)
701
Victor Stinner0c8c3892017-01-17 01:42:54 +0100702 parser_prototype_fastcall = normalize_snippet("""
703 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200704 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300705 """)
706
707 parser_prototype_fastcall_keywords = normalize_snippet("""
708 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200709 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
Victor Stinner0c8c3892017-01-17 01:42:54 +0100710 """)
711
Larry Hastings7726ac92014-01-31 22:03:12 -0800712 # parser_body_fields remembers the fields passed in to the
713 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800714 parser_body_fields = ()
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800715 def parser_body(prototype, *fields):
716 nonlocal parser_body_fields
717 add, output = text_accumulator()
718 add(prototype)
719 parser_body_fields = fields
Larry Hastings7726ac92014-01-31 22:03:12 -0800720
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800721 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800722 fields.insert(0, normalize_snippet("""
723 {{
724 {return_value_declaration}
725 {declarations}
726 {initializers}
727 """) + "\n")
728 # just imagine--your code is here in the middle
729 fields.append(normalize_snippet("""
730 {modifications}
731 {return_value} = {c_basename}_impl({impl_arguments});
732 {return_conversion}
733
734 {exit_label}
735 {cleanup}
736 return return_value;
737 }}
738 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800739 for field in fields:
740 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800741 add(field)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800742 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800743
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800744 def insert_keywords(s):
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300745 return linear_format(s, declarations=
746 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
747 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};\n'
748 '{declarations}')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800749
750 if not parameters:
751 # no parameters, METH_NOARGS
752
753 flags = "METH_NOARGS"
754
Larry Hastings7726ac92014-01-31 22:03:12 -0800755 parser_prototype = normalize_snippet("""
756 static PyObject *
757 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
758 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800759 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800760
761 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800762 parser_definition = parser_prototype + '\n' + normalize_snippet("""
763 {{
764 return {c_basename}_impl({impl_arguments});
765 }}
766 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800767 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800768 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700769
Larry Hastingsbebf7352014-01-17 17:47:17 -0800770 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800771 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800772
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300773 if (isinstance(converters[0], object_converter) and
774 converters[0].format_unit == 'O'):
775 meth_o_prototype = normalize_snippet("""
776 static PyObject *
777 {c_basename}({impl_parameters})
778 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800779
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300780 if default_return_converter:
781 # maps perfectly to METH_O, doesn't need a return converter.
782 # so we skip making a parse function
783 # and call directly into the impl function.
784 impl_prototype = parser_prototype = parser_definition = ''
785 impl_definition = meth_o_prototype
786 else:
787 # SLIGHT HACK
788 # use impl_parameters for the parser here!
789 parser_prototype = meth_o_prototype
790 parser_definition = parser_body(parser_prototype)
791
Larry Hastingsbebf7352014-01-17 17:47:17 -0800792 else:
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300793 argname = 'arg'
794 if parameters[0].name == argname:
795 argname += '_'
796 parser_prototype = normalize_snippet("""
797 static PyObject *
798 {c_basename}({self_type}{self_name}, PyObject *%s)
799 """ % argname)
800
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200801 parsearg = converters[0].parse_arg(argname, 0)
802 if parsearg is None:
803 parsearg = """
804 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
805 goto exit;
806 }}
807 """ % argname
Serhiy Storchaka32d96a22018-12-25 13:23:47 +0200808 parser_definition = parser_body(parser_prototype,
809 normalize_snippet(parsearg, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700810
Larry Hastingsbebf7352014-01-17 17:47:17 -0800811 elif has_option_groups:
812 # positional parameters with option groups
813 # (we have to generate lots of PyArg_ParseTuple calls
814 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700815
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800816 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800817 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700818
Larry Hastings7726ac92014-01-31 22:03:12 -0800819 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700820
Larry Hastingsbebf7352014-01-17 17:47:17 -0800821 elif positional:
Victor Stinner0c8c3892017-01-17 01:42:54 +0100822 if not new_or_init:
823 # positional-only, but no option groups
824 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800825
Victor Stinner0c8c3892017-01-17 01:42:54 +0100826 flags = "METH_FASTCALL"
827 parser_prototype = parser_prototype_fastcall
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200828 nargs = 'nargs'
829 argname_fmt = 'args[%d]'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100830 else:
831 # positional-only, but no option groups
832 # we only need one call to PyArg_ParseTuple
833
834 flags = "METH_VARARGS"
835 parser_prototype = parser_prototype_varargs
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200836 nargs = 'PyTuple_GET_SIZE(args)'
837 argname_fmt = 'PyTuple_GET_ITEM(args, %d)'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100838
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200839 parser_code = []
840 has_optional = False
841 for i, converter in enumerate(converters):
842 parsearg = converter.parse_arg(argname_fmt % i, i + 1)
843 if parsearg is None:
844 #print('Cannot convert %s %r for %s' % (converter.__class__.__name__, converter.format_unit, converter.name), file=sys.stderr)
845 parser_code = None
846 break
847 if has_optional or converter.default is not unspecified:
848 has_optional = True
849 parser_code.append(normalize_snippet("""
850 if (%s < %d) {{
851 goto skip_optional;
852 }}
853 """, indent=4) % (nargs, i + 1))
854 parser_code.append(normalize_snippet(parsearg, indent=4))
855
856 if parser_code is not None:
857 parser_code.insert(0, normalize_snippet("""
858 if (!_PyArg_CheckPositional("{name}", %s, {unpack_min}, {unpack_max})) {{
Victor Stinner0c8c3892017-01-17 01:42:54 +0100859 goto exit;
860 }}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200861 """ % nargs, indent=4))
862 if has_optional:
863 parser_code.append("skip_optional:")
864 else:
865 if not new_or_init:
866 parser_code = [normalize_snippet("""
867 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
868 {parse_arguments})) {{
869 goto exit;
870 }}
871 """, indent=4)]
872 else:
873 parser_code = [normalize_snippet("""
874 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
875 {parse_arguments})) {{
876 goto exit;
877 }}
878 """, indent=4)]
879 parser_definition = parser_body(parser_prototype, *parser_code)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800880
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700881 elif not new_or_init:
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300882 flags = "METH_FASTCALL|METH_KEYWORDS"
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700883
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300884 parser_prototype = parser_prototype_fastcall_keywords
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700885
886 body = normalize_snippet("""
Victor Stinner3e1fad62017-01-17 01:29:01 +0100887 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700888 {parse_arguments})) {{
889 goto exit;
890 }}
891 """, indent=4)
892 parser_definition = parser_body(parser_prototype, body)
893 parser_definition = insert_keywords(parser_definition)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800894 else:
895 # positional-or-keyword arguments
896 flags = "METH_VARARGS|METH_KEYWORDS"
897
Larry Hastings7726ac92014-01-31 22:03:12 -0800898 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800899
Larry Hastings7726ac92014-01-31 22:03:12 -0800900 body = normalize_snippet("""
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300901 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300902 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800903 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300904 }}
905 """, indent=4)
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300906 parser_definition = parser_body(parser_prototype, body)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800907 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700908
Larry Hastings31826802013-10-19 00:09:25 -0700909
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800910 if new_or_init:
911 methoddef_define = ''
912
913 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800914 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800915 else:
916 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800917 parser_prototype = normalize_snippet("""
918 static int
919 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
920 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800921
922 fields = list(parser_body_fields)
923 parses_positional = 'METH_NOARGS' not in flags
924 parses_keywords = 'METH_KEYWORDS' in flags
925 if parses_keywords:
926 assert parses_positional
927
928 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800929 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300930 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800931 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300932 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800933 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800934 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800935 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300936 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800937 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300938 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800939 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800940
941 parser_definition = parser_body(parser_prototype, *fields)
942 if parses_keywords:
943 parser_definition = insert_keywords(parser_definition)
944
Larry Hastings31826802013-10-19 00:09:25 -0700945
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200946 if flags in ('METH_NOARGS', 'METH_O', 'METH_VARARGS'):
947 methoddef_cast = "(PyCFunction)"
948 else:
949 methoddef_cast = "(PyCFunction)(void(*)(void))"
950
Larry Hastingsbebf7352014-01-17 17:47:17 -0800951 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800952 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700953
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800954 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200955 methoddef_define = methoddef_define.replace('{methoddef_cast}', methoddef_cast)
Larry Hastings31826802013-10-19 00:09:25 -0700956
Larry Hastings7726ac92014-01-31 22:03:12 -0800957 methoddef_ifndef = ''
958 conditional = self.cpp.condition()
959 if not conditional:
960 cpp_if = cpp_endif = ''
961 else:
962 cpp_if = "#if " + conditional
963 cpp_endif = "#endif /* " + conditional + " */"
964
Tal Einat4f574092017-11-03 11:09:00 +0200965 if methoddef_define and f.full_name not in clinic.ifndef_symbols:
966 clinic.ifndef_symbols.add(f.full_name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800967 methoddef_ifndef = normalize_snippet("""
968 #ifndef {methoddef_name}
969 #define {methoddef_name}
970 #endif /* !defined({methoddef_name}) */
971 """)
972
973
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800974 # add ';' to the end of parser_prototype and impl_prototype
975 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800976 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800977 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800978 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800979 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700980
Larry Hastingsbebf7352014-01-17 17:47:17 -0800981 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800982 impl_prototype = impl_definition
983 if impl_prototype:
984 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700985
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800986 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800987
988 d = {
989 "docstring_prototype" : docstring_prototype,
990 "docstring_definition" : docstring_definition,
991 "impl_prototype" : impl_prototype,
992 "methoddef_define" : methoddef_define,
993 "parser_prototype" : parser_prototype,
994 "parser_definition" : parser_definition,
995 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800996 "cpp_if" : cpp_if,
997 "cpp_endif" : cpp_endif,
998 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800999 }
1000
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001001 # make sure we didn't forget to assign something,
1002 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001003 d2 = {}
1004 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001005 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001006 if value:
1007 value = '\n' + value + '\n'
1008 d2[name] = value
1009 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001010
1011 @staticmethod
1012 def group_to_variable_name(group):
1013 adjective = "left_" if group < 0 else "right_"
1014 return "group_" + adjective + str(abs(group))
1015
1016 def render_option_group_parsing(self, f, template_dict):
1017 # positional only, grouped, optional arguments!
1018 # can be optional on the left or right.
1019 # here's an example:
1020 #
1021 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1022 #
1023 # Here group D are required, and all other groups are optional.
1024 # (Group D's "group" is actually None.)
1025 # We can figure out which sets of arguments we have based on
1026 # how many arguments are in the tuple.
1027 #
1028 # Note that you need to count up on both sides. For example,
1029 # you could have groups C+D, or C+D+E, or C+D+E+F.
1030 #
1031 # What if the number of arguments leads us to an ambiguous result?
1032 # Clinic prefers groups on the left. So in the above example,
1033 # five arguments would map to B+C, not C+D.
1034
1035 add, output = text_accumulator()
1036 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001037 if isinstance(parameters[0].converter, self_converter):
1038 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001039
1040 groups = []
1041 group = None
1042 left = []
1043 right = []
1044 required = []
1045 last = unspecified
1046
1047 for p in parameters:
1048 group_id = p.group
1049 if group_id != last:
1050 last = group_id
1051 group = []
1052 if group_id < 0:
1053 left.append(group)
1054 elif group_id == 0:
1055 group = required
1056 else:
1057 right.append(group)
1058 group.append(p)
1059
1060 count_min = sys.maxsize
1061 count_max = -1
1062
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001063 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001064 for subset in permute_optional_groups(left, required, right):
1065 count = len(subset)
1066 count_min = min(count_min, count)
1067 count_max = max(count_max, count)
1068
Larry Hastings583baa82014-01-12 08:49:30 -08001069 if count == 0:
1070 add(""" case 0:
1071 break;
1072""")
1073 continue
1074
Larry Hastings31826802013-10-19 00:09:25 -07001075 group_ids = {p.group for p in subset} # eliminate duplicates
1076 d = {}
1077 d['count'] = count
1078 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001079 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1080
1081 parse_arguments = []
1082 for p in subset:
1083 p.converter.parse_argument(parse_arguments)
1084 d['parse_arguments'] = ", ".join(parse_arguments)
1085
1086 group_ids.discard(0)
1087 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1088 lines = "\n".join(lines)
1089
1090 s = """
1091 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001092 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001093 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001094 }}
Larry Hastings31826802013-10-19 00:09:25 -07001095 {group_booleans}
1096 break;
1097"""[1:]
1098 s = linear_format(s, group_booleans=lines)
1099 s = s.format_map(d)
1100 add(s)
1101
1102 add(" default:\n")
1103 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1104 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001105 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001106 add("}")
1107 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001108
Larry Hastingsbebf7352014-01-17 17:47:17 -08001109 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001110 if not f:
1111 return ""
1112
1113 add, output = text_accumulator()
1114 data = CRenderData()
1115
Larry Hastings7726ac92014-01-31 22:03:12 -08001116 assert f.parameters, "We should always have a 'self' at this point!"
1117 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001118 converters = [p.converter for p in parameters]
1119
Larry Hastings5c661892014-01-24 06:17:25 -08001120 templates = self.output_templates(f)
1121
1122 f_self = parameters[0]
1123 selfless = parameters[1:]
1124 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1125
1126 last_group = 0
1127 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001128 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001129 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1130 default_return_converter = (not f.return_converter or
1131 f.return_converter.type == 'PyObject *')
1132 has_option_groups = False
1133
1134 # offset i by -1 because first_optional needs to ignore self
1135 for i, p in enumerate(parameters, -1):
1136 c = p.converter
1137
1138 if (i != -1) and (p.default is not unspecified):
1139 first_optional = min(first_optional, i)
1140
1141 # insert group variable
1142 group = p.group
1143 if last_group != group:
1144 last_group = group
1145 if group:
1146 group_name = self.group_to_variable_name(group)
1147 data.impl_arguments.append(group_name)
1148 data.declarations.append("int " + group_name + " = 0;")
1149 data.impl_parameters.append("int " + group_name)
1150 has_option_groups = True
1151
1152 c.render(p, data)
1153
1154 if has_option_groups and (not positional):
1155 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1156
1157 # HACK
1158 # when we're METH_O, but have a custom return converter,
1159 # we use "impl_parameters" for the parsing function
1160 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001161 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001162 # as variables in the parsing function. but since it's
1163 # METH_O, we have exactly one anyway, so we know exactly
1164 # where it is.
1165 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001166 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001167 data.declarations.pop(0)
1168
Larry Hastings31826802013-10-19 00:09:25 -07001169 template_dict = {}
1170
1171 full_name = f.full_name
1172 template_dict['full_name'] = full_name
1173
Larry Hastings5c661892014-01-24 06:17:25 -08001174 if new_or_init:
1175 name = f.cls.name
1176 else:
1177 name = f.name
1178
Larry Hastings31826802013-10-19 00:09:25 -07001179 template_dict['name'] = name
1180
Larry Hastings8666e652014-01-12 14:12:59 -08001181 if f.c_basename:
1182 c_basename = f.c_basename
1183 else:
1184 fields = full_name.split(".")
1185 if fields[-1] == '__new__':
1186 fields.pop()
1187 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001188
Larry Hastings31826802013-10-19 00:09:25 -07001189 template_dict['c_basename'] = c_basename
1190
1191 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1192 template_dict['methoddef_name'] = methoddef_name
1193
1194 template_dict['docstring'] = self.docstring_for_c_string(f)
1195
Larry Hastingsc2047262014-01-25 20:43:29 -08001196 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001197 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001198
Larry Hastings31826802013-10-19 00:09:25 -07001199 f.return_converter.render(f, data)
1200 template_dict['impl_return_type'] = f.return_converter.type
1201
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001202 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001203 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001204 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001205 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1206 template_dict['format_units'] = ''.join(data.format_units)
1207 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1208 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1209 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001210 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1211 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001212 template_dict['return_value'] = data.return_value
1213
Larry Hastings5c661892014-01-24 06:17:25 -08001214 # used by unpack tuple code generator
1215 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1216 unpack_min = first_optional
1217 unpack_max = len(selfless)
1218 template_dict['unpack_min'] = str(unpack_min)
1219 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001220
Larry Hastingsbebf7352014-01-17 17:47:17 -08001221 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001222 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001223
Larry Hastings0759f842015-04-03 13:09:02 -07001224 # buffers, not destination
1225 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001226 template = templates[name]
1227 if has_option_groups:
1228 template = linear_format(template,
1229 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001230 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001231 declarations=template_dict['declarations'],
1232 return_conversion=template_dict['return_conversion'],
1233 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001234 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001235 cleanup=template_dict['cleanup'],
1236 )
Larry Hastings31826802013-10-19 00:09:25 -07001237
Larry Hastingsbebf7352014-01-17 17:47:17 -08001238 # Only generate the "exit:" label
1239 # if we have any gotos
1240 need_exit_label = "goto exit;" in template
1241 template = linear_format(template,
1242 exit_label="exit:" if need_exit_label else ''
1243 )
Larry Hastings31826802013-10-19 00:09:25 -07001244
Larry Hastingsbebf7352014-01-17 17:47:17 -08001245 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001246
Larry Hastings89964c42015-04-14 18:07:59 -04001247 # mild hack:
1248 # reflow long impl declarations
1249 if name in {"impl_prototype", "impl_definition"}:
1250 s = wrap_declarations(s)
1251
Larry Hastingsbebf7352014-01-17 17:47:17 -08001252 if clinic.line_prefix:
1253 s = indent_all_lines(s, clinic.line_prefix)
1254 if clinic.line_suffix:
1255 s = suffix_all_lines(s, clinic.line_suffix)
1256
1257 destination.append(s)
1258
1259 return clinic.get_destination('block').dump()
1260
Larry Hastings31826802013-10-19 00:09:25 -07001261
1262
Larry Hastings5c661892014-01-24 06:17:25 -08001263
Larry Hastings31826802013-10-19 00:09:25 -07001264@contextlib.contextmanager
1265def OverrideStdioWith(stdout):
1266 saved_stdout = sys.stdout
1267 sys.stdout = stdout
1268 try:
1269 yield
1270 finally:
1271 assert sys.stdout is stdout
1272 sys.stdout = saved_stdout
1273
1274
Larry Hastings2623c8c2014-02-08 22:15:29 -08001275def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001276 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001277 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001278 pattern = r'{}({}){}'
1279 if whole_line:
1280 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001281 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1282 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001283
1284
1285class Block:
1286 r"""
1287 Represents a single block of text embedded in
1288 another file. If dsl_name is None, the block represents
1289 verbatim text, raw original text from the file, in
1290 which case "input" will be the only non-false member.
1291 If dsl_name is not None, the block represents a Clinic
1292 block.
1293
1294 input is always str, with embedded \n characters.
1295 input represents the original text from the file;
1296 if it's a Clinic block, it is the original text with
1297 the body_prefix and redundant leading whitespace removed.
1298
1299 dsl_name is either str or None. If str, it's the text
1300 found on the start line of the block between the square
1301 brackets.
1302
1303 signatures is either list or None. If it's a list,
1304 it may only contain clinic.Module, clinic.Class, and
1305 clinic.Function objects. At the moment it should
1306 contain at most one of each.
1307
1308 output is either str or None. If str, it's the output
1309 from this block, with embedded '\n' characters.
1310
1311 indent is either str or None. It's the leading whitespace
1312 that was found on every line of input. (If body_prefix is
1313 not empty, this is the indent *after* removing the
1314 body_prefix.)
1315
1316 preindent is either str or None. It's the whitespace that
1317 was found in front of every line of input *before* the
1318 "body_prefix" (see the Language object). If body_prefix
1319 is empty, preindent must always be empty too.
1320
1321 To illustrate indent and preindent: Assume that '_'
1322 represents whitespace. If the block processed was in a
1323 Python file, and looked like this:
1324 ____#/*[python]
1325 ____#__for a in range(20):
1326 ____#____print(a)
1327 ____#[python]*/
1328 "preindent" would be "____" and "indent" would be "__".
1329
1330 """
1331 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1332 assert isinstance(input, str)
1333 self.input = input
1334 self.dsl_name = dsl_name
1335 self.signatures = signatures or []
1336 self.output = output
1337 self.indent = indent
1338 self.preindent = preindent
1339
Larry Hastings581ee362014-01-28 05:00:08 -08001340 def __repr__(self):
1341 dsl_name = self.dsl_name or "text"
1342 def summarize(s):
1343 s = repr(s)
1344 if len(s) > 30:
1345 return s[:26] + "..." + s[0]
1346 return s
1347 return "".join((
1348 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1349
Larry Hastings31826802013-10-19 00:09:25 -07001350
1351class BlockParser:
1352 """
1353 Block-oriented parser for Argument Clinic.
1354 Iterator, yields Block objects.
1355 """
1356
1357 def __init__(self, input, language, *, verify=True):
1358 """
1359 "input" should be a str object
1360 with embedded \n characters.
1361
1362 "language" should be a Language object.
1363 """
1364 language.validate()
1365
1366 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1367 self.block_start_line_number = self.line_number = 0
1368
1369 self.language = language
1370 before, _, after = language.start_line.partition('{dsl_name}')
1371 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001372 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001373 self.start_re = create_regex(before, after)
1374 self.verify = verify
1375 self.last_checksum_re = None
1376 self.last_dsl_name = None
1377 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001378 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001379
1380 def __iter__(self):
1381 return self
1382
1383 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001384 while True:
1385 if not self.input:
1386 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001387
Larry Hastingsbebf7352014-01-17 17:47:17 -08001388 if self.dsl_name:
1389 return_value = self.parse_clinic_block(self.dsl_name)
1390 self.dsl_name = None
1391 self.first_block = False
1392 return return_value
1393 block = self.parse_verbatim_block()
1394 if self.first_block and not block.input:
1395 continue
1396 self.first_block = False
1397 return block
1398
Larry Hastings31826802013-10-19 00:09:25 -07001399
1400 def is_start_line(self, line):
1401 match = self.start_re.match(line.lstrip())
1402 return match.group(1) if match else None
1403
Larry Hastingse1b82532014-07-27 16:22:20 +02001404 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001405 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001406 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001407 if not lookahead:
1408 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001409 return line
Larry Hastings31826802013-10-19 00:09:25 -07001410
1411 def parse_verbatim_block(self):
1412 add, output = text_accumulator()
1413 self.block_start_line_number = self.line_number
1414
1415 while self.input:
1416 line = self._line()
1417 dsl_name = self.is_start_line(line)
1418 if dsl_name:
1419 self.dsl_name = dsl_name
1420 break
1421 add(line)
1422
1423 return Block(output())
1424
1425 def parse_clinic_block(self, dsl_name):
1426 input_add, input_output = text_accumulator()
1427 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001428 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001429 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1430
Larry Hastings90261132014-01-07 12:21:08 -08001431 def is_stop_line(line):
1432 # make sure to recognize stop line even if it
1433 # doesn't end with EOL (it could be the very end of the file)
1434 if not line.startswith(stop_line):
1435 return False
1436 remainder = line[len(stop_line):]
1437 return (not remainder) or remainder.isspace()
1438
Larry Hastings31826802013-10-19 00:09:25 -07001439 # consume body of program
1440 while self.input:
1441 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001442 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001443 break
1444 if body_prefix:
1445 line = line.lstrip()
1446 assert line.startswith(body_prefix)
1447 line = line[len(body_prefix):]
1448 input_add(line)
1449
1450 # consume output and checksum line, if present.
1451 if self.last_dsl_name == dsl_name:
1452 checksum_re = self.last_checksum_re
1453 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001454 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1455 assert _ == '{arguments}'
1456 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001457 self.last_dsl_name = dsl_name
1458 self.last_checksum_re = checksum_re
1459
1460 # scan forward for checksum line
1461 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001462 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001463 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001464 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001465 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001466 arguments = match.group(1) if match else None
1467 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001468 break
1469 output_add(line)
1470 if self.is_start_line(line):
1471 break
1472
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001473 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001474 if arguments:
1475 d = {}
1476 for field in shlex.split(arguments):
1477 name, equals, value = field.partition('=')
1478 if not equals:
1479 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1480 d[name.strip()] = value.strip()
1481
Larry Hastings31826802013-10-19 00:09:25 -07001482 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001483 if 'input' in d:
1484 checksum = d['output']
1485 input_checksum = d['input']
1486 else:
1487 checksum = d['checksum']
1488 input_checksum = None
1489
1490 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001491 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001492 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1493 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001494 "the end marker,\n"
1495 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001496 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001497 else:
1498 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001499 output_lines = output.splitlines(keepends=True)
1500 self.line_number -= len(output_lines)
1501 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001502 output = None
1503
1504 return Block(input_output(), dsl_name, output=output)
1505
1506
1507class BlockPrinter:
1508
1509 def __init__(self, language, f=None):
1510 self.language = language
1511 self.f = f or io.StringIO()
1512
1513 def print_block(self, block):
1514 input = block.input
1515 output = block.output
1516 dsl_name = block.dsl_name
1517 write = self.f.write
1518
Larry Hastings31826802013-10-19 00:09:25 -07001519 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1520
1521 if not dsl_name:
1522 write(input)
1523 return
1524
1525 write(self.language.start_line.format(dsl_name=dsl_name))
1526 write("\n")
1527
1528 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1529 if not body_prefix:
1530 write(input)
1531 else:
1532 for line in input.split('\n'):
1533 write(body_prefix)
1534 write(line)
1535 write("\n")
1536
1537 write(self.language.stop_line.format(dsl_name=dsl_name))
1538 write("\n")
1539
Larry Hastings581ee362014-01-28 05:00:08 -08001540 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001541 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001542 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001543 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001544 output += '\n'
1545 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001546
Larry Hastings581ee362014-01-28 05:00:08 -08001547 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1548 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001549 write("\n")
1550
Larry Hastingsbebf7352014-01-17 17:47:17 -08001551 def write(self, text):
1552 self.f.write(text)
1553
1554
Larry Hastings0759f842015-04-03 13:09:02 -07001555class BufferSeries:
1556 """
1557 Behaves like a "defaultlist".
1558 When you ask for an index that doesn't exist yet,
1559 the object grows the list until that item exists.
1560 So o[n] will always work.
1561
1562 Supports negative indices for actual items.
1563 e.g. o[-1] is an element immediately preceding o[0].
1564 """
1565
1566 def __init__(self):
1567 self._start = 0
1568 self._array = []
1569 self._constructor = _text_accumulator
1570
1571 def __getitem__(self, i):
1572 i -= self._start
1573 if i < 0:
1574 self._start += i
1575 prefix = [self._constructor() for x in range(-i)]
1576 self._array = prefix + self._array
1577 i = 0
1578 while i >= len(self._array):
1579 self._array.append(self._constructor())
1580 return self._array[i]
1581
1582 def clear(self):
1583 for ta in self._array:
1584 ta._text.clear()
1585
1586 def dump(self):
1587 texts = [ta.output() for ta in self._array]
1588 return "".join(texts)
1589
1590
Larry Hastingsbebf7352014-01-17 17:47:17 -08001591class Destination:
1592 def __init__(self, name, type, clinic, *args):
1593 self.name = name
1594 self.type = type
1595 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001596 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001597 if type not in valid_types:
1598 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1599 extra_arguments = 1 if type == "file" else 0
1600 if len(args) < extra_arguments:
1601 fail("Not enough arguments for destination " + name + " new " + type)
1602 if len(args) > extra_arguments:
1603 fail("Too many arguments for destination " + name + " new " + type)
1604 if type =='file':
1605 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001606 filename = clinic.filename
1607 d['path'] = filename
1608 dirname, basename = os.path.split(filename)
1609 if not dirname:
1610 dirname = '.'
1611 d['dirname'] = dirname
1612 d['basename'] = basename
1613 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001614 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001615
Larry Hastings0759f842015-04-03 13:09:02 -07001616 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001617
1618 def __repr__(self):
1619 if self.type == 'file':
1620 file_repr = " " + repr(self.filename)
1621 else:
1622 file_repr = ''
1623 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1624
1625 def clear(self):
1626 if self.type != 'buffer':
1627 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001628 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001629
1630 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001631 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001632
Larry Hastings31826802013-10-19 00:09:25 -07001633
1634# maps strings to Language objects.
1635# "languages" maps the name of the language ("C", "Python").
1636# "extensions" maps the file extension ("c", "py").
1637languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001638extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1639extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001640
1641
1642# maps strings to callables.
1643# these callables must be of the form:
1644# def foo(name, default, *, ...)
1645# The callable may have any number of keyword-only parameters.
1646# The callable must return a CConverter object.
1647# The callable should not call builtins.print.
1648converters = {}
1649
1650# maps strings to callables.
1651# these callables follow the same rules as those for "converters" above.
1652# note however that they will never be called with keyword-only parameters.
1653legacy_converters = {}
1654
1655
1656# maps strings to callables.
1657# these callables must be of the form:
1658# def foo(*, ...)
1659# The callable may have any number of keyword-only parameters.
1660# The callable must return a CConverter object.
1661# The callable should not call builtins.print.
1662return_converters = {}
1663
Larry Hastings7726ac92014-01-31 22:03:12 -08001664clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001665class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001666
1667 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001668preset block
1669everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001670methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001671docstring_prototype suppress
1672parser_prototype suppress
1673cpp_if suppress
1674cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001675
Larry Hastingsbebf7352014-01-17 17:47:17 -08001676preset original
1677everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001678methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001679docstring_prototype suppress
1680parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001681cpp_if suppress
1682cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001683
1684preset file
1685everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001686methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001687docstring_prototype suppress
1688parser_prototype suppress
1689impl_definition block
1690
1691preset buffer
1692everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001693methoddef_ifndef buffer 1
1694impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001695docstring_prototype suppress
1696impl_prototype suppress
1697parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001698
1699preset partial-buffer
1700everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001701methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001702docstring_prototype block
1703impl_prototype suppress
1704methoddef_define block
1705parser_prototype block
1706impl_definition block
1707
Larry Hastingsbebf7352014-01-17 17:47:17 -08001708"""
1709
Larry Hastings581ee362014-01-28 05:00:08 -08001710 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001711 # maps strings to Parser objects.
1712 # (instantiated from the "parsers" global.)
1713 self.parsers = {}
1714 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001715 if printer:
1716 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001717 self.printer = printer or BlockPrinter(language)
1718 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001719 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001720 self.filename = filename
1721 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001722 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001723 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001724
Larry Hastingsbebf7352014-01-17 17:47:17 -08001725 self.line_prefix = self.line_suffix = ''
1726
1727 self.destinations = {}
1728 self.add_destination("block", "buffer")
1729 self.add_destination("suppress", "suppress")
1730 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001731 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001732 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001733
Larry Hastings0759f842015-04-03 13:09:02 -07001734 d = self.get_destination_buffer
1735 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001736 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001737 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001738 ('docstring_definition', d('file')),
1739 ('methoddef_define', d('file')),
1740 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001741 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001742 ('parser_definition', d('file')),
1743 ('cpp_endif', d('file')),
1744 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001745 ('impl_definition', d('block')),
1746 ))
1747
Larry Hastings0759f842015-04-03 13:09:02 -07001748 self.destination_buffers_stack = []
1749 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001750
1751 self.presets = {}
1752 preset = None
1753 for line in self.presets_text.strip().split('\n'):
1754 line = line.strip()
1755 if not line:
1756 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001757 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001758 if name == 'preset':
1759 self.presets[value] = preset = collections.OrderedDict()
1760 continue
1761
Larry Hastings0759f842015-04-03 13:09:02 -07001762 if len(options):
1763 index = int(options[0])
1764 else:
1765 index = 0
1766 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001767
1768 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001769 for name in self.destination_buffers:
1770 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001771 continue
1772
Larry Hastings0759f842015-04-03 13:09:02 -07001773 assert name in self.destination_buffers
1774 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001775
Larry Hastings31826802013-10-19 00:09:25 -07001776 global clinic
1777 clinic = self
1778
Larry Hastingsbebf7352014-01-17 17:47:17 -08001779 def add_destination(self, name, type, *args):
1780 if name in self.destinations:
1781 fail("Destination already exists: " + repr(name))
1782 self.destinations[name] = Destination(name, type, self, *args)
1783
Larry Hastings0759f842015-04-03 13:09:02 -07001784 def get_destination(self, name):
1785 d = self.destinations.get(name)
1786 if not d:
1787 fail("Destination does not exist: " + repr(name))
1788 return d
1789
1790 def get_destination_buffer(self, name, item=0):
1791 d = self.get_destination(name)
1792 return d.buffers[item]
1793
Larry Hastings31826802013-10-19 00:09:25 -07001794 def parse(self, input):
1795 printer = self.printer
1796 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1797 for block in self.block_parser:
1798 dsl_name = block.dsl_name
1799 if dsl_name:
1800 if dsl_name not in self.parsers:
1801 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1802 self.parsers[dsl_name] = parsers[dsl_name](self)
1803 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001804 try:
1805 parser.parse(block)
1806 except Exception:
1807 fail('Exception raised during parsing:\n' +
1808 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001809 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001810
1811 second_pass_replacements = {}
1812
Larry Hastings0759f842015-04-03 13:09:02 -07001813 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001814 for name, destination in self.destinations.items():
1815 if destination.type == 'suppress':
1816 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001817 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001818
1819 if output:
1820
1821 block = Block("", dsl_name="clinic", output=output)
1822
1823 if destination.type == 'buffer':
1824 block.input = "dump " + name + "\n"
1825 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1826 printer.write("\n")
1827 printer.print_block(block)
1828 continue
1829
1830 if destination.type == 'file':
1831 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001832 dirname = os.path.dirname(destination.filename)
1833 try:
1834 os.makedirs(dirname)
1835 except FileExistsError:
1836 if not os.path.isdir(dirname):
1837 fail("Can't write to destination {}, "
1838 "can't make directory {}!".format(
1839 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001840 if self.verify:
1841 with open(destination.filename, "rt") as f:
1842 parser_2 = BlockParser(f.read(), language=self.language)
1843 blocks = list(parser_2)
1844 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1845 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001846 except FileNotFoundError:
1847 pass
1848
1849 block.input = 'preserve\n'
1850 printer_2 = BlockPrinter(self.language)
1851 printer_2.print_block(block)
1852 with open(destination.filename, "wt") as f:
1853 f.write(printer_2.f.getvalue())
1854 continue
1855 text = printer.f.getvalue()
1856
1857 if second_pass_replacements:
1858 printer_2 = BlockPrinter(self.language)
1859 parser_2 = BlockParser(text, self.language)
1860 changed = False
1861 for block in parser_2:
1862 if block.dsl_name:
1863 for id, replacement in second_pass_replacements.items():
1864 if id in block.output:
1865 changed = True
1866 block.output = block.output.replace(id, replacement)
1867 printer_2.print_block(block)
1868 if changed:
1869 text = printer_2.f.getvalue()
1870
1871 return text
1872
Larry Hastings31826802013-10-19 00:09:25 -07001873
1874 def _module_and_class(self, fields):
1875 """
1876 fields should be an iterable of field names.
1877 returns a tuple of (module, class).
1878 the module object could actually be self (a clinic object).
1879 this function is only ever used to find the parent of where
1880 a new class/module should go.
1881 """
1882 in_classes = False
1883 parent = module = self
1884 cls = None
1885 so_far = []
1886
1887 for field in fields:
1888 so_far.append(field)
1889 if not in_classes:
1890 child = parent.modules.get(field)
1891 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001892 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001893 continue
1894 in_classes = True
1895 if not hasattr(parent, 'classes'):
1896 return module, cls
1897 child = parent.classes.get(field)
1898 if not child:
1899 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1900 cls = parent = child
1901
1902 return module, cls
1903
1904
Larry Hastings581ee362014-01-28 05:00:08 -08001905def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001906 extension = os.path.splitext(filename)[1][1:]
1907 if not extension:
1908 fail("Can't extract file type for file " + repr(filename))
1909
1910 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001911 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001912 except KeyError:
1913 fail("Can't identify file type for file " + repr(filename))
1914
Larry Hastings31826802013-10-19 00:09:25 -07001915 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001916 raw = f.read()
1917
Larry Hastings2623c8c2014-02-08 22:15:29 -08001918 # exit quickly if there are no clinic markers in the file
1919 find_start_re = BlockParser("", language).find_start_re
1920 if not find_start_re.search(raw):
1921 return
1922
1923 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001924 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001925 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001926 return
Larry Hastings31826802013-10-19 00:09:25 -07001927
1928 directory = os.path.dirname(filename) or '.'
1929
1930 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001931 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001932 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1933 with open(tmpfilename, "wb") as f:
1934 f.write(bytes)
1935 os.replace(tmpfilename, output or filename)
1936
1937
Larry Hastings581ee362014-01-28 05:00:08 -08001938def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001939 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001940 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1941 if length:
1942 s = s[:length]
1943 return s
Larry Hastings31826802013-10-19 00:09:25 -07001944
1945
1946
1947
1948class PythonParser:
1949 def __init__(self, clinic):
1950 pass
1951
1952 def parse(self, block):
1953 s = io.StringIO()
1954 with OverrideStdioWith(s):
1955 exec(block.input)
1956 block.output = s.getvalue()
1957
1958
1959class Module:
1960 def __init__(self, name, module=None):
1961 self.name = name
1962 self.module = self.parent = module
1963
1964 self.modules = collections.OrderedDict()
1965 self.classes = collections.OrderedDict()
1966 self.functions = []
1967
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001968 def __repr__(self):
1969 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1970
Larry Hastings31826802013-10-19 00:09:25 -07001971class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001972 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001973 self.name = name
1974 self.module = module
1975 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001976 self.typedef = typedef
1977 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001978 self.parent = cls or module
1979
1980 self.classes = collections.OrderedDict()
1981 self.functions = []
1982
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001983 def __repr__(self):
1984 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1985
Larry Hastings8666e652014-01-12 14:12:59 -08001986unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001987
Larry Hastings8666e652014-01-12 14:12:59 -08001988__abs__
1989__add__
1990__and__
1991__bytes__
1992__call__
1993__complex__
1994__delitem__
1995__divmod__
1996__eq__
1997__float__
1998__floordiv__
1999__ge__
2000__getattr__
2001__getattribute__
2002__getitem__
2003__gt__
2004__hash__
2005__iadd__
2006__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002007__ifloordiv__
2008__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002009__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002010__imod__
2011__imul__
2012__index__
2013__int__
2014__invert__
2015__ior__
2016__ipow__
2017__irshift__
2018__isub__
2019__iter__
2020__itruediv__
2021__ixor__
2022__le__
2023__len__
2024__lshift__
2025__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002026__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002027__mod__
2028__mul__
2029__neg__
2030__new__
2031__next__
2032__or__
2033__pos__
2034__pow__
2035__radd__
2036__rand__
2037__rdivmod__
2038__repr__
2039__rfloordiv__
2040__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002041__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002042__rmod__
2043__rmul__
2044__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002045__rpow__
2046__rrshift__
2047__rshift__
2048__rsub__
2049__rtruediv__
2050__rxor__
2051__setattr__
2052__setitem__
2053__str__
2054__sub__
2055__truediv__
2056__xor__
2057
2058""".strip().split())
2059
2060
Larry Hastings5c661892014-01-24 06:17:25 -08002061INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2062INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2063""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002064
2065class Function:
2066 """
2067 Mutable duck type for inspect.Function.
2068
2069 docstring - a str containing
2070 * embedded line breaks
2071 * text outdented to the left margin
2072 * no trailing whitespace.
2073 It will always be true that
2074 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2075 """
2076
2077 def __init__(self, parameters=None, *, name,
2078 module, cls=None, c_basename=None,
2079 full_name=None,
2080 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002081 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002082 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002083 self.parameters = parameters or collections.OrderedDict()
2084 self.return_annotation = return_annotation
2085 self.name = name
2086 self.full_name = full_name
2087 self.module = module
2088 self.cls = cls
2089 self.parent = cls or module
2090 self.c_basename = c_basename
2091 self.return_converter = return_converter
2092 self.docstring = docstring or ''
2093 self.kind = kind
2094 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002095 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002096 # docstring_only means "don't generate a machine-readable
2097 # signature, just a normal docstring". it's True for
2098 # functions with optional groups because we can't represent
2099 # those accurately with inspect.Signature in 3.4.
2100 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002101
Larry Hastings7726ac92014-01-31 22:03:12 -08002102 self.rendered_parameters = None
2103
2104 __render_parameters__ = None
2105 @property
2106 def render_parameters(self):
2107 if not self.__render_parameters__:
2108 self.__render_parameters__ = l = []
2109 for p in self.parameters.values():
2110 p = p.copy()
2111 p.converter.pre_render()
2112 l.append(p)
2113 return self.__render_parameters__
2114
Larry Hastingsebdcb502013-11-23 14:54:00 -08002115 @property
2116 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002117 if self.kind in (METHOD_INIT, METHOD_NEW):
2118 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002119 flags = []
2120 if self.kind == CLASS_METHOD:
2121 flags.append('METH_CLASS')
2122 elif self.kind == STATIC_METHOD:
2123 flags.append('METH_STATIC')
2124 else:
2125 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2126 if self.coexist:
2127 flags.append('METH_COEXIST')
2128 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002129
2130 def __repr__(self):
2131 return '<clinic.Function ' + self.name + '>'
2132
Larry Hastings7726ac92014-01-31 22:03:12 -08002133 def copy(self, **overrides):
2134 kwargs = {
2135 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2136 'cls': self.cls, 'c_basename': self.c_basename,
2137 'full_name': self.full_name,
2138 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2139 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002140 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002141 }
2142 kwargs.update(overrides)
2143 f = Function(**kwargs)
2144
2145 parameters = collections.OrderedDict()
2146 for name, value in f.parameters.items():
2147 value = value.copy(function=f)
2148 parameters[name] = value
2149 f.parameters = parameters
2150 return f
2151
Larry Hastings31826802013-10-19 00:09:25 -07002152
2153class Parameter:
2154 """
2155 Mutable duck type of inspect.Parameter.
2156 """
2157
2158 def __init__(self, name, kind, *, default=_empty,
2159 function, converter, annotation=_empty,
2160 docstring=None, group=0):
2161 self.name = name
2162 self.kind = kind
2163 self.default = default
2164 self.function = function
2165 self.converter = converter
2166 self.annotation = annotation
2167 self.docstring = docstring or ''
2168 self.group = group
2169
2170 def __repr__(self):
2171 return '<clinic.Parameter ' + self.name + '>'
2172
2173 def is_keyword_only(self):
2174 return self.kind == inspect.Parameter.KEYWORD_ONLY
2175
Larry Hastings2623c8c2014-02-08 22:15:29 -08002176 def is_positional_only(self):
2177 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2178
Larry Hastings7726ac92014-01-31 22:03:12 -08002179 def copy(self, **overrides):
2180 kwargs = {
2181 'name': self.name, 'kind': self.kind, 'default':self.default,
2182 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2183 'docstring': self.docstring, 'group': self.group,
2184 }
2185 kwargs.update(overrides)
2186 if 'converter' not in overrides:
2187 converter = copy.copy(self.converter)
2188 converter.function = kwargs['function']
2189 kwargs['converter'] = converter
2190 return Parameter(**kwargs)
2191
2192
2193
2194class LandMine:
2195 # try to access any
2196 def __init__(self, message):
2197 self.__message__ = message
2198
2199 def __repr__(self):
2200 return '<LandMine ' + repr(self.__message__) + ">"
2201
2202 def __getattribute__(self, name):
2203 if name in ('__repr__', '__message__'):
2204 return super().__getattribute__(name)
2205 # raise RuntimeError(repr(name))
2206 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002207
Larry Hastings31826802013-10-19 00:09:25 -07002208
2209def add_c_converter(f, name=None):
2210 if not name:
2211 name = f.__name__
2212 if not name.endswith('_converter'):
2213 return f
2214 name = name[:-len('_converter')]
2215 converters[name] = f
2216 return f
2217
2218def add_default_legacy_c_converter(cls):
2219 # automatically add converter for default format unit
2220 # (but without stomping on the existing one if it's already
2221 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002222 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002223 (cls.format_unit not in legacy_converters)):
2224 legacy_converters[cls.format_unit] = cls
2225 return cls
2226
2227def add_legacy_c_converter(format_unit, **kwargs):
2228 """
2229 Adds a legacy converter.
2230 """
2231 def closure(f):
2232 if not kwargs:
2233 added_f = f
2234 else:
2235 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002236 if format_unit:
2237 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002238 return f
2239 return closure
2240
2241class CConverterAutoRegister(type):
2242 def __init__(cls, name, bases, classdict):
2243 add_c_converter(cls)
2244 add_default_legacy_c_converter(cls)
2245
2246class CConverter(metaclass=CConverterAutoRegister):
2247 """
2248 For the init function, self, name, function, and default
2249 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002250 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002251 """
2252
Larry Hastings7726ac92014-01-31 22:03:12 -08002253 # The C name to use for this variable.
2254 name = None
2255
2256 # The Python name to use for this variable.
2257 py_name = None
2258
Larry Hastings78cf85c2014-01-04 12:44:57 -08002259 # The C type to use for this variable.
2260 # 'type' should be a Python string specifying the type, e.g. "int".
2261 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002262 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002263
2264 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002265 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002266 # Or the magic value "unknown" if this value is a cannot be evaluated
2267 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2268 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002269 default = unspecified
2270
Larry Hastings4a55fc52014-01-12 11:09:57 -08002271 # If not None, default must be isinstance() of this type.
2272 # (You can also specify a tuple of types.)
2273 default_type = None
2274
Larry Hastings31826802013-10-19 00:09:25 -07002275 # "default" converted into a C value, as a string.
2276 # Or None if there is no default.
2277 c_default = None
2278
Larry Hastings2a727912014-01-16 11:32:01 -08002279 # "default" converted into a Python value, as a string.
2280 # Or None if there is no default.
2281 py_default = None
2282
Larry Hastingsabc716b2013-11-20 09:13:52 -08002283 # The default value used to initialize the C variable when
2284 # there is no default, but not specifying a default may
2285 # result in an "uninitialized variable" warning. This can
2286 # easily happen when using option groups--although
2287 # properly-written code won't actually use the variable,
2288 # the variable does get passed in to the _impl. (Ah, if
2289 # only dataflow analysis could inline the static function!)
2290 #
2291 # This value is specified as a string.
2292 # Every non-abstract subclass should supply a valid value.
2293 c_ignored_default = 'NULL'
2294
Larry Hastings31826802013-10-19 00:09:25 -07002295 # The C converter *function* to be used, if any.
2296 # (If this is not None, format_unit must be 'O&'.)
2297 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002298
Larry Hastings78cf85c2014-01-04 12:44:57 -08002299 # Should Argument Clinic add a '&' before the name of
2300 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002301 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002302
2303 # Should Argument Clinic add a '&' before the name of
2304 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002305 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002306
2307 #############################################################
2308 #############################################################
2309 ## You shouldn't need to read anything below this point to ##
2310 ## write your own converter functions. ##
2311 #############################################################
2312 #############################################################
2313
2314 # The "format unit" to specify for this variable when
2315 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2316 # Custom converters should always use the default value of 'O&'.
2317 format_unit = 'O&'
2318
2319 # What encoding do we want for this variable? Only used
2320 # by format units starting with 'e'.
2321 encoding = None
2322
Larry Hastings77561cc2014-01-07 12:13:13 -08002323 # Should this object be required to be a subclass of a specific type?
2324 # If not None, should be a string representing a pointer to a
2325 # PyTypeObject (e.g. "&PyUnicode_Type").
2326 # Only used by the 'O!' format unit (and the "object" converter).
2327 subclass_of = None
2328
Larry Hastings78cf85c2014-01-04 12:44:57 -08002329 # Do we want an adjacent '_length' variable for this variable?
2330 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002331 length = False
2332
Larry Hastings5c661892014-01-24 06:17:25 -08002333 # Should we show this parameter in the generated
2334 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002335 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002336 show_in_signature = True
2337
2338 # Overrides the name used in a text signature.
2339 # The name used for a "self" parameter must be one of
2340 # self, type, or module; however users can set their own.
2341 # This lets the self_converter overrule the user-settable
2342 # name, *just* for the text signature.
2343 # Only set by self_converter.
2344 signature_name = None
2345
2346 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002347 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 +02002348 self.name = ensure_legal_c_identifier(name)
Larry Hastings7726ac92014-01-31 22:03:12 -08002349 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002350
2351 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002352 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002353 if isinstance(self.default_type, type):
2354 types_str = self.default_type.__name__
2355 else:
2356 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2357 fail("{}: default value {!r} for field {} is not of type {}".format(
2358 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002359 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002360
Larry Hastingsb4705752014-01-18 21:54:15 -08002361 if c_default:
2362 self.c_default = c_default
2363 if py_default:
2364 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002365
Larry Hastings31826802013-10-19 00:09:25 -07002366 if annotation != unspecified:
2367 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002368
2369 # this is deliberate, to prevent you from caching information
2370 # about the function in the init.
2371 # (that breaks if we get cloned.)
2372 # so after this change we will noisily fail.
2373 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002374 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002375 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002376
2377 def converter_init(self):
2378 pass
2379
2380 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002381 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002382
Larry Hastings5c661892014-01-24 06:17:25 -08002383 def _render_self(self, parameter, data):
2384 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002385 name = self.name
Larry Hastings5c661892014-01-24 06:17:25 -08002386
2387 # impl_arguments
2388 s = ("&" if self.impl_by_reference else "") + name
2389 data.impl_arguments.append(s)
2390 if self.length:
2391 data.impl_arguments.append(self.length_name())
2392
2393 # impl_parameters
2394 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2395 if self.length:
2396 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2397
2398 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002399 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002400 name = self.name
Larry Hastings31826802013-10-19 00:09:25 -07002401
2402 # declarations
2403 d = self.declaration()
2404 data.declarations.append(d)
2405
2406 # initializers
2407 initializers = self.initialize()
2408 if initializers:
2409 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2410
Larry Hastingsc2047262014-01-25 20:43:29 -08002411 # modifications
2412 modifications = self.modify()
2413 if modifications:
2414 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2415
Larry Hastings31826802013-10-19 00:09:25 -07002416 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002417 if parameter.is_positional_only():
2418 data.keywords.append('')
2419 else:
2420 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002421
2422 # format_units
2423 if self.is_optional() and '|' not in data.format_units:
2424 data.format_units.append('|')
2425 if parameter.is_keyword_only() and '$' not in data.format_units:
2426 data.format_units.append('$')
2427 data.format_units.append(self.format_unit)
2428
2429 # parse_arguments
2430 self.parse_argument(data.parse_arguments)
2431
Larry Hastings31826802013-10-19 00:09:25 -07002432 # cleanup
2433 cleanup = self.cleanup()
2434 if cleanup:
2435 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2436
Larry Hastings5c661892014-01-24 06:17:25 -08002437 def render(self, parameter, data):
2438 """
2439 parameter is a clinic.Parameter instance.
2440 data is a CRenderData instance.
2441 """
2442 self._render_self(parameter, data)
2443 self._render_non_self(parameter, data)
2444
Larry Hastingsebdcb502013-11-23 14:54:00 -08002445 def length_name(self):
2446 """Computes the name of the associated "length" variable."""
2447 if not self.length:
2448 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002449 return self.name + "_length"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002450
Larry Hastings31826802013-10-19 00:09:25 -07002451 # Why is this one broken out separately?
2452 # For "positional-only" function parsing,
2453 # which generates a bunch of PyArg_ParseTuple calls.
2454 def parse_argument(self, list):
2455 assert not (self.converter and self.encoding)
2456 if self.format_unit == 'O&':
2457 assert self.converter
2458 list.append(self.converter)
2459
2460 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002461 list.append(c_repr(self.encoding))
2462 elif self.subclass_of:
2463 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002464
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002465 s = ("&" if self.parse_by_reference else "") + self.name
Larry Hastings31826802013-10-19 00:09:25 -07002466 list.append(s)
2467
Larry Hastingsebdcb502013-11-23 14:54:00 -08002468 if self.length:
2469 list.append("&" + self.length_name())
2470
Larry Hastings31826802013-10-19 00:09:25 -07002471 #
2472 # All the functions after here are intended as extension points.
2473 #
2474
2475 def simple_declaration(self, by_reference=False):
2476 """
2477 Computes the basic declaration of the variable.
2478 Used in computing the prototype declaration and the
2479 variable declaration.
2480 """
2481 prototype = [self.type]
2482 if by_reference or not self.type.endswith('*'):
2483 prototype.append(" ")
2484 if by_reference:
2485 prototype.append('*')
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002486 prototype.append(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07002487 return "".join(prototype)
2488
2489 def declaration(self):
2490 """
2491 The C statement to declare this variable.
2492 """
2493 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002494 default = self.c_default
2495 if not default and self.parameter.group:
2496 default = self.c_ignored_default
2497 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002498 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002499 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002500 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002501 if self.length:
2502 declaration.append('\nPy_ssize_clean_t ')
2503 declaration.append(self.length_name())
2504 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002505 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002506
2507 def initialize(self):
2508 """
2509 The C statements required to set up this variable before parsing.
2510 Returns a string containing this code indented at column 0.
2511 If no initialization is necessary, returns an empty string.
2512 """
2513 return ""
2514
Larry Hastingsc2047262014-01-25 20:43:29 -08002515 def modify(self):
2516 """
2517 The C statements required to modify this variable after parsing.
2518 Returns a string containing this code indented at column 0.
2519 If no initialization is necessary, returns an empty string.
2520 """
2521 return ""
2522
Larry Hastings31826802013-10-19 00:09:25 -07002523 def cleanup(self):
2524 """
2525 The C statements required to clean up after this variable.
2526 Returns a string containing this code indented at column 0.
2527 If no cleanup is necessary, returns an empty string.
2528 """
2529 return ""
2530
Larry Hastings7726ac92014-01-31 22:03:12 -08002531 def pre_render(self):
2532 """
2533 A second initialization function, like converter_init,
2534 called just before rendering.
2535 You are permitted to examine self.function here.
2536 """
2537 pass
2538
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002539 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002540 if self.format_unit == 'O&':
2541 return """
2542 if (!{converter}({argname}, &{paramname})) {{{{
2543 goto exit;
2544 }}}}
2545 """.format(argname=argname, paramname=self.name,
2546 converter=self.converter)
2547 if self.format_unit == 'O!':
2548 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2549 if self.subclass_of in type_checks:
2550 typecheck, typename = type_checks[self.subclass_of]
2551 return """
2552 if (!{typecheck}({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002553 _PyArg_BadArgument("{{name}}", {argnum}, "{typename}", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002554 goto exit;
2555 }}}}
2556 {paramname} = {cast}{argname};
2557 """.format(argname=argname, paramname=self.name,
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002558 argnum=argnum,
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002559 typecheck=typecheck, typename=typename, cast=cast)
2560 return """
2561 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002562 _PyArg_BadArgument("{{name}}", {argnum}, ({subclass_of})->tp_name, {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002563 goto exit;
2564 }}}}
2565 {paramname} = {cast}{argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002566 """.format(argname=argname, paramname=self.name, argnum=argnum,
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002567 subclass_of=self.subclass_of, cast=cast)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002568 if self.format_unit == 'O':
2569 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2570 return """
2571 {paramname} = {cast}{argname};
2572 """.format(argname=argname, paramname=self.name, cast=cast)
2573 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002574
2575type_checks = {
2576 '&PyLong_Type': ('PyLong_Check', 'int'),
2577 '&PyTuple_Type': ('PyTuple_Check', 'tuple'),
2578 '&PyList_Type': ('PyList_Check', 'list'),
2579 '&PySet_Type': ('PySet_Check', 'set'),
2580 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'),
2581 '&PyDict_Type': ('PyDict_Check', 'dict'),
2582 '&PyUnicode_Type': ('PyUnicode_Check', 'str'),
2583 '&PyBytes_Type': ('PyBytes_Check', 'bytes'),
2584 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'),
2585}
2586
Larry Hastings31826802013-10-19 00:09:25 -07002587
2588class bool_converter(CConverter):
2589 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002590 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002591 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002592 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002593
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002594 def converter_init(self, *, accept={object}):
2595 if accept == {int}:
2596 self.format_unit = 'i'
2597 elif accept != {object}:
2598 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002599 if self.default is not unspecified:
2600 self.default = bool(self.default)
2601 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002602
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002603 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002604 if self.format_unit == 'i':
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +02002605 # XXX PyFloat_Check can be removed after the end of the
2606 # deprecation in _PyLong_FromNbIndexOrNbInt.
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002607 return """
2608 if (PyFloat_Check({argname})) {{{{
2609 PyErr_SetString(PyExc_TypeError,
2610 "integer argument expected, got float" );
2611 goto exit;
2612 }}}}
2613 {paramname} = _PyLong_AsInt({argname});
2614 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2615 goto exit;
2616 }}}}
2617 """.format(argname=argname, paramname=self.name)
2618 elif self.format_unit == 'p':
2619 return """
2620 {paramname} = PyObject_IsTrue({argname});
2621 if ({paramname} < 0) {{{{
2622 goto exit;
2623 }}}}
2624 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002625 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002626
Larry Hastings31826802013-10-19 00:09:25 -07002627class char_converter(CConverter):
2628 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002629 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002630 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002631 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002632
Larry Hastings4a55fc52014-01-12 11:09:57 -08002633 def converter_init(self):
Tal Einatc929df32018-07-06 13:17:38 +03002634 if isinstance(self.default, self.default_type):
2635 if len(self.default) != 1:
2636 fail("char_converter: illegal default value " + repr(self.default))
2637
Serhiy Storchaka65ce60a2018-12-25 11:10:05 +02002638 self.c_default = repr(bytes(self.default))[1:]
2639 if self.c_default == '"\'"':
2640 self.c_default = r"'\''"
Larry Hastings4a55fc52014-01-12 11:09:57 -08002641
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002642 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002643 if self.format_unit == 'c':
2644 return """
2645 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
2646 {paramname} = PyBytes_AS_STRING({argname})[0];
2647 }}}}
2648 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{
2649 {paramname} = PyByteArray_AS_STRING({argname})[0];
2650 }}}}
2651 else {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002652 _PyArg_BadArgument("{{name}}", {argnum}, "a byte string of length 1", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002653 goto exit;
2654 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002655 """.format(argname=argname, paramname=self.name, argnum=argnum)
2656 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002657
Larry Hastings4a55fc52014-01-12 11:09:57 -08002658
Larry Hastings31826802013-10-19 00:09:25 -07002659@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002660class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002661 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002662 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002663 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002664 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002665
2666 def converter_init(self, *, bitwise=False):
2667 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002668 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002669
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002670 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002671 if self.format_unit == 'b':
2672 return """
2673 if (PyFloat_Check({argname})) {{{{
2674 PyErr_SetString(PyExc_TypeError,
2675 "integer argument expected, got float" );
2676 goto exit;
2677 }}}}
2678 {{{{
2679 long ival = PyLong_AsLong({argname});
2680 if (ival == -1 && PyErr_Occurred()) {{{{
2681 goto exit;
2682 }}}}
2683 else if (ival < 0) {{{{
2684 PyErr_SetString(PyExc_OverflowError,
2685 "unsigned byte integer is less than minimum");
2686 goto exit;
2687 }}}}
2688 else if (ival > UCHAR_MAX) {{{{
2689 PyErr_SetString(PyExc_OverflowError,
2690 "unsigned byte integer is greater than maximum");
2691 goto exit;
2692 }}}}
2693 else {{{{
2694 {paramname} = (unsigned char) ival;
2695 }}}}
2696 }}}}
2697 """.format(argname=argname, paramname=self.name)
2698 elif self.format_unit == 'B':
2699 return """
2700 if (PyFloat_Check({argname})) {{{{
2701 PyErr_SetString(PyExc_TypeError,
2702 "integer argument expected, got float" );
2703 goto exit;
2704 }}}}
2705 {{{{
2706 long ival = PyLong_AsUnsignedLongMask({argname});
2707 if (ival == -1 && PyErr_Occurred()) {{{{
2708 goto exit;
2709 }}}}
2710 else {{{{
2711 {paramname} = (unsigned char) ival;
2712 }}}}
2713 }}}}
2714 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002715 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002716
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002717class byte_converter(unsigned_char_converter): pass
2718
Larry Hastings31826802013-10-19 00:09:25 -07002719class short_converter(CConverter):
2720 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002721 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002722 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002723 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002724
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002725 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002726 if self.format_unit == 'h':
2727 return """
2728 if (PyFloat_Check({argname})) {{{{
2729 PyErr_SetString(PyExc_TypeError,
2730 "integer argument expected, got float" );
2731 goto exit;
2732 }}}}
2733 {{{{
2734 long ival = PyLong_AsLong({argname});
2735 if (ival == -1 && PyErr_Occurred()) {{{{
2736 goto exit;
2737 }}}}
2738 else if (ival < SHRT_MIN) {{{{
2739 PyErr_SetString(PyExc_OverflowError,
2740 "signed short integer is less than minimum");
2741 goto exit;
2742 }}}}
2743 else if (ival > SHRT_MAX) {{{{
2744 PyErr_SetString(PyExc_OverflowError,
2745 "signed short integer is greater than maximum");
2746 goto exit;
2747 }}}}
2748 else {{{{
2749 {paramname} = (short) ival;
2750 }}}}
2751 }}}}
2752 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002753 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002754
Larry Hastings31826802013-10-19 00:09:25 -07002755class unsigned_short_converter(CConverter):
2756 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002757 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002758 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002759
2760 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002761 if bitwise:
2762 self.format_unit = 'H'
2763 else:
2764 self.converter = '_PyLong_UnsignedShort_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002765
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002766 def parse_arg(self, argname, argnum):
2767 if self.format_unit == 'H':
2768 return """
2769 if (PyFloat_Check({argname})) {{{{
2770 PyErr_SetString(PyExc_TypeError,
2771 "integer argument expected, got float" );
2772 goto exit;
2773 }}}}
2774 {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname});
2775 if ({paramname} == (unsigned short)-1 && PyErr_Occurred()) {{{{
2776 goto exit;
2777 }}}}
2778 """.format(argname=argname, paramname=self.name)
2779 return super().parse_arg(argname, argnum)
2780
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002781@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002782class int_converter(CConverter):
2783 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002784 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002785 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002786 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002787
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002788 def converter_init(self, *, accept={int}, type=None):
2789 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002790 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002791 elif accept != {int}:
2792 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002793 if type != None:
2794 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002795
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002796 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002797 if self.format_unit == 'i':
2798 return """
2799 if (PyFloat_Check({argname})) {{{{
2800 PyErr_SetString(PyExc_TypeError,
2801 "integer argument expected, got float" );
2802 goto exit;
2803 }}}}
2804 {paramname} = _PyLong_AsInt({argname});
2805 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2806 goto exit;
2807 }}}}
2808 """.format(argname=argname, paramname=self.name)
2809 elif self.format_unit == 'C':
2810 return """
2811 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002812 _PyArg_BadArgument("{{name}}", {argnum}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002813 goto exit;
2814 }}}}
2815 if (PyUnicode_READY({argname})) {{{{
2816 goto exit;
2817 }}}}
2818 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002819 _PyArg_BadArgument("{{name}}", {argnum}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002820 goto exit;
2821 }}}}
2822 {paramname} = PyUnicode_READ_CHAR({argname}, 0);
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002823 """.format(argname=argname, paramname=self.name, argnum=argnum)
2824 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002825
Larry Hastings31826802013-10-19 00:09:25 -07002826class unsigned_int_converter(CConverter):
2827 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002828 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002829 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002830
2831 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002832 if bitwise:
2833 self.format_unit = 'I'
2834 else:
2835 self.converter = '_PyLong_UnsignedInt_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002836
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002837 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002838 if self.format_unit == 'I':
2839 return """
2840 if (PyFloat_Check({argname})) {{{{
2841 PyErr_SetString(PyExc_TypeError,
2842 "integer argument expected, got float" );
2843 goto exit;
2844 }}}}
2845 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
2846 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{
2847 goto exit;
2848 }}}}
2849 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002850 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002851
Larry Hastings31826802013-10-19 00:09:25 -07002852class long_converter(CConverter):
2853 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002854 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002855 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002856 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002857
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002858 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002859 if self.format_unit == 'l':
2860 return """
2861 if (PyFloat_Check({argname})) {{{{
2862 PyErr_SetString(PyExc_TypeError,
2863 "integer argument expected, got float" );
2864 goto exit;
2865 }}}}
2866 {paramname} = PyLong_AsLong({argname});
2867 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2868 goto exit;
2869 }}}}
2870 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002871 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002872
Larry Hastings31826802013-10-19 00:09:25 -07002873class unsigned_long_converter(CConverter):
2874 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002875 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002876 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002877
2878 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002879 if bitwise:
2880 self.format_unit = 'k'
2881 else:
2882 self.converter = '_PyLong_UnsignedLong_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002883
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002884 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002885 if self.format_unit == 'k':
2886 return """
2887 if (!PyLong_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002888 _PyArg_BadArgument("{{name}}", {argnum}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002889 goto exit;
2890 }}}}
2891 {paramname} = PyLong_AsUnsignedLongMask({argname});
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002892 """.format(argname=argname, paramname=self.name, argnum=argnum)
2893 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002894
Benjamin Petersoncc854492016-09-08 09:29:11 -07002895class long_long_converter(CConverter):
2896 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002897 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002898 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002899 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002900
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002901 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002902 if self.format_unit == 'L':
2903 return """
2904 if (PyFloat_Check({argname})) {{{{
2905 PyErr_SetString(PyExc_TypeError,
2906 "integer argument expected, got float" );
2907 goto exit;
2908 }}}}
2909 {paramname} = PyLong_AsLongLong({argname});
2910 if ({paramname} == (PY_LONG_LONG)-1 && PyErr_Occurred()) {{{{
2911 goto exit;
2912 }}}}
2913 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002914 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002915
Benjamin Petersoncc854492016-09-08 09:29:11 -07002916class unsigned_long_long_converter(CConverter):
2917 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002918 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002919 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002920
2921 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002922 if bitwise:
2923 self.format_unit = 'K'
2924 else:
2925 self.converter = '_PyLong_UnsignedLongLong_Converter'
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002926
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002927 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002928 if self.format_unit == 'K':
2929 return """
2930 if (!PyLong_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002931 _PyArg_BadArgument("{{name}}", {argnum}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002932 goto exit;
2933 }}}}
2934 {paramname} = PyLong_AsUnsignedLongLongMask({argname});
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002935 """.format(argname=argname, paramname=self.name, argnum=argnum)
2936 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002937
Larry Hastings31826802013-10-19 00:09:25 -07002938class Py_ssize_t_converter(CConverter):
2939 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002940 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002941
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002942 def converter_init(self, *, accept={int}):
2943 if accept == {int}:
2944 self.format_unit = 'n'
2945 self.default_type = int
2946 elif accept == {int, NoneType}:
2947 self.converter = '_Py_convert_optional_to_ssize_t'
2948 else:
2949 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
2950
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002951 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002952 if self.format_unit == 'n':
2953 return """
2954 if (PyFloat_Check({argname})) {{{{
2955 PyErr_SetString(PyExc_TypeError,
2956 "integer argument expected, got float" );
2957 goto exit;
2958 }}}}
2959 {{{{
2960 Py_ssize_t ival = -1;
2961 PyObject *iobj = PyNumber_Index({argname});
2962 if (iobj != NULL) {{{{
2963 ival = PyLong_AsSsize_t(iobj);
2964 Py_DECREF(iobj);
2965 }}}}
2966 if (ival == -1 && PyErr_Occurred()) {{{{
2967 goto exit;
2968 }}}}
2969 {paramname} = ival;
2970 }}}}
2971 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002972 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002973
Larry Hastings31826802013-10-19 00:09:25 -07002974
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002975class slice_index_converter(CConverter):
2976 type = 'Py_ssize_t'
2977
2978 def converter_init(self, *, accept={int, NoneType}):
2979 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002980 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002981 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002982 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002983 else:
2984 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
2985
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002986class size_t_converter(CConverter):
2987 type = 'size_t'
2988 converter = '_PyLong_Size_t_Converter'
2989 c_ignored_default = "0"
2990
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002991 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002992 if self.format_unit == 'n':
2993 return """
2994 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
2995 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2996 goto exit;
2997 }}}}
2998 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002999 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003000
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003001
Larry Hastings31826802013-10-19 00:09:25 -07003002class float_converter(CConverter):
3003 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003004 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003005 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003006 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003007
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003008 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003009 if self.format_unit == 'f':
3010 return """
3011 {paramname} = (float) PyFloat_AsDouble({argname});
3012 if (PyErr_Occurred()) {{{{
3013 goto exit;
3014 }}}}
3015 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003016 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003017
Larry Hastings31826802013-10-19 00:09:25 -07003018class double_converter(CConverter):
3019 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003020 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003021 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003022 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003023
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003024 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003025 if self.format_unit == 'd':
3026 return """
3027 {paramname} = PyFloat_AsDouble({argname});
3028 if (PyErr_Occurred()) {{{{
3029 goto exit;
3030 }}}}
3031 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003032 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003033
Larry Hastings31826802013-10-19 00:09:25 -07003034
3035class Py_complex_converter(CConverter):
3036 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003037 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07003038 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003039 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07003040
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003041 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003042 if self.format_unit == 'D':
3043 return """
3044 {paramname} = PyComplex_AsCComplex({argname});
3045 if (PyErr_Occurred()) {{{{
3046 goto exit;
3047 }}}}
3048 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003049 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003050
Larry Hastings31826802013-10-19 00:09:25 -07003051
3052class object_converter(CConverter):
3053 type = 'PyObject *'
3054 format_unit = 'O'
3055
Larry Hastings4a55fc52014-01-12 11:09:57 -08003056 def converter_init(self, *, converter=None, type=None, subclass_of=None):
3057 if converter:
3058 if subclass_of:
3059 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
3060 self.format_unit = 'O&'
3061 self.converter = converter
3062 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07003063 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08003064 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08003065
Larry Hastings77561cc2014-01-07 12:13:13 -08003066 if type is not None:
3067 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07003068
3069
Larry Hastings7f90cba2015-04-15 23:02:12 -04003070#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003071# We define three conventions for buffer types in the 'accept' argument:
3072#
3073# buffer : any object supporting the buffer interface
3074# rwbuffer: any object supporting the buffer interface, but must be writeable
3075# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04003076#
3077
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003078class buffer: pass
3079class rwbuffer: pass
3080class robuffer: pass
3081
Larry Hastings38337d12015-05-07 23:30:09 -07003082def str_converter_key(types, encoding, zeroes):
3083 return (frozenset(types), bool(encoding), bool(zeroes))
3084
3085str_converter_argument_map = {}
3086
Larry Hastings31826802013-10-19 00:09:25 -07003087class str_converter(CConverter):
3088 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003089 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003090 format_unit = 's'
3091
Larry Hastings38337d12015-05-07 23:30:09 -07003092 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003093
Larry Hastings38337d12015-05-07 23:30:09 -07003094 key = str_converter_key(accept, encoding, zeroes)
3095 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003096 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07003097 fail("str_converter: illegal combination of arguments", key)
3098
Larry Hastingsebdcb502013-11-23 14:54:00 -08003099 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07003100 self.length = bool(zeroes)
3101 if encoding:
3102 if self.default not in (Null, None, unspecified):
3103 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
3104 self.encoding = encoding
3105 self.type = 'char *'
3106 # sorry, clinic can't support preallocated buffers
3107 # for es# and et#
3108 self.c_default = "NULL"
3109
3110 def cleanup(self):
3111 if self.encoding:
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003112 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003113 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07003114
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003115 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003116 if self.format_unit == 's':
3117 return """
3118 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003119 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003120 goto exit;
3121 }}}}
3122 Py_ssize_t {paramname}_length;
3123 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3124 if ({paramname} == NULL) {{{{
3125 goto exit;
3126 }}}}
3127 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3128 PyErr_SetString(PyExc_ValueError, "embedded null character");
3129 goto exit;
3130 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003131 """.format(argname=argname, paramname=self.name, argnum=argnum)
3132 if self.format_unit == 'z':
3133 return """
3134 if ({argname} == Py_None) {{{{
3135 {paramname} = NULL;
3136 }}}}
3137 else if (PyUnicode_Check({argname})) {{{{
3138 Py_ssize_t {paramname}_length;
3139 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3140 if ({paramname} == NULL) {{{{
3141 goto exit;
3142 }}}}
3143 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3144 PyErr_SetString(PyExc_ValueError, "embedded null character");
3145 goto exit;
3146 }}}}
3147 }}}}
3148 else {{{{
3149 _PyArg_BadArgument("{{name}}", {argnum}, "str or None", {argname});
3150 goto exit;
3151 }}}}
3152 """.format(argname=argname, paramname=self.name, argnum=argnum)
3153 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003154
Larry Hastings38337d12015-05-07 23:30:09 -07003155#
3156# This is the fourth or fifth rewrite of registering all the
Raymond Hettinger14010182018-09-13 21:17:40 -07003157# string converter format units. Previous approaches hid
Larry Hastings38337d12015-05-07 23:30:09 -07003158# bugs--generally mismatches between the semantics of the format
3159# unit and the arguments necessary to represent those semantics
3160# properly. Hopefully with this approach we'll get it 100% right.
3161#
3162# The r() function (short for "register") both registers the
3163# mapping from arguments to format unit *and* registers the
3164# legacy C converter for that format unit.
3165#
3166def r(format_unit, *, accept, encoding=False, zeroes=False):
3167 if not encoding and format_unit != 's':
3168 # add the legacy c converters here too.
3169 #
3170 # note: add_legacy_c_converter can't work for
3171 # es, es#, et, or et#
3172 # because of their extra encoding argument
3173 #
3174 # also don't add the converter for 's' because
3175 # the metaclass for CConverter adds it for us.
3176 kwargs = {}
3177 if accept != {str}:
3178 kwargs['accept'] = accept
3179 if zeroes:
3180 kwargs['zeroes'] = True
3181 added_f = functools.partial(str_converter, **kwargs)
3182 legacy_converters[format_unit] = added_f
3183
3184 d = str_converter_argument_map
3185 key = str_converter_key(accept, encoding, zeroes)
3186 if key in d:
3187 sys.exit("Duplicate keys specified for str_converter_argument_map!")
3188 d[key] = format_unit
3189
3190r('es', encoding=True, accept={str})
3191r('es#', encoding=True, zeroes=True, accept={str})
3192r('et', encoding=True, accept={bytes, bytearray, str})
3193r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
3194r('s', accept={str})
3195r('s#', zeroes=True, accept={robuffer, str})
3196r('y', accept={robuffer})
3197r('y#', zeroes=True, accept={robuffer})
3198r('z', accept={str, NoneType})
3199r('z#', zeroes=True, accept={robuffer, str, NoneType})
3200del r
Larry Hastings31826802013-10-19 00:09:25 -07003201
3202
3203class PyBytesObject_converter(CConverter):
3204 type = 'PyBytesObject *'
3205 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003206 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07003207
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003208 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003209 if self.format_unit == 'S':
3210 return """
3211 if (!PyBytes_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003212 _PyArg_BadArgument("{{name}}", {argnum}, "bytes", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003213 goto exit;
3214 }}}}
3215 {paramname} = ({type}){argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003216 """.format(argname=argname, paramname=self.name, argnum=argnum,
3217 type=self.type)
3218 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003219
Larry Hastings31826802013-10-19 00:09:25 -07003220class PyByteArrayObject_converter(CConverter):
3221 type = 'PyByteArrayObject *'
3222 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003223 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07003224
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003225 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003226 if self.format_unit == 'Y':
3227 return """
3228 if (!PyByteArray_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003229 _PyArg_BadArgument("{{name}}", {argnum}, "bytearray", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003230 goto exit;
3231 }}}}
3232 {paramname} = ({type}){argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003233 """.format(argname=argname, paramname=self.name, argnum=argnum,
3234 type=self.type)
3235 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003236
Larry Hastings31826802013-10-19 00:09:25 -07003237class unicode_converter(CConverter):
3238 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003239 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003240 format_unit = 'U'
3241
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003242 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003243 if self.format_unit == 'U':
3244 return """
3245 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003246 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003247 goto exit;
3248 }}}}
3249 if (PyUnicode_READY({argname}) == -1) {{{{
3250 goto exit;
3251 }}}}
3252 {paramname} = {argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003253 """.format(argname=argname, paramname=self.name, argnum=argnum)
3254 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003255
Larry Hastings38337d12015-05-07 23:30:09 -07003256@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003257@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07003258@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07003259class Py_UNICODE_converter(CConverter):
Serhiy Storchakaafb3e712018-12-14 11:19:51 +02003260 type = 'const Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003261 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003262 format_unit = 'u'
3263
Larry Hastings38337d12015-05-07 23:30:09 -07003264 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003265 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07003266 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003267 format_unit += '#'
3268 self.length = True
3269 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003270
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003271@add_legacy_c_converter('s*', accept={str, buffer})
3272@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
3273@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07003274class Py_buffer_converter(CConverter):
3275 type = 'Py_buffer'
3276 format_unit = 'y*'
3277 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08003278 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07003279
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003280 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08003281 if self.default not in (unspecified, None):
3282 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003283
Larry Hastings3f144c22014-01-06 10:34:00 -08003284 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08003285
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003286 if accept == {str, buffer, NoneType}:
3287 format_unit = 'z*'
3288 elif accept == {str, buffer}:
3289 format_unit = 's*'
3290 elif accept == {buffer}:
3291 format_unit = 'y*'
3292 elif accept == {rwbuffer}:
3293 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07003294 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003295 fail("Py_buffer_converter: illegal combination of arguments")
3296
3297 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003298
3299 def cleanup(self):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003300 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003301 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08003302
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003303 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003304 if self.format_unit == 'y*':
3305 return """
3306 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3307 goto exit;
3308 }}}}
3309 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003310 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003311 goto exit;
3312 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003313 """.format(argname=argname, paramname=self.name, argnum=argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003314 elif self.format_unit == 's*':
3315 return """
3316 if (PyUnicode_Check({argname})) {{{{
3317 Py_ssize_t len;
3318 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
3319 if (ptr == NULL) {{{{
3320 goto exit;
3321 }}}}
3322 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
3323 }}}}
3324 else {{{{ /* any bytes-like object */
3325 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3326 goto exit;
3327 }}}}
3328 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003329 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003330 goto exit;
3331 }}}}
3332 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003333 """.format(argname=argname, paramname=self.name, argnum=argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003334 elif self.format_unit == 'w*':
3335 return """
3336 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
3337 PyErr_Clear();
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003338 _PyArg_BadArgument("{{name}}", {argnum}, "read-write bytes-like object", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003339 goto exit;
3340 }}}}
3341 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003342 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003343 goto exit;
3344 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003345 """.format(argname=argname, paramname=self.name, argnum=argnum)
3346 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003347
Larry Hastingsebdcb502013-11-23 14:54:00 -08003348
Larry Hastings5c661892014-01-24 06:17:25 -08003349def correct_name_for_self(f):
3350 if f.kind in (CALLABLE, METHOD_INIT):
3351 if f.cls:
3352 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03003353 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08003354 if f.kind == STATIC_METHOD:
3355 return "void *", "null"
3356 if f.kind in (CLASS_METHOD, METHOD_NEW):
3357 return "PyTypeObject *", "type"
3358 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
3359
Larry Hastingsc2047262014-01-25 20:43:29 -08003360def required_type_for_self_for_parser(f):
3361 type, _ = correct_name_for_self(f)
3362 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
3363 return type
3364 return None
3365
Larry Hastings5c661892014-01-24 06:17:25 -08003366
Larry Hastingsebdcb502013-11-23 14:54:00 -08003367class self_converter(CConverter):
3368 """
3369 A special-case converter:
3370 this is the default converter used for "self".
3371 """
Larry Hastings5c661892014-01-24 06:17:25 -08003372 type = None
3373 format_unit = ''
3374
Larry Hastings78cf85c2014-01-04 12:44:57 -08003375 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08003376 self.specified_type = type
3377
3378 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003379 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08003380 default_type, default_name = correct_name_for_self(f)
3381 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08003382 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08003383
Larry Hastings5c661892014-01-24 06:17:25 -08003384 kind = self.function.kind
3385 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
3386
3387 if (kind == STATIC_METHOD) or new_or_init:
3388 self.show_in_signature = False
3389
3390 # tp_new (METHOD_NEW) functions are of type newfunc:
3391 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
3392 # PyTypeObject is a typedef for struct _typeobject.
3393 #
3394 # tp_init (METHOD_INIT) functions are of type initproc:
3395 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
3396 #
3397 # All other functions generated by Argument Clinic are stored in
3398 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
3399 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
3400 # However! We habitually cast these functions to PyCFunction,
3401 # since functions that accept keyword arguments don't fit this signature
3402 # but are stored there anyway. So strict type equality isn't important
3403 # for these functions.
3404 #
3405 # So:
3406 #
3407 # * The name of the first parameter to the impl and the parsing function will always
3408 # be self.name.
3409 #
3410 # * The type of the first parameter to the impl will always be of self.type.
3411 #
3412 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
3413 # * The type of the first parameter to the parsing function is also self.type.
3414 # This means that if you step into the parsing function, your "self" parameter
3415 # is of the correct type, which may make debugging more pleasant.
3416 #
3417 # * Else if the function is tp_new (METHOD_NEW):
3418 # * The type of the first parameter to the parsing function is "PyTypeObject *",
3419 # so the type signature of the function call is an exact match.
3420 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
3421 # in the impl call.
3422 #
3423 # * Else if the function is tp_init (METHOD_INIT):
3424 # * The type of the first parameter to the parsing function is "PyObject *",
3425 # so the type signature of the function call is an exact match.
3426 # * If self.type != "PyObject *", we cast the first parameter to self.type
3427 # in the impl call.
3428
3429 @property
3430 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08003431 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08003432
Larry Hastingsebdcb502013-11-23 14:54:00 -08003433 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08003434 """
3435 parameter is a clinic.Parameter instance.
3436 data is a CRenderData instance.
3437 """
3438 if self.function.kind == STATIC_METHOD:
3439 return
3440
3441 self._render_self(parameter, data)
3442
3443 if self.type != self.parser_type:
3444 # insert cast to impl_argument[0], aka self.
3445 # we know we're in the first slot in all the CRenderData lists,
3446 # because we render parameters in order, and self is always first.
3447 assert len(data.impl_arguments) == 1
3448 assert data.impl_arguments[0] == self.name
3449 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3450
3451 def set_template_dict(self, template_dict):
3452 template_dict['self_name'] = self.name
3453 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003454 kind = self.function.kind
3455 cls = self.function.cls
3456
3457 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3458 if kind == METHOD_NEW:
3459 passed_in_type = self.name
3460 else:
3461 passed_in_type = 'Py_TYPE({})'.format(self.name)
3462
3463 line = '({passed_in_type} == {type_object}) &&\n '
3464 d = {
3465 'type_object': self.function.cls.type_object,
3466 'passed_in_type': passed_in_type
3467 }
3468 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003469
Larry Hastings31826802013-10-19 00:09:25 -07003470
3471
3472def add_c_return_converter(f, name=None):
3473 if not name:
3474 name = f.__name__
3475 if not name.endswith('_return_converter'):
3476 return f
3477 name = name[:-len('_return_converter')]
3478 return_converters[name] = f
3479 return f
3480
3481
3482class CReturnConverterAutoRegister(type):
3483 def __init__(cls, name, bases, classdict):
3484 add_c_return_converter(cls)
3485
3486class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3487
Larry Hastings78cf85c2014-01-04 12:44:57 -08003488 # The C type to use for this variable.
3489 # 'type' should be a Python string specifying the type, e.g. "int".
3490 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003491 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003492
3493 # The Python default value for this parameter, as a Python value.
3494 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003495 default = None
3496
Larry Hastings2a727912014-01-16 11:32:01 -08003497 def __init__(self, *, py_default=None, **kwargs):
3498 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003499 try:
3500 self.return_converter_init(**kwargs)
3501 except TypeError as e:
3502 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3503 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3504
3505 def return_converter_init(self):
3506 pass
3507
3508 def declare(self, data, name="_return_value"):
3509 line = []
3510 add = line.append
3511 add(self.type)
3512 if not self.type.endswith('*'):
3513 add(' ')
3514 add(name + ';')
3515 data.declarations.append(''.join(line))
3516 data.return_value = name
3517
3518 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003519 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003520
3521 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003522 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003523
3524 def render(self, function, data):
3525 """
3526 function is a clinic.Function instance.
3527 data is a CRenderData instance.
3528 """
3529 pass
3530
3531add_c_return_converter(CReturnConverter, 'object')
3532
Larry Hastings78cf85c2014-01-04 12:44:57 -08003533class NoneType_return_converter(CReturnConverter):
3534 def render(self, function, data):
3535 self.declare(data)
3536 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003537if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003538 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003539}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003540return_value = Py_None;
3541Py_INCREF(Py_None);
3542'''.strip())
3543
Larry Hastings4a55fc52014-01-12 11:09:57 -08003544class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003545 type = 'int'
3546
3547 def render(self, function, data):
3548 self.declare(data)
3549 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003550 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003551
3552class long_return_converter(CReturnConverter):
3553 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003554 conversion_fn = 'PyLong_FromLong'
3555 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003556 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003557
3558 def render(self, function, data):
3559 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003560 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003561 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003562 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003563
Larry Hastings4a55fc52014-01-12 11:09:57 -08003564class int_return_converter(long_return_converter):
3565 type = 'int'
3566 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003567
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003568class init_return_converter(long_return_converter):
3569 """
3570 Special return converter for __init__ functions.
3571 """
3572 type = 'int'
3573 cast = '(long)'
3574
3575 def render(self, function, data):
3576 pass
3577
Larry Hastings4a55fc52014-01-12 11:09:57 -08003578class unsigned_long_return_converter(long_return_converter):
3579 type = 'unsigned long'
3580 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003581 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003582
3583class unsigned_int_return_converter(unsigned_long_return_converter):
3584 type = 'unsigned int'
3585 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003586 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003587
3588class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003589 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003590 conversion_fn = 'PyLong_FromSsize_t'
3591
3592class size_t_return_converter(long_return_converter):
3593 type = 'size_t'
3594 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003595 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003596
3597
3598class double_return_converter(CReturnConverter):
3599 type = 'double'
3600 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003601
3602 def render(self, function, data):
3603 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003604 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003605 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003606 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3607
3608class float_return_converter(double_return_converter):
3609 type = 'float'
3610 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003611
3612
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003613def eval_ast_expr(node, globals, *, filename='-'):
3614 """
3615 Takes an ast.Expr node. Compiles and evaluates it.
3616 Returns the result of the expression.
3617
3618 globals represents the globals dict the expression
3619 should see. (There's no equivalent for "locals" here.)
3620 """
3621
3622 if isinstance(node, ast.Expr):
3623 node = node.value
3624
3625 node = ast.Expression(node)
3626 co = compile(node, filename, 'eval')
3627 fn = types.FunctionType(co, globals)
3628 return fn()
3629
3630
Larry Hastings31826802013-10-19 00:09:25 -07003631class IndentStack:
3632 def __init__(self):
3633 self.indents = []
3634 self.margin = None
3635
3636 def _ensure(self):
3637 if not self.indents:
3638 fail('IndentStack expected indents, but none are defined.')
3639
3640 def measure(self, line):
3641 """
3642 Returns the length of the line's margin.
3643 """
3644 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003645 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003646 stripped = line.lstrip()
3647 if not len(stripped):
3648 # we can't tell anything from an empty line
3649 # so just pretend it's indented like our current indent
3650 self._ensure()
3651 return self.indents[-1]
3652 return len(line) - len(stripped)
3653
3654 def infer(self, line):
3655 """
3656 Infer what is now the current margin based on this line.
3657 Returns:
3658 1 if we have indented (or this is the first margin)
3659 0 if the margin has not changed
3660 -N if we have dedented N times
3661 """
3662 indent = self.measure(line)
3663 margin = ' ' * indent
3664 if not self.indents:
3665 self.indents.append(indent)
3666 self.margin = margin
3667 return 1
3668 current = self.indents[-1]
3669 if indent == current:
3670 return 0
3671 if indent > current:
3672 self.indents.append(indent)
3673 self.margin = margin
3674 return 1
3675 # indent < current
3676 if indent not in self.indents:
3677 fail("Illegal outdent.")
3678 outdent_count = 0
3679 while indent != current:
3680 self.indents.pop()
3681 current = self.indents[-1]
3682 outdent_count -= 1
3683 self.margin = margin
3684 return outdent_count
3685
3686 @property
3687 def depth(self):
3688 """
3689 Returns how many margins are currently defined.
3690 """
3691 return len(self.indents)
3692
3693 def indent(self, line):
3694 """
3695 Indents a line by the currently defined margin.
3696 """
3697 return self.margin + line
3698
3699 def dedent(self, line):
3700 """
3701 Dedents a line by the currently defined margin.
3702 (The inverse of 'indent'.)
3703 """
3704 margin = self.margin
3705 indent = self.indents[-1]
3706 if not line.startswith(margin):
3707 fail('Cannot dedent, line does not start with the previous margin:')
3708 return line[indent:]
3709
3710
3711class DSLParser:
3712 def __init__(self, clinic):
3713 self.clinic = clinic
3714
3715 self.directives = {}
3716 for name in dir(self):
3717 # functions that start with directive_ are added to directives
3718 _, s, key = name.partition("directive_")
3719 if s:
3720 self.directives[key] = getattr(self, name)
3721
3722 # functions that start with at_ are too, with an @ in front
3723 _, s, key = name.partition("at_")
3724 if s:
3725 self.directives['@' + key] = getattr(self, name)
3726
3727 self.reset()
3728
3729 def reset(self):
3730 self.function = None
3731 self.state = self.state_dsl_start
3732 self.parameter_indent = None
3733 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003734 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003735 self.group = 0
3736 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003737 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003738 self.indent = IndentStack()
3739 self.kind = CALLABLE
3740 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003741 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003742 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003743
Larry Hastingsebdcb502013-11-23 14:54:00 -08003744 def directive_version(self, required):
3745 global version
3746 if version_comparitor(version, required) < 0:
3747 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3748
Larry Hastings31826802013-10-19 00:09:25 -07003749 def directive_module(self, name):
3750 fields = name.split('.')
3751 new = fields.pop()
3752 module, cls = self.clinic._module_and_class(fields)
3753 if cls:
3754 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003755
3756 if name in module.classes:
3757 fail("Already defined module " + repr(name) + "!")
3758
Larry Hastings31826802013-10-19 00:09:25 -07003759 m = Module(name, module)
3760 module.modules[name] = m
3761 self.block.signatures.append(m)
3762
Larry Hastingsc2047262014-01-25 20:43:29 -08003763 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003764 fields = name.split('.')
3765 in_classes = False
3766 parent = self
3767 name = fields.pop()
3768 so_far = []
3769 module, cls = self.clinic._module_and_class(fields)
3770
Larry Hastingsc2047262014-01-25 20:43:29 -08003771 parent = cls or module
3772 if name in parent.classes:
3773 fail("Already defined class " + repr(name) + "!")
3774
3775 c = Class(name, module, cls, typedef, type_object)
3776 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003777 self.block.signatures.append(c)
3778
Larry Hastingsbebf7352014-01-17 17:47:17 -08003779 def directive_set(self, name, value):
3780 if name not in ("line_prefix", "line_suffix"):
3781 fail("unknown variable", repr(name))
3782
3783 value = value.format_map({
3784 'block comment start': '/*',
3785 'block comment end': '*/',
3786 })
3787
3788 self.clinic.__dict__[name] = value
3789
3790 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003791 if command == 'new':
3792 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003793 return
3794
Zachary Ware071baa62014-01-21 23:07:12 -06003795 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003796 self.clinic.get_destination(name).clear()
3797 fail("unknown destination command", repr(command))
3798
3799
Larry Hastings0759f842015-04-03 13:09:02 -07003800 def directive_output(self, command_or_name, destination=''):
3801 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003802
Larry Hastings0759f842015-04-03 13:09:02 -07003803 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003804 preset = self.clinic.presets.get(destination)
3805 if not preset:
3806 fail("Unknown preset " + repr(destination) + "!")
3807 fd.update(preset)
3808 return
3809
Larry Hastings0759f842015-04-03 13:09:02 -07003810 if command_or_name == "push":
3811 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003812 return
3813
Larry Hastings0759f842015-04-03 13:09:02 -07003814 if command_or_name == "pop":
3815 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003816 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003817 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003818 fd.update(previous_fd)
3819 return
3820
3821 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003822 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003823 self.block.output.append(pprint.pformat(fd))
3824 self.block.output.append('\n')
3825 return
3826
3827 d = self.clinic.get_destination(destination)
3828
Larry Hastings0759f842015-04-03 13:09:02 -07003829 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003830 for name in list(fd):
3831 fd[name] = d
3832 return
3833
Larry Hastings0759f842015-04-03 13:09:02 -07003834 if command_or_name not in fd:
3835 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3836 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003837
3838 def directive_dump(self, name):
3839 self.block.output.append(self.clinic.get_destination(name).dump())
3840
3841 def directive_print(self, *args):
3842 self.block.output.append(' '.join(args))
3843 self.block.output.append('\n')
3844
3845 def directive_preserve(self):
3846 if self.preserve_output:
3847 fail("Can't have preserve twice in one block!")
3848 self.preserve_output = True
3849
Larry Hastings31826802013-10-19 00:09:25 -07003850 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003851 if self.kind is not CALLABLE:
3852 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003853 self.kind = CLASS_METHOD
3854
3855 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003856 if self.kind is not CALLABLE:
3857 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003858 self.kind = STATIC_METHOD
3859
3860 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003861 if self.coexist:
3862 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003863 self.coexist = True
3864
3865 def parse(self, block):
3866 self.reset()
3867 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003868 self.saved_output = self.block.output
3869 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003870 block_start = self.clinic.block_parser.line_number
3871 lines = block.input.split('\n')
3872 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3873 if '\t' in line:
3874 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3875 self.state(line)
3876
3877 self.next(self.state_terminal)
3878 self.state(None)
3879
Larry Hastingsbebf7352014-01-17 17:47:17 -08003880 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3881
3882 if self.preserve_output:
3883 if block.output:
3884 fail("'preserve' only works for blocks that don't produce any output!")
3885 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003886
3887 @staticmethod
3888 def ignore_line(line):
3889 # ignore comment-only lines
3890 if line.lstrip().startswith('#'):
3891 return True
3892
3893 # Ignore empty lines too
3894 # (but not in docstring sections!)
3895 if not line.strip():
3896 return True
3897
3898 return False
3899
3900 @staticmethod
3901 def calculate_indent(line):
3902 return len(line) - len(line.strip())
3903
3904 def next(self, state, line=None):
3905 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3906 self.state = state
3907 if line is not None:
3908 self.state(line)
3909
3910 def state_dsl_start(self, line):
3911 # self.block = self.ClinicOutputBlock(self)
3912 if self.ignore_line(line):
3913 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003914
3915 # is it a directive?
3916 fields = shlex.split(line)
3917 directive_name = fields[0]
3918 directive = self.directives.get(directive_name, None)
3919 if directive:
3920 try:
3921 directive(*fields[1:])
3922 except TypeError as e:
3923 fail(str(e))
3924 return
3925
Larry Hastings31826802013-10-19 00:09:25 -07003926 self.next(self.state_modulename_name, line)
3927
3928 def state_modulename_name(self, line):
3929 # looking for declaration, which establishes the leftmost column
3930 # line should be
3931 # modulename.fnname [as c_basename] [-> return annotation]
3932 # square brackets denote optional syntax.
3933 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003934 # alternatively:
3935 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3936 # clones the parameters and return converter from that
3937 # function. you can't modify them. you must enter a
3938 # new docstring.
3939 #
Larry Hastings31826802013-10-19 00:09:25 -07003940 # (but we might find a directive first!)
3941 #
3942 # this line is permitted to start with whitespace.
3943 # we'll call this number of spaces F (for "function").
3944
3945 if not line.strip():
3946 return
3947
3948 self.indent.infer(line)
3949
Larry Hastings4a714d42014-01-14 22:22:41 -08003950 # are we cloning?
3951 before, equals, existing = line.rpartition('=')
3952 if equals:
3953 full_name, _, c_basename = before.partition(' as ')
3954 full_name = full_name.strip()
3955 c_basename = c_basename.strip()
3956 existing = existing.strip()
3957 if (is_legal_py_identifier(full_name) and
3958 (not c_basename or is_legal_c_identifier(c_basename)) and
3959 is_legal_py_identifier(existing)):
3960 # we're cloning!
3961 fields = [x.strip() for x in existing.split('.')]
3962 function_name = fields.pop()
3963 module, cls = self.clinic._module_and_class(fields)
3964
3965 for existing_function in (cls or module).functions:
3966 if existing_function.name == function_name:
3967 break
3968 else:
3969 existing_function = None
3970 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003971 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003972 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003973 fail("Couldn't find existing function " + repr(existing) + "!")
3974
3975 fields = [x.strip() for x in full_name.split('.')]
3976 function_name = fields.pop()
3977 module, cls = self.clinic._module_and_class(fields)
3978
3979 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3980 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003981 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 -08003982
3983 self.block.signatures.append(self.function)
3984 (cls or module).functions.append(self.function)
3985 self.next(self.state_function_docstring)
3986 return
3987
Larry Hastings31826802013-10-19 00:09:25 -07003988 line, _, returns = line.partition('->')
3989
3990 full_name, _, c_basename = line.partition(' as ')
3991 full_name = full_name.strip()
3992 c_basename = c_basename.strip() or None
3993
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003994 if not is_legal_py_identifier(full_name):
3995 fail("Illegal function name: {}".format(full_name))
3996 if c_basename and not is_legal_c_identifier(c_basename):
3997 fail("Illegal C basename: {}".format(c_basename))
3998
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003999 return_converter = None
4000 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07004001 ast_input = "def x() -> {}: pass".format(returns)
4002 module = None
4003 try:
4004 module = ast.parse(ast_input)
4005 except SyntaxError:
4006 pass
4007 if not module:
4008 fail("Badly-formed annotation for " + full_name + ": " + returns)
4009 try:
4010 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004011 if legacy:
4012 fail("Legacy converter {!r} not allowed as a return converter"
4013 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07004014 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004015 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07004016 return_converter = return_converters[name](**kwargs)
4017 except ValueError:
4018 fail("Badly-formed annotation for " + full_name + ": " + returns)
4019
4020 fields = [x.strip() for x in full_name.split('.')]
4021 function_name = fields.pop()
4022 module, cls = self.clinic._module_and_class(fields)
4023
Larry Hastings8666e652014-01-12 14:12:59 -08004024 fields = full_name.split('.')
4025 if fields[-1] == '__new__':
4026 if (self.kind != CLASS_METHOD) or (not cls):
4027 fail("__new__ must be a class method!")
4028 self.kind = METHOD_NEW
4029 elif fields[-1] == '__init__':
4030 if (self.kind != CALLABLE) or (not cls):
4031 fail("__init__ must be a normal method, not a class or static method!")
4032 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004033 if not return_converter:
4034 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08004035 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08004036 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08004037
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004038 if not return_converter:
4039 return_converter = CReturnConverter()
4040
Larry Hastings31826802013-10-19 00:09:25 -07004041 if not module:
4042 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
4043 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
4044 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
4045 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08004046
4047 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08004048 type, name = correct_name_for_self(self.function)
4049 kwargs = {}
4050 if cls and type == "PyObject *":
4051 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08004052 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08004053 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
4054 self.function.parameters[sc.name] = p_self
4055
Larry Hastings4a714d42014-01-14 22:22:41 -08004056 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07004057 self.next(self.state_parameters_start)
4058
4059 # Now entering the parameters section. The rules, formally stated:
4060 #
4061 # * All lines must be indented with spaces only.
4062 # * The first line must be a parameter declaration.
4063 # * The first line must be indented.
4064 # * This first line establishes the indent for parameters.
4065 # * We'll call this number of spaces P (for "parameter").
4066 # * Thenceforth:
4067 # * Lines indented with P spaces specify a parameter.
4068 # * Lines indented with > P spaces are docstrings for the previous
4069 # parameter.
4070 # * We'll call this number of spaces D (for "docstring").
4071 # * All subsequent lines indented with >= D spaces are stored as
4072 # part of the per-parameter docstring.
4073 # * All lines will have the first D spaces of the indent stripped
4074 # before they are stored.
4075 # * It's illegal to have a line starting with a number of spaces X
4076 # such that P < X < D.
4077 # * A line with < P spaces is the first line of the function
4078 # docstring, which ends processing for parameters and per-parameter
4079 # docstrings.
4080 # * The first line of the function docstring must be at the same
4081 # indent as the function declaration.
4082 # * It's illegal to have any line in the parameters section starting
4083 # with X spaces such that F < X < P. (As before, F is the indent
4084 # of the function declaration.)
4085 #
Larry Hastings31826802013-10-19 00:09:25 -07004086 # Also, currently Argument Clinic places the following restrictions on groups:
4087 # * Each group must contain at least one parameter.
4088 # * Each group may contain at most one group, which must be the furthest
4089 # thing in the group from the required parameters. (The nested group
4090 # must be the first in the group when it's before the required
4091 # parameters, and the last thing in the group when after the required
4092 # parameters.)
4093 # * There may be at most one (top-level) group to the left or right of
4094 # the required parameters.
4095 # * You must specify a slash, and it must be after all parameters.
4096 # (In other words: either all parameters are positional-only,
4097 # or none are.)
4098 #
4099 # Said another way:
4100 # * Each group must contain at least one parameter.
4101 # * All left square brackets before the required parameters must be
4102 # consecutive. (You can't have a left square bracket followed
4103 # by a parameter, then another left square bracket. You can't
4104 # have a left square bracket, a parameter, a right square bracket,
4105 # and then a left square bracket.)
4106 # * All right square brackets after the required parameters must be
4107 # consecutive.
4108 #
4109 # These rules are enforced with a single state variable:
4110 # "parameter_state". (Previously the code was a miasma of ifs and
4111 # separate boolean state variables.) The states are:
4112 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004113 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4114 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07004115 #
4116 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4117 # 1: ps_left_square_before. left square brackets before required parameters.
4118 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08004119 # 3: ps_required. required parameters, positional-or-keyword or positional-only
4120 # (we don't know yet). (renumber left groups!)
4121 # 4: ps_optional. positional-or-keyword or positional-only parameters that
4122 # now must have default values.
4123 # 5: ps_group_after. in a group, after required parameters.
4124 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07004125 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004126 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07004127
4128 def state_parameters_start(self, line):
4129 if self.ignore_line(line):
4130 return
4131
4132 # if this line is not indented, we have no parameters
4133 if not self.indent.infer(line):
4134 return self.next(self.state_function_docstring, line)
4135
Larry Hastings2a727912014-01-16 11:32:01 -08004136 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07004137 return self.next(self.state_parameter, line)
4138
4139
4140 def to_required(self):
4141 """
4142 Transition to the "required" parameter state.
4143 """
4144 if self.parameter_state != self.ps_required:
4145 self.parameter_state = self.ps_required
4146 for p in self.function.parameters.values():
4147 p.group = -p.group
4148
4149 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08004150 if self.parameter_continuation:
4151 line = self.parameter_continuation + ' ' + line.lstrip()
4152 self.parameter_continuation = ''
4153
Larry Hastings31826802013-10-19 00:09:25 -07004154 if self.ignore_line(line):
4155 return
4156
4157 assert self.indent.depth == 2
4158 indent = self.indent.infer(line)
4159 if indent == -1:
4160 # we outdented, must be to definition column
4161 return self.next(self.state_function_docstring, line)
4162
4163 if indent == 1:
4164 # we indented, must be to new parameter docstring column
4165 return self.next(self.state_parameter_docstring_start, line)
4166
Larry Hastings2a727912014-01-16 11:32:01 -08004167 line = line.rstrip()
4168 if line.endswith('\\'):
4169 self.parameter_continuation = line[:-1]
4170 return
4171
Larry Hastings31826802013-10-19 00:09:25 -07004172 line = line.lstrip()
4173
4174 if line in ('*', '/', '[', ']'):
4175 self.parse_special_symbol(line)
4176 return
4177
4178 if self.parameter_state in (self.ps_start, self.ps_required):
4179 self.to_required()
4180 elif self.parameter_state == self.ps_left_square_before:
4181 self.parameter_state = self.ps_group_before
4182 elif self.parameter_state == self.ps_group_before:
4183 if not self.group:
4184 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08004185 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07004186 pass
4187 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004188 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07004189
Larry Hastings7726ac92014-01-31 22:03:12 -08004190 # handle "as" for parameters too
4191 c_name = None
4192 name, have_as_token, trailing = line.partition(' as ')
4193 if have_as_token:
4194 name = name.strip()
4195 if ' ' not in name:
4196 fields = trailing.strip().split(' ')
4197 if not fields:
4198 fail("Invalid 'as' clause!")
4199 c_name = fields[0]
4200 if c_name.endswith(':'):
4201 name += ':'
4202 c_name = c_name[:-1]
4203 fields[0] = name
4204 line = ' '.join(fields)
4205
Larry Hastings2a727912014-01-16 11:32:01 -08004206 base, equals, default = line.rpartition('=')
4207 if not equals:
4208 base = default
4209 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08004210
Larry Hastings31826802013-10-19 00:09:25 -07004211 module = None
4212 try:
Larry Hastings2a727912014-01-16 11:32:01 -08004213 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07004214 module = ast.parse(ast_input)
4215 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08004216 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08004217 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004218 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08004219 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08004220 default = None
4221 ast_input = "def x({}): pass".format(line)
4222 module = ast.parse(ast_input)
4223 except SyntaxError:
4224 pass
Larry Hastings31826802013-10-19 00:09:25 -07004225 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07004226 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07004227
4228 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004229
4230 if len(function_args.args) > 1:
4231 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
4232 if function_args.defaults or function_args.kw_defaults:
4233 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
4234 if function_args.vararg or function_args.kwarg:
4235 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
4236
Larry Hastings31826802013-10-19 00:09:25 -07004237 parameter = function_args.args[0]
4238
Larry Hastings16c51912014-01-07 11:53:01 -08004239 parameter_name = parameter.arg
4240 name, legacy, kwargs = self.parse_converter(parameter.annotation)
4241
Larry Hastings2a727912014-01-16 11:32:01 -08004242 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08004243 if self.parameter_state == self.ps_optional:
4244 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 -08004245 value = unspecified
4246 if 'py_default' in kwargs:
4247 fail("You can't specify py_default without specifying a default value!")
4248 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004249 if self.parameter_state == self.ps_required:
4250 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08004251 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06004252 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004253 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08004254 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004255 try:
4256 module = ast.parse(ast_input)
4257
Larry Hastings5c661892014-01-24 06:17:25 -08004258 if 'c_default' not in kwargs:
4259 # we can only represent very simple data values in C.
4260 # detect whether default is okay, via a blacklist
4261 # of disallowed ast nodes.
4262 class DetectBadNodes(ast.NodeVisitor):
4263 bad = False
4264 def bad_node(self, node):
4265 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08004266
Larry Hastings5c661892014-01-24 06:17:25 -08004267 # inline function call
4268 visit_Call = bad_node
4269 # inline if statement ("x = 3 if y else z")
4270 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004271
Larry Hastings5c661892014-01-24 06:17:25 -08004272 # comprehensions and generator expressions
4273 visit_ListComp = visit_SetComp = bad_node
4274 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004275
Larry Hastings5c661892014-01-24 06:17:25 -08004276 # literals for advanced types
4277 visit_Dict = visit_Set = bad_node
4278 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004279
Larry Hastings5c661892014-01-24 06:17:25 -08004280 # "starred": "a = [1, 2, 3]; *a"
4281 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004282
Larry Hastings5c661892014-01-24 06:17:25 -08004283 blacklist = DetectBadNodes()
4284 blacklist.visit(module)
4285 bad = blacklist.bad
4286 else:
4287 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06004288 # but at least make an attempt at ensuring it's a valid expression.
4289 try:
4290 value = eval(default)
4291 if value == unspecified:
4292 fail("'unspecified' is not a legal default value!")
4293 except NameError:
4294 pass # probably a named constant
4295 except Exception as e:
4296 fail("Malformed expression given as default value\n"
4297 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08004298 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08004299 fail("Unsupported expression as default value: " + repr(default))
4300
4301 expr = module.body[0].value
4302 # mild hack: explicitly support NULL as a default value
4303 if isinstance(expr, ast.Name) and expr.id == 'NULL':
4304 value = NULL
4305 py_default = 'None'
4306 c_default = "NULL"
4307 elif (isinstance(expr, ast.BinOp) or
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004308 (isinstance(expr, ast.UnaryOp) and
4309 not (isinstance(expr.operand, ast.Num) or
4310 (hasattr(ast, 'Constant') and
4311 isinstance(expr.operand, ast.Constant) and
4312 type(expr.operand.value) in (int, float, complex)))
4313 )):
Larry Hastings2a727912014-01-16 11:32:01 -08004314 c_default = kwargs.get("c_default")
4315 if not (isinstance(c_default, str) and c_default):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004316 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 -08004317 py_default = default
4318 value = unknown
4319 elif isinstance(expr, ast.Attribute):
4320 a = []
4321 n = expr
4322 while isinstance(n, ast.Attribute):
4323 a.append(n.attr)
4324 n = n.value
4325 if not isinstance(n, ast.Name):
4326 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
4327 a.append(n.id)
4328 py_default = ".".join(reversed(a))
4329
4330 c_default = kwargs.get("c_default")
4331 if not (isinstance(c_default, str) and c_default):
4332 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4333
4334 try:
4335 value = eval(py_default)
4336 except NameError:
4337 value = unknown
4338 else:
4339 value = ast.literal_eval(expr)
4340 py_default = repr(value)
4341 if isinstance(value, (bool, None.__class__)):
4342 c_default = "Py_" + py_default
4343 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08004344 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08004345 else:
4346 c_default = py_default
4347
4348 except SyntaxError as e:
4349 fail("Syntax error: " + repr(e.text))
4350 except (ValueError, AttributeError):
4351 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08004352 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08004353 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08004354 if not (isinstance(c_default, str) and c_default):
4355 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4356
Larry Hastings2a727912014-01-16 11:32:01 -08004357 kwargs.setdefault('c_default', c_default)
4358 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004359
Larry Hastings31826802013-10-19 00:09:25 -07004360 dict = legacy_converters if legacy else converters
4361 legacy_str = "legacy " if legacy else ""
4362 if name not in dict:
4363 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08004364 # if you use a c_name for the parameter, we just give that name to the converter
4365 # but the parameter object gets the python name
4366 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07004367
4368 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08004369
4370 if isinstance(converter, self_converter):
4371 if len(self.function.parameters) == 1:
4372 if (self.parameter_state != self.ps_required):
4373 fail("A 'self' parameter cannot be marked optional.")
4374 if value is not unspecified:
4375 fail("A 'self' parameter cannot have a default value.")
4376 if self.group:
4377 fail("A 'self' parameter cannot be in an optional group.")
4378 kind = inspect.Parameter.POSITIONAL_ONLY
4379 self.parameter_state = self.ps_start
4380 self.function.parameters.clear()
4381 else:
4382 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
4383
Larry Hastings31826802013-10-19 00:09:25 -07004384 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08004385
4386 if parameter_name in self.function.parameters:
4387 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07004388 self.function.parameters[parameter_name] = p
4389
4390 def parse_converter(self, annotation):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004391 if (hasattr(ast, 'Constant') and
4392 isinstance(annotation, ast.Constant) and
4393 type(annotation.value) is str):
4394 return annotation.value, True, {}
4395
Larry Hastings31826802013-10-19 00:09:25 -07004396 if isinstance(annotation, ast.Str):
4397 return annotation.s, True, {}
4398
4399 if isinstance(annotation, ast.Name):
4400 return annotation.id, False, {}
4401
Larry Hastings4a55fc52014-01-12 11:09:57 -08004402 if not isinstance(annotation, ast.Call):
4403 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07004404
4405 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004406 symbols = globals()
4407
4408 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07004409 return name, False, kwargs
4410
4411 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07004412 if symbol == '*':
4413 if self.keyword_only:
4414 fail("Function " + self.function.name + " uses '*' more than once.")
4415 self.keyword_only = True
4416 elif symbol == '[':
4417 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
4418 self.parameter_state = self.ps_left_square_before
4419 elif self.parameter_state in (self.ps_required, self.ps_group_after):
4420 self.parameter_state = self.ps_group_after
4421 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004422 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07004423 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08004424 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07004425 elif symbol == ']':
4426 if not self.group:
4427 fail("Function " + self.function.name + " has a ] without a matching [.")
4428 if not any(p.group == self.group for p in self.function.parameters.values()):
4429 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
4430 self.group -= 1
4431 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
4432 self.parameter_state = self.ps_group_before
4433 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
4434 self.parameter_state = self.ps_right_square_after
4435 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004436 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07004437 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004438 if self.positional_only:
4439 fail("Function " + self.function.name + " uses '/' more than once.")
4440 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08004441 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07004442 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08004443 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
4444 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07004445 if self.keyword_only:
4446 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004447 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004448 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004449 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004450 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4451 p.kind = inspect.Parameter.POSITIONAL_ONLY
4452
4453 def state_parameter_docstring_start(self, line):
4454 self.parameter_docstring_indent = len(self.indent.margin)
4455 assert self.indent.depth == 3
4456 return self.next(self.state_parameter_docstring, line)
4457
4458 # every line of the docstring must start with at least F spaces,
4459 # where F > P.
4460 # these F spaces will be stripped.
4461 def state_parameter_docstring(self, line):
4462 stripped = line.strip()
4463 if stripped.startswith('#'):
4464 return
4465
4466 indent = self.indent.measure(line)
4467 if indent < self.parameter_docstring_indent:
4468 self.indent.infer(line)
4469 assert self.indent.depth < 3
4470 if self.indent.depth == 2:
4471 # back to a parameter
4472 return self.next(self.state_parameter, line)
4473 assert self.indent.depth == 1
4474 return self.next(self.state_function_docstring, line)
4475
4476 assert self.function.parameters
4477 last_parameter = next(reversed(list(self.function.parameters.values())))
4478
4479 new_docstring = last_parameter.docstring
4480
4481 if new_docstring:
4482 new_docstring += '\n'
4483 if stripped:
4484 new_docstring += self.indent.dedent(line)
4485
4486 last_parameter.docstring = new_docstring
4487
4488 # the final stanza of the DSL is the docstring.
4489 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004490 if self.group:
4491 fail("Function " + self.function.name + " has a ] without a matching [.")
4492
4493 stripped = line.strip()
4494 if stripped.startswith('#'):
4495 return
4496
4497 new_docstring = self.function.docstring
4498 if new_docstring:
4499 new_docstring += "\n"
4500 if stripped:
4501 line = self.indent.dedent(line).rstrip()
4502 else:
4503 line = ''
4504 new_docstring += line
4505 self.function.docstring = new_docstring
4506
4507 def format_docstring(self):
4508 f = self.function
4509
Larry Hastings5c661892014-01-24 06:17:25 -08004510 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4511 if new_or_init and not f.docstring:
4512 # don't render a docstring at all, no signature, nothing.
4513 return f.docstring
4514
Larry Hastings2623c8c2014-02-08 22:15:29 -08004515 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004516 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004517
4518 ##
4519 ## docstring first line
4520 ##
4521
Larry Hastings2623c8c2014-02-08 22:15:29 -08004522 if new_or_init:
4523 # classes get *just* the name of the class
4524 # not __new__, not __init__, and not module.classname
4525 assert f.cls
4526 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004527 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004528 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004529 add('(')
4530
4531 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004532 assert parameters, "We should always have a self parameter. " + repr(f)
4533 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004534 # self is always positional-only.
4535 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004536 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004537 positional_only = True
4538 for p in parameters[1:]:
4539 if not p.is_positional_only():
4540 positional_only = False
4541 else:
4542 assert positional_only
4543 if positional_only:
4544 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004545 else:
4546 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004547 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004548
4549 right_bracket_count = 0
4550
4551 def fix_right_bracket_count(desired):
4552 nonlocal right_bracket_count
4553 s = ''
4554 while right_bracket_count < desired:
4555 s += '['
4556 right_bracket_count += 1
4557 while right_bracket_count > desired:
4558 s += ']'
4559 right_bracket_count -= 1
4560 return s
4561
Larry Hastings2623c8c2014-02-08 22:15:29 -08004562 need_slash = False
4563 added_slash = False
4564 need_a_trailing_slash = False
4565
4566 # we only need a trailing slash:
4567 # * if this is not a "docstring_only" signature
4568 # * and if the last *shown* parameter is
4569 # positional only
4570 if not f.docstring_only:
4571 for p in reversed(parameters):
4572 if not p.converter.show_in_signature:
4573 continue
4574 if p.is_positional_only():
4575 need_a_trailing_slash = True
4576 break
4577
4578
Larry Hastings31826802013-10-19 00:09:25 -07004579 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004580
4581 first_parameter = True
4582 last_p = parameters[-1]
4583 line_length = len(''.join(text))
4584 indent = " " * line_length
4585 def add_parameter(text):
4586 nonlocal line_length
4587 nonlocal first_parameter
4588 if first_parameter:
4589 s = text
4590 first_parameter = False
4591 else:
4592 s = ' ' + text
4593 if line_length + len(s) >= 72:
4594 add('\n')
4595 add(indent)
4596 line_length = len(indent)
4597 s = text
4598 line_length += len(s)
4599 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004600
4601 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004602 if not p.converter.show_in_signature:
4603 continue
Larry Hastings31826802013-10-19 00:09:25 -07004604 assert p.name
4605
Larry Hastings2623c8c2014-02-08 22:15:29 -08004606 is_self = isinstance(p.converter, self_converter)
4607 if is_self and f.docstring_only:
4608 # this isn't a real machine-parsable signature,
4609 # so let's not print the "self" parameter
4610 continue
4611
4612 if p.is_positional_only():
4613 need_slash = not f.docstring_only
4614 elif need_slash and not (added_slash or p.is_positional_only()):
4615 added_slash = True
4616 add_parameter('/,')
4617
Larry Hastings31826802013-10-19 00:09:25 -07004618 if p.is_keyword_only() and not added_star:
4619 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004620 add_parameter('*,')
4621
4622 p_add, p_output = text_accumulator()
4623 p_add(fix_right_bracket_count(p.right_bracket_count))
4624
4625 if isinstance(p.converter, self_converter):
4626 # annotate first parameter as being a "self".
4627 #
4628 # if inspect.Signature gets this function,
4629 # and it's already bound, the self parameter
4630 # will be stripped off.
4631 #
4632 # if it's not bound, it should be marked
4633 # as positional-only.
4634 #
4635 # note: we don't print "self" for __init__,
4636 # because this isn't actually the signature
4637 # for __init__. (it can't be, __init__ doesn't
4638 # have a docstring.) if this is an __init__
4639 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004640 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004641 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004642
Larry Hastings5c661892014-01-24 06:17:25 -08004643 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004644 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004645
Larry Hastings31826802013-10-19 00:09:25 -07004646 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004647 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004648 value = p.converter.py_default
4649 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004650 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004651 p_add(value)
4652
4653 if (p != last_p) or need_a_trailing_slash:
4654 p_add(',')
4655
4656 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004657
4658 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004659 if need_a_trailing_slash:
4660 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004661 add(')')
4662
Larry Hastings2a727912014-01-16 11:32:01 -08004663 # PEP 8 says:
4664 #
4665 # The Python standard library will not use function annotations
4666 # as that would result in a premature commitment to a particular
4667 # annotation style. Instead, the annotations are left for users
4668 # to discover and experiment with useful annotation styles.
4669 #
4670 # therefore this is commented out:
4671 #
4672 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004673 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004674 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004675
Larry Hastings2623c8c2014-02-08 22:15:29 -08004676 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004677 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004678
Larry Hastings31826802013-10-19 00:09:25 -07004679 docstring_first_line = output()
4680
4681 # now fix up the places where the brackets look wrong
4682 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4683
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004684 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004685 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004686 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004687 for p in parameters:
4688 if not p.docstring.strip():
4689 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004690 if spacer_line:
4691 add('\n')
4692 else:
4693 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004694 add(" ")
4695 add(p.name)
4696 add('\n')
4697 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004698 parameters = output()
4699 if parameters:
4700 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004701
4702 ##
4703 ## docstring body
4704 ##
4705
4706 docstring = f.docstring.rstrip()
4707 lines = [line.rstrip() for line in docstring.split('\n')]
4708
4709 # Enforce the summary line!
4710 # The first line of a docstring should be a summary of the function.
4711 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4712 # by itself.
4713 #
4714 # Argument Clinic enforces the following rule:
4715 # * either the docstring is empty,
4716 # * or it must have a summary line.
4717 #
4718 # Guido said Clinic should enforce this:
4719 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4720
4721 if len(lines) >= 2:
4722 if lines[1]:
4723 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4724 "Every non-blank function docstring must start with\n" +
4725 "a single line summary followed by an empty line.")
4726 elif len(lines) == 1:
4727 # the docstring is only one line right now--the summary line.
4728 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004729 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004730 lines.append('')
4731
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004732 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4733 if parameters_marker_count > 1:
4734 fail('You may not specify {parameters} more than once in a docstring!')
4735
4736 if not parameters_marker_count:
4737 # insert after summary line
4738 lines.insert(2, '{parameters}')
4739
4740 # insert at front of docstring
4741 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004742
4743 docstring = "\n".join(lines)
4744
4745 add(docstring)
4746 docstring = output()
4747
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004748 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004749 docstring = docstring.rstrip()
4750
4751 return docstring
4752
4753 def state_terminal(self, line):
4754 """
4755 Called when processing the block is done.
4756 """
4757 assert not line
4758
4759 if not self.function:
4760 return
4761
4762 if self.keyword_only:
4763 values = self.function.parameters.values()
4764 if not values:
4765 no_parameter_after_star = True
4766 else:
4767 last_parameter = next(reversed(list(values)))
4768 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4769 if no_parameter_after_star:
4770 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4771
4772 # remove trailing whitespace from all parameter docstrings
4773 for name, value in self.function.parameters.items():
4774 if not value:
4775 continue
4776 value.docstring = value.docstring.rstrip()
4777
4778 self.function.docstring = self.format_docstring()
4779
4780
Larry Hastings5c661892014-01-24 06:17:25 -08004781
4782
Larry Hastings31826802013-10-19 00:09:25 -07004783# maps strings to callables.
4784# the callable should return an object
4785# that implements the clinic parser
4786# interface (__init__ and parse).
4787#
4788# example parsers:
4789# "clinic", handles the Clinic DSL
4790# "python", handles running Python code
4791#
4792parsers = {'clinic' : DSLParser, 'python': PythonParser}
4793
4794
4795clinic = None
4796
4797
4798def main(argv):
4799 import sys
4800
4801 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4802 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4803
4804 import argparse
4805 cmdline = argparse.ArgumentParser()
4806 cmdline.add_argument("-f", "--force", action='store_true')
4807 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004808 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004809 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004810 cmdline.add_argument("--make", action='store_true',
4811 help="Walk --srcdir to run over all relevant files.")
4812 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4813 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004814 cmdline.add_argument("filename", type=str, nargs="*")
4815 ns = cmdline.parse_args(argv)
4816
4817 if ns.converters:
4818 if ns.filename:
4819 print("Usage error: can't specify --converters and a filename at the same time.")
4820 print()
4821 cmdline.print_usage()
4822 sys.exit(-1)
4823 converters = []
4824 return_converters = []
4825 ignored = set("""
4826 add_c_converter
4827 add_c_return_converter
4828 add_default_legacy_c_converter
4829 add_legacy_c_converter
4830 """.strip().split())
4831 module = globals()
4832 for name in module:
4833 for suffix, ids in (
4834 ("_return_converter", return_converters),
4835 ("_converter", converters),
4836 ):
4837 if name in ignored:
4838 continue
4839 if name.endswith(suffix):
4840 ids.append((name, name[:-len(suffix)]))
4841 break
4842 print()
4843
4844 print("Legacy converters:")
4845 legacy = sorted(legacy_converters)
4846 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4847 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4848 print()
4849
4850 for title, attribute, ids in (
4851 ("Converters", 'converter_init', converters),
4852 ("Return converters", 'return_converter_init', return_converters),
4853 ):
4854 print(title + ":")
4855 longest = -1
4856 for name, short_name in ids:
4857 longest = max(longest, len(short_name))
4858 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4859 cls = module[name]
4860 callable = getattr(cls, attribute, None)
4861 if not callable:
4862 continue
4863 signature = inspect.signature(callable)
4864 parameters = []
4865 for parameter_name, parameter in signature.parameters.items():
4866 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4867 if parameter.default != inspect.Parameter.empty:
4868 s = '{}={!r}'.format(parameter_name, parameter.default)
4869 else:
4870 s = parameter_name
4871 parameters.append(s)
4872 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004873 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004874 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4875 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004876 sys.exit(0)
4877
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004878 if ns.make:
4879 if ns.output or ns.filename:
4880 print("Usage error: can't use -o or filenames with --make.")
4881 print()
4882 cmdline.print_usage()
4883 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07004884 if not ns.srcdir:
4885 print("Usage error: --srcdir must not be empty with --make.")
4886 print()
4887 cmdline.print_usage()
4888 sys.exit(-1)
4889 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004890 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004891 if rcs_dir in dirs:
4892 dirs.remove(rcs_dir)
4893 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004894 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004895 continue
4896 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004897 if ns.verbose:
4898 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004899 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004900 return
4901
Larry Hastings31826802013-10-19 00:09:25 -07004902 if not ns.filename:
4903 cmdline.print_usage()
4904 sys.exit(-1)
4905
4906 if ns.output and len(ns.filename) > 1:
4907 print("Usage error: can't use -o with multiple filenames.")
4908 print()
4909 cmdline.print_usage()
4910 sys.exit(-1)
4911
4912 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004913 if ns.verbose:
4914 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004915 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004916
4917
4918if __name__ == "__main__":
4919 sys.exit(main(sys.argv[1:]))