blob: cec7c5392db34098d9d5fd48a13486a7704e71c7 [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
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800648 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
649
Serhiy Storchaka31913912019-03-14 10:32:22 +0200650 pos_only = min_pos = max_pos = min_kw_only = 0
651 for i, p in enumerate(parameters, 1):
652 if p.is_keyword_only():
653 assert not p.is_positional_only()
654 if not p.is_optional():
655 min_kw_only = i - max_pos
656 else:
657 max_pos = i
658 if p.is_positional_only():
659 pos_only = i
660 if not p.is_optional():
661 min_pos = i
662
Larry Hastingsbebf7352014-01-17 17:47:17 -0800663 meth_o = (len(parameters) == 1 and
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300664 parameters[0].is_positional_only() and
Larry Hastingsbebf7352014-01-17 17:47:17 -0800665 not converters[0].is_optional() and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800666 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800667
Larry Hastings7726ac92014-01-31 22:03:12 -0800668 # we have to set these things before we're done:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800669 #
670 # docstring_prototype
671 # docstring_definition
672 # impl_prototype
673 # methoddef_define
674 # parser_prototype
675 # parser_definition
676 # impl_definition
Larry Hastings7726ac92014-01-31 22:03:12 -0800677 # cpp_if
678 # cpp_endif
679 # methoddef_ifndef
Larry Hastingsbebf7352014-01-17 17:47:17 -0800680
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800681 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700682
Larry Hastings7726ac92014-01-31 22:03:12 -0800683 methoddef_define = normalize_snippet("""
684 #define {methoddef_name} \\
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200685 {{"{name}", {methoddef_cast}{c_basename}, {methoddef_flags}, {c_basename}__doc__}},
Larry Hastings7726ac92014-01-31 22:03:12 -0800686 """)
Larry Hastings5c661892014-01-24 06:17:25 -0800687 if new_or_init and not f.docstring:
688 docstring_prototype = docstring_definition = ''
689 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800690 docstring_prototype = normalize_snippet("""
691 PyDoc_VAR({c_basename}__doc__);
692 """)
693 docstring_definition = normalize_snippet("""
694 PyDoc_STRVAR({c_basename}__doc__,
695 {docstring});
696 """)
697 impl_definition = normalize_snippet("""
698 static {impl_return_type}
699 {c_basename}_impl({impl_parameters})
700 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800701 impl_prototype = parser_prototype = parser_definition = None
702
Larry Hastings7726ac92014-01-31 22:03:12 -0800703 parser_prototype_keyword = normalize_snippet("""
704 static PyObject *
705 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
706 """)
707
708 parser_prototype_varargs = normalize_snippet("""
709 static PyObject *
710 {c_basename}({self_type}{self_name}, PyObject *args)
711 """)
712
Victor Stinner0c8c3892017-01-17 01:42:54 +0100713 parser_prototype_fastcall = normalize_snippet("""
714 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200715 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300716 """)
717
718 parser_prototype_fastcall_keywords = normalize_snippet("""
719 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200720 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
Victor Stinner0c8c3892017-01-17 01:42:54 +0100721 """)
722
Larry Hastings7726ac92014-01-31 22:03:12 -0800723 # parser_body_fields remembers the fields passed in to the
724 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800725 parser_body_fields = ()
Serhiy Storchaka31913912019-03-14 10:32:22 +0200726 parser_body_declarations = ''
727 def parser_body(prototype, *fields, declarations=''):
728 nonlocal parser_body_fields, parser_body_declarations
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800729 add, output = text_accumulator()
730 add(prototype)
731 parser_body_fields = fields
Serhiy Storchaka31913912019-03-14 10:32:22 +0200732 parser_body_declarations = declarations
Larry Hastings7726ac92014-01-31 22:03:12 -0800733
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800734 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800735 fields.insert(0, normalize_snippet("""
736 {{
737 {return_value_declaration}
Serhiy Storchaka31913912019-03-14 10:32:22 +0200738 {parser_declarations}
Larry Hastings7726ac92014-01-31 22:03:12 -0800739 {declarations}
740 {initializers}
741 """) + "\n")
742 # just imagine--your code is here in the middle
743 fields.append(normalize_snippet("""
744 {modifications}
745 {return_value} = {c_basename}_impl({impl_arguments});
746 {return_conversion}
747
748 {exit_label}
749 {cleanup}
750 return return_value;
751 }}
752 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800753 for field in fields:
754 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800755 add(field)
Serhiy Storchaka31913912019-03-14 10:32:22 +0200756 return linear_format(output(), parser_declarations=declarations)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800757
758 if not parameters:
759 # no parameters, METH_NOARGS
760
761 flags = "METH_NOARGS"
762
Larry Hastings7726ac92014-01-31 22:03:12 -0800763 parser_prototype = normalize_snippet("""
764 static PyObject *
765 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
766 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800767 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800768
769 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800770 parser_definition = parser_prototype + '\n' + normalize_snippet("""
771 {{
772 return {c_basename}_impl({impl_arguments});
773 }}
774 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800775 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800776 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700777
Larry Hastingsbebf7352014-01-17 17:47:17 -0800778 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800779 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800780
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300781 if (isinstance(converters[0], object_converter) and
782 converters[0].format_unit == 'O'):
783 meth_o_prototype = normalize_snippet("""
784 static PyObject *
785 {c_basename}({impl_parameters})
786 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800787
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300788 if default_return_converter:
789 # maps perfectly to METH_O, doesn't need a return converter.
790 # so we skip making a parse function
791 # and call directly into the impl function.
792 impl_prototype = parser_prototype = parser_definition = ''
793 impl_definition = meth_o_prototype
794 else:
795 # SLIGHT HACK
796 # use impl_parameters for the parser here!
797 parser_prototype = meth_o_prototype
798 parser_definition = parser_body(parser_prototype)
799
Larry Hastingsbebf7352014-01-17 17:47:17 -0800800 else:
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300801 argname = 'arg'
802 if parameters[0].name == argname:
803 argname += '_'
804 parser_prototype = normalize_snippet("""
805 static PyObject *
806 {c_basename}({self_type}{self_name}, PyObject *%s)
807 """ % argname)
808
Rémi Lapeyre4901fe22019-08-29 16:49:08 +0200809 displayname = parameters[0].get_displayname(0)
810 parsearg = converters[0].parse_arg(argname, displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200811 if parsearg is None:
812 parsearg = """
813 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
814 goto exit;
815 }}
816 """ % argname
Serhiy Storchaka32d96a22018-12-25 13:23:47 +0200817 parser_definition = parser_body(parser_prototype,
818 normalize_snippet(parsearg, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700819
Larry Hastingsbebf7352014-01-17 17:47:17 -0800820 elif has_option_groups:
821 # positional parameters with option groups
822 # (we have to generate lots of PyArg_ParseTuple calls
823 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700824
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800825 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800826 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700827
Larry Hastings7726ac92014-01-31 22:03:12 -0800828 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700829
Serhiy Storchaka31913912019-03-14 10:32:22 +0200830 elif pos_only == len(parameters):
Victor Stinner0c8c3892017-01-17 01:42:54 +0100831 if not new_or_init:
832 # positional-only, but no option groups
833 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800834
Victor Stinner0c8c3892017-01-17 01:42:54 +0100835 flags = "METH_FASTCALL"
836 parser_prototype = parser_prototype_fastcall
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200837 nargs = 'nargs'
838 argname_fmt = 'args[%d]'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100839 else:
840 # positional-only, but no option groups
841 # we only need one call to PyArg_ParseTuple
842
843 flags = "METH_VARARGS"
844 parser_prototype = parser_prototype_varargs
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200845 nargs = 'PyTuple_GET_SIZE(args)'
846 argname_fmt = 'PyTuple_GET_ITEM(args, %d)'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100847
Serhiy Storchaka31913912019-03-14 10:32:22 +0200848 parser_code = [normalize_snippet("""
849 if (!_PyArg_CheckPositional("{name}", %s, %d, %d)) {{
850 goto exit;
851 }}
852 """ % (nargs, min_pos, max_pos), indent=4)]
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200853 has_optional = False
Serhiy Storchaka31913912019-03-14 10:32:22 +0200854 for i, p in enumerate(parameters):
Rémi Lapeyre4901fe22019-08-29 16:49:08 +0200855 displayname = p.get_displayname(i+1)
856 parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200857 if parsearg is None:
Serhiy Storchaka31913912019-03-14 10:32:22 +0200858 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200859 parser_code = None
860 break
Serhiy Storchaka31913912019-03-14 10:32:22 +0200861 if has_optional or p.is_optional():
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200862 has_optional = True
863 parser_code.append(normalize_snippet("""
864 if (%s < %d) {{
865 goto skip_optional;
866 }}
867 """, indent=4) % (nargs, i + 1))
868 parser_code.append(normalize_snippet(parsearg, indent=4))
869
870 if parser_code is not None:
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200871 if has_optional:
872 parser_code.append("skip_optional:")
873 else:
874 if not new_or_init:
875 parser_code = [normalize_snippet("""
876 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
877 {parse_arguments})) {{
878 goto exit;
879 }}
880 """, indent=4)]
881 else:
882 parser_code = [normalize_snippet("""
883 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
884 {parse_arguments})) {{
885 goto exit;
886 }}
887 """, indent=4)]
888 parser_definition = parser_body(parser_prototype, *parser_code)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800889
890 else:
Serhiy Storchaka31913912019-03-14 10:32:22 +0200891 has_optional_kw = (max(pos_only, min_pos) + min_kw_only < len(converters))
892 if not new_or_init:
893 flags = "METH_FASTCALL|METH_KEYWORDS"
894 parser_prototype = parser_prototype_fastcall_keywords
895 argname_fmt = 'args[%d]'
896 declarations = normalize_snippet("""
897 static const char * const _keywords[] = {{{keywords}, NULL}};
898 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
899 PyObject *argsbuf[%s];
900 """ % len(converters))
901 if has_optional_kw:
902 declarations += "\nPy_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (min_pos + min_kw_only)
903 parser_code = [normalize_snippet("""
904 args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, %d, %d, %d, argsbuf);
905 if (!args) {{
906 goto exit;
907 }}
908 """ % (min_pos, max_pos, min_kw_only), indent=4)]
909 else:
910 # positional-or-keyword arguments
911 flags = "METH_VARARGS|METH_KEYWORDS"
912 parser_prototype = parser_prototype_keyword
913 argname_fmt = 'fastargs[%d]'
914 declarations = normalize_snippet("""
915 static const char * const _keywords[] = {{{keywords}, NULL}};
916 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
917 PyObject *argsbuf[%s];
918 PyObject * const *fastargs;
919 Py_ssize_t nargs = PyTuple_GET_SIZE(args);
920 """ % len(converters))
921 if has_optional_kw:
922 declarations += "\nPy_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (min_pos + min_kw_only)
923 parser_code = [normalize_snippet("""
924 fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %d, %d, %d, argsbuf);
925 if (!fastargs) {{
926 goto exit;
927 }}
928 """ % (min_pos, max_pos, min_kw_only), indent=4)]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800929
Serhiy Storchaka31913912019-03-14 10:32:22 +0200930 add_label = None
931 for i, p in enumerate(parameters):
Rémi Lapeyre4901fe22019-08-29 16:49:08 +0200932 displayname = p.get_displayname(i+1)
933 parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
Serhiy Storchaka31913912019-03-14 10:32:22 +0200934 if parsearg is None:
935 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr)
936 parser_code = None
937 break
938 if add_label and (i == pos_only or i == max_pos):
939 parser_code.append("%s:" % add_label)
940 add_label = None
941 if not p.is_optional():
942 parser_code.append(normalize_snippet(parsearg, indent=4))
943 elif i < pos_only:
944 add_label = 'skip_optional_posonly'
945 parser_code.append(normalize_snippet("""
946 if (nargs < %d) {{
947 goto %s;
948 }}
949 """ % (i + 1, add_label), indent=4))
950 if has_optional_kw:
951 parser_code.append(normalize_snippet("""
952 noptargs--;
953 """, indent=4))
954 parser_code.append(normalize_snippet(parsearg, indent=4))
955 else:
956 if i < max_pos:
957 label = 'skip_optional_pos'
958 first_opt = max(min_pos, pos_only)
959 else:
960 label = 'skip_optional_kwonly'
961 first_opt = max_pos + min_kw_only
962 if i == first_opt:
963 add_label = label
964 parser_code.append(normalize_snippet("""
965 if (!noptargs) {{
966 goto %s;
967 }}
968 """ % add_label, indent=4))
969 if i + 1 == len(parameters):
970 parser_code.append(normalize_snippet(parsearg, indent=4))
971 else:
972 add_label = label
973 parser_code.append(normalize_snippet("""
974 if (%s) {{
975 """ % (argname_fmt % i), indent=4))
976 parser_code.append(normalize_snippet(parsearg, indent=8))
977 parser_code.append(normalize_snippet("""
978 if (!--noptargs) {{
979 goto %s;
980 }}
981 }}
982 """ % add_label, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800983
Serhiy Storchaka31913912019-03-14 10:32:22 +0200984 if parser_code is not None:
985 if add_label:
986 parser_code.append("%s:" % add_label)
987 else:
988 declarations = (
989 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
990 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};')
991 if not new_or_init:
992 parser_code = [normalize_snippet("""
993 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
994 {parse_arguments})) {{
995 goto exit;
996 }}
997 """, indent=4)]
998 else:
999 parser_code = [normalize_snippet("""
1000 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
1001 {parse_arguments})) {{
1002 goto exit;
1003 }}
1004 """, indent=4)]
1005 parser_definition = parser_body(parser_prototype, *parser_code,
1006 declarations=declarations)
Larry Hastings31826802013-10-19 00:09:25 -07001007
Larry Hastings31826802013-10-19 00:09:25 -07001008
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001009 if new_or_init:
1010 methoddef_define = ''
1011
1012 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -08001013 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001014 else:
1015 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -08001016 parser_prototype = normalize_snippet("""
1017 static int
1018 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
1019 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001020
1021 fields = list(parser_body_fields)
1022 parses_positional = 'METH_NOARGS' not in flags
1023 parses_keywords = 'METH_KEYWORDS' in flags
1024 if parses_keywords:
1025 assert parses_positional
1026
1027 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -08001028 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001029 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -08001030 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001031 }}
Larry Hastings7726ac92014-01-31 22:03:12 -08001032 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001033 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -08001034 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001035 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -08001036 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001037 }}
Larry Hastings7726ac92014-01-31 22:03:12 -08001038 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001039
Serhiy Storchaka31913912019-03-14 10:32:22 +02001040 parser_definition = parser_body(parser_prototype, *fields,
1041 declarations=parser_body_declarations)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001042
Larry Hastings31826802013-10-19 00:09:25 -07001043
Serhiy Storchaka4a934d42018-11-27 11:27:36 +02001044 if flags in ('METH_NOARGS', 'METH_O', 'METH_VARARGS'):
1045 methoddef_cast = "(PyCFunction)"
1046 else:
1047 methoddef_cast = "(PyCFunction)(void(*)(void))"
1048
Larry Hastingsbebf7352014-01-17 17:47:17 -08001049 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001050 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -07001051
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001052 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Serhiy Storchaka4a934d42018-11-27 11:27:36 +02001053 methoddef_define = methoddef_define.replace('{methoddef_cast}', methoddef_cast)
Larry Hastings31826802013-10-19 00:09:25 -07001054
Larry Hastings7726ac92014-01-31 22:03:12 -08001055 methoddef_ifndef = ''
1056 conditional = self.cpp.condition()
1057 if not conditional:
1058 cpp_if = cpp_endif = ''
1059 else:
1060 cpp_if = "#if " + conditional
1061 cpp_endif = "#endif /* " + conditional + " */"
1062
Tal Einat4f574092017-11-03 11:09:00 +02001063 if methoddef_define and f.full_name not in clinic.ifndef_symbols:
1064 clinic.ifndef_symbols.add(f.full_name)
Larry Hastings7726ac92014-01-31 22:03:12 -08001065 methoddef_ifndef = normalize_snippet("""
1066 #ifndef {methoddef_name}
1067 #define {methoddef_name}
1068 #endif /* !defined({methoddef_name}) */
1069 """)
1070
1071
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001072 # add ';' to the end of parser_prototype and impl_prototype
1073 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001074 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001075 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001076 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001077 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -07001078
Larry Hastingsbebf7352014-01-17 17:47:17 -08001079 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001080 impl_prototype = impl_definition
1081 if impl_prototype:
1082 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -07001083
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001084 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001085
1086 d = {
1087 "docstring_prototype" : docstring_prototype,
1088 "docstring_definition" : docstring_definition,
1089 "impl_prototype" : impl_prototype,
1090 "methoddef_define" : methoddef_define,
1091 "parser_prototype" : parser_prototype,
1092 "parser_definition" : parser_definition,
1093 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -08001094 "cpp_if" : cpp_if,
1095 "cpp_endif" : cpp_endif,
1096 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001097 }
1098
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001099 # make sure we didn't forget to assign something,
1100 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001101 d2 = {}
1102 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001103 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001104 if value:
1105 value = '\n' + value + '\n'
1106 d2[name] = value
1107 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001108
1109 @staticmethod
1110 def group_to_variable_name(group):
1111 adjective = "left_" if group < 0 else "right_"
1112 return "group_" + adjective + str(abs(group))
1113
1114 def render_option_group_parsing(self, f, template_dict):
1115 # positional only, grouped, optional arguments!
1116 # can be optional on the left or right.
1117 # here's an example:
1118 #
1119 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1120 #
1121 # Here group D are required, and all other groups are optional.
1122 # (Group D's "group" is actually None.)
1123 # We can figure out which sets of arguments we have based on
1124 # how many arguments are in the tuple.
1125 #
1126 # Note that you need to count up on both sides. For example,
1127 # you could have groups C+D, or C+D+E, or C+D+E+F.
1128 #
1129 # What if the number of arguments leads us to an ambiguous result?
1130 # Clinic prefers groups on the left. So in the above example,
1131 # five arguments would map to B+C, not C+D.
1132
1133 add, output = text_accumulator()
1134 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001135 if isinstance(parameters[0].converter, self_converter):
1136 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001137
1138 groups = []
1139 group = None
1140 left = []
1141 right = []
1142 required = []
1143 last = unspecified
1144
1145 for p in parameters:
1146 group_id = p.group
1147 if group_id != last:
1148 last = group_id
1149 group = []
1150 if group_id < 0:
1151 left.append(group)
1152 elif group_id == 0:
1153 group = required
1154 else:
1155 right.append(group)
1156 group.append(p)
1157
1158 count_min = sys.maxsize
1159 count_max = -1
1160
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001161 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001162 for subset in permute_optional_groups(left, required, right):
1163 count = len(subset)
1164 count_min = min(count_min, count)
1165 count_max = max(count_max, count)
1166
Larry Hastings583baa82014-01-12 08:49:30 -08001167 if count == 0:
1168 add(""" case 0:
1169 break;
1170""")
1171 continue
1172
Larry Hastings31826802013-10-19 00:09:25 -07001173 group_ids = {p.group for p in subset} # eliminate duplicates
1174 d = {}
1175 d['count'] = count
1176 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001177 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1178
1179 parse_arguments = []
1180 for p in subset:
1181 p.converter.parse_argument(parse_arguments)
1182 d['parse_arguments'] = ", ".join(parse_arguments)
1183
1184 group_ids.discard(0)
1185 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1186 lines = "\n".join(lines)
1187
1188 s = """
1189 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001190 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001191 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001192 }}
Larry Hastings31826802013-10-19 00:09:25 -07001193 {group_booleans}
1194 break;
1195"""[1:]
1196 s = linear_format(s, group_booleans=lines)
1197 s = s.format_map(d)
1198 add(s)
1199
1200 add(" default:\n")
1201 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1202 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001203 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001204 add("}")
1205 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001206
Larry Hastingsbebf7352014-01-17 17:47:17 -08001207 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001208 if not f:
1209 return ""
1210
1211 add, output = text_accumulator()
1212 data = CRenderData()
1213
Larry Hastings7726ac92014-01-31 22:03:12 -08001214 assert f.parameters, "We should always have a 'self' at this point!"
1215 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001216 converters = [p.converter for p in parameters]
1217
Larry Hastings5c661892014-01-24 06:17:25 -08001218 templates = self.output_templates(f)
1219
1220 f_self = parameters[0]
1221 selfless = parameters[1:]
1222 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1223
1224 last_group = 0
1225 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001226 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001227 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1228 default_return_converter = (not f.return_converter or
1229 f.return_converter.type == 'PyObject *')
1230 has_option_groups = False
1231
1232 # offset i by -1 because first_optional needs to ignore self
1233 for i, p in enumerate(parameters, -1):
1234 c = p.converter
1235
1236 if (i != -1) and (p.default is not unspecified):
1237 first_optional = min(first_optional, i)
1238
1239 # insert group variable
1240 group = p.group
1241 if last_group != group:
1242 last_group = group
1243 if group:
1244 group_name = self.group_to_variable_name(group)
1245 data.impl_arguments.append(group_name)
1246 data.declarations.append("int " + group_name + " = 0;")
1247 data.impl_parameters.append("int " + group_name)
1248 has_option_groups = True
1249
1250 c.render(p, data)
1251
1252 if has_option_groups and (not positional):
1253 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1254
1255 # HACK
1256 # when we're METH_O, but have a custom return converter,
1257 # we use "impl_parameters" for the parsing function
1258 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001259 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001260 # as variables in the parsing function. but since it's
1261 # METH_O, we have exactly one anyway, so we know exactly
1262 # where it is.
1263 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001264 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001265 data.declarations.pop(0)
1266
Larry Hastings31826802013-10-19 00:09:25 -07001267 template_dict = {}
1268
1269 full_name = f.full_name
1270 template_dict['full_name'] = full_name
1271
Larry Hastings5c661892014-01-24 06:17:25 -08001272 if new_or_init:
1273 name = f.cls.name
1274 else:
1275 name = f.name
1276
Larry Hastings31826802013-10-19 00:09:25 -07001277 template_dict['name'] = name
1278
Larry Hastings8666e652014-01-12 14:12:59 -08001279 if f.c_basename:
1280 c_basename = f.c_basename
1281 else:
1282 fields = full_name.split(".")
1283 if fields[-1] == '__new__':
1284 fields.pop()
1285 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001286
Larry Hastings31826802013-10-19 00:09:25 -07001287 template_dict['c_basename'] = c_basename
1288
1289 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1290 template_dict['methoddef_name'] = methoddef_name
1291
1292 template_dict['docstring'] = self.docstring_for_c_string(f)
1293
Larry Hastingsc2047262014-01-25 20:43:29 -08001294 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001295 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001296
Larry Hastings31826802013-10-19 00:09:25 -07001297 f.return_converter.render(f, data)
1298 template_dict['impl_return_type'] = f.return_converter.type
1299
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001300 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001301 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001302 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001303 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1304 template_dict['format_units'] = ''.join(data.format_units)
1305 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1306 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1307 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001308 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1309 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001310 template_dict['return_value'] = data.return_value
1311
Larry Hastings5c661892014-01-24 06:17:25 -08001312 # used by unpack tuple code generator
1313 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1314 unpack_min = first_optional
1315 unpack_max = len(selfless)
1316 template_dict['unpack_min'] = str(unpack_min)
1317 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001318
Larry Hastingsbebf7352014-01-17 17:47:17 -08001319 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001320 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001321
Larry Hastings0759f842015-04-03 13:09:02 -07001322 # buffers, not destination
1323 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001324 template = templates[name]
1325 if has_option_groups:
1326 template = linear_format(template,
1327 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001328 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001329 declarations=template_dict['declarations'],
1330 return_conversion=template_dict['return_conversion'],
1331 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001332 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001333 cleanup=template_dict['cleanup'],
1334 )
Larry Hastings31826802013-10-19 00:09:25 -07001335
Larry Hastingsbebf7352014-01-17 17:47:17 -08001336 # Only generate the "exit:" label
1337 # if we have any gotos
1338 need_exit_label = "goto exit;" in template
1339 template = linear_format(template,
1340 exit_label="exit:" if need_exit_label else ''
1341 )
Larry Hastings31826802013-10-19 00:09:25 -07001342
Larry Hastingsbebf7352014-01-17 17:47:17 -08001343 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001344
Larry Hastings89964c42015-04-14 18:07:59 -04001345 # mild hack:
1346 # reflow long impl declarations
1347 if name in {"impl_prototype", "impl_definition"}:
1348 s = wrap_declarations(s)
1349
Larry Hastingsbebf7352014-01-17 17:47:17 -08001350 if clinic.line_prefix:
1351 s = indent_all_lines(s, clinic.line_prefix)
1352 if clinic.line_suffix:
1353 s = suffix_all_lines(s, clinic.line_suffix)
1354
1355 destination.append(s)
1356
1357 return clinic.get_destination('block').dump()
1358
Larry Hastings31826802013-10-19 00:09:25 -07001359
1360
Larry Hastings5c661892014-01-24 06:17:25 -08001361
Larry Hastings31826802013-10-19 00:09:25 -07001362@contextlib.contextmanager
1363def OverrideStdioWith(stdout):
1364 saved_stdout = sys.stdout
1365 sys.stdout = stdout
1366 try:
1367 yield
1368 finally:
1369 assert sys.stdout is stdout
1370 sys.stdout = saved_stdout
1371
1372
Larry Hastings2623c8c2014-02-08 22:15:29 -08001373def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001374 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001375 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001376 pattern = r'{}({}){}'
1377 if whole_line:
1378 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001379 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1380 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001381
1382
1383class Block:
1384 r"""
1385 Represents a single block of text embedded in
1386 another file. If dsl_name is None, the block represents
1387 verbatim text, raw original text from the file, in
1388 which case "input" will be the only non-false member.
1389 If dsl_name is not None, the block represents a Clinic
1390 block.
1391
1392 input is always str, with embedded \n characters.
1393 input represents the original text from the file;
1394 if it's a Clinic block, it is the original text with
1395 the body_prefix and redundant leading whitespace removed.
1396
1397 dsl_name is either str or None. If str, it's the text
1398 found on the start line of the block between the square
1399 brackets.
1400
1401 signatures is either list or None. If it's a list,
1402 it may only contain clinic.Module, clinic.Class, and
1403 clinic.Function objects. At the moment it should
1404 contain at most one of each.
1405
1406 output is either str or None. If str, it's the output
1407 from this block, with embedded '\n' characters.
1408
1409 indent is either str or None. It's the leading whitespace
1410 that was found on every line of input. (If body_prefix is
1411 not empty, this is the indent *after* removing the
1412 body_prefix.)
1413
1414 preindent is either str or None. It's the whitespace that
1415 was found in front of every line of input *before* the
1416 "body_prefix" (see the Language object). If body_prefix
1417 is empty, preindent must always be empty too.
1418
1419 To illustrate indent and preindent: Assume that '_'
1420 represents whitespace. If the block processed was in a
1421 Python file, and looked like this:
1422 ____#/*[python]
1423 ____#__for a in range(20):
1424 ____#____print(a)
1425 ____#[python]*/
1426 "preindent" would be "____" and "indent" would be "__".
1427
1428 """
1429 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1430 assert isinstance(input, str)
1431 self.input = input
1432 self.dsl_name = dsl_name
1433 self.signatures = signatures or []
1434 self.output = output
1435 self.indent = indent
1436 self.preindent = preindent
1437
Larry Hastings581ee362014-01-28 05:00:08 -08001438 def __repr__(self):
1439 dsl_name = self.dsl_name or "text"
1440 def summarize(s):
1441 s = repr(s)
1442 if len(s) > 30:
1443 return s[:26] + "..." + s[0]
1444 return s
1445 return "".join((
1446 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1447
Larry Hastings31826802013-10-19 00:09:25 -07001448
1449class BlockParser:
1450 """
1451 Block-oriented parser for Argument Clinic.
1452 Iterator, yields Block objects.
1453 """
1454
1455 def __init__(self, input, language, *, verify=True):
1456 """
1457 "input" should be a str object
1458 with embedded \n characters.
1459
1460 "language" should be a Language object.
1461 """
1462 language.validate()
1463
1464 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1465 self.block_start_line_number = self.line_number = 0
1466
1467 self.language = language
1468 before, _, after = language.start_line.partition('{dsl_name}')
1469 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001470 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001471 self.start_re = create_regex(before, after)
1472 self.verify = verify
1473 self.last_checksum_re = None
1474 self.last_dsl_name = None
1475 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001476 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001477
1478 def __iter__(self):
1479 return self
1480
1481 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001482 while True:
1483 if not self.input:
1484 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001485
Larry Hastingsbebf7352014-01-17 17:47:17 -08001486 if self.dsl_name:
1487 return_value = self.parse_clinic_block(self.dsl_name)
1488 self.dsl_name = None
1489 self.first_block = False
1490 return return_value
1491 block = self.parse_verbatim_block()
1492 if self.first_block and not block.input:
1493 continue
1494 self.first_block = False
1495 return block
1496
Larry Hastings31826802013-10-19 00:09:25 -07001497
1498 def is_start_line(self, line):
1499 match = self.start_re.match(line.lstrip())
1500 return match.group(1) if match else None
1501
Larry Hastingse1b82532014-07-27 16:22:20 +02001502 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001503 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001504 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001505 if not lookahead:
1506 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001507 return line
Larry Hastings31826802013-10-19 00:09:25 -07001508
1509 def parse_verbatim_block(self):
1510 add, output = text_accumulator()
1511 self.block_start_line_number = self.line_number
1512
1513 while self.input:
1514 line = self._line()
1515 dsl_name = self.is_start_line(line)
1516 if dsl_name:
1517 self.dsl_name = dsl_name
1518 break
1519 add(line)
1520
1521 return Block(output())
1522
1523 def parse_clinic_block(self, dsl_name):
1524 input_add, input_output = text_accumulator()
1525 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001526 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001527 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1528
Larry Hastings90261132014-01-07 12:21:08 -08001529 def is_stop_line(line):
1530 # make sure to recognize stop line even if it
1531 # doesn't end with EOL (it could be the very end of the file)
1532 if not line.startswith(stop_line):
1533 return False
1534 remainder = line[len(stop_line):]
1535 return (not remainder) or remainder.isspace()
1536
Larry Hastings31826802013-10-19 00:09:25 -07001537 # consume body of program
1538 while self.input:
1539 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001540 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001541 break
1542 if body_prefix:
1543 line = line.lstrip()
1544 assert line.startswith(body_prefix)
1545 line = line[len(body_prefix):]
1546 input_add(line)
1547
1548 # consume output and checksum line, if present.
1549 if self.last_dsl_name == dsl_name:
1550 checksum_re = self.last_checksum_re
1551 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001552 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1553 assert _ == '{arguments}'
1554 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001555 self.last_dsl_name = dsl_name
1556 self.last_checksum_re = checksum_re
1557
1558 # scan forward for checksum line
1559 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001560 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001561 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001562 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001563 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001564 arguments = match.group(1) if match else None
1565 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001566 break
1567 output_add(line)
1568 if self.is_start_line(line):
1569 break
1570
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001571 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001572 if arguments:
1573 d = {}
1574 for field in shlex.split(arguments):
1575 name, equals, value = field.partition('=')
1576 if not equals:
1577 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1578 d[name.strip()] = value.strip()
1579
Larry Hastings31826802013-10-19 00:09:25 -07001580 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001581 if 'input' in d:
1582 checksum = d['output']
1583 input_checksum = d['input']
1584 else:
1585 checksum = d['checksum']
1586 input_checksum = None
1587
1588 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001589 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001590 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1591 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001592 "the end marker,\n"
1593 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001594 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001595 else:
1596 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001597 output_lines = output.splitlines(keepends=True)
1598 self.line_number -= len(output_lines)
1599 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001600 output = None
1601
1602 return Block(input_output(), dsl_name, output=output)
1603
1604
1605class BlockPrinter:
1606
1607 def __init__(self, language, f=None):
1608 self.language = language
1609 self.f = f or io.StringIO()
1610
1611 def print_block(self, block):
1612 input = block.input
1613 output = block.output
1614 dsl_name = block.dsl_name
1615 write = self.f.write
1616
Larry Hastings31826802013-10-19 00:09:25 -07001617 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1618
1619 if not dsl_name:
1620 write(input)
1621 return
1622
1623 write(self.language.start_line.format(dsl_name=dsl_name))
1624 write("\n")
1625
1626 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1627 if not body_prefix:
1628 write(input)
1629 else:
1630 for line in input.split('\n'):
1631 write(body_prefix)
1632 write(line)
1633 write("\n")
1634
1635 write(self.language.stop_line.format(dsl_name=dsl_name))
1636 write("\n")
1637
Larry Hastings581ee362014-01-28 05:00:08 -08001638 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001639 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001640 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001641 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001642 output += '\n'
1643 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001644
Larry Hastings581ee362014-01-28 05:00:08 -08001645 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1646 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001647 write("\n")
1648
Larry Hastingsbebf7352014-01-17 17:47:17 -08001649 def write(self, text):
1650 self.f.write(text)
1651
1652
Larry Hastings0759f842015-04-03 13:09:02 -07001653class BufferSeries:
1654 """
1655 Behaves like a "defaultlist".
1656 When you ask for an index that doesn't exist yet,
1657 the object grows the list until that item exists.
1658 So o[n] will always work.
1659
1660 Supports negative indices for actual items.
1661 e.g. o[-1] is an element immediately preceding o[0].
1662 """
1663
1664 def __init__(self):
1665 self._start = 0
1666 self._array = []
1667 self._constructor = _text_accumulator
1668
1669 def __getitem__(self, i):
1670 i -= self._start
1671 if i < 0:
1672 self._start += i
1673 prefix = [self._constructor() for x in range(-i)]
1674 self._array = prefix + self._array
1675 i = 0
1676 while i >= len(self._array):
1677 self._array.append(self._constructor())
1678 return self._array[i]
1679
1680 def clear(self):
1681 for ta in self._array:
1682 ta._text.clear()
1683
1684 def dump(self):
1685 texts = [ta.output() for ta in self._array]
1686 return "".join(texts)
1687
1688
Larry Hastingsbebf7352014-01-17 17:47:17 -08001689class Destination:
1690 def __init__(self, name, type, clinic, *args):
1691 self.name = name
1692 self.type = type
1693 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001694 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001695 if type not in valid_types:
1696 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1697 extra_arguments = 1 if type == "file" else 0
1698 if len(args) < extra_arguments:
1699 fail("Not enough arguments for destination " + name + " new " + type)
1700 if len(args) > extra_arguments:
1701 fail("Too many arguments for destination " + name + " new " + type)
1702 if type =='file':
1703 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001704 filename = clinic.filename
1705 d['path'] = filename
1706 dirname, basename = os.path.split(filename)
1707 if not dirname:
1708 dirname = '.'
1709 d['dirname'] = dirname
1710 d['basename'] = basename
1711 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001712 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001713
Larry Hastings0759f842015-04-03 13:09:02 -07001714 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001715
1716 def __repr__(self):
1717 if self.type == 'file':
1718 file_repr = " " + repr(self.filename)
1719 else:
1720 file_repr = ''
1721 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1722
1723 def clear(self):
1724 if self.type != 'buffer':
1725 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001726 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001727
1728 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001729 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001730
Larry Hastings31826802013-10-19 00:09:25 -07001731
1732# maps strings to Language objects.
1733# "languages" maps the name of the language ("C", "Python").
1734# "extensions" maps the file extension ("c", "py").
1735languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001736extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1737extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001738
1739
1740# maps strings to callables.
1741# these callables must be of the form:
1742# def foo(name, default, *, ...)
1743# The callable may have any number of keyword-only parameters.
1744# The callable must return a CConverter object.
1745# The callable should not call builtins.print.
1746converters = {}
1747
1748# maps strings to callables.
1749# these callables follow the same rules as those for "converters" above.
1750# note however that they will never be called with keyword-only parameters.
1751legacy_converters = {}
1752
1753
1754# maps strings to callables.
1755# these callables must be of the form:
1756# def foo(*, ...)
1757# The callable may have any number of keyword-only parameters.
1758# The callable must return a CConverter object.
1759# The callable should not call builtins.print.
1760return_converters = {}
1761
Larry Hastings7726ac92014-01-31 22:03:12 -08001762clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001763class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001764
1765 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001766preset block
1767everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001768methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001769docstring_prototype suppress
1770parser_prototype suppress
1771cpp_if suppress
1772cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001773
Larry Hastingsbebf7352014-01-17 17:47:17 -08001774preset original
1775everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001776methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001777docstring_prototype suppress
1778parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001779cpp_if suppress
1780cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001781
1782preset file
1783everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001784methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001785docstring_prototype suppress
1786parser_prototype suppress
1787impl_definition block
1788
1789preset buffer
1790everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001791methoddef_ifndef buffer 1
1792impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001793docstring_prototype suppress
1794impl_prototype suppress
1795parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001796
1797preset partial-buffer
1798everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001799methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001800docstring_prototype block
1801impl_prototype suppress
1802methoddef_define block
1803parser_prototype block
1804impl_definition block
1805
Larry Hastingsbebf7352014-01-17 17:47:17 -08001806"""
1807
Larry Hastings581ee362014-01-28 05:00:08 -08001808 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001809 # maps strings to Parser objects.
1810 # (instantiated from the "parsers" global.)
1811 self.parsers = {}
1812 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001813 if printer:
1814 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001815 self.printer = printer or BlockPrinter(language)
1816 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001817 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001818 self.filename = filename
1819 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001820 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001821 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001822
Larry Hastingsbebf7352014-01-17 17:47:17 -08001823 self.line_prefix = self.line_suffix = ''
1824
1825 self.destinations = {}
1826 self.add_destination("block", "buffer")
1827 self.add_destination("suppress", "suppress")
1828 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001829 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001830 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001831
Larry Hastings0759f842015-04-03 13:09:02 -07001832 d = self.get_destination_buffer
1833 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001834 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001835 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001836 ('docstring_definition', d('file')),
1837 ('methoddef_define', d('file')),
1838 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001839 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001840 ('parser_definition', d('file')),
1841 ('cpp_endif', d('file')),
1842 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001843 ('impl_definition', d('block')),
1844 ))
1845
Larry Hastings0759f842015-04-03 13:09:02 -07001846 self.destination_buffers_stack = []
1847 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001848
1849 self.presets = {}
1850 preset = None
1851 for line in self.presets_text.strip().split('\n'):
1852 line = line.strip()
1853 if not line:
1854 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001855 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001856 if name == 'preset':
1857 self.presets[value] = preset = collections.OrderedDict()
1858 continue
1859
Larry Hastings0759f842015-04-03 13:09:02 -07001860 if len(options):
1861 index = int(options[0])
1862 else:
1863 index = 0
1864 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001865
1866 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001867 for name in self.destination_buffers:
1868 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001869 continue
1870
Larry Hastings0759f842015-04-03 13:09:02 -07001871 assert name in self.destination_buffers
1872 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001873
Larry Hastings31826802013-10-19 00:09:25 -07001874 global clinic
1875 clinic = self
1876
Larry Hastingsbebf7352014-01-17 17:47:17 -08001877 def add_destination(self, name, type, *args):
1878 if name in self.destinations:
1879 fail("Destination already exists: " + repr(name))
1880 self.destinations[name] = Destination(name, type, self, *args)
1881
Larry Hastings0759f842015-04-03 13:09:02 -07001882 def get_destination(self, name):
1883 d = self.destinations.get(name)
1884 if not d:
1885 fail("Destination does not exist: " + repr(name))
1886 return d
1887
1888 def get_destination_buffer(self, name, item=0):
1889 d = self.get_destination(name)
1890 return d.buffers[item]
1891
Larry Hastings31826802013-10-19 00:09:25 -07001892 def parse(self, input):
1893 printer = self.printer
1894 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1895 for block in self.block_parser:
1896 dsl_name = block.dsl_name
1897 if dsl_name:
1898 if dsl_name not in self.parsers:
1899 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1900 self.parsers[dsl_name] = parsers[dsl_name](self)
1901 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001902 try:
1903 parser.parse(block)
1904 except Exception:
1905 fail('Exception raised during parsing:\n' +
1906 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001907 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001908
1909 second_pass_replacements = {}
1910
Larry Hastings0759f842015-04-03 13:09:02 -07001911 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001912 for name, destination in self.destinations.items():
1913 if destination.type == 'suppress':
1914 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001915 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001916
1917 if output:
1918
1919 block = Block("", dsl_name="clinic", output=output)
1920
1921 if destination.type == 'buffer':
1922 block.input = "dump " + name + "\n"
1923 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1924 printer.write("\n")
1925 printer.print_block(block)
1926 continue
1927
1928 if destination.type == 'file':
1929 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001930 dirname = os.path.dirname(destination.filename)
1931 try:
1932 os.makedirs(dirname)
1933 except FileExistsError:
1934 if not os.path.isdir(dirname):
1935 fail("Can't write to destination {}, "
1936 "can't make directory {}!".format(
1937 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001938 if self.verify:
1939 with open(destination.filename, "rt") as f:
1940 parser_2 = BlockParser(f.read(), language=self.language)
1941 blocks = list(parser_2)
1942 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1943 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001944 except FileNotFoundError:
1945 pass
1946
1947 block.input = 'preserve\n'
1948 printer_2 = BlockPrinter(self.language)
1949 printer_2.print_block(block)
1950 with open(destination.filename, "wt") as f:
1951 f.write(printer_2.f.getvalue())
1952 continue
1953 text = printer.f.getvalue()
1954
1955 if second_pass_replacements:
1956 printer_2 = BlockPrinter(self.language)
1957 parser_2 = BlockParser(text, self.language)
1958 changed = False
1959 for block in parser_2:
1960 if block.dsl_name:
1961 for id, replacement in second_pass_replacements.items():
1962 if id in block.output:
1963 changed = True
1964 block.output = block.output.replace(id, replacement)
1965 printer_2.print_block(block)
1966 if changed:
1967 text = printer_2.f.getvalue()
1968
1969 return text
1970
Larry Hastings31826802013-10-19 00:09:25 -07001971
1972 def _module_and_class(self, fields):
1973 """
1974 fields should be an iterable of field names.
1975 returns a tuple of (module, class).
1976 the module object could actually be self (a clinic object).
1977 this function is only ever used to find the parent of where
1978 a new class/module should go.
1979 """
1980 in_classes = False
1981 parent = module = self
1982 cls = None
1983 so_far = []
1984
1985 for field in fields:
1986 so_far.append(field)
1987 if not in_classes:
1988 child = parent.modules.get(field)
1989 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001990 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001991 continue
1992 in_classes = True
1993 if not hasattr(parent, 'classes'):
1994 return module, cls
1995 child = parent.classes.get(field)
1996 if not child:
1997 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1998 cls = parent = child
1999
2000 return module, cls
2001
2002
Larry Hastings581ee362014-01-28 05:00:08 -08002003def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07002004 extension = os.path.splitext(filename)[1][1:]
2005 if not extension:
2006 fail("Can't extract file type for file " + repr(filename))
2007
2008 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08002009 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07002010 except KeyError:
2011 fail("Can't identify file type for file " + repr(filename))
2012
Larry Hastings31826802013-10-19 00:09:25 -07002013 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002014 raw = f.read()
2015
Larry Hastings2623c8c2014-02-08 22:15:29 -08002016 # exit quickly if there are no clinic markers in the file
2017 find_start_re = BlockParser("", language).find_start_re
2018 if not find_start_re.search(raw):
2019 return
2020
2021 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002022 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08002023 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002024 return
Larry Hastings31826802013-10-19 00:09:25 -07002025
2026 directory = os.path.dirname(filename) or '.'
2027
2028 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002029 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07002030 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
2031 with open(tmpfilename, "wb") as f:
2032 f.write(bytes)
2033 os.replace(tmpfilename, output or filename)
2034
2035
Larry Hastings581ee362014-01-28 05:00:08 -08002036def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07002037 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08002038 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
2039 if length:
2040 s = s[:length]
2041 return s
Larry Hastings31826802013-10-19 00:09:25 -07002042
2043
2044
2045
2046class PythonParser:
2047 def __init__(self, clinic):
2048 pass
2049
2050 def parse(self, block):
2051 s = io.StringIO()
2052 with OverrideStdioWith(s):
2053 exec(block.input)
2054 block.output = s.getvalue()
2055
2056
2057class Module:
2058 def __init__(self, name, module=None):
2059 self.name = name
2060 self.module = self.parent = module
2061
2062 self.modules = collections.OrderedDict()
2063 self.classes = collections.OrderedDict()
2064 self.functions = []
2065
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002066 def __repr__(self):
2067 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
2068
Larry Hastings31826802013-10-19 00:09:25 -07002069class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08002070 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07002071 self.name = name
2072 self.module = module
2073 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08002074 self.typedef = typedef
2075 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07002076 self.parent = cls or module
2077
2078 self.classes = collections.OrderedDict()
2079 self.functions = []
2080
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002081 def __repr__(self):
2082 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
2083
Larry Hastings8666e652014-01-12 14:12:59 -08002084unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002085
Larry Hastings8666e652014-01-12 14:12:59 -08002086__abs__
2087__add__
2088__and__
2089__bytes__
2090__call__
2091__complex__
2092__delitem__
2093__divmod__
2094__eq__
2095__float__
2096__floordiv__
2097__ge__
2098__getattr__
2099__getattribute__
2100__getitem__
2101__gt__
2102__hash__
2103__iadd__
2104__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002105__ifloordiv__
2106__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002107__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002108__imod__
2109__imul__
2110__index__
2111__int__
2112__invert__
2113__ior__
2114__ipow__
2115__irshift__
2116__isub__
2117__iter__
2118__itruediv__
2119__ixor__
2120__le__
2121__len__
2122__lshift__
2123__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002124__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002125__mod__
2126__mul__
2127__neg__
2128__new__
2129__next__
2130__or__
2131__pos__
2132__pow__
2133__radd__
2134__rand__
2135__rdivmod__
2136__repr__
2137__rfloordiv__
2138__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002139__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002140__rmod__
2141__rmul__
2142__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002143__rpow__
2144__rrshift__
2145__rshift__
2146__rsub__
2147__rtruediv__
2148__rxor__
2149__setattr__
2150__setitem__
2151__str__
2152__sub__
2153__truediv__
2154__xor__
2155
2156""".strip().split())
2157
2158
Larry Hastings5c661892014-01-24 06:17:25 -08002159INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2160INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2161""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002162
2163class Function:
2164 """
2165 Mutable duck type for inspect.Function.
2166
2167 docstring - a str containing
2168 * embedded line breaks
2169 * text outdented to the left margin
2170 * no trailing whitespace.
2171 It will always be true that
2172 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2173 """
2174
2175 def __init__(self, parameters=None, *, name,
2176 module, cls=None, c_basename=None,
2177 full_name=None,
2178 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002179 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002180 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002181 self.parameters = parameters or collections.OrderedDict()
2182 self.return_annotation = return_annotation
2183 self.name = name
2184 self.full_name = full_name
2185 self.module = module
2186 self.cls = cls
2187 self.parent = cls or module
2188 self.c_basename = c_basename
2189 self.return_converter = return_converter
2190 self.docstring = docstring or ''
2191 self.kind = kind
2192 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002193 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002194 # docstring_only means "don't generate a machine-readable
2195 # signature, just a normal docstring". it's True for
2196 # functions with optional groups because we can't represent
2197 # those accurately with inspect.Signature in 3.4.
2198 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002199
Larry Hastings7726ac92014-01-31 22:03:12 -08002200 self.rendered_parameters = None
2201
2202 __render_parameters__ = None
2203 @property
2204 def render_parameters(self):
2205 if not self.__render_parameters__:
2206 self.__render_parameters__ = l = []
2207 for p in self.parameters.values():
2208 p = p.copy()
2209 p.converter.pre_render()
2210 l.append(p)
2211 return self.__render_parameters__
2212
Larry Hastingsebdcb502013-11-23 14:54:00 -08002213 @property
2214 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002215 if self.kind in (METHOD_INIT, METHOD_NEW):
2216 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002217 flags = []
2218 if self.kind == CLASS_METHOD:
2219 flags.append('METH_CLASS')
2220 elif self.kind == STATIC_METHOD:
2221 flags.append('METH_STATIC')
2222 else:
2223 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2224 if self.coexist:
2225 flags.append('METH_COEXIST')
2226 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002227
2228 def __repr__(self):
2229 return '<clinic.Function ' + self.name + '>'
2230
Larry Hastings7726ac92014-01-31 22:03:12 -08002231 def copy(self, **overrides):
2232 kwargs = {
2233 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2234 'cls': self.cls, 'c_basename': self.c_basename,
2235 'full_name': self.full_name,
2236 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2237 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002238 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002239 }
2240 kwargs.update(overrides)
2241 f = Function(**kwargs)
2242
2243 parameters = collections.OrderedDict()
2244 for name, value in f.parameters.items():
2245 value = value.copy(function=f)
2246 parameters[name] = value
2247 f.parameters = parameters
2248 return f
2249
Larry Hastings31826802013-10-19 00:09:25 -07002250
2251class Parameter:
2252 """
2253 Mutable duck type of inspect.Parameter.
2254 """
2255
2256 def __init__(self, name, kind, *, default=_empty,
2257 function, converter, annotation=_empty,
2258 docstring=None, group=0):
2259 self.name = name
2260 self.kind = kind
2261 self.default = default
2262 self.function = function
2263 self.converter = converter
2264 self.annotation = annotation
2265 self.docstring = docstring or ''
2266 self.group = group
2267
2268 def __repr__(self):
2269 return '<clinic.Parameter ' + self.name + '>'
2270
2271 def is_keyword_only(self):
2272 return self.kind == inspect.Parameter.KEYWORD_ONLY
2273
Larry Hastings2623c8c2014-02-08 22:15:29 -08002274 def is_positional_only(self):
2275 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2276
Serhiy Storchaka31913912019-03-14 10:32:22 +02002277 def is_optional(self):
2278 return (self.default is not unspecified)
2279
Larry Hastings7726ac92014-01-31 22:03:12 -08002280 def copy(self, **overrides):
2281 kwargs = {
2282 'name': self.name, 'kind': self.kind, 'default':self.default,
2283 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2284 'docstring': self.docstring, 'group': self.group,
2285 }
2286 kwargs.update(overrides)
2287 if 'converter' not in overrides:
2288 converter = copy.copy(self.converter)
2289 converter.function = kwargs['function']
2290 kwargs['converter'] = converter
2291 return Parameter(**kwargs)
2292
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002293 def get_displayname(self, i):
2294 if i == 0:
2295 return '"argument"'
2296 if not self.is_positional_only():
2297 return '''"argument '{}'"'''.format(self.name)
2298 else:
2299 return '"argument {}"'.format(i)
Larry Hastings7726ac92014-01-31 22:03:12 -08002300
2301
2302class LandMine:
2303 # try to access any
2304 def __init__(self, message):
2305 self.__message__ = message
2306
2307 def __repr__(self):
2308 return '<LandMine ' + repr(self.__message__) + ">"
2309
2310 def __getattribute__(self, name):
2311 if name in ('__repr__', '__message__'):
2312 return super().__getattribute__(name)
2313 # raise RuntimeError(repr(name))
2314 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002315
Larry Hastings31826802013-10-19 00:09:25 -07002316
2317def add_c_converter(f, name=None):
2318 if not name:
2319 name = f.__name__
2320 if not name.endswith('_converter'):
2321 return f
2322 name = name[:-len('_converter')]
2323 converters[name] = f
2324 return f
2325
2326def add_default_legacy_c_converter(cls):
2327 # automatically add converter for default format unit
2328 # (but without stomping on the existing one if it's already
2329 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002330 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002331 (cls.format_unit not in legacy_converters)):
2332 legacy_converters[cls.format_unit] = cls
2333 return cls
2334
2335def add_legacy_c_converter(format_unit, **kwargs):
2336 """
2337 Adds a legacy converter.
2338 """
2339 def closure(f):
2340 if not kwargs:
2341 added_f = f
2342 else:
2343 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002344 if format_unit:
2345 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002346 return f
2347 return closure
2348
2349class CConverterAutoRegister(type):
2350 def __init__(cls, name, bases, classdict):
2351 add_c_converter(cls)
2352 add_default_legacy_c_converter(cls)
2353
2354class CConverter(metaclass=CConverterAutoRegister):
2355 """
2356 For the init function, self, name, function, and default
2357 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002358 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002359 """
2360
Larry Hastings7726ac92014-01-31 22:03:12 -08002361 # The C name to use for this variable.
2362 name = None
2363
2364 # The Python name to use for this variable.
2365 py_name = None
2366
Larry Hastings78cf85c2014-01-04 12:44:57 -08002367 # The C type to use for this variable.
2368 # 'type' should be a Python string specifying the type, e.g. "int".
2369 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002370 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002371
2372 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002373 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002374 # Or the magic value "unknown" if this value is a cannot be evaluated
2375 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2376 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002377 default = unspecified
2378
Larry Hastings4a55fc52014-01-12 11:09:57 -08002379 # If not None, default must be isinstance() of this type.
2380 # (You can also specify a tuple of types.)
2381 default_type = None
2382
Larry Hastings31826802013-10-19 00:09:25 -07002383 # "default" converted into a C value, as a string.
2384 # Or None if there is no default.
2385 c_default = None
2386
Larry Hastings2a727912014-01-16 11:32:01 -08002387 # "default" converted into a Python value, as a string.
2388 # Or None if there is no default.
2389 py_default = None
2390
Larry Hastingsabc716b2013-11-20 09:13:52 -08002391 # The default value used to initialize the C variable when
2392 # there is no default, but not specifying a default may
2393 # result in an "uninitialized variable" warning. This can
2394 # easily happen when using option groups--although
2395 # properly-written code won't actually use the variable,
2396 # the variable does get passed in to the _impl. (Ah, if
2397 # only dataflow analysis could inline the static function!)
2398 #
2399 # This value is specified as a string.
2400 # Every non-abstract subclass should supply a valid value.
2401 c_ignored_default = 'NULL'
2402
Larry Hastings31826802013-10-19 00:09:25 -07002403 # The C converter *function* to be used, if any.
2404 # (If this is not None, format_unit must be 'O&'.)
2405 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002406
Larry Hastings78cf85c2014-01-04 12:44:57 -08002407 # Should Argument Clinic add a '&' before the name of
2408 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002409 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002410
2411 # Should Argument Clinic add a '&' before the name of
2412 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002413 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002414
2415 #############################################################
2416 #############################################################
2417 ## You shouldn't need to read anything below this point to ##
2418 ## write your own converter functions. ##
2419 #############################################################
2420 #############################################################
2421
2422 # The "format unit" to specify for this variable when
2423 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2424 # Custom converters should always use the default value of 'O&'.
2425 format_unit = 'O&'
2426
2427 # What encoding do we want for this variable? Only used
2428 # by format units starting with 'e'.
2429 encoding = None
2430
Larry Hastings77561cc2014-01-07 12:13:13 -08002431 # Should this object be required to be a subclass of a specific type?
2432 # If not None, should be a string representing a pointer to a
2433 # PyTypeObject (e.g. "&PyUnicode_Type").
2434 # Only used by the 'O!' format unit (and the "object" converter).
2435 subclass_of = None
2436
Larry Hastings78cf85c2014-01-04 12:44:57 -08002437 # Do we want an adjacent '_length' variable for this variable?
2438 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002439 length = False
2440
Larry Hastings5c661892014-01-24 06:17:25 -08002441 # Should we show this parameter in the generated
2442 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002443 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002444 show_in_signature = True
2445
2446 # Overrides the name used in a text signature.
2447 # The name used for a "self" parameter must be one of
2448 # self, type, or module; however users can set their own.
2449 # This lets the self_converter overrule the user-settable
2450 # name, *just* for the text signature.
2451 # Only set by self_converter.
2452 signature_name = None
2453
2454 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002455 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 +02002456 self.name = ensure_legal_c_identifier(name)
Larry Hastings7726ac92014-01-31 22:03:12 -08002457 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002458
2459 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002460 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002461 if isinstance(self.default_type, type):
2462 types_str = self.default_type.__name__
2463 else:
2464 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2465 fail("{}: default value {!r} for field {} is not of type {}".format(
2466 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002467 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002468
Larry Hastingsb4705752014-01-18 21:54:15 -08002469 if c_default:
2470 self.c_default = c_default
2471 if py_default:
2472 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002473
Larry Hastings31826802013-10-19 00:09:25 -07002474 if annotation != unspecified:
2475 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002476
2477 # this is deliberate, to prevent you from caching information
2478 # about the function in the init.
2479 # (that breaks if we get cloned.)
2480 # so after this change we will noisily fail.
2481 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002482 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002483 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002484
2485 def converter_init(self):
2486 pass
2487
2488 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002489 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002490
Larry Hastings5c661892014-01-24 06:17:25 -08002491 def _render_self(self, parameter, data):
2492 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002493 name = self.name
Larry Hastings5c661892014-01-24 06:17:25 -08002494
2495 # impl_arguments
2496 s = ("&" if self.impl_by_reference else "") + name
2497 data.impl_arguments.append(s)
2498 if self.length:
2499 data.impl_arguments.append(self.length_name())
2500
2501 # impl_parameters
2502 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2503 if self.length:
2504 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2505
2506 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002507 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002508 name = self.name
Larry Hastings31826802013-10-19 00:09:25 -07002509
2510 # declarations
2511 d = self.declaration()
2512 data.declarations.append(d)
2513
2514 # initializers
2515 initializers = self.initialize()
2516 if initializers:
2517 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2518
Larry Hastingsc2047262014-01-25 20:43:29 -08002519 # modifications
2520 modifications = self.modify()
2521 if modifications:
2522 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2523
Larry Hastings31826802013-10-19 00:09:25 -07002524 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002525 if parameter.is_positional_only():
2526 data.keywords.append('')
2527 else:
2528 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002529
2530 # format_units
2531 if self.is_optional() and '|' not in data.format_units:
2532 data.format_units.append('|')
2533 if parameter.is_keyword_only() and '$' not in data.format_units:
2534 data.format_units.append('$')
2535 data.format_units.append(self.format_unit)
2536
2537 # parse_arguments
2538 self.parse_argument(data.parse_arguments)
2539
Larry Hastings31826802013-10-19 00:09:25 -07002540 # cleanup
2541 cleanup = self.cleanup()
2542 if cleanup:
2543 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2544
Larry Hastings5c661892014-01-24 06:17:25 -08002545 def render(self, parameter, data):
2546 """
2547 parameter is a clinic.Parameter instance.
2548 data is a CRenderData instance.
2549 """
2550 self._render_self(parameter, data)
2551 self._render_non_self(parameter, data)
2552
Larry Hastingsebdcb502013-11-23 14:54:00 -08002553 def length_name(self):
2554 """Computes the name of the associated "length" variable."""
2555 if not self.length:
2556 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002557 return self.name + "_length"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002558
Larry Hastings31826802013-10-19 00:09:25 -07002559 # Why is this one broken out separately?
2560 # For "positional-only" function parsing,
2561 # which generates a bunch of PyArg_ParseTuple calls.
2562 def parse_argument(self, list):
2563 assert not (self.converter and self.encoding)
2564 if self.format_unit == 'O&':
2565 assert self.converter
2566 list.append(self.converter)
2567
2568 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002569 list.append(c_repr(self.encoding))
2570 elif self.subclass_of:
2571 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002572
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002573 s = ("&" if self.parse_by_reference else "") + self.name
Larry Hastings31826802013-10-19 00:09:25 -07002574 list.append(s)
2575
Larry Hastingsebdcb502013-11-23 14:54:00 -08002576 if self.length:
2577 list.append("&" + self.length_name())
2578
Larry Hastings31826802013-10-19 00:09:25 -07002579 #
2580 # All the functions after here are intended as extension points.
2581 #
2582
2583 def simple_declaration(self, by_reference=False):
2584 """
2585 Computes the basic declaration of the variable.
2586 Used in computing the prototype declaration and the
2587 variable declaration.
2588 """
2589 prototype = [self.type]
2590 if by_reference or not self.type.endswith('*'):
2591 prototype.append(" ")
2592 if by_reference:
2593 prototype.append('*')
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002594 prototype.append(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07002595 return "".join(prototype)
2596
2597 def declaration(self):
2598 """
2599 The C statement to declare this variable.
2600 """
2601 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002602 default = self.c_default
2603 if not default and self.parameter.group:
2604 default = self.c_ignored_default
2605 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002606 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002607 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002608 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002609 if self.length:
2610 declaration.append('\nPy_ssize_clean_t ')
2611 declaration.append(self.length_name())
2612 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002613 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002614
2615 def initialize(self):
2616 """
2617 The C statements required to set up this variable before parsing.
2618 Returns a string containing this code indented at column 0.
2619 If no initialization is necessary, returns an empty string.
2620 """
2621 return ""
2622
Larry Hastingsc2047262014-01-25 20:43:29 -08002623 def modify(self):
2624 """
2625 The C statements required to modify this variable after parsing.
2626 Returns a string containing this code indented at column 0.
2627 If no initialization is necessary, returns an empty string.
2628 """
2629 return ""
2630
Larry Hastings31826802013-10-19 00:09:25 -07002631 def cleanup(self):
2632 """
2633 The C statements required to clean up after this variable.
2634 Returns a string containing this code indented at column 0.
2635 If no cleanup is necessary, returns an empty string.
2636 """
2637 return ""
2638
Larry Hastings7726ac92014-01-31 22:03:12 -08002639 def pre_render(self):
2640 """
2641 A second initialization function, like converter_init,
2642 called just before rendering.
2643 You are permitted to examine self.function here.
2644 """
2645 pass
2646
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002647 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002648 if self.format_unit == 'O&':
2649 return """
2650 if (!{converter}({argname}, &{paramname})) {{{{
2651 goto exit;
2652 }}}}
2653 """.format(argname=argname, paramname=self.name,
2654 converter=self.converter)
2655 if self.format_unit == 'O!':
2656 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2657 if self.subclass_of in type_checks:
2658 typecheck, typename = type_checks[self.subclass_of]
2659 return """
2660 if (!{typecheck}({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002661 _PyArg_BadArgument("{{name}}", {displayname}, "{typename}", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002662 goto exit;
2663 }}}}
2664 {paramname} = {cast}{argname};
2665 """.format(argname=argname, paramname=self.name,
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002666 displayname=displayname, typecheck=typecheck,
2667 typename=typename, cast=cast)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002668 return """
2669 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002670 _PyArg_BadArgument("{{name}}", {displayname}, ({subclass_of})->tp_name, {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002671 goto exit;
2672 }}}}
2673 {paramname} = {cast}{argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002674 """.format(argname=argname, paramname=self.name,
2675 subclass_of=self.subclass_of, cast=cast,
2676 displayname=displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002677 if self.format_unit == 'O':
2678 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2679 return """
2680 {paramname} = {cast}{argname};
2681 """.format(argname=argname, paramname=self.name, cast=cast)
2682 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002683
2684type_checks = {
2685 '&PyLong_Type': ('PyLong_Check', 'int'),
2686 '&PyTuple_Type': ('PyTuple_Check', 'tuple'),
2687 '&PyList_Type': ('PyList_Check', 'list'),
2688 '&PySet_Type': ('PySet_Check', 'set'),
2689 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'),
2690 '&PyDict_Type': ('PyDict_Check', 'dict'),
2691 '&PyUnicode_Type': ('PyUnicode_Check', 'str'),
2692 '&PyBytes_Type': ('PyBytes_Check', 'bytes'),
2693 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'),
2694}
2695
Larry Hastings31826802013-10-19 00:09:25 -07002696
2697class bool_converter(CConverter):
2698 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002699 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002700 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002701 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002702
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002703 def converter_init(self, *, accept={object}):
2704 if accept == {int}:
2705 self.format_unit = 'i'
2706 elif accept != {object}:
2707 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002708 if self.default is not unspecified:
2709 self.default = bool(self.default)
2710 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002711
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002712 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002713 if self.format_unit == 'i':
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +02002714 # XXX PyFloat_Check can be removed after the end of the
2715 # deprecation in _PyLong_FromNbIndexOrNbInt.
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002716 return """
2717 if (PyFloat_Check({argname})) {{{{
2718 PyErr_SetString(PyExc_TypeError,
2719 "integer argument expected, got float" );
2720 goto exit;
2721 }}}}
2722 {paramname} = _PyLong_AsInt({argname});
2723 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2724 goto exit;
2725 }}}}
2726 """.format(argname=argname, paramname=self.name)
2727 elif self.format_unit == 'p':
2728 return """
2729 {paramname} = PyObject_IsTrue({argname});
2730 if ({paramname} < 0) {{{{
2731 goto exit;
2732 }}}}
2733 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002734 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002735
Larry Hastings31826802013-10-19 00:09:25 -07002736class char_converter(CConverter):
2737 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002738 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002739 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002740 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002741
Larry Hastings4a55fc52014-01-12 11:09:57 -08002742 def converter_init(self):
Tal Einatc929df32018-07-06 13:17:38 +03002743 if isinstance(self.default, self.default_type):
2744 if len(self.default) != 1:
2745 fail("char_converter: illegal default value " + repr(self.default))
2746
Serhiy Storchaka65ce60a2018-12-25 11:10:05 +02002747 self.c_default = repr(bytes(self.default))[1:]
2748 if self.c_default == '"\'"':
2749 self.c_default = r"'\''"
Larry Hastings4a55fc52014-01-12 11:09:57 -08002750
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002751 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002752 if self.format_unit == 'c':
2753 return """
2754 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
2755 {paramname} = PyBytes_AS_STRING({argname})[0];
2756 }}}}
2757 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{
2758 {paramname} = PyByteArray_AS_STRING({argname})[0];
2759 }}}}
2760 else {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002761 _PyArg_BadArgument("{{name}}", {displayname}, "a byte string of length 1", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002762 goto exit;
2763 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002764 """.format(argname=argname, paramname=self.name,
2765 displayname=displayname)
2766 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002767
Larry Hastings4a55fc52014-01-12 11:09:57 -08002768
Larry Hastings31826802013-10-19 00:09:25 -07002769@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002770class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002771 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002772 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002773 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002774 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002775
2776 def converter_init(self, *, bitwise=False):
2777 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002778 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002779
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002780 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002781 if self.format_unit == 'b':
2782 return """
2783 if (PyFloat_Check({argname})) {{{{
2784 PyErr_SetString(PyExc_TypeError,
2785 "integer argument expected, got float" );
2786 goto exit;
2787 }}}}
2788 {{{{
2789 long ival = PyLong_AsLong({argname});
2790 if (ival == -1 && PyErr_Occurred()) {{{{
2791 goto exit;
2792 }}}}
2793 else if (ival < 0) {{{{
2794 PyErr_SetString(PyExc_OverflowError,
2795 "unsigned byte integer is less than minimum");
2796 goto exit;
2797 }}}}
2798 else if (ival > UCHAR_MAX) {{{{
2799 PyErr_SetString(PyExc_OverflowError,
2800 "unsigned byte integer is greater than maximum");
2801 goto exit;
2802 }}}}
2803 else {{{{
2804 {paramname} = (unsigned char) ival;
2805 }}}}
2806 }}}}
2807 """.format(argname=argname, paramname=self.name)
2808 elif self.format_unit == 'B':
2809 return """
2810 if (PyFloat_Check({argname})) {{{{
2811 PyErr_SetString(PyExc_TypeError,
2812 "integer argument expected, got float" );
2813 goto exit;
2814 }}}}
2815 {{{{
2816 long ival = PyLong_AsUnsignedLongMask({argname});
2817 if (ival == -1 && PyErr_Occurred()) {{{{
2818 goto exit;
2819 }}}}
2820 else {{{{
2821 {paramname} = (unsigned char) ival;
2822 }}}}
2823 }}}}
2824 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002825 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002826
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002827class byte_converter(unsigned_char_converter): pass
2828
Larry Hastings31826802013-10-19 00:09:25 -07002829class short_converter(CConverter):
2830 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002831 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002832 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002833 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002834
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002835 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002836 if self.format_unit == 'h':
2837 return """
2838 if (PyFloat_Check({argname})) {{{{
2839 PyErr_SetString(PyExc_TypeError,
2840 "integer argument expected, got float" );
2841 goto exit;
2842 }}}}
2843 {{{{
2844 long ival = PyLong_AsLong({argname});
2845 if (ival == -1 && PyErr_Occurred()) {{{{
2846 goto exit;
2847 }}}}
2848 else if (ival < SHRT_MIN) {{{{
2849 PyErr_SetString(PyExc_OverflowError,
2850 "signed short integer is less than minimum");
2851 goto exit;
2852 }}}}
2853 else if (ival > SHRT_MAX) {{{{
2854 PyErr_SetString(PyExc_OverflowError,
2855 "signed short integer is greater than maximum");
2856 goto exit;
2857 }}}}
2858 else {{{{
2859 {paramname} = (short) ival;
2860 }}}}
2861 }}}}
2862 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002863 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002864
Larry Hastings31826802013-10-19 00:09:25 -07002865class unsigned_short_converter(CConverter):
2866 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002867 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002868 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002869
2870 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002871 if bitwise:
2872 self.format_unit = 'H'
2873 else:
2874 self.converter = '_PyLong_UnsignedShort_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002875
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002876 def parse_arg(self, argname, displayname):
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002877 if self.format_unit == 'H':
2878 return """
2879 if (PyFloat_Check({argname})) {{{{
2880 PyErr_SetString(PyExc_TypeError,
2881 "integer argument expected, got float" );
2882 goto exit;
2883 }}}}
2884 {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname});
2885 if ({paramname} == (unsigned short)-1 && PyErr_Occurred()) {{{{
2886 goto exit;
2887 }}}}
2888 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002889 return super().parse_arg(argname, displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002890
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002891@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002892class int_converter(CConverter):
2893 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002894 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002895 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002896 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002897
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002898 def converter_init(self, *, accept={int}, type=None):
2899 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002900 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002901 elif accept != {int}:
2902 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002903 if type != None:
2904 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002905
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002906 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002907 if self.format_unit == 'i':
2908 return """
2909 if (PyFloat_Check({argname})) {{{{
2910 PyErr_SetString(PyExc_TypeError,
2911 "integer argument expected, got float" );
2912 goto exit;
2913 }}}}
2914 {paramname} = _PyLong_AsInt({argname});
2915 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2916 goto exit;
2917 }}}}
2918 """.format(argname=argname, paramname=self.name)
2919 elif self.format_unit == 'C':
2920 return """
2921 if (!PyUnicode_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002922 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002923 goto exit;
2924 }}}}
2925 if (PyUnicode_READY({argname})) {{{{
2926 goto exit;
2927 }}}}
2928 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002929 _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002930 goto exit;
2931 }}}}
2932 {paramname} = PyUnicode_READ_CHAR({argname}, 0);
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002933 """.format(argname=argname, paramname=self.name,
2934 displayname=displayname)
2935 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002936
Larry Hastings31826802013-10-19 00:09:25 -07002937class unsigned_int_converter(CConverter):
2938 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002939 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002940 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002941
2942 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002943 if bitwise:
2944 self.format_unit = 'I'
2945 else:
2946 self.converter = '_PyLong_UnsignedInt_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002947
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002948 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002949 if self.format_unit == 'I':
2950 return """
2951 if (PyFloat_Check({argname})) {{{{
2952 PyErr_SetString(PyExc_TypeError,
2953 "integer argument expected, got float" );
2954 goto exit;
2955 }}}}
2956 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
2957 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{
2958 goto exit;
2959 }}}}
2960 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002961 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002962
Larry Hastings31826802013-10-19 00:09:25 -07002963class long_converter(CConverter):
2964 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002965 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002966 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002967 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002968
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002969 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002970 if self.format_unit == 'l':
2971 return """
2972 if (PyFloat_Check({argname})) {{{{
2973 PyErr_SetString(PyExc_TypeError,
2974 "integer argument expected, got float" );
2975 goto exit;
2976 }}}}
2977 {paramname} = PyLong_AsLong({argname});
2978 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2979 goto exit;
2980 }}}}
2981 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002982 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002983
Larry Hastings31826802013-10-19 00:09:25 -07002984class unsigned_long_converter(CConverter):
2985 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002986 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002987 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002988
2989 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002990 if bitwise:
2991 self.format_unit = 'k'
2992 else:
2993 self.converter = '_PyLong_UnsignedLong_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002994
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002995 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002996 if self.format_unit == 'k':
2997 return """
2998 if (!PyLong_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02002999 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003000 goto exit;
3001 }}}}
3002 {paramname} = PyLong_AsUnsignedLongMask({argname});
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003003 """.format(argname=argname, paramname=self.name,
3004 displayname=displayname)
3005 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003006
Benjamin Petersoncc854492016-09-08 09:29:11 -07003007class long_long_converter(CConverter):
3008 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003009 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07003010 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003011 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003012
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003013 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003014 if self.format_unit == 'L':
3015 return """
3016 if (PyFloat_Check({argname})) {{{{
3017 PyErr_SetString(PyExc_TypeError,
3018 "integer argument expected, got float" );
3019 goto exit;
3020 }}}}
3021 {paramname} = PyLong_AsLongLong({argname});
3022 if ({paramname} == (PY_LONG_LONG)-1 && PyErr_Occurred()) {{{{
3023 goto exit;
3024 }}}}
3025 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003026 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003027
Benjamin Petersoncc854492016-09-08 09:29:11 -07003028class unsigned_long_long_converter(CConverter):
3029 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003030 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08003031 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003032
3033 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03003034 if bitwise:
3035 self.format_unit = 'K'
3036 else:
3037 self.converter = '_PyLong_UnsignedLongLong_Converter'
Serhiy Storchaka762bf402017-03-30 09:15:31 +03003038
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003039 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003040 if self.format_unit == 'K':
3041 return """
3042 if (!PyLong_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003043 _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003044 goto exit;
3045 }}}}
3046 {paramname} = PyLong_AsUnsignedLongLongMask({argname});
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003047 """.format(argname=argname, paramname=self.name,
3048 displayname=displayname)
3049 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003050
Larry Hastings31826802013-10-19 00:09:25 -07003051class Py_ssize_t_converter(CConverter):
3052 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003053 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003054
Serhiy Storchaka762bf402017-03-30 09:15:31 +03003055 def converter_init(self, *, accept={int}):
3056 if accept == {int}:
3057 self.format_unit = 'n'
3058 self.default_type = int
3059 elif accept == {int, NoneType}:
3060 self.converter = '_Py_convert_optional_to_ssize_t'
3061 else:
3062 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
3063
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003064 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003065 if self.format_unit == 'n':
3066 return """
3067 if (PyFloat_Check({argname})) {{{{
3068 PyErr_SetString(PyExc_TypeError,
3069 "integer argument expected, got float" );
3070 goto exit;
3071 }}}}
3072 {{{{
3073 Py_ssize_t ival = -1;
3074 PyObject *iobj = PyNumber_Index({argname});
3075 if (iobj != NULL) {{{{
3076 ival = PyLong_AsSsize_t(iobj);
3077 Py_DECREF(iobj);
3078 }}}}
3079 if (ival == -1 && PyErr_Occurred()) {{{{
3080 goto exit;
3081 }}}}
3082 {paramname} = ival;
3083 }}}}
3084 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003085 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003086
Larry Hastings31826802013-10-19 00:09:25 -07003087
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003088class slice_index_converter(CConverter):
3089 type = 'Py_ssize_t'
3090
3091 def converter_init(self, *, accept={int, NoneType}):
3092 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03003093 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003094 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03003095 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003096 else:
3097 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
3098
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03003099class size_t_converter(CConverter):
3100 type = 'size_t'
3101 converter = '_PyLong_Size_t_Converter'
3102 c_ignored_default = "0"
3103
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003104 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003105 if self.format_unit == 'n':
3106 return """
3107 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
3108 if ({paramname} == -1 && PyErr_Occurred()) {{{{
3109 goto exit;
3110 }}}}
3111 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003112 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003113
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003114
Larry Hastings31826802013-10-19 00:09:25 -07003115class float_converter(CConverter):
3116 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003117 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003118 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003119 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003120
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003121 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003122 if self.format_unit == 'f':
3123 return """
Raymond Hettingeraef9ad82019-08-24 19:10:39 -07003124 if (PyFloat_CheckExact({argname})) {{{{
3125 {paramname} = (float) (PyFloat_AS_DOUBLE({argname}));
3126 }}}}
3127 else
3128 {{{{
3129 {paramname} = (float) PyFloat_AsDouble({argname});
3130 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{
3131 goto exit;
3132 }}}}
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003133 }}}}
3134 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003135 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003136
Larry Hastings31826802013-10-19 00:09:25 -07003137class double_converter(CConverter):
3138 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003139 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003140 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003141 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003142
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003143 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003144 if self.format_unit == 'd':
3145 return """
Raymond Hettingeraef9ad82019-08-24 19:10:39 -07003146 if (PyFloat_CheckExact({argname})) {{{{
3147 {paramname} = PyFloat_AS_DOUBLE({argname});
3148 }}}}
3149 else
3150 {{{{
3151 {paramname} = PyFloat_AsDouble({argname});
3152 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{
3153 goto exit;
3154 }}}}
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003155 }}}}
3156 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003157 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003158
Larry Hastings31826802013-10-19 00:09:25 -07003159
3160class Py_complex_converter(CConverter):
3161 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003162 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07003163 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003164 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07003165
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003166 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003167 if self.format_unit == 'D':
3168 return """
3169 {paramname} = PyComplex_AsCComplex({argname});
3170 if (PyErr_Occurred()) {{{{
3171 goto exit;
3172 }}}}
3173 """.format(argname=argname, paramname=self.name)
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003174 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003175
Larry Hastings31826802013-10-19 00:09:25 -07003176
3177class object_converter(CConverter):
3178 type = 'PyObject *'
3179 format_unit = 'O'
3180
Larry Hastings4a55fc52014-01-12 11:09:57 -08003181 def converter_init(self, *, converter=None, type=None, subclass_of=None):
3182 if converter:
3183 if subclass_of:
3184 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
3185 self.format_unit = 'O&'
3186 self.converter = converter
3187 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07003188 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08003189 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08003190
Larry Hastings77561cc2014-01-07 12:13:13 -08003191 if type is not None:
3192 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07003193
3194
Larry Hastings7f90cba2015-04-15 23:02:12 -04003195#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003196# We define three conventions for buffer types in the 'accept' argument:
3197#
3198# buffer : any object supporting the buffer interface
3199# rwbuffer: any object supporting the buffer interface, but must be writeable
3200# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04003201#
3202
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003203class buffer: pass
3204class rwbuffer: pass
3205class robuffer: pass
3206
Larry Hastings38337d12015-05-07 23:30:09 -07003207def str_converter_key(types, encoding, zeroes):
3208 return (frozenset(types), bool(encoding), bool(zeroes))
3209
3210str_converter_argument_map = {}
3211
Larry Hastings31826802013-10-19 00:09:25 -07003212class str_converter(CConverter):
3213 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003214 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003215 format_unit = 's'
3216
Larry Hastings38337d12015-05-07 23:30:09 -07003217 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003218
Larry Hastings38337d12015-05-07 23:30:09 -07003219 key = str_converter_key(accept, encoding, zeroes)
3220 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003221 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07003222 fail("str_converter: illegal combination of arguments", key)
3223
Larry Hastingsebdcb502013-11-23 14:54:00 -08003224 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07003225 self.length = bool(zeroes)
3226 if encoding:
3227 if self.default not in (Null, None, unspecified):
3228 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
3229 self.encoding = encoding
3230 self.type = 'char *'
3231 # sorry, clinic can't support preallocated buffers
3232 # for es# and et#
3233 self.c_default = "NULL"
3234
3235 def cleanup(self):
3236 if self.encoding:
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003237 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003238 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07003239
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003240 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003241 if self.format_unit == 's':
3242 return """
3243 if (!PyUnicode_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003244 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003245 goto exit;
3246 }}}}
3247 Py_ssize_t {paramname}_length;
3248 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3249 if ({paramname} == NULL) {{{{
3250 goto exit;
3251 }}}}
3252 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3253 PyErr_SetString(PyExc_ValueError, "embedded null character");
3254 goto exit;
3255 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003256 """.format(argname=argname, paramname=self.name,
3257 displayname=displayname)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003258 if self.format_unit == 'z':
3259 return """
3260 if ({argname} == Py_None) {{{{
3261 {paramname} = NULL;
3262 }}}}
3263 else if (PyUnicode_Check({argname})) {{{{
3264 Py_ssize_t {paramname}_length;
3265 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3266 if ({paramname} == NULL) {{{{
3267 goto exit;
3268 }}}}
3269 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3270 PyErr_SetString(PyExc_ValueError, "embedded null character");
3271 goto exit;
3272 }}}}
3273 }}}}
3274 else {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003275 _PyArg_BadArgument("{{name}}", {displayname}, "str or None", {argname});
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003276 goto exit;
3277 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003278 """.format(argname=argname, paramname=self.name,
3279 displayname=displayname)
3280 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003281
Larry Hastings38337d12015-05-07 23:30:09 -07003282#
3283# This is the fourth or fifth rewrite of registering all the
Raymond Hettinger14010182018-09-13 21:17:40 -07003284# string converter format units. Previous approaches hid
Larry Hastings38337d12015-05-07 23:30:09 -07003285# bugs--generally mismatches between the semantics of the format
3286# unit and the arguments necessary to represent those semantics
3287# properly. Hopefully with this approach we'll get it 100% right.
3288#
3289# The r() function (short for "register") both registers the
3290# mapping from arguments to format unit *and* registers the
3291# legacy C converter for that format unit.
3292#
3293def r(format_unit, *, accept, encoding=False, zeroes=False):
3294 if not encoding and format_unit != 's':
3295 # add the legacy c converters here too.
3296 #
3297 # note: add_legacy_c_converter can't work for
3298 # es, es#, et, or et#
3299 # because of their extra encoding argument
3300 #
3301 # also don't add the converter for 's' because
3302 # the metaclass for CConverter adds it for us.
3303 kwargs = {}
3304 if accept != {str}:
3305 kwargs['accept'] = accept
3306 if zeroes:
3307 kwargs['zeroes'] = True
3308 added_f = functools.partial(str_converter, **kwargs)
3309 legacy_converters[format_unit] = added_f
3310
3311 d = str_converter_argument_map
3312 key = str_converter_key(accept, encoding, zeroes)
3313 if key in d:
3314 sys.exit("Duplicate keys specified for str_converter_argument_map!")
3315 d[key] = format_unit
3316
3317r('es', encoding=True, accept={str})
3318r('es#', encoding=True, zeroes=True, accept={str})
3319r('et', encoding=True, accept={bytes, bytearray, str})
3320r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
3321r('s', accept={str})
3322r('s#', zeroes=True, accept={robuffer, str})
3323r('y', accept={robuffer})
3324r('y#', zeroes=True, accept={robuffer})
3325r('z', accept={str, NoneType})
3326r('z#', zeroes=True, accept={robuffer, str, NoneType})
3327del r
Larry Hastings31826802013-10-19 00:09:25 -07003328
3329
3330class PyBytesObject_converter(CConverter):
3331 type = 'PyBytesObject *'
3332 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003333 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07003334
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003335 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003336 if self.format_unit == 'S':
3337 return """
3338 if (!PyBytes_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003339 _PyArg_BadArgument("{{name}}", {displayname}, "bytes", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003340 goto exit;
3341 }}}}
3342 {paramname} = ({type}){argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003343 """.format(argname=argname, paramname=self.name,
3344 type=self.type, displayname=displayname)
3345 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003346
Larry Hastings31826802013-10-19 00:09:25 -07003347class PyByteArrayObject_converter(CConverter):
3348 type = 'PyByteArrayObject *'
3349 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003350 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07003351
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003352 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003353 if self.format_unit == 'Y':
3354 return """
3355 if (!PyByteArray_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003356 _PyArg_BadArgument("{{name}}", {displayname}, "bytearray", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003357 goto exit;
3358 }}}}
3359 {paramname} = ({type}){argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003360 """.format(argname=argname, paramname=self.name,
3361 type=self.type, displayname=displayname)
3362 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003363
Larry Hastings31826802013-10-19 00:09:25 -07003364class unicode_converter(CConverter):
3365 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003366 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003367 format_unit = 'U'
3368
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003369 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003370 if self.format_unit == 'U':
3371 return """
3372 if (!PyUnicode_Check({argname})) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003373 _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003374 goto exit;
3375 }}}}
3376 if (PyUnicode_READY({argname}) == -1) {{{{
3377 goto exit;
3378 }}}}
3379 {paramname} = {argname};
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003380 """.format(argname=argname, paramname=self.name,
3381 displayname=displayname)
3382 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003383
Larry Hastings38337d12015-05-07 23:30:09 -07003384@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003385@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07003386@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07003387class Py_UNICODE_converter(CConverter):
Serhiy Storchakaafb3e712018-12-14 11:19:51 +02003388 type = 'const Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003389 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003390 format_unit = 'u'
3391
Larry Hastings38337d12015-05-07 23:30:09 -07003392 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003393 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07003394 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003395 format_unit += '#'
3396 self.length = True
3397 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003398
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003399@add_legacy_c_converter('s*', accept={str, buffer})
3400@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
3401@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07003402class Py_buffer_converter(CConverter):
3403 type = 'Py_buffer'
3404 format_unit = 'y*'
3405 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08003406 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07003407
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003408 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08003409 if self.default not in (unspecified, None):
3410 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003411
Larry Hastings3f144c22014-01-06 10:34:00 -08003412 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08003413
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003414 if accept == {str, buffer, NoneType}:
3415 format_unit = 'z*'
3416 elif accept == {str, buffer}:
3417 format_unit = 's*'
3418 elif accept == {buffer}:
3419 format_unit = 'y*'
3420 elif accept == {rwbuffer}:
3421 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07003422 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003423 fail("Py_buffer_converter: illegal combination of arguments")
3424
3425 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003426
3427 def cleanup(self):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003428 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003429 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08003430
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003431 def parse_arg(self, argname, displayname):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003432 if self.format_unit == 'y*':
3433 return """
3434 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3435 goto exit;
3436 }}}}
3437 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003438 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003439 goto exit;
3440 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003441 """.format(argname=argname, paramname=self.name,
3442 displayname=displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003443 elif self.format_unit == 's*':
3444 return """
3445 if (PyUnicode_Check({argname})) {{{{
3446 Py_ssize_t len;
3447 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
3448 if (ptr == NULL) {{{{
3449 goto exit;
3450 }}}}
3451 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
3452 }}}}
3453 else {{{{ /* any bytes-like object */
3454 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3455 goto exit;
3456 }}}}
3457 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003458 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003459 goto exit;
3460 }}}}
3461 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003462 """.format(argname=argname, paramname=self.name,
3463 displayname=displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003464 elif self.format_unit == 'w*':
3465 return """
3466 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
3467 PyErr_Clear();
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003468 _PyArg_BadArgument("{{name}}", {displayname}, "read-write bytes-like object", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003469 goto exit;
3470 }}}}
3471 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003472 _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003473 goto exit;
3474 }}}}
Rémi Lapeyre4901fe22019-08-29 16:49:08 +02003475 """.format(argname=argname, paramname=self.name,
3476 displayname=displayname)
3477 return super().parse_arg(argname, displayname)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003478
Larry Hastingsebdcb502013-11-23 14:54:00 -08003479
Larry Hastings5c661892014-01-24 06:17:25 -08003480def correct_name_for_self(f):
3481 if f.kind in (CALLABLE, METHOD_INIT):
3482 if f.cls:
3483 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03003484 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08003485 if f.kind == STATIC_METHOD:
3486 return "void *", "null"
3487 if f.kind in (CLASS_METHOD, METHOD_NEW):
3488 return "PyTypeObject *", "type"
3489 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
3490
Larry Hastingsc2047262014-01-25 20:43:29 -08003491def required_type_for_self_for_parser(f):
3492 type, _ = correct_name_for_self(f)
3493 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
3494 return type
3495 return None
3496
Larry Hastings5c661892014-01-24 06:17:25 -08003497
Larry Hastingsebdcb502013-11-23 14:54:00 -08003498class self_converter(CConverter):
3499 """
3500 A special-case converter:
3501 this is the default converter used for "self".
3502 """
Larry Hastings5c661892014-01-24 06:17:25 -08003503 type = None
3504 format_unit = ''
3505
Larry Hastings78cf85c2014-01-04 12:44:57 -08003506 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08003507 self.specified_type = type
3508
3509 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003510 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08003511 default_type, default_name = correct_name_for_self(f)
3512 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08003513 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08003514
Larry Hastings5c661892014-01-24 06:17:25 -08003515 kind = self.function.kind
3516 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
3517
3518 if (kind == STATIC_METHOD) or new_or_init:
3519 self.show_in_signature = False
3520
3521 # tp_new (METHOD_NEW) functions are of type newfunc:
3522 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
3523 # PyTypeObject is a typedef for struct _typeobject.
3524 #
3525 # tp_init (METHOD_INIT) functions are of type initproc:
3526 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
3527 #
3528 # All other functions generated by Argument Clinic are stored in
3529 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
3530 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
3531 # However! We habitually cast these functions to PyCFunction,
3532 # since functions that accept keyword arguments don't fit this signature
3533 # but are stored there anyway. So strict type equality isn't important
3534 # for these functions.
3535 #
3536 # So:
3537 #
3538 # * The name of the first parameter to the impl and the parsing function will always
3539 # be self.name.
3540 #
3541 # * The type of the first parameter to the impl will always be of self.type.
3542 #
3543 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
3544 # * The type of the first parameter to the parsing function is also self.type.
3545 # This means that if you step into the parsing function, your "self" parameter
3546 # is of the correct type, which may make debugging more pleasant.
3547 #
3548 # * Else if the function is tp_new (METHOD_NEW):
3549 # * The type of the first parameter to the parsing function is "PyTypeObject *",
3550 # so the type signature of the function call is an exact match.
3551 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
3552 # in the impl call.
3553 #
3554 # * Else if the function is tp_init (METHOD_INIT):
3555 # * The type of the first parameter to the parsing function is "PyObject *",
3556 # so the type signature of the function call is an exact match.
3557 # * If self.type != "PyObject *", we cast the first parameter to self.type
3558 # in the impl call.
3559
3560 @property
3561 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08003562 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08003563
Larry Hastingsebdcb502013-11-23 14:54:00 -08003564 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08003565 """
3566 parameter is a clinic.Parameter instance.
3567 data is a CRenderData instance.
3568 """
3569 if self.function.kind == STATIC_METHOD:
3570 return
3571
3572 self._render_self(parameter, data)
3573
3574 if self.type != self.parser_type:
3575 # insert cast to impl_argument[0], aka self.
3576 # we know we're in the first slot in all the CRenderData lists,
3577 # because we render parameters in order, and self is always first.
3578 assert len(data.impl_arguments) == 1
3579 assert data.impl_arguments[0] == self.name
3580 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3581
3582 def set_template_dict(self, template_dict):
3583 template_dict['self_name'] = self.name
3584 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003585 kind = self.function.kind
3586 cls = self.function.cls
3587
3588 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3589 if kind == METHOD_NEW:
3590 passed_in_type = self.name
3591 else:
3592 passed_in_type = 'Py_TYPE({})'.format(self.name)
3593
3594 line = '({passed_in_type} == {type_object}) &&\n '
3595 d = {
3596 'type_object': self.function.cls.type_object,
3597 'passed_in_type': passed_in_type
3598 }
3599 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003600
Larry Hastings31826802013-10-19 00:09:25 -07003601
3602
3603def add_c_return_converter(f, name=None):
3604 if not name:
3605 name = f.__name__
3606 if not name.endswith('_return_converter'):
3607 return f
3608 name = name[:-len('_return_converter')]
3609 return_converters[name] = f
3610 return f
3611
3612
3613class CReturnConverterAutoRegister(type):
3614 def __init__(cls, name, bases, classdict):
3615 add_c_return_converter(cls)
3616
3617class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3618
Larry Hastings78cf85c2014-01-04 12:44:57 -08003619 # The C type to use for this variable.
3620 # 'type' should be a Python string specifying the type, e.g. "int".
3621 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003622 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003623
3624 # The Python default value for this parameter, as a Python value.
3625 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003626 default = None
3627
Larry Hastings2a727912014-01-16 11:32:01 -08003628 def __init__(self, *, py_default=None, **kwargs):
3629 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003630 try:
3631 self.return_converter_init(**kwargs)
3632 except TypeError as e:
3633 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3634 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3635
3636 def return_converter_init(self):
3637 pass
3638
3639 def declare(self, data, name="_return_value"):
3640 line = []
3641 add = line.append
3642 add(self.type)
3643 if not self.type.endswith('*'):
3644 add(' ')
3645 add(name + ';')
3646 data.declarations.append(''.join(line))
3647 data.return_value = name
3648
3649 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003650 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003651
3652 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003653 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003654
3655 def render(self, function, data):
3656 """
3657 function is a clinic.Function instance.
3658 data is a CRenderData instance.
3659 """
3660 pass
3661
3662add_c_return_converter(CReturnConverter, 'object')
3663
Larry Hastings78cf85c2014-01-04 12:44:57 -08003664class NoneType_return_converter(CReturnConverter):
3665 def render(self, function, data):
3666 self.declare(data)
3667 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003668if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003669 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003670}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003671return_value = Py_None;
3672Py_INCREF(Py_None);
3673'''.strip())
3674
Larry Hastings4a55fc52014-01-12 11:09:57 -08003675class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003676 type = 'int'
3677
3678 def render(self, function, data):
3679 self.declare(data)
3680 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003681 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003682
3683class long_return_converter(CReturnConverter):
3684 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003685 conversion_fn = 'PyLong_FromLong'
3686 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003687 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003688
3689 def render(self, function, data):
3690 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003691 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003692 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003693 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003694
Larry Hastings4a55fc52014-01-12 11:09:57 -08003695class int_return_converter(long_return_converter):
3696 type = 'int'
3697 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003698
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003699class init_return_converter(long_return_converter):
3700 """
3701 Special return converter for __init__ functions.
3702 """
3703 type = 'int'
3704 cast = '(long)'
3705
3706 def render(self, function, data):
3707 pass
3708
Larry Hastings4a55fc52014-01-12 11:09:57 -08003709class unsigned_long_return_converter(long_return_converter):
3710 type = 'unsigned long'
3711 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003712 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003713
3714class unsigned_int_return_converter(unsigned_long_return_converter):
3715 type = 'unsigned int'
3716 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003717 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003718
3719class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003720 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003721 conversion_fn = 'PyLong_FromSsize_t'
3722
3723class size_t_return_converter(long_return_converter):
3724 type = 'size_t'
3725 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003726 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003727
3728
3729class double_return_converter(CReturnConverter):
3730 type = 'double'
3731 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003732
3733 def render(self, function, data):
3734 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003735 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003736 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003737 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3738
3739class float_return_converter(double_return_converter):
3740 type = 'float'
3741 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003742
3743
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003744def eval_ast_expr(node, globals, *, filename='-'):
3745 """
3746 Takes an ast.Expr node. Compiles and evaluates it.
3747 Returns the result of the expression.
3748
3749 globals represents the globals dict the expression
3750 should see. (There's no equivalent for "locals" here.)
3751 """
3752
3753 if isinstance(node, ast.Expr):
3754 node = node.value
3755
3756 node = ast.Expression(node)
3757 co = compile(node, filename, 'eval')
3758 fn = types.FunctionType(co, globals)
3759 return fn()
3760
3761
Larry Hastings31826802013-10-19 00:09:25 -07003762class IndentStack:
3763 def __init__(self):
3764 self.indents = []
3765 self.margin = None
3766
3767 def _ensure(self):
3768 if not self.indents:
3769 fail('IndentStack expected indents, but none are defined.')
3770
3771 def measure(self, line):
3772 """
3773 Returns the length of the line's margin.
3774 """
3775 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003776 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003777 stripped = line.lstrip()
3778 if not len(stripped):
3779 # we can't tell anything from an empty line
3780 # so just pretend it's indented like our current indent
3781 self._ensure()
3782 return self.indents[-1]
3783 return len(line) - len(stripped)
3784
3785 def infer(self, line):
3786 """
3787 Infer what is now the current margin based on this line.
3788 Returns:
3789 1 if we have indented (or this is the first margin)
3790 0 if the margin has not changed
3791 -N if we have dedented N times
3792 """
3793 indent = self.measure(line)
3794 margin = ' ' * indent
3795 if not self.indents:
3796 self.indents.append(indent)
3797 self.margin = margin
3798 return 1
3799 current = self.indents[-1]
3800 if indent == current:
3801 return 0
3802 if indent > current:
3803 self.indents.append(indent)
3804 self.margin = margin
3805 return 1
3806 # indent < current
3807 if indent not in self.indents:
3808 fail("Illegal outdent.")
3809 outdent_count = 0
3810 while indent != current:
3811 self.indents.pop()
3812 current = self.indents[-1]
3813 outdent_count -= 1
3814 self.margin = margin
3815 return outdent_count
3816
3817 @property
3818 def depth(self):
3819 """
3820 Returns how many margins are currently defined.
3821 """
3822 return len(self.indents)
3823
3824 def indent(self, line):
3825 """
3826 Indents a line by the currently defined margin.
3827 """
3828 return self.margin + line
3829
3830 def dedent(self, line):
3831 """
3832 Dedents a line by the currently defined margin.
3833 (The inverse of 'indent'.)
3834 """
3835 margin = self.margin
3836 indent = self.indents[-1]
3837 if not line.startswith(margin):
3838 fail('Cannot dedent, line does not start with the previous margin:')
3839 return line[indent:]
3840
3841
3842class DSLParser:
3843 def __init__(self, clinic):
3844 self.clinic = clinic
3845
3846 self.directives = {}
3847 for name in dir(self):
3848 # functions that start with directive_ are added to directives
3849 _, s, key = name.partition("directive_")
3850 if s:
3851 self.directives[key] = getattr(self, name)
3852
3853 # functions that start with at_ are too, with an @ in front
3854 _, s, key = name.partition("at_")
3855 if s:
3856 self.directives['@' + key] = getattr(self, name)
3857
3858 self.reset()
3859
3860 def reset(self):
3861 self.function = None
3862 self.state = self.state_dsl_start
3863 self.parameter_indent = None
3864 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003865 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003866 self.group = 0
3867 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003868 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003869 self.indent = IndentStack()
3870 self.kind = CALLABLE
3871 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003872 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003873 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003874
Larry Hastingsebdcb502013-11-23 14:54:00 -08003875 def directive_version(self, required):
3876 global version
3877 if version_comparitor(version, required) < 0:
3878 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3879
Larry Hastings31826802013-10-19 00:09:25 -07003880 def directive_module(self, name):
3881 fields = name.split('.')
3882 new = fields.pop()
3883 module, cls = self.clinic._module_and_class(fields)
3884 if cls:
3885 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003886
3887 if name in module.classes:
3888 fail("Already defined module " + repr(name) + "!")
3889
Larry Hastings31826802013-10-19 00:09:25 -07003890 m = Module(name, module)
3891 module.modules[name] = m
3892 self.block.signatures.append(m)
3893
Larry Hastingsc2047262014-01-25 20:43:29 -08003894 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003895 fields = name.split('.')
3896 in_classes = False
3897 parent = self
3898 name = fields.pop()
3899 so_far = []
3900 module, cls = self.clinic._module_and_class(fields)
3901
Larry Hastingsc2047262014-01-25 20:43:29 -08003902 parent = cls or module
3903 if name in parent.classes:
3904 fail("Already defined class " + repr(name) + "!")
3905
3906 c = Class(name, module, cls, typedef, type_object)
3907 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003908 self.block.signatures.append(c)
3909
Larry Hastingsbebf7352014-01-17 17:47:17 -08003910 def directive_set(self, name, value):
3911 if name not in ("line_prefix", "line_suffix"):
3912 fail("unknown variable", repr(name))
3913
3914 value = value.format_map({
3915 'block comment start': '/*',
3916 'block comment end': '*/',
3917 })
3918
3919 self.clinic.__dict__[name] = value
3920
3921 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003922 if command == 'new':
3923 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003924 return
3925
Zachary Ware071baa62014-01-21 23:07:12 -06003926 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003927 self.clinic.get_destination(name).clear()
3928 fail("unknown destination command", repr(command))
3929
3930
Larry Hastings0759f842015-04-03 13:09:02 -07003931 def directive_output(self, command_or_name, destination=''):
3932 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003933
Larry Hastings0759f842015-04-03 13:09:02 -07003934 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003935 preset = self.clinic.presets.get(destination)
3936 if not preset:
3937 fail("Unknown preset " + repr(destination) + "!")
3938 fd.update(preset)
3939 return
3940
Larry Hastings0759f842015-04-03 13:09:02 -07003941 if command_or_name == "push":
3942 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003943 return
3944
Larry Hastings0759f842015-04-03 13:09:02 -07003945 if command_or_name == "pop":
3946 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003947 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003948 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003949 fd.update(previous_fd)
3950 return
3951
3952 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003953 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003954 self.block.output.append(pprint.pformat(fd))
3955 self.block.output.append('\n')
3956 return
3957
3958 d = self.clinic.get_destination(destination)
3959
Larry Hastings0759f842015-04-03 13:09:02 -07003960 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003961 for name in list(fd):
3962 fd[name] = d
3963 return
3964
Larry Hastings0759f842015-04-03 13:09:02 -07003965 if command_or_name not in fd:
3966 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3967 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003968
3969 def directive_dump(self, name):
3970 self.block.output.append(self.clinic.get_destination(name).dump())
3971
3972 def directive_print(self, *args):
3973 self.block.output.append(' '.join(args))
3974 self.block.output.append('\n')
3975
3976 def directive_preserve(self):
3977 if self.preserve_output:
3978 fail("Can't have preserve twice in one block!")
3979 self.preserve_output = True
3980
Larry Hastings31826802013-10-19 00:09:25 -07003981 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003982 if self.kind is not CALLABLE:
3983 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003984 self.kind = CLASS_METHOD
3985
3986 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003987 if self.kind is not CALLABLE:
3988 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003989 self.kind = STATIC_METHOD
3990
3991 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003992 if self.coexist:
3993 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003994 self.coexist = True
3995
3996 def parse(self, block):
3997 self.reset()
3998 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003999 self.saved_output = self.block.output
4000 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07004001 block_start = self.clinic.block_parser.line_number
4002 lines = block.input.split('\n')
4003 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
4004 if '\t' in line:
4005 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
4006 self.state(line)
4007
4008 self.next(self.state_terminal)
4009 self.state(None)
4010
Larry Hastingsbebf7352014-01-17 17:47:17 -08004011 block.output.extend(self.clinic.language.render(clinic, block.signatures))
4012
4013 if self.preserve_output:
4014 if block.output:
4015 fail("'preserve' only works for blocks that don't produce any output!")
4016 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07004017
4018 @staticmethod
4019 def ignore_line(line):
4020 # ignore comment-only lines
4021 if line.lstrip().startswith('#'):
4022 return True
4023
4024 # Ignore empty lines too
4025 # (but not in docstring sections!)
4026 if not line.strip():
4027 return True
4028
4029 return False
4030
4031 @staticmethod
4032 def calculate_indent(line):
4033 return len(line) - len(line.strip())
4034
4035 def next(self, state, line=None):
4036 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
4037 self.state = state
4038 if line is not None:
4039 self.state(line)
4040
4041 def state_dsl_start(self, line):
4042 # self.block = self.ClinicOutputBlock(self)
4043 if self.ignore_line(line):
4044 return
Larry Hastings7726ac92014-01-31 22:03:12 -08004045
4046 # is it a directive?
4047 fields = shlex.split(line)
4048 directive_name = fields[0]
4049 directive = self.directives.get(directive_name, None)
4050 if directive:
4051 try:
4052 directive(*fields[1:])
4053 except TypeError as e:
4054 fail(str(e))
4055 return
4056
Larry Hastings31826802013-10-19 00:09:25 -07004057 self.next(self.state_modulename_name, line)
4058
4059 def state_modulename_name(self, line):
4060 # looking for declaration, which establishes the leftmost column
4061 # line should be
4062 # modulename.fnname [as c_basename] [-> return annotation]
4063 # square brackets denote optional syntax.
4064 #
Larry Hastings4a714d42014-01-14 22:22:41 -08004065 # alternatively:
4066 # modulename.fnname [as c_basename] = modulename.existing_fn_name
4067 # clones the parameters and return converter from that
4068 # function. you can't modify them. you must enter a
4069 # new docstring.
4070 #
Larry Hastings31826802013-10-19 00:09:25 -07004071 # (but we might find a directive first!)
4072 #
4073 # this line is permitted to start with whitespace.
4074 # we'll call this number of spaces F (for "function").
4075
4076 if not line.strip():
4077 return
4078
4079 self.indent.infer(line)
4080
Larry Hastings4a714d42014-01-14 22:22:41 -08004081 # are we cloning?
4082 before, equals, existing = line.rpartition('=')
4083 if equals:
4084 full_name, _, c_basename = before.partition(' as ')
4085 full_name = full_name.strip()
4086 c_basename = c_basename.strip()
4087 existing = existing.strip()
4088 if (is_legal_py_identifier(full_name) and
4089 (not c_basename or is_legal_c_identifier(c_basename)) and
4090 is_legal_py_identifier(existing)):
4091 # we're cloning!
4092 fields = [x.strip() for x in existing.split('.')]
4093 function_name = fields.pop()
4094 module, cls = self.clinic._module_and_class(fields)
4095
4096 for existing_function in (cls or module).functions:
4097 if existing_function.name == function_name:
4098 break
4099 else:
4100 existing_function = None
4101 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08004102 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08004103 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08004104 fail("Couldn't find existing function " + repr(existing) + "!")
4105
4106 fields = [x.strip() for x in full_name.split('.')]
4107 function_name = fields.pop()
4108 module, cls = self.clinic._module_and_class(fields)
4109
4110 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
4111 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08004112 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 -08004113
4114 self.block.signatures.append(self.function)
4115 (cls or module).functions.append(self.function)
4116 self.next(self.state_function_docstring)
4117 return
4118
Larry Hastings31826802013-10-19 00:09:25 -07004119 line, _, returns = line.partition('->')
4120
4121 full_name, _, c_basename = line.partition(' as ')
4122 full_name = full_name.strip()
4123 c_basename = c_basename.strip() or None
4124
Larry Hastingsdfcd4672013-10-27 02:49:39 -07004125 if not is_legal_py_identifier(full_name):
4126 fail("Illegal function name: {}".format(full_name))
4127 if c_basename and not is_legal_c_identifier(c_basename):
4128 fail("Illegal C basename: {}".format(c_basename))
4129
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004130 return_converter = None
4131 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07004132 ast_input = "def x() -> {}: pass".format(returns)
4133 module = None
4134 try:
4135 module = ast.parse(ast_input)
4136 except SyntaxError:
4137 pass
4138 if not module:
4139 fail("Badly-formed annotation for " + full_name + ": " + returns)
4140 try:
4141 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004142 if legacy:
4143 fail("Legacy converter {!r} not allowed as a return converter"
4144 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07004145 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004146 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07004147 return_converter = return_converters[name](**kwargs)
4148 except ValueError:
4149 fail("Badly-formed annotation for " + full_name + ": " + returns)
4150
4151 fields = [x.strip() for x in full_name.split('.')]
4152 function_name = fields.pop()
4153 module, cls = self.clinic._module_and_class(fields)
4154
Larry Hastings8666e652014-01-12 14:12:59 -08004155 fields = full_name.split('.')
4156 if fields[-1] == '__new__':
4157 if (self.kind != CLASS_METHOD) or (not cls):
4158 fail("__new__ must be a class method!")
4159 self.kind = METHOD_NEW
4160 elif fields[-1] == '__init__':
4161 if (self.kind != CALLABLE) or (not cls):
4162 fail("__init__ must be a normal method, not a class or static method!")
4163 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004164 if not return_converter:
4165 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08004166 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08004167 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08004168
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004169 if not return_converter:
4170 return_converter = CReturnConverter()
4171
Larry Hastings31826802013-10-19 00:09:25 -07004172 if not module:
4173 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
4174 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
4175 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
4176 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08004177
4178 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08004179 type, name = correct_name_for_self(self.function)
4180 kwargs = {}
4181 if cls and type == "PyObject *":
4182 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08004183 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08004184 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
4185 self.function.parameters[sc.name] = p_self
4186
Larry Hastings4a714d42014-01-14 22:22:41 -08004187 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07004188 self.next(self.state_parameters_start)
4189
4190 # Now entering the parameters section. The rules, formally stated:
4191 #
4192 # * All lines must be indented with spaces only.
4193 # * The first line must be a parameter declaration.
4194 # * The first line must be indented.
4195 # * This first line establishes the indent for parameters.
4196 # * We'll call this number of spaces P (for "parameter").
4197 # * Thenceforth:
4198 # * Lines indented with P spaces specify a parameter.
4199 # * Lines indented with > P spaces are docstrings for the previous
4200 # parameter.
4201 # * We'll call this number of spaces D (for "docstring").
4202 # * All subsequent lines indented with >= D spaces are stored as
4203 # part of the per-parameter docstring.
4204 # * All lines will have the first D spaces of the indent stripped
4205 # before they are stored.
4206 # * It's illegal to have a line starting with a number of spaces X
4207 # such that P < X < D.
4208 # * A line with < P spaces is the first line of the function
4209 # docstring, which ends processing for parameters and per-parameter
4210 # docstrings.
4211 # * The first line of the function docstring must be at the same
4212 # indent as the function declaration.
4213 # * It's illegal to have any line in the parameters section starting
4214 # with X spaces such that F < X < P. (As before, F is the indent
4215 # of the function declaration.)
4216 #
Larry Hastings31826802013-10-19 00:09:25 -07004217 # Also, currently Argument Clinic places the following restrictions on groups:
4218 # * Each group must contain at least one parameter.
4219 # * Each group may contain at most one group, which must be the furthest
4220 # thing in the group from the required parameters. (The nested group
4221 # must be the first in the group when it's before the required
4222 # parameters, and the last thing in the group when after the required
4223 # parameters.)
4224 # * There may be at most one (top-level) group to the left or right of
4225 # the required parameters.
4226 # * You must specify a slash, and it must be after all parameters.
4227 # (In other words: either all parameters are positional-only,
4228 # or none are.)
4229 #
4230 # Said another way:
4231 # * Each group must contain at least one parameter.
4232 # * All left square brackets before the required parameters must be
4233 # consecutive. (You can't have a left square bracket followed
4234 # by a parameter, then another left square bracket. You can't
4235 # have a left square bracket, a parameter, a right square bracket,
4236 # and then a left square bracket.)
4237 # * All right square brackets after the required parameters must be
4238 # consecutive.
4239 #
4240 # These rules are enforced with a single state variable:
4241 # "parameter_state". (Previously the code was a miasma of ifs and
4242 # separate boolean state variables.) The states are:
4243 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004244 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4245 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07004246 #
4247 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4248 # 1: ps_left_square_before. left square brackets before required parameters.
4249 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08004250 # 3: ps_required. required parameters, positional-or-keyword or positional-only
4251 # (we don't know yet). (renumber left groups!)
4252 # 4: ps_optional. positional-or-keyword or positional-only parameters that
4253 # now must have default values.
4254 # 5: ps_group_after. in a group, after required parameters.
4255 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07004256 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004257 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07004258
4259 def state_parameters_start(self, line):
4260 if self.ignore_line(line):
4261 return
4262
4263 # if this line is not indented, we have no parameters
4264 if not self.indent.infer(line):
4265 return self.next(self.state_function_docstring, line)
4266
Larry Hastings2a727912014-01-16 11:32:01 -08004267 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07004268 return self.next(self.state_parameter, line)
4269
4270
4271 def to_required(self):
4272 """
4273 Transition to the "required" parameter state.
4274 """
4275 if self.parameter_state != self.ps_required:
4276 self.parameter_state = self.ps_required
4277 for p in self.function.parameters.values():
4278 p.group = -p.group
4279
4280 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08004281 if self.parameter_continuation:
4282 line = self.parameter_continuation + ' ' + line.lstrip()
4283 self.parameter_continuation = ''
4284
Larry Hastings31826802013-10-19 00:09:25 -07004285 if self.ignore_line(line):
4286 return
4287
4288 assert self.indent.depth == 2
4289 indent = self.indent.infer(line)
4290 if indent == -1:
4291 # we outdented, must be to definition column
4292 return self.next(self.state_function_docstring, line)
4293
4294 if indent == 1:
4295 # we indented, must be to new parameter docstring column
4296 return self.next(self.state_parameter_docstring_start, line)
4297
Larry Hastings2a727912014-01-16 11:32:01 -08004298 line = line.rstrip()
4299 if line.endswith('\\'):
4300 self.parameter_continuation = line[:-1]
4301 return
4302
Larry Hastings31826802013-10-19 00:09:25 -07004303 line = line.lstrip()
4304
4305 if line in ('*', '/', '[', ']'):
4306 self.parse_special_symbol(line)
4307 return
4308
4309 if self.parameter_state in (self.ps_start, self.ps_required):
4310 self.to_required()
4311 elif self.parameter_state == self.ps_left_square_before:
4312 self.parameter_state = self.ps_group_before
4313 elif self.parameter_state == self.ps_group_before:
4314 if not self.group:
4315 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08004316 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07004317 pass
4318 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004319 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07004320
Larry Hastings7726ac92014-01-31 22:03:12 -08004321 # handle "as" for parameters too
4322 c_name = None
4323 name, have_as_token, trailing = line.partition(' as ')
4324 if have_as_token:
4325 name = name.strip()
4326 if ' ' not in name:
4327 fields = trailing.strip().split(' ')
4328 if not fields:
4329 fail("Invalid 'as' clause!")
4330 c_name = fields[0]
4331 if c_name.endswith(':'):
4332 name += ':'
4333 c_name = c_name[:-1]
4334 fields[0] = name
4335 line = ' '.join(fields)
4336
Larry Hastings2a727912014-01-16 11:32:01 -08004337 base, equals, default = line.rpartition('=')
4338 if not equals:
4339 base = default
4340 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08004341
Larry Hastings31826802013-10-19 00:09:25 -07004342 module = None
4343 try:
Larry Hastings2a727912014-01-16 11:32:01 -08004344 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07004345 module = ast.parse(ast_input)
4346 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08004347 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08004348 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004349 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08004350 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08004351 default = None
4352 ast_input = "def x({}): pass".format(line)
4353 module = ast.parse(ast_input)
4354 except SyntaxError:
4355 pass
Larry Hastings31826802013-10-19 00:09:25 -07004356 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07004357 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07004358
4359 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004360
4361 if len(function_args.args) > 1:
4362 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
4363 if function_args.defaults or function_args.kw_defaults:
4364 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
4365 if function_args.vararg or function_args.kwarg:
4366 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
4367
Larry Hastings31826802013-10-19 00:09:25 -07004368 parameter = function_args.args[0]
4369
Larry Hastings16c51912014-01-07 11:53:01 -08004370 parameter_name = parameter.arg
4371 name, legacy, kwargs = self.parse_converter(parameter.annotation)
4372
Larry Hastings2a727912014-01-16 11:32:01 -08004373 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08004374 if self.parameter_state == self.ps_optional:
4375 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 -08004376 value = unspecified
4377 if 'py_default' in kwargs:
4378 fail("You can't specify py_default without specifying a default value!")
4379 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004380 if self.parameter_state == self.ps_required:
4381 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08004382 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06004383 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004384 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08004385 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004386 try:
4387 module = ast.parse(ast_input)
4388
Larry Hastings5c661892014-01-24 06:17:25 -08004389 if 'c_default' not in kwargs:
4390 # we can only represent very simple data values in C.
4391 # detect whether default is okay, via a blacklist
4392 # of disallowed ast nodes.
4393 class DetectBadNodes(ast.NodeVisitor):
4394 bad = False
4395 def bad_node(self, node):
4396 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08004397
Larry Hastings5c661892014-01-24 06:17:25 -08004398 # inline function call
4399 visit_Call = bad_node
4400 # inline if statement ("x = 3 if y else z")
4401 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004402
Larry Hastings5c661892014-01-24 06:17:25 -08004403 # comprehensions and generator expressions
4404 visit_ListComp = visit_SetComp = bad_node
4405 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004406
Larry Hastings5c661892014-01-24 06:17:25 -08004407 # literals for advanced types
4408 visit_Dict = visit_Set = bad_node
4409 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004410
Larry Hastings5c661892014-01-24 06:17:25 -08004411 # "starred": "a = [1, 2, 3]; *a"
4412 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004413
Larry Hastings5c661892014-01-24 06:17:25 -08004414 blacklist = DetectBadNodes()
4415 blacklist.visit(module)
4416 bad = blacklist.bad
4417 else:
4418 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06004419 # but at least make an attempt at ensuring it's a valid expression.
4420 try:
4421 value = eval(default)
4422 if value == unspecified:
4423 fail("'unspecified' is not a legal default value!")
4424 except NameError:
4425 pass # probably a named constant
4426 except Exception as e:
4427 fail("Malformed expression given as default value\n"
4428 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08004429 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08004430 fail("Unsupported expression as default value: " + repr(default))
4431
4432 expr = module.body[0].value
4433 # mild hack: explicitly support NULL as a default value
4434 if isinstance(expr, ast.Name) and expr.id == 'NULL':
4435 value = NULL
4436 py_default = 'None'
4437 c_default = "NULL"
4438 elif (isinstance(expr, ast.BinOp) or
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004439 (isinstance(expr, ast.UnaryOp) and
4440 not (isinstance(expr.operand, ast.Num) or
4441 (hasattr(ast, 'Constant') and
4442 isinstance(expr.operand, ast.Constant) and
4443 type(expr.operand.value) in (int, float, complex)))
4444 )):
Larry Hastings2a727912014-01-16 11:32:01 -08004445 c_default = kwargs.get("c_default")
4446 if not (isinstance(c_default, str) and c_default):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004447 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 -08004448 py_default = default
4449 value = unknown
4450 elif isinstance(expr, ast.Attribute):
4451 a = []
4452 n = expr
4453 while isinstance(n, ast.Attribute):
4454 a.append(n.attr)
4455 n = n.value
4456 if not isinstance(n, ast.Name):
4457 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
4458 a.append(n.id)
4459 py_default = ".".join(reversed(a))
4460
4461 c_default = kwargs.get("c_default")
4462 if not (isinstance(c_default, str) and c_default):
4463 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4464
4465 try:
4466 value = eval(py_default)
4467 except NameError:
4468 value = unknown
4469 else:
4470 value = ast.literal_eval(expr)
4471 py_default = repr(value)
4472 if isinstance(value, (bool, None.__class__)):
4473 c_default = "Py_" + py_default
4474 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08004475 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08004476 else:
4477 c_default = py_default
4478
4479 except SyntaxError as e:
4480 fail("Syntax error: " + repr(e.text))
4481 except (ValueError, AttributeError):
4482 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08004483 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08004484 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08004485 if not (isinstance(c_default, str) and c_default):
4486 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4487
Larry Hastings2a727912014-01-16 11:32:01 -08004488 kwargs.setdefault('c_default', c_default)
4489 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004490
Larry Hastings31826802013-10-19 00:09:25 -07004491 dict = legacy_converters if legacy else converters
4492 legacy_str = "legacy " if legacy else ""
4493 if name not in dict:
4494 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08004495 # if you use a c_name for the parameter, we just give that name to the converter
4496 # but the parameter object gets the python name
4497 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07004498
4499 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08004500
4501 if isinstance(converter, self_converter):
4502 if len(self.function.parameters) == 1:
4503 if (self.parameter_state != self.ps_required):
4504 fail("A 'self' parameter cannot be marked optional.")
4505 if value is not unspecified:
4506 fail("A 'self' parameter cannot have a default value.")
4507 if self.group:
4508 fail("A 'self' parameter cannot be in an optional group.")
4509 kind = inspect.Parameter.POSITIONAL_ONLY
4510 self.parameter_state = self.ps_start
4511 self.function.parameters.clear()
4512 else:
4513 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
4514
Larry Hastings31826802013-10-19 00:09:25 -07004515 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08004516
4517 if parameter_name in self.function.parameters:
4518 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07004519 self.function.parameters[parameter_name] = p
4520
4521 def parse_converter(self, annotation):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004522 if (hasattr(ast, 'Constant') and
4523 isinstance(annotation, ast.Constant) and
4524 type(annotation.value) is str):
4525 return annotation.value, True, {}
4526
Larry Hastings31826802013-10-19 00:09:25 -07004527 if isinstance(annotation, ast.Str):
4528 return annotation.s, True, {}
4529
4530 if isinstance(annotation, ast.Name):
4531 return annotation.id, False, {}
4532
Larry Hastings4a55fc52014-01-12 11:09:57 -08004533 if not isinstance(annotation, ast.Call):
4534 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07004535
4536 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004537 symbols = globals()
4538
4539 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07004540 return name, False, kwargs
4541
4542 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07004543 if symbol == '*':
4544 if self.keyword_only:
4545 fail("Function " + self.function.name + " uses '*' more than once.")
4546 self.keyword_only = True
4547 elif symbol == '[':
4548 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
4549 self.parameter_state = self.ps_left_square_before
4550 elif self.parameter_state in (self.ps_required, self.ps_group_after):
4551 self.parameter_state = self.ps_group_after
4552 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004553 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07004554 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08004555 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07004556 elif symbol == ']':
4557 if not self.group:
4558 fail("Function " + self.function.name + " has a ] without a matching [.")
4559 if not any(p.group == self.group for p in self.function.parameters.values()):
4560 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
4561 self.group -= 1
4562 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
4563 self.parameter_state = self.ps_group_before
4564 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
4565 self.parameter_state = self.ps_right_square_after
4566 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004567 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07004568 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004569 if self.positional_only:
4570 fail("Function " + self.function.name + " uses '/' more than once.")
4571 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08004572 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07004573 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08004574 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
4575 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07004576 if self.keyword_only:
4577 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004578 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004579 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004580 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004581 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4582 p.kind = inspect.Parameter.POSITIONAL_ONLY
4583
4584 def state_parameter_docstring_start(self, line):
4585 self.parameter_docstring_indent = len(self.indent.margin)
4586 assert self.indent.depth == 3
4587 return self.next(self.state_parameter_docstring, line)
4588
4589 # every line of the docstring must start with at least F spaces,
4590 # where F > P.
4591 # these F spaces will be stripped.
4592 def state_parameter_docstring(self, line):
4593 stripped = line.strip()
4594 if stripped.startswith('#'):
4595 return
4596
4597 indent = self.indent.measure(line)
4598 if indent < self.parameter_docstring_indent:
4599 self.indent.infer(line)
4600 assert self.indent.depth < 3
4601 if self.indent.depth == 2:
4602 # back to a parameter
4603 return self.next(self.state_parameter, line)
4604 assert self.indent.depth == 1
4605 return self.next(self.state_function_docstring, line)
4606
4607 assert self.function.parameters
4608 last_parameter = next(reversed(list(self.function.parameters.values())))
4609
4610 new_docstring = last_parameter.docstring
4611
4612 if new_docstring:
4613 new_docstring += '\n'
4614 if stripped:
4615 new_docstring += self.indent.dedent(line)
4616
4617 last_parameter.docstring = new_docstring
4618
4619 # the final stanza of the DSL is the docstring.
4620 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004621 if self.group:
4622 fail("Function " + self.function.name + " has a ] without a matching [.")
4623
4624 stripped = line.strip()
4625 if stripped.startswith('#'):
4626 return
4627
4628 new_docstring = self.function.docstring
4629 if new_docstring:
4630 new_docstring += "\n"
4631 if stripped:
4632 line = self.indent.dedent(line).rstrip()
4633 else:
4634 line = ''
4635 new_docstring += line
4636 self.function.docstring = new_docstring
4637
4638 def format_docstring(self):
4639 f = self.function
4640
Larry Hastings5c661892014-01-24 06:17:25 -08004641 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4642 if new_or_init and not f.docstring:
4643 # don't render a docstring at all, no signature, nothing.
4644 return f.docstring
4645
Larry Hastings2623c8c2014-02-08 22:15:29 -08004646 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004647 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004648
4649 ##
4650 ## docstring first line
4651 ##
4652
Larry Hastings2623c8c2014-02-08 22:15:29 -08004653 if new_or_init:
4654 # classes get *just* the name of the class
4655 # not __new__, not __init__, and not module.classname
4656 assert f.cls
4657 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004658 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004659 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004660 add('(')
4661
4662 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004663 assert parameters, "We should always have a self parameter. " + repr(f)
4664 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004665 # self is always positional-only.
4666 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004667 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004668 positional_only = True
4669 for p in parameters[1:]:
4670 if not p.is_positional_only():
4671 positional_only = False
4672 else:
4673 assert positional_only
4674 if positional_only:
4675 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004676 else:
4677 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004678 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004679
4680 right_bracket_count = 0
4681
4682 def fix_right_bracket_count(desired):
4683 nonlocal right_bracket_count
4684 s = ''
4685 while right_bracket_count < desired:
4686 s += '['
4687 right_bracket_count += 1
4688 while right_bracket_count > desired:
4689 s += ']'
4690 right_bracket_count -= 1
4691 return s
4692
Larry Hastings2623c8c2014-02-08 22:15:29 -08004693 need_slash = False
4694 added_slash = False
4695 need_a_trailing_slash = False
4696
4697 # we only need a trailing slash:
4698 # * if this is not a "docstring_only" signature
4699 # * and if the last *shown* parameter is
4700 # positional only
4701 if not f.docstring_only:
4702 for p in reversed(parameters):
4703 if not p.converter.show_in_signature:
4704 continue
4705 if p.is_positional_only():
4706 need_a_trailing_slash = True
4707 break
4708
4709
Larry Hastings31826802013-10-19 00:09:25 -07004710 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004711
4712 first_parameter = True
4713 last_p = parameters[-1]
4714 line_length = len(''.join(text))
4715 indent = " " * line_length
4716 def add_parameter(text):
4717 nonlocal line_length
4718 nonlocal first_parameter
4719 if first_parameter:
4720 s = text
4721 first_parameter = False
4722 else:
4723 s = ' ' + text
4724 if line_length + len(s) >= 72:
4725 add('\n')
4726 add(indent)
4727 line_length = len(indent)
4728 s = text
4729 line_length += len(s)
4730 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004731
4732 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004733 if not p.converter.show_in_signature:
4734 continue
Larry Hastings31826802013-10-19 00:09:25 -07004735 assert p.name
4736
Larry Hastings2623c8c2014-02-08 22:15:29 -08004737 is_self = isinstance(p.converter, self_converter)
4738 if is_self and f.docstring_only:
4739 # this isn't a real machine-parsable signature,
4740 # so let's not print the "self" parameter
4741 continue
4742
4743 if p.is_positional_only():
4744 need_slash = not f.docstring_only
4745 elif need_slash and not (added_slash or p.is_positional_only()):
4746 added_slash = True
4747 add_parameter('/,')
4748
Larry Hastings31826802013-10-19 00:09:25 -07004749 if p.is_keyword_only() and not added_star:
4750 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004751 add_parameter('*,')
4752
4753 p_add, p_output = text_accumulator()
4754 p_add(fix_right_bracket_count(p.right_bracket_count))
4755
4756 if isinstance(p.converter, self_converter):
4757 # annotate first parameter as being a "self".
4758 #
4759 # if inspect.Signature gets this function,
4760 # and it's already bound, the self parameter
4761 # will be stripped off.
4762 #
4763 # if it's not bound, it should be marked
4764 # as positional-only.
4765 #
4766 # note: we don't print "self" for __init__,
4767 # because this isn't actually the signature
4768 # for __init__. (it can't be, __init__ doesn't
4769 # have a docstring.) if this is an __init__
4770 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004771 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004772 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004773
Larry Hastings5c661892014-01-24 06:17:25 -08004774 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004775 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004776
Larry Hastings31826802013-10-19 00:09:25 -07004777 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004778 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004779 value = p.converter.py_default
4780 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004781 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004782 p_add(value)
4783
4784 if (p != last_p) or need_a_trailing_slash:
4785 p_add(',')
4786
4787 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004788
4789 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004790 if need_a_trailing_slash:
4791 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004792 add(')')
4793
Larry Hastings2a727912014-01-16 11:32:01 -08004794 # PEP 8 says:
4795 #
4796 # The Python standard library will not use function annotations
4797 # as that would result in a premature commitment to a particular
4798 # annotation style. Instead, the annotations are left for users
4799 # to discover and experiment with useful annotation styles.
4800 #
4801 # therefore this is commented out:
4802 #
4803 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004804 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004805 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004806
Larry Hastings2623c8c2014-02-08 22:15:29 -08004807 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004808 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004809
Larry Hastings31826802013-10-19 00:09:25 -07004810 docstring_first_line = output()
4811
4812 # now fix up the places where the brackets look wrong
4813 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4814
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004815 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004816 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004817 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004818 for p in parameters:
4819 if not p.docstring.strip():
4820 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004821 if spacer_line:
4822 add('\n')
4823 else:
4824 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004825 add(" ")
4826 add(p.name)
4827 add('\n')
4828 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004829 parameters = output()
4830 if parameters:
4831 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004832
4833 ##
4834 ## docstring body
4835 ##
4836
4837 docstring = f.docstring.rstrip()
4838 lines = [line.rstrip() for line in docstring.split('\n')]
4839
4840 # Enforce the summary line!
4841 # The first line of a docstring should be a summary of the function.
4842 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4843 # by itself.
4844 #
4845 # Argument Clinic enforces the following rule:
4846 # * either the docstring is empty,
4847 # * or it must have a summary line.
4848 #
4849 # Guido said Clinic should enforce this:
4850 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4851
4852 if len(lines) >= 2:
4853 if lines[1]:
4854 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4855 "Every non-blank function docstring must start with\n" +
4856 "a single line summary followed by an empty line.")
4857 elif len(lines) == 1:
4858 # the docstring is only one line right now--the summary line.
4859 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004860 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004861 lines.append('')
4862
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004863 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4864 if parameters_marker_count > 1:
4865 fail('You may not specify {parameters} more than once in a docstring!')
4866
4867 if not parameters_marker_count:
4868 # insert after summary line
4869 lines.insert(2, '{parameters}')
4870
4871 # insert at front of docstring
4872 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004873
4874 docstring = "\n".join(lines)
4875
4876 add(docstring)
4877 docstring = output()
4878
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004879 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004880 docstring = docstring.rstrip()
4881
4882 return docstring
4883
4884 def state_terminal(self, line):
4885 """
4886 Called when processing the block is done.
4887 """
4888 assert not line
4889
4890 if not self.function:
4891 return
4892
4893 if self.keyword_only:
4894 values = self.function.parameters.values()
4895 if not values:
4896 no_parameter_after_star = True
4897 else:
4898 last_parameter = next(reversed(list(values)))
4899 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4900 if no_parameter_after_star:
4901 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4902
4903 # remove trailing whitespace from all parameter docstrings
4904 for name, value in self.function.parameters.items():
4905 if not value:
4906 continue
4907 value.docstring = value.docstring.rstrip()
4908
4909 self.function.docstring = self.format_docstring()
4910
4911
Larry Hastings5c661892014-01-24 06:17:25 -08004912
4913
Larry Hastings31826802013-10-19 00:09:25 -07004914# maps strings to callables.
4915# the callable should return an object
4916# that implements the clinic parser
4917# interface (__init__ and parse).
4918#
4919# example parsers:
4920# "clinic", handles the Clinic DSL
4921# "python", handles running Python code
4922#
4923parsers = {'clinic' : DSLParser, 'python': PythonParser}
4924
4925
4926clinic = None
4927
4928
4929def main(argv):
4930 import sys
4931
4932 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4933 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4934
4935 import argparse
Tim Hoffmann5df40252019-06-02 18:58:10 +02004936 cmdline = argparse.ArgumentParser(
4937 description="""Preprocessor for CPython C files.
4938
4939The purpose of the Argument Clinic is automating all the boilerplate involved
4940with writing argument parsing code for builtins and providing introspection
4941signatures ("docstrings") for CPython builtins.
4942
4943For more information see https://docs.python.org/3/howto/clinic.html""")
Larry Hastings31826802013-10-19 00:09:25 -07004944 cmdline.add_argument("-f", "--force", action='store_true')
4945 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004946 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004947 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004948 cmdline.add_argument("--make", action='store_true',
4949 help="Walk --srcdir to run over all relevant files.")
4950 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4951 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004952 cmdline.add_argument("filename", type=str, nargs="*")
4953 ns = cmdline.parse_args(argv)
4954
4955 if ns.converters:
4956 if ns.filename:
4957 print("Usage error: can't specify --converters and a filename at the same time.")
4958 print()
4959 cmdline.print_usage()
4960 sys.exit(-1)
4961 converters = []
4962 return_converters = []
4963 ignored = set("""
4964 add_c_converter
4965 add_c_return_converter
4966 add_default_legacy_c_converter
4967 add_legacy_c_converter
4968 """.strip().split())
4969 module = globals()
4970 for name in module:
4971 for suffix, ids in (
4972 ("_return_converter", return_converters),
4973 ("_converter", converters),
4974 ):
4975 if name in ignored:
4976 continue
4977 if name.endswith(suffix):
4978 ids.append((name, name[:-len(suffix)]))
4979 break
4980 print()
4981
4982 print("Legacy converters:")
4983 legacy = sorted(legacy_converters)
4984 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4985 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4986 print()
4987
4988 for title, attribute, ids in (
4989 ("Converters", 'converter_init', converters),
4990 ("Return converters", 'return_converter_init', return_converters),
4991 ):
4992 print(title + ":")
4993 longest = -1
4994 for name, short_name in ids:
4995 longest = max(longest, len(short_name))
4996 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4997 cls = module[name]
4998 callable = getattr(cls, attribute, None)
4999 if not callable:
5000 continue
5001 signature = inspect.signature(callable)
5002 parameters = []
5003 for parameter_name, parameter in signature.parameters.items():
5004 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
5005 if parameter.default != inspect.Parameter.empty:
5006 s = '{}={!r}'.format(parameter_name, parameter.default)
5007 else:
5008 s = parameter_name
5009 parameters.append(s)
5010 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07005011 print()
Larry Hastings2a727912014-01-16 11:32:01 -08005012 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
5013 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07005014 sys.exit(0)
5015
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005016 if ns.make:
5017 if ns.output or ns.filename:
5018 print("Usage error: can't use -o or filenames with --make.")
5019 print()
5020 cmdline.print_usage()
5021 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07005022 if not ns.srcdir:
5023 print("Usage error: --srcdir must not be empty with --make.")
5024 print()
5025 cmdline.print_usage()
5026 sys.exit(-1)
5027 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05005028 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005029 if rcs_dir in dirs:
5030 dirs.remove(rcs_dir)
5031 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08005032 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005033 continue
5034 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08005035 if ns.verbose:
5036 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08005037 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005038 return
5039
Larry Hastings31826802013-10-19 00:09:25 -07005040 if not ns.filename:
5041 cmdline.print_usage()
5042 sys.exit(-1)
5043
5044 if ns.output and len(ns.filename) > 1:
5045 print("Usage error: can't use -o with multiple filenames.")
5046 print()
5047 cmdline.print_usage()
5048 sys.exit(-1)
5049
5050 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08005051 if ns.verbose:
5052 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08005053 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07005054
5055
5056if __name__ == "__main__":
5057 sys.exit(main(sys.argv[1:]))