blob: d5863a3effe9e10361d7926681dd55a03d599f91 [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
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200809 parsearg = converters[0].parse_arg(argname, 0)
810 if parsearg is None:
811 parsearg = """
812 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
813 goto exit;
814 }}
815 """ % argname
Serhiy Storchaka32d96a22018-12-25 13:23:47 +0200816 parser_definition = parser_body(parser_prototype,
817 normalize_snippet(parsearg, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700818
Larry Hastingsbebf7352014-01-17 17:47:17 -0800819 elif has_option_groups:
820 # positional parameters with option groups
821 # (we have to generate lots of PyArg_ParseTuple calls
822 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700823
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800824 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800825 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700826
Larry Hastings7726ac92014-01-31 22:03:12 -0800827 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700828
Serhiy Storchaka31913912019-03-14 10:32:22 +0200829 elif pos_only == len(parameters):
Victor Stinner0c8c3892017-01-17 01:42:54 +0100830 if not new_or_init:
831 # positional-only, but no option groups
832 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800833
Victor Stinner0c8c3892017-01-17 01:42:54 +0100834 flags = "METH_FASTCALL"
835 parser_prototype = parser_prototype_fastcall
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200836 nargs = 'nargs'
837 argname_fmt = 'args[%d]'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100838 else:
839 # positional-only, but no option groups
840 # we only need one call to PyArg_ParseTuple
841
842 flags = "METH_VARARGS"
843 parser_prototype = parser_prototype_varargs
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200844 nargs = 'PyTuple_GET_SIZE(args)'
845 argname_fmt = 'PyTuple_GET_ITEM(args, %d)'
Victor Stinner0c8c3892017-01-17 01:42:54 +0100846
Serhiy Storchaka31913912019-03-14 10:32:22 +0200847 parser_code = [normalize_snippet("""
848 if (!_PyArg_CheckPositional("{name}", %s, %d, %d)) {{
849 goto exit;
850 }}
851 """ % (nargs, min_pos, max_pos), indent=4)]
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200852 has_optional = False
Serhiy Storchaka31913912019-03-14 10:32:22 +0200853 for i, p in enumerate(parameters):
854 parsearg = p.converter.parse_arg(argname_fmt % i, i + 1)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200855 if parsearg is None:
Serhiy Storchaka31913912019-03-14 10:32:22 +0200856 #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 +0200857 parser_code = None
858 break
Serhiy Storchaka31913912019-03-14 10:32:22 +0200859 if has_optional or p.is_optional():
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200860 has_optional = True
861 parser_code.append(normalize_snippet("""
862 if (%s < %d) {{
863 goto skip_optional;
864 }}
865 """, indent=4) % (nargs, i + 1))
866 parser_code.append(normalize_snippet(parsearg, indent=4))
867
868 if parser_code is not None:
Serhiy Storchaka4fa95912019-01-11 16:01:14 +0200869 if has_optional:
870 parser_code.append("skip_optional:")
871 else:
872 if not new_or_init:
873 parser_code = [normalize_snippet("""
874 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
875 {parse_arguments})) {{
876 goto exit;
877 }}
878 """, indent=4)]
879 else:
880 parser_code = [normalize_snippet("""
881 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
882 {parse_arguments})) {{
883 goto exit;
884 }}
885 """, indent=4)]
886 parser_definition = parser_body(parser_prototype, *parser_code)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800887
888 else:
Serhiy Storchaka31913912019-03-14 10:32:22 +0200889 has_optional_kw = (max(pos_only, min_pos) + min_kw_only < len(converters))
890 if not new_or_init:
891 flags = "METH_FASTCALL|METH_KEYWORDS"
892 parser_prototype = parser_prototype_fastcall_keywords
893 argname_fmt = 'args[%d]'
894 declarations = normalize_snippet("""
895 static const char * const _keywords[] = {{{keywords}, NULL}};
896 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
897 PyObject *argsbuf[%s];
898 """ % len(converters))
899 if has_optional_kw:
900 declarations += "\nPy_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (min_pos + min_kw_only)
901 parser_code = [normalize_snippet("""
902 args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, %d, %d, %d, argsbuf);
903 if (!args) {{
904 goto exit;
905 }}
906 """ % (min_pos, max_pos, min_kw_only), indent=4)]
907 else:
908 # positional-or-keyword arguments
909 flags = "METH_VARARGS|METH_KEYWORDS"
910 parser_prototype = parser_prototype_keyword
911 argname_fmt = 'fastargs[%d]'
912 declarations = normalize_snippet("""
913 static const char * const _keywords[] = {{{keywords}, NULL}};
914 static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
915 PyObject *argsbuf[%s];
916 PyObject * const *fastargs;
917 Py_ssize_t nargs = PyTuple_GET_SIZE(args);
918 """ % len(converters))
919 if has_optional_kw:
920 declarations += "\nPy_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (min_pos + min_kw_only)
921 parser_code = [normalize_snippet("""
922 fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %d, %d, %d, argsbuf);
923 if (!fastargs) {{
924 goto exit;
925 }}
926 """ % (min_pos, max_pos, min_kw_only), indent=4)]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800927
Serhiy Storchaka31913912019-03-14 10:32:22 +0200928 add_label = None
929 for i, p in enumerate(parameters):
930 parsearg = p.converter.parse_arg(argname_fmt % i, i + 1)
931 if parsearg is None:
932 #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr)
933 parser_code = None
934 break
935 if add_label and (i == pos_only or i == max_pos):
936 parser_code.append("%s:" % add_label)
937 add_label = None
938 if not p.is_optional():
939 parser_code.append(normalize_snippet(parsearg, indent=4))
940 elif i < pos_only:
941 add_label = 'skip_optional_posonly'
942 parser_code.append(normalize_snippet("""
943 if (nargs < %d) {{
944 goto %s;
945 }}
946 """ % (i + 1, add_label), indent=4))
947 if has_optional_kw:
948 parser_code.append(normalize_snippet("""
949 noptargs--;
950 """, indent=4))
951 parser_code.append(normalize_snippet(parsearg, indent=4))
952 else:
953 if i < max_pos:
954 label = 'skip_optional_pos'
955 first_opt = max(min_pos, pos_only)
956 else:
957 label = 'skip_optional_kwonly'
958 first_opt = max_pos + min_kw_only
959 if i == first_opt:
960 add_label = label
961 parser_code.append(normalize_snippet("""
962 if (!noptargs) {{
963 goto %s;
964 }}
965 """ % add_label, indent=4))
966 if i + 1 == len(parameters):
967 parser_code.append(normalize_snippet(parsearg, indent=4))
968 else:
969 add_label = label
970 parser_code.append(normalize_snippet("""
971 if (%s) {{
972 """ % (argname_fmt % i), indent=4))
973 parser_code.append(normalize_snippet(parsearg, indent=8))
974 parser_code.append(normalize_snippet("""
975 if (!--noptargs) {{
976 goto %s;
977 }}
978 }}
979 """ % add_label, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800980
Serhiy Storchaka31913912019-03-14 10:32:22 +0200981 if parser_code is not None:
982 if add_label:
983 parser_code.append("%s:" % add_label)
984 else:
985 declarations = (
986 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
987 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};')
988 if not new_or_init:
989 parser_code = [normalize_snippet("""
990 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
991 {parse_arguments})) {{
992 goto exit;
993 }}
994 """, indent=4)]
995 else:
996 parser_code = [normalize_snippet("""
997 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
998 {parse_arguments})) {{
999 goto exit;
1000 }}
1001 """, indent=4)]
1002 parser_definition = parser_body(parser_prototype, *parser_code,
1003 declarations=declarations)
Larry Hastings31826802013-10-19 00:09:25 -07001004
Larry Hastings31826802013-10-19 00:09:25 -07001005
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001006 if new_or_init:
1007 methoddef_define = ''
1008
1009 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -08001010 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001011 else:
1012 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -08001013 parser_prototype = normalize_snippet("""
1014 static int
1015 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
1016 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001017
1018 fields = list(parser_body_fields)
1019 parses_positional = 'METH_NOARGS' not in flags
1020 parses_keywords = 'METH_KEYWORDS' in flags
1021 if parses_keywords:
1022 assert parses_positional
1023
1024 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -08001025 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001026 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -08001027 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001028 }}
Larry Hastings7726ac92014-01-31 22:03:12 -08001029 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001030 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -08001031 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001032 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -08001033 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001034 }}
Larry Hastings7726ac92014-01-31 22:03:12 -08001035 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001036
Serhiy Storchaka31913912019-03-14 10:32:22 +02001037 parser_definition = parser_body(parser_prototype, *fields,
1038 declarations=parser_body_declarations)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001039
Larry Hastings31826802013-10-19 00:09:25 -07001040
Serhiy Storchaka4a934d42018-11-27 11:27:36 +02001041 if flags in ('METH_NOARGS', 'METH_O', 'METH_VARARGS'):
1042 methoddef_cast = "(PyCFunction)"
1043 else:
1044 methoddef_cast = "(PyCFunction)(void(*)(void))"
1045
Larry Hastingsbebf7352014-01-17 17:47:17 -08001046 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001047 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -07001048
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001049 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Serhiy Storchaka4a934d42018-11-27 11:27:36 +02001050 methoddef_define = methoddef_define.replace('{methoddef_cast}', methoddef_cast)
Larry Hastings31826802013-10-19 00:09:25 -07001051
Larry Hastings7726ac92014-01-31 22:03:12 -08001052 methoddef_ifndef = ''
1053 conditional = self.cpp.condition()
1054 if not conditional:
1055 cpp_if = cpp_endif = ''
1056 else:
1057 cpp_if = "#if " + conditional
1058 cpp_endif = "#endif /* " + conditional + " */"
1059
Tal Einat4f574092017-11-03 11:09:00 +02001060 if methoddef_define and f.full_name not in clinic.ifndef_symbols:
1061 clinic.ifndef_symbols.add(f.full_name)
Larry Hastings7726ac92014-01-31 22:03:12 -08001062 methoddef_ifndef = normalize_snippet("""
1063 #ifndef {methoddef_name}
1064 #define {methoddef_name}
1065 #endif /* !defined({methoddef_name}) */
1066 """)
1067
1068
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001069 # add ';' to the end of parser_prototype and impl_prototype
1070 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001071 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001072 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001073 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001074 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -07001075
Larry Hastingsbebf7352014-01-17 17:47:17 -08001076 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001077 impl_prototype = impl_definition
1078 if impl_prototype:
1079 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -07001080
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001081 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001082
1083 d = {
1084 "docstring_prototype" : docstring_prototype,
1085 "docstring_definition" : docstring_definition,
1086 "impl_prototype" : impl_prototype,
1087 "methoddef_define" : methoddef_define,
1088 "parser_prototype" : parser_prototype,
1089 "parser_definition" : parser_definition,
1090 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -08001091 "cpp_if" : cpp_if,
1092 "cpp_endif" : cpp_endif,
1093 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001094 }
1095
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001096 # make sure we didn't forget to assign something,
1097 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001098 d2 = {}
1099 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001100 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001101 if value:
1102 value = '\n' + value + '\n'
1103 d2[name] = value
1104 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001105
1106 @staticmethod
1107 def group_to_variable_name(group):
1108 adjective = "left_" if group < 0 else "right_"
1109 return "group_" + adjective + str(abs(group))
1110
1111 def render_option_group_parsing(self, f, template_dict):
1112 # positional only, grouped, optional arguments!
1113 # can be optional on the left or right.
1114 # here's an example:
1115 #
1116 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1117 #
1118 # Here group D are required, and all other groups are optional.
1119 # (Group D's "group" is actually None.)
1120 # We can figure out which sets of arguments we have based on
1121 # how many arguments are in the tuple.
1122 #
1123 # Note that you need to count up on both sides. For example,
1124 # you could have groups C+D, or C+D+E, or C+D+E+F.
1125 #
1126 # What if the number of arguments leads us to an ambiguous result?
1127 # Clinic prefers groups on the left. So in the above example,
1128 # five arguments would map to B+C, not C+D.
1129
1130 add, output = text_accumulator()
1131 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001132 if isinstance(parameters[0].converter, self_converter):
1133 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001134
1135 groups = []
1136 group = None
1137 left = []
1138 right = []
1139 required = []
1140 last = unspecified
1141
1142 for p in parameters:
1143 group_id = p.group
1144 if group_id != last:
1145 last = group_id
1146 group = []
1147 if group_id < 0:
1148 left.append(group)
1149 elif group_id == 0:
1150 group = required
1151 else:
1152 right.append(group)
1153 group.append(p)
1154
1155 count_min = sys.maxsize
1156 count_max = -1
1157
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001158 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001159 for subset in permute_optional_groups(left, required, right):
1160 count = len(subset)
1161 count_min = min(count_min, count)
1162 count_max = max(count_max, count)
1163
Larry Hastings583baa82014-01-12 08:49:30 -08001164 if count == 0:
1165 add(""" case 0:
1166 break;
1167""")
1168 continue
1169
Larry Hastings31826802013-10-19 00:09:25 -07001170 group_ids = {p.group for p in subset} # eliminate duplicates
1171 d = {}
1172 d['count'] = count
1173 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001174 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1175
1176 parse_arguments = []
1177 for p in subset:
1178 p.converter.parse_argument(parse_arguments)
1179 d['parse_arguments'] = ", ".join(parse_arguments)
1180
1181 group_ids.discard(0)
1182 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1183 lines = "\n".join(lines)
1184
1185 s = """
1186 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001187 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001188 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001189 }}
Larry Hastings31826802013-10-19 00:09:25 -07001190 {group_booleans}
1191 break;
1192"""[1:]
1193 s = linear_format(s, group_booleans=lines)
1194 s = s.format_map(d)
1195 add(s)
1196
1197 add(" default:\n")
1198 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1199 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001200 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001201 add("}")
1202 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001203
Larry Hastingsbebf7352014-01-17 17:47:17 -08001204 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001205 if not f:
1206 return ""
1207
1208 add, output = text_accumulator()
1209 data = CRenderData()
1210
Larry Hastings7726ac92014-01-31 22:03:12 -08001211 assert f.parameters, "We should always have a 'self' at this point!"
1212 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001213 converters = [p.converter for p in parameters]
1214
Larry Hastings5c661892014-01-24 06:17:25 -08001215 templates = self.output_templates(f)
1216
1217 f_self = parameters[0]
1218 selfless = parameters[1:]
1219 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1220
1221 last_group = 0
1222 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001223 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001224 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1225 default_return_converter = (not f.return_converter or
1226 f.return_converter.type == 'PyObject *')
1227 has_option_groups = False
1228
1229 # offset i by -1 because first_optional needs to ignore self
1230 for i, p in enumerate(parameters, -1):
1231 c = p.converter
1232
1233 if (i != -1) and (p.default is not unspecified):
1234 first_optional = min(first_optional, i)
1235
1236 # insert group variable
1237 group = p.group
1238 if last_group != group:
1239 last_group = group
1240 if group:
1241 group_name = self.group_to_variable_name(group)
1242 data.impl_arguments.append(group_name)
1243 data.declarations.append("int " + group_name + " = 0;")
1244 data.impl_parameters.append("int " + group_name)
1245 has_option_groups = True
1246
1247 c.render(p, data)
1248
1249 if has_option_groups and (not positional):
1250 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1251
1252 # HACK
1253 # when we're METH_O, but have a custom return converter,
1254 # we use "impl_parameters" for the parsing function
1255 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001256 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001257 # as variables in the parsing function. but since it's
1258 # METH_O, we have exactly one anyway, so we know exactly
1259 # where it is.
1260 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001261 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001262 data.declarations.pop(0)
1263
Larry Hastings31826802013-10-19 00:09:25 -07001264 template_dict = {}
1265
1266 full_name = f.full_name
1267 template_dict['full_name'] = full_name
1268
Larry Hastings5c661892014-01-24 06:17:25 -08001269 if new_or_init:
1270 name = f.cls.name
1271 else:
1272 name = f.name
1273
Larry Hastings31826802013-10-19 00:09:25 -07001274 template_dict['name'] = name
1275
Larry Hastings8666e652014-01-12 14:12:59 -08001276 if f.c_basename:
1277 c_basename = f.c_basename
1278 else:
1279 fields = full_name.split(".")
1280 if fields[-1] == '__new__':
1281 fields.pop()
1282 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001283
Larry Hastings31826802013-10-19 00:09:25 -07001284 template_dict['c_basename'] = c_basename
1285
1286 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1287 template_dict['methoddef_name'] = methoddef_name
1288
1289 template_dict['docstring'] = self.docstring_for_c_string(f)
1290
Larry Hastingsc2047262014-01-25 20:43:29 -08001291 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001292 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001293
Larry Hastings31826802013-10-19 00:09:25 -07001294 f.return_converter.render(f, data)
1295 template_dict['impl_return_type'] = f.return_converter.type
1296
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001297 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001298 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001299 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001300 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1301 template_dict['format_units'] = ''.join(data.format_units)
1302 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1303 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1304 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001305 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1306 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001307 template_dict['return_value'] = data.return_value
1308
Larry Hastings5c661892014-01-24 06:17:25 -08001309 # used by unpack tuple code generator
1310 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1311 unpack_min = first_optional
1312 unpack_max = len(selfless)
1313 template_dict['unpack_min'] = str(unpack_min)
1314 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001315
Larry Hastingsbebf7352014-01-17 17:47:17 -08001316 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001317 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001318
Larry Hastings0759f842015-04-03 13:09:02 -07001319 # buffers, not destination
1320 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001321 template = templates[name]
1322 if has_option_groups:
1323 template = linear_format(template,
1324 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001325 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001326 declarations=template_dict['declarations'],
1327 return_conversion=template_dict['return_conversion'],
1328 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001329 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001330 cleanup=template_dict['cleanup'],
1331 )
Larry Hastings31826802013-10-19 00:09:25 -07001332
Larry Hastingsbebf7352014-01-17 17:47:17 -08001333 # Only generate the "exit:" label
1334 # if we have any gotos
1335 need_exit_label = "goto exit;" in template
1336 template = linear_format(template,
1337 exit_label="exit:" if need_exit_label else ''
1338 )
Larry Hastings31826802013-10-19 00:09:25 -07001339
Larry Hastingsbebf7352014-01-17 17:47:17 -08001340 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001341
Larry Hastings89964c42015-04-14 18:07:59 -04001342 # mild hack:
1343 # reflow long impl declarations
1344 if name in {"impl_prototype", "impl_definition"}:
1345 s = wrap_declarations(s)
1346
Larry Hastingsbebf7352014-01-17 17:47:17 -08001347 if clinic.line_prefix:
1348 s = indent_all_lines(s, clinic.line_prefix)
1349 if clinic.line_suffix:
1350 s = suffix_all_lines(s, clinic.line_suffix)
1351
1352 destination.append(s)
1353
1354 return clinic.get_destination('block').dump()
1355
Larry Hastings31826802013-10-19 00:09:25 -07001356
1357
Larry Hastings5c661892014-01-24 06:17:25 -08001358
Larry Hastings31826802013-10-19 00:09:25 -07001359@contextlib.contextmanager
1360def OverrideStdioWith(stdout):
1361 saved_stdout = sys.stdout
1362 sys.stdout = stdout
1363 try:
1364 yield
1365 finally:
1366 assert sys.stdout is stdout
1367 sys.stdout = saved_stdout
1368
1369
Larry Hastings2623c8c2014-02-08 22:15:29 -08001370def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001371 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001372 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001373 pattern = r'{}({}){}'
1374 if whole_line:
1375 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001376 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1377 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001378
1379
1380class Block:
1381 r"""
1382 Represents a single block of text embedded in
1383 another file. If dsl_name is None, the block represents
1384 verbatim text, raw original text from the file, in
1385 which case "input" will be the only non-false member.
1386 If dsl_name is not None, the block represents a Clinic
1387 block.
1388
1389 input is always str, with embedded \n characters.
1390 input represents the original text from the file;
1391 if it's a Clinic block, it is the original text with
1392 the body_prefix and redundant leading whitespace removed.
1393
1394 dsl_name is either str or None. If str, it's the text
1395 found on the start line of the block between the square
1396 brackets.
1397
1398 signatures is either list or None. If it's a list,
1399 it may only contain clinic.Module, clinic.Class, and
1400 clinic.Function objects. At the moment it should
1401 contain at most one of each.
1402
1403 output is either str or None. If str, it's the output
1404 from this block, with embedded '\n' characters.
1405
1406 indent is either str or None. It's the leading whitespace
1407 that was found on every line of input. (If body_prefix is
1408 not empty, this is the indent *after* removing the
1409 body_prefix.)
1410
1411 preindent is either str or None. It's the whitespace that
1412 was found in front of every line of input *before* the
1413 "body_prefix" (see the Language object). If body_prefix
1414 is empty, preindent must always be empty too.
1415
1416 To illustrate indent and preindent: Assume that '_'
1417 represents whitespace. If the block processed was in a
1418 Python file, and looked like this:
1419 ____#/*[python]
1420 ____#__for a in range(20):
1421 ____#____print(a)
1422 ____#[python]*/
1423 "preindent" would be "____" and "indent" would be "__".
1424
1425 """
1426 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1427 assert isinstance(input, str)
1428 self.input = input
1429 self.dsl_name = dsl_name
1430 self.signatures = signatures or []
1431 self.output = output
1432 self.indent = indent
1433 self.preindent = preindent
1434
Larry Hastings581ee362014-01-28 05:00:08 -08001435 def __repr__(self):
1436 dsl_name = self.dsl_name or "text"
1437 def summarize(s):
1438 s = repr(s)
1439 if len(s) > 30:
1440 return s[:26] + "..." + s[0]
1441 return s
1442 return "".join((
1443 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1444
Larry Hastings31826802013-10-19 00:09:25 -07001445
1446class BlockParser:
1447 """
1448 Block-oriented parser for Argument Clinic.
1449 Iterator, yields Block objects.
1450 """
1451
1452 def __init__(self, input, language, *, verify=True):
1453 """
1454 "input" should be a str object
1455 with embedded \n characters.
1456
1457 "language" should be a Language object.
1458 """
1459 language.validate()
1460
1461 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1462 self.block_start_line_number = self.line_number = 0
1463
1464 self.language = language
1465 before, _, after = language.start_line.partition('{dsl_name}')
1466 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001467 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001468 self.start_re = create_regex(before, after)
1469 self.verify = verify
1470 self.last_checksum_re = None
1471 self.last_dsl_name = None
1472 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001473 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001474
1475 def __iter__(self):
1476 return self
1477
1478 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001479 while True:
1480 if not self.input:
1481 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001482
Larry Hastingsbebf7352014-01-17 17:47:17 -08001483 if self.dsl_name:
1484 return_value = self.parse_clinic_block(self.dsl_name)
1485 self.dsl_name = None
1486 self.first_block = False
1487 return return_value
1488 block = self.parse_verbatim_block()
1489 if self.first_block and not block.input:
1490 continue
1491 self.first_block = False
1492 return block
1493
Larry Hastings31826802013-10-19 00:09:25 -07001494
1495 def is_start_line(self, line):
1496 match = self.start_re.match(line.lstrip())
1497 return match.group(1) if match else None
1498
Larry Hastingse1b82532014-07-27 16:22:20 +02001499 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001500 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001501 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001502 if not lookahead:
1503 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001504 return line
Larry Hastings31826802013-10-19 00:09:25 -07001505
1506 def parse_verbatim_block(self):
1507 add, output = text_accumulator()
1508 self.block_start_line_number = self.line_number
1509
1510 while self.input:
1511 line = self._line()
1512 dsl_name = self.is_start_line(line)
1513 if dsl_name:
1514 self.dsl_name = dsl_name
1515 break
1516 add(line)
1517
1518 return Block(output())
1519
1520 def parse_clinic_block(self, dsl_name):
1521 input_add, input_output = text_accumulator()
1522 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001523 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001524 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1525
Larry Hastings90261132014-01-07 12:21:08 -08001526 def is_stop_line(line):
1527 # make sure to recognize stop line even if it
1528 # doesn't end with EOL (it could be the very end of the file)
1529 if not line.startswith(stop_line):
1530 return False
1531 remainder = line[len(stop_line):]
1532 return (not remainder) or remainder.isspace()
1533
Larry Hastings31826802013-10-19 00:09:25 -07001534 # consume body of program
1535 while self.input:
1536 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001537 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001538 break
1539 if body_prefix:
1540 line = line.lstrip()
1541 assert line.startswith(body_prefix)
1542 line = line[len(body_prefix):]
1543 input_add(line)
1544
1545 # consume output and checksum line, if present.
1546 if self.last_dsl_name == dsl_name:
1547 checksum_re = self.last_checksum_re
1548 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001549 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1550 assert _ == '{arguments}'
1551 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001552 self.last_dsl_name = dsl_name
1553 self.last_checksum_re = checksum_re
1554
1555 # scan forward for checksum line
1556 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001557 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001558 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001559 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001560 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001561 arguments = match.group(1) if match else None
1562 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001563 break
1564 output_add(line)
1565 if self.is_start_line(line):
1566 break
1567
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001568 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001569 if arguments:
1570 d = {}
1571 for field in shlex.split(arguments):
1572 name, equals, value = field.partition('=')
1573 if not equals:
1574 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1575 d[name.strip()] = value.strip()
1576
Larry Hastings31826802013-10-19 00:09:25 -07001577 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001578 if 'input' in d:
1579 checksum = d['output']
1580 input_checksum = d['input']
1581 else:
1582 checksum = d['checksum']
1583 input_checksum = None
1584
1585 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001586 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001587 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1588 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001589 "the end marker,\n"
1590 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001591 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001592 else:
1593 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001594 output_lines = output.splitlines(keepends=True)
1595 self.line_number -= len(output_lines)
1596 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001597 output = None
1598
1599 return Block(input_output(), dsl_name, output=output)
1600
1601
1602class BlockPrinter:
1603
1604 def __init__(self, language, f=None):
1605 self.language = language
1606 self.f = f or io.StringIO()
1607
1608 def print_block(self, block):
1609 input = block.input
1610 output = block.output
1611 dsl_name = block.dsl_name
1612 write = self.f.write
1613
Larry Hastings31826802013-10-19 00:09:25 -07001614 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1615
1616 if not dsl_name:
1617 write(input)
1618 return
1619
1620 write(self.language.start_line.format(dsl_name=dsl_name))
1621 write("\n")
1622
1623 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1624 if not body_prefix:
1625 write(input)
1626 else:
1627 for line in input.split('\n'):
1628 write(body_prefix)
1629 write(line)
1630 write("\n")
1631
1632 write(self.language.stop_line.format(dsl_name=dsl_name))
1633 write("\n")
1634
Larry Hastings581ee362014-01-28 05:00:08 -08001635 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001636 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001637 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001638 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001639 output += '\n'
1640 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001641
Larry Hastings581ee362014-01-28 05:00:08 -08001642 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1643 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001644 write("\n")
1645
Larry Hastingsbebf7352014-01-17 17:47:17 -08001646 def write(self, text):
1647 self.f.write(text)
1648
1649
Larry Hastings0759f842015-04-03 13:09:02 -07001650class BufferSeries:
1651 """
1652 Behaves like a "defaultlist".
1653 When you ask for an index that doesn't exist yet,
1654 the object grows the list until that item exists.
1655 So o[n] will always work.
1656
1657 Supports negative indices for actual items.
1658 e.g. o[-1] is an element immediately preceding o[0].
1659 """
1660
1661 def __init__(self):
1662 self._start = 0
1663 self._array = []
1664 self._constructor = _text_accumulator
1665
1666 def __getitem__(self, i):
1667 i -= self._start
1668 if i < 0:
1669 self._start += i
1670 prefix = [self._constructor() for x in range(-i)]
1671 self._array = prefix + self._array
1672 i = 0
1673 while i >= len(self._array):
1674 self._array.append(self._constructor())
1675 return self._array[i]
1676
1677 def clear(self):
1678 for ta in self._array:
1679 ta._text.clear()
1680
1681 def dump(self):
1682 texts = [ta.output() for ta in self._array]
1683 return "".join(texts)
1684
1685
Larry Hastingsbebf7352014-01-17 17:47:17 -08001686class Destination:
1687 def __init__(self, name, type, clinic, *args):
1688 self.name = name
1689 self.type = type
1690 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001691 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001692 if type not in valid_types:
1693 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1694 extra_arguments = 1 if type == "file" else 0
1695 if len(args) < extra_arguments:
1696 fail("Not enough arguments for destination " + name + " new " + type)
1697 if len(args) > extra_arguments:
1698 fail("Too many arguments for destination " + name + " new " + type)
1699 if type =='file':
1700 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001701 filename = clinic.filename
1702 d['path'] = filename
1703 dirname, basename = os.path.split(filename)
1704 if not dirname:
1705 dirname = '.'
1706 d['dirname'] = dirname
1707 d['basename'] = basename
1708 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001709 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001710
Larry Hastings0759f842015-04-03 13:09:02 -07001711 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001712
1713 def __repr__(self):
1714 if self.type == 'file':
1715 file_repr = " " + repr(self.filename)
1716 else:
1717 file_repr = ''
1718 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1719
1720 def clear(self):
1721 if self.type != 'buffer':
1722 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001723 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001724
1725 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001726 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001727
Larry Hastings31826802013-10-19 00:09:25 -07001728
1729# maps strings to Language objects.
1730# "languages" maps the name of the language ("C", "Python").
1731# "extensions" maps the file extension ("c", "py").
1732languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001733extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1734extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001735
1736
1737# maps strings to callables.
1738# these callables must be of the form:
1739# def foo(name, default, *, ...)
1740# The callable may have any number of keyword-only parameters.
1741# The callable must return a CConverter object.
1742# The callable should not call builtins.print.
1743converters = {}
1744
1745# maps strings to callables.
1746# these callables follow the same rules as those for "converters" above.
1747# note however that they will never be called with keyword-only parameters.
1748legacy_converters = {}
1749
1750
1751# maps strings to callables.
1752# these callables must be of the form:
1753# def foo(*, ...)
1754# The callable may have any number of keyword-only parameters.
1755# The callable must return a CConverter object.
1756# The callable should not call builtins.print.
1757return_converters = {}
1758
Larry Hastings7726ac92014-01-31 22:03:12 -08001759clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001760class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001761
1762 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001763preset block
1764everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001765methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001766docstring_prototype suppress
1767parser_prototype suppress
1768cpp_if suppress
1769cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001770
Larry Hastingsbebf7352014-01-17 17:47:17 -08001771preset original
1772everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001773methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001774docstring_prototype suppress
1775parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001776cpp_if suppress
1777cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001778
1779preset file
1780everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001781methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001782docstring_prototype suppress
1783parser_prototype suppress
1784impl_definition block
1785
1786preset buffer
1787everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001788methoddef_ifndef buffer 1
1789impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001790docstring_prototype suppress
1791impl_prototype suppress
1792parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001793
1794preset partial-buffer
1795everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001796methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001797docstring_prototype block
1798impl_prototype suppress
1799methoddef_define block
1800parser_prototype block
1801impl_definition block
1802
Larry Hastingsbebf7352014-01-17 17:47:17 -08001803"""
1804
Larry Hastings581ee362014-01-28 05:00:08 -08001805 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001806 # maps strings to Parser objects.
1807 # (instantiated from the "parsers" global.)
1808 self.parsers = {}
1809 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001810 if printer:
1811 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001812 self.printer = printer or BlockPrinter(language)
1813 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001814 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001815 self.filename = filename
1816 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001817 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001818 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001819
Larry Hastingsbebf7352014-01-17 17:47:17 -08001820 self.line_prefix = self.line_suffix = ''
1821
1822 self.destinations = {}
1823 self.add_destination("block", "buffer")
1824 self.add_destination("suppress", "suppress")
1825 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001826 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001827 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001828
Larry Hastings0759f842015-04-03 13:09:02 -07001829 d = self.get_destination_buffer
1830 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001831 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001832 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001833 ('docstring_definition', d('file')),
1834 ('methoddef_define', d('file')),
1835 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001836 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001837 ('parser_definition', d('file')),
1838 ('cpp_endif', d('file')),
1839 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001840 ('impl_definition', d('block')),
1841 ))
1842
Larry Hastings0759f842015-04-03 13:09:02 -07001843 self.destination_buffers_stack = []
1844 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001845
1846 self.presets = {}
1847 preset = None
1848 for line in self.presets_text.strip().split('\n'):
1849 line = line.strip()
1850 if not line:
1851 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001852 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001853 if name == 'preset':
1854 self.presets[value] = preset = collections.OrderedDict()
1855 continue
1856
Larry Hastings0759f842015-04-03 13:09:02 -07001857 if len(options):
1858 index = int(options[0])
1859 else:
1860 index = 0
1861 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001862
1863 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001864 for name in self.destination_buffers:
1865 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001866 continue
1867
Larry Hastings0759f842015-04-03 13:09:02 -07001868 assert name in self.destination_buffers
1869 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001870
Larry Hastings31826802013-10-19 00:09:25 -07001871 global clinic
1872 clinic = self
1873
Larry Hastingsbebf7352014-01-17 17:47:17 -08001874 def add_destination(self, name, type, *args):
1875 if name in self.destinations:
1876 fail("Destination already exists: " + repr(name))
1877 self.destinations[name] = Destination(name, type, self, *args)
1878
Larry Hastings0759f842015-04-03 13:09:02 -07001879 def get_destination(self, name):
1880 d = self.destinations.get(name)
1881 if not d:
1882 fail("Destination does not exist: " + repr(name))
1883 return d
1884
1885 def get_destination_buffer(self, name, item=0):
1886 d = self.get_destination(name)
1887 return d.buffers[item]
1888
Larry Hastings31826802013-10-19 00:09:25 -07001889 def parse(self, input):
1890 printer = self.printer
1891 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1892 for block in self.block_parser:
1893 dsl_name = block.dsl_name
1894 if dsl_name:
1895 if dsl_name not in self.parsers:
1896 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1897 self.parsers[dsl_name] = parsers[dsl_name](self)
1898 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001899 try:
1900 parser.parse(block)
1901 except Exception:
1902 fail('Exception raised during parsing:\n' +
1903 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001904 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001905
1906 second_pass_replacements = {}
1907
Larry Hastings0759f842015-04-03 13:09:02 -07001908 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001909 for name, destination in self.destinations.items():
1910 if destination.type == 'suppress':
1911 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001912 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001913
1914 if output:
1915
1916 block = Block("", dsl_name="clinic", output=output)
1917
1918 if destination.type == 'buffer':
1919 block.input = "dump " + name + "\n"
1920 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1921 printer.write("\n")
1922 printer.print_block(block)
1923 continue
1924
1925 if destination.type == 'file':
1926 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001927 dirname = os.path.dirname(destination.filename)
1928 try:
1929 os.makedirs(dirname)
1930 except FileExistsError:
1931 if not os.path.isdir(dirname):
1932 fail("Can't write to destination {}, "
1933 "can't make directory {}!".format(
1934 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001935 if self.verify:
1936 with open(destination.filename, "rt") as f:
1937 parser_2 = BlockParser(f.read(), language=self.language)
1938 blocks = list(parser_2)
1939 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1940 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001941 except FileNotFoundError:
1942 pass
1943
1944 block.input = 'preserve\n'
1945 printer_2 = BlockPrinter(self.language)
1946 printer_2.print_block(block)
1947 with open(destination.filename, "wt") as f:
1948 f.write(printer_2.f.getvalue())
1949 continue
1950 text = printer.f.getvalue()
1951
1952 if second_pass_replacements:
1953 printer_2 = BlockPrinter(self.language)
1954 parser_2 = BlockParser(text, self.language)
1955 changed = False
1956 for block in parser_2:
1957 if block.dsl_name:
1958 for id, replacement in second_pass_replacements.items():
1959 if id in block.output:
1960 changed = True
1961 block.output = block.output.replace(id, replacement)
1962 printer_2.print_block(block)
1963 if changed:
1964 text = printer_2.f.getvalue()
1965
1966 return text
1967
Larry Hastings31826802013-10-19 00:09:25 -07001968
1969 def _module_and_class(self, fields):
1970 """
1971 fields should be an iterable of field names.
1972 returns a tuple of (module, class).
1973 the module object could actually be self (a clinic object).
1974 this function is only ever used to find the parent of where
1975 a new class/module should go.
1976 """
1977 in_classes = False
1978 parent = module = self
1979 cls = None
1980 so_far = []
1981
1982 for field in fields:
1983 so_far.append(field)
1984 if not in_classes:
1985 child = parent.modules.get(field)
1986 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001987 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001988 continue
1989 in_classes = True
1990 if not hasattr(parent, 'classes'):
1991 return module, cls
1992 child = parent.classes.get(field)
1993 if not child:
1994 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1995 cls = parent = child
1996
1997 return module, cls
1998
1999
Larry Hastings581ee362014-01-28 05:00:08 -08002000def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07002001 extension = os.path.splitext(filename)[1][1:]
2002 if not extension:
2003 fail("Can't extract file type for file " + repr(filename))
2004
2005 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08002006 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07002007 except KeyError:
2008 fail("Can't identify file type for file " + repr(filename))
2009
Larry Hastings31826802013-10-19 00:09:25 -07002010 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002011 raw = f.read()
2012
Larry Hastings2623c8c2014-02-08 22:15:29 -08002013 # exit quickly if there are no clinic markers in the file
2014 find_start_re = BlockParser("", language).find_start_re
2015 if not find_start_re.search(raw):
2016 return
2017
2018 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002019 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08002020 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002021 return
Larry Hastings31826802013-10-19 00:09:25 -07002022
2023 directory = os.path.dirname(filename) or '.'
2024
2025 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002026 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07002027 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
2028 with open(tmpfilename, "wb") as f:
2029 f.write(bytes)
2030 os.replace(tmpfilename, output or filename)
2031
2032
Larry Hastings581ee362014-01-28 05:00:08 -08002033def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07002034 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08002035 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
2036 if length:
2037 s = s[:length]
2038 return s
Larry Hastings31826802013-10-19 00:09:25 -07002039
2040
2041
2042
2043class PythonParser:
2044 def __init__(self, clinic):
2045 pass
2046
2047 def parse(self, block):
2048 s = io.StringIO()
2049 with OverrideStdioWith(s):
2050 exec(block.input)
2051 block.output = s.getvalue()
2052
2053
2054class Module:
2055 def __init__(self, name, module=None):
2056 self.name = name
2057 self.module = self.parent = module
2058
2059 self.modules = collections.OrderedDict()
2060 self.classes = collections.OrderedDict()
2061 self.functions = []
2062
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002063 def __repr__(self):
2064 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
2065
Larry Hastings31826802013-10-19 00:09:25 -07002066class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08002067 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07002068 self.name = name
2069 self.module = module
2070 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08002071 self.typedef = typedef
2072 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07002073 self.parent = cls or module
2074
2075 self.classes = collections.OrderedDict()
2076 self.functions = []
2077
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002078 def __repr__(self):
2079 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
2080
Larry Hastings8666e652014-01-12 14:12:59 -08002081unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002082
Larry Hastings8666e652014-01-12 14:12:59 -08002083__abs__
2084__add__
2085__and__
2086__bytes__
2087__call__
2088__complex__
2089__delitem__
2090__divmod__
2091__eq__
2092__float__
2093__floordiv__
2094__ge__
2095__getattr__
2096__getattribute__
2097__getitem__
2098__gt__
2099__hash__
2100__iadd__
2101__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002102__ifloordiv__
2103__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002104__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002105__imod__
2106__imul__
2107__index__
2108__int__
2109__invert__
2110__ior__
2111__ipow__
2112__irshift__
2113__isub__
2114__iter__
2115__itruediv__
2116__ixor__
2117__le__
2118__len__
2119__lshift__
2120__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002121__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002122__mod__
2123__mul__
2124__neg__
2125__new__
2126__next__
2127__or__
2128__pos__
2129__pow__
2130__radd__
2131__rand__
2132__rdivmod__
2133__repr__
2134__rfloordiv__
2135__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002136__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002137__rmod__
2138__rmul__
2139__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002140__rpow__
2141__rrshift__
2142__rshift__
2143__rsub__
2144__rtruediv__
2145__rxor__
2146__setattr__
2147__setitem__
2148__str__
2149__sub__
2150__truediv__
2151__xor__
2152
2153""".strip().split())
2154
2155
Larry Hastings5c661892014-01-24 06:17:25 -08002156INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2157INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2158""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002159
2160class Function:
2161 """
2162 Mutable duck type for inspect.Function.
2163
2164 docstring - a str containing
2165 * embedded line breaks
2166 * text outdented to the left margin
2167 * no trailing whitespace.
2168 It will always be true that
2169 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2170 """
2171
2172 def __init__(self, parameters=None, *, name,
2173 module, cls=None, c_basename=None,
2174 full_name=None,
2175 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002176 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002177 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002178 self.parameters = parameters or collections.OrderedDict()
2179 self.return_annotation = return_annotation
2180 self.name = name
2181 self.full_name = full_name
2182 self.module = module
2183 self.cls = cls
2184 self.parent = cls or module
2185 self.c_basename = c_basename
2186 self.return_converter = return_converter
2187 self.docstring = docstring or ''
2188 self.kind = kind
2189 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002190 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002191 # docstring_only means "don't generate a machine-readable
2192 # signature, just a normal docstring". it's True for
2193 # functions with optional groups because we can't represent
2194 # those accurately with inspect.Signature in 3.4.
2195 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002196
Larry Hastings7726ac92014-01-31 22:03:12 -08002197 self.rendered_parameters = None
2198
2199 __render_parameters__ = None
2200 @property
2201 def render_parameters(self):
2202 if not self.__render_parameters__:
2203 self.__render_parameters__ = l = []
2204 for p in self.parameters.values():
2205 p = p.copy()
2206 p.converter.pre_render()
2207 l.append(p)
2208 return self.__render_parameters__
2209
Larry Hastingsebdcb502013-11-23 14:54:00 -08002210 @property
2211 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002212 if self.kind in (METHOD_INIT, METHOD_NEW):
2213 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002214 flags = []
2215 if self.kind == CLASS_METHOD:
2216 flags.append('METH_CLASS')
2217 elif self.kind == STATIC_METHOD:
2218 flags.append('METH_STATIC')
2219 else:
2220 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2221 if self.coexist:
2222 flags.append('METH_COEXIST')
2223 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002224
2225 def __repr__(self):
2226 return '<clinic.Function ' + self.name + '>'
2227
Larry Hastings7726ac92014-01-31 22:03:12 -08002228 def copy(self, **overrides):
2229 kwargs = {
2230 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2231 'cls': self.cls, 'c_basename': self.c_basename,
2232 'full_name': self.full_name,
2233 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2234 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002235 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002236 }
2237 kwargs.update(overrides)
2238 f = Function(**kwargs)
2239
2240 parameters = collections.OrderedDict()
2241 for name, value in f.parameters.items():
2242 value = value.copy(function=f)
2243 parameters[name] = value
2244 f.parameters = parameters
2245 return f
2246
Larry Hastings31826802013-10-19 00:09:25 -07002247
2248class Parameter:
2249 """
2250 Mutable duck type of inspect.Parameter.
2251 """
2252
2253 def __init__(self, name, kind, *, default=_empty,
2254 function, converter, annotation=_empty,
2255 docstring=None, group=0):
2256 self.name = name
2257 self.kind = kind
2258 self.default = default
2259 self.function = function
2260 self.converter = converter
2261 self.annotation = annotation
2262 self.docstring = docstring or ''
2263 self.group = group
2264
2265 def __repr__(self):
2266 return '<clinic.Parameter ' + self.name + '>'
2267
2268 def is_keyword_only(self):
2269 return self.kind == inspect.Parameter.KEYWORD_ONLY
2270
Larry Hastings2623c8c2014-02-08 22:15:29 -08002271 def is_positional_only(self):
2272 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2273
Serhiy Storchaka31913912019-03-14 10:32:22 +02002274 def is_optional(self):
2275 return (self.default is not unspecified)
2276
Larry Hastings7726ac92014-01-31 22:03:12 -08002277 def copy(self, **overrides):
2278 kwargs = {
2279 'name': self.name, 'kind': self.kind, 'default':self.default,
2280 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2281 'docstring': self.docstring, 'group': self.group,
2282 }
2283 kwargs.update(overrides)
2284 if 'converter' not in overrides:
2285 converter = copy.copy(self.converter)
2286 converter.function = kwargs['function']
2287 kwargs['converter'] = converter
2288 return Parameter(**kwargs)
2289
2290
2291
2292class LandMine:
2293 # try to access any
2294 def __init__(self, message):
2295 self.__message__ = message
2296
2297 def __repr__(self):
2298 return '<LandMine ' + repr(self.__message__) + ">"
2299
2300 def __getattribute__(self, name):
2301 if name in ('__repr__', '__message__'):
2302 return super().__getattribute__(name)
2303 # raise RuntimeError(repr(name))
2304 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002305
Larry Hastings31826802013-10-19 00:09:25 -07002306
2307def add_c_converter(f, name=None):
2308 if not name:
2309 name = f.__name__
2310 if not name.endswith('_converter'):
2311 return f
2312 name = name[:-len('_converter')]
2313 converters[name] = f
2314 return f
2315
2316def add_default_legacy_c_converter(cls):
2317 # automatically add converter for default format unit
2318 # (but without stomping on the existing one if it's already
2319 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002320 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002321 (cls.format_unit not in legacy_converters)):
2322 legacy_converters[cls.format_unit] = cls
2323 return cls
2324
2325def add_legacy_c_converter(format_unit, **kwargs):
2326 """
2327 Adds a legacy converter.
2328 """
2329 def closure(f):
2330 if not kwargs:
2331 added_f = f
2332 else:
2333 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002334 if format_unit:
2335 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002336 return f
2337 return closure
2338
2339class CConverterAutoRegister(type):
2340 def __init__(cls, name, bases, classdict):
2341 add_c_converter(cls)
2342 add_default_legacy_c_converter(cls)
2343
2344class CConverter(metaclass=CConverterAutoRegister):
2345 """
2346 For the init function, self, name, function, and default
2347 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002348 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002349 """
2350
Larry Hastings7726ac92014-01-31 22:03:12 -08002351 # The C name to use for this variable.
2352 name = None
2353
2354 # The Python name to use for this variable.
2355 py_name = None
2356
Larry Hastings78cf85c2014-01-04 12:44:57 -08002357 # The C type to use for this variable.
2358 # 'type' should be a Python string specifying the type, e.g. "int".
2359 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002360 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002361
2362 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002363 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002364 # Or the magic value "unknown" if this value is a cannot be evaluated
2365 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2366 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002367 default = unspecified
2368
Larry Hastings4a55fc52014-01-12 11:09:57 -08002369 # If not None, default must be isinstance() of this type.
2370 # (You can also specify a tuple of types.)
2371 default_type = None
2372
Larry Hastings31826802013-10-19 00:09:25 -07002373 # "default" converted into a C value, as a string.
2374 # Or None if there is no default.
2375 c_default = None
2376
Larry Hastings2a727912014-01-16 11:32:01 -08002377 # "default" converted into a Python value, as a string.
2378 # Or None if there is no default.
2379 py_default = None
2380
Larry Hastingsabc716b2013-11-20 09:13:52 -08002381 # The default value used to initialize the C variable when
2382 # there is no default, but not specifying a default may
2383 # result in an "uninitialized variable" warning. This can
2384 # easily happen when using option groups--although
2385 # properly-written code won't actually use the variable,
2386 # the variable does get passed in to the _impl. (Ah, if
2387 # only dataflow analysis could inline the static function!)
2388 #
2389 # This value is specified as a string.
2390 # Every non-abstract subclass should supply a valid value.
2391 c_ignored_default = 'NULL'
2392
Larry Hastings31826802013-10-19 00:09:25 -07002393 # The C converter *function* to be used, if any.
2394 # (If this is not None, format_unit must be 'O&'.)
2395 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002396
Larry Hastings78cf85c2014-01-04 12:44:57 -08002397 # Should Argument Clinic add a '&' before the name of
2398 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002399 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002400
2401 # Should Argument Clinic add a '&' before the name of
2402 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002403 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002404
2405 #############################################################
2406 #############################################################
2407 ## You shouldn't need to read anything below this point to ##
2408 ## write your own converter functions. ##
2409 #############################################################
2410 #############################################################
2411
2412 # The "format unit" to specify for this variable when
2413 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2414 # Custom converters should always use the default value of 'O&'.
2415 format_unit = 'O&'
2416
2417 # What encoding do we want for this variable? Only used
2418 # by format units starting with 'e'.
2419 encoding = None
2420
Larry Hastings77561cc2014-01-07 12:13:13 -08002421 # Should this object be required to be a subclass of a specific type?
2422 # If not None, should be a string representing a pointer to a
2423 # PyTypeObject (e.g. "&PyUnicode_Type").
2424 # Only used by the 'O!' format unit (and the "object" converter).
2425 subclass_of = None
2426
Larry Hastings78cf85c2014-01-04 12:44:57 -08002427 # Do we want an adjacent '_length' variable for this variable?
2428 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002429 length = False
2430
Larry Hastings5c661892014-01-24 06:17:25 -08002431 # Should we show this parameter in the generated
2432 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002433 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002434 show_in_signature = True
2435
2436 # Overrides the name used in a text signature.
2437 # The name used for a "self" parameter must be one of
2438 # self, type, or module; however users can set their own.
2439 # This lets the self_converter overrule the user-settable
2440 # name, *just* for the text signature.
2441 # Only set by self_converter.
2442 signature_name = None
2443
2444 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002445 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 +02002446 self.name = ensure_legal_c_identifier(name)
Larry Hastings7726ac92014-01-31 22:03:12 -08002447 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002448
2449 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002450 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002451 if isinstance(self.default_type, type):
2452 types_str = self.default_type.__name__
2453 else:
2454 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2455 fail("{}: default value {!r} for field {} is not of type {}".format(
2456 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002457 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002458
Larry Hastingsb4705752014-01-18 21:54:15 -08002459 if c_default:
2460 self.c_default = c_default
2461 if py_default:
2462 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002463
Larry Hastings31826802013-10-19 00:09:25 -07002464 if annotation != unspecified:
2465 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002466
2467 # this is deliberate, to prevent you from caching information
2468 # about the function in the init.
2469 # (that breaks if we get cloned.)
2470 # so after this change we will noisily fail.
2471 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002472 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002473 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002474
2475 def converter_init(self):
2476 pass
2477
2478 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002479 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002480
Larry Hastings5c661892014-01-24 06:17:25 -08002481 def _render_self(self, parameter, data):
2482 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002483 name = self.name
Larry Hastings5c661892014-01-24 06:17:25 -08002484
2485 # impl_arguments
2486 s = ("&" if self.impl_by_reference else "") + name
2487 data.impl_arguments.append(s)
2488 if self.length:
2489 data.impl_arguments.append(self.length_name())
2490
2491 # impl_parameters
2492 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2493 if self.length:
2494 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2495
2496 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002497 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002498 name = self.name
Larry Hastings31826802013-10-19 00:09:25 -07002499
2500 # declarations
2501 d = self.declaration()
2502 data.declarations.append(d)
2503
2504 # initializers
2505 initializers = self.initialize()
2506 if initializers:
2507 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2508
Larry Hastingsc2047262014-01-25 20:43:29 -08002509 # modifications
2510 modifications = self.modify()
2511 if modifications:
2512 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2513
Larry Hastings31826802013-10-19 00:09:25 -07002514 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002515 if parameter.is_positional_only():
2516 data.keywords.append('')
2517 else:
2518 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002519
2520 # format_units
2521 if self.is_optional() and '|' not in data.format_units:
2522 data.format_units.append('|')
2523 if parameter.is_keyword_only() and '$' not in data.format_units:
2524 data.format_units.append('$')
2525 data.format_units.append(self.format_unit)
2526
2527 # parse_arguments
2528 self.parse_argument(data.parse_arguments)
2529
Larry Hastings31826802013-10-19 00:09:25 -07002530 # cleanup
2531 cleanup = self.cleanup()
2532 if cleanup:
2533 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2534
Larry Hastings5c661892014-01-24 06:17:25 -08002535 def render(self, parameter, data):
2536 """
2537 parameter is a clinic.Parameter instance.
2538 data is a CRenderData instance.
2539 """
2540 self._render_self(parameter, data)
2541 self._render_non_self(parameter, data)
2542
Larry Hastingsebdcb502013-11-23 14:54:00 -08002543 def length_name(self):
2544 """Computes the name of the associated "length" variable."""
2545 if not self.length:
2546 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002547 return self.name + "_length"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002548
Larry Hastings31826802013-10-19 00:09:25 -07002549 # Why is this one broken out separately?
2550 # For "positional-only" function parsing,
2551 # which generates a bunch of PyArg_ParseTuple calls.
2552 def parse_argument(self, list):
2553 assert not (self.converter and self.encoding)
2554 if self.format_unit == 'O&':
2555 assert self.converter
2556 list.append(self.converter)
2557
2558 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002559 list.append(c_repr(self.encoding))
2560 elif self.subclass_of:
2561 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002562
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002563 s = ("&" if self.parse_by_reference else "") + self.name
Larry Hastings31826802013-10-19 00:09:25 -07002564 list.append(s)
2565
Larry Hastingsebdcb502013-11-23 14:54:00 -08002566 if self.length:
2567 list.append("&" + self.length_name())
2568
Larry Hastings31826802013-10-19 00:09:25 -07002569 #
2570 # All the functions after here are intended as extension points.
2571 #
2572
2573 def simple_declaration(self, by_reference=False):
2574 """
2575 Computes the basic declaration of the variable.
2576 Used in computing the prototype declaration and the
2577 variable declaration.
2578 """
2579 prototype = [self.type]
2580 if by_reference or not self.type.endswith('*'):
2581 prototype.append(" ")
2582 if by_reference:
2583 prototype.append('*')
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002584 prototype.append(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07002585 return "".join(prototype)
2586
2587 def declaration(self):
2588 """
2589 The C statement to declare this variable.
2590 """
2591 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002592 default = self.c_default
2593 if not default and self.parameter.group:
2594 default = self.c_ignored_default
2595 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002596 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002597 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002598 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002599 if self.length:
2600 declaration.append('\nPy_ssize_clean_t ')
2601 declaration.append(self.length_name())
2602 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002603 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002604
2605 def initialize(self):
2606 """
2607 The C statements required to set up this variable before parsing.
2608 Returns a string containing this code indented at column 0.
2609 If no initialization is necessary, returns an empty string.
2610 """
2611 return ""
2612
Larry Hastingsc2047262014-01-25 20:43:29 -08002613 def modify(self):
2614 """
2615 The C statements required to modify this variable after parsing.
2616 Returns a string containing this code indented at column 0.
2617 If no initialization is necessary, returns an empty string.
2618 """
2619 return ""
2620
Larry Hastings31826802013-10-19 00:09:25 -07002621 def cleanup(self):
2622 """
2623 The C statements required to clean up after this variable.
2624 Returns a string containing this code indented at column 0.
2625 If no cleanup is necessary, returns an empty string.
2626 """
2627 return ""
2628
Larry Hastings7726ac92014-01-31 22:03:12 -08002629 def pre_render(self):
2630 """
2631 A second initialization function, like converter_init,
2632 called just before rendering.
2633 You are permitted to examine self.function here.
2634 """
2635 pass
2636
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002637 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002638 if self.format_unit == 'O&':
2639 return """
2640 if (!{converter}({argname}, &{paramname})) {{{{
2641 goto exit;
2642 }}}}
2643 """.format(argname=argname, paramname=self.name,
2644 converter=self.converter)
2645 if self.format_unit == 'O!':
2646 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2647 if self.subclass_of in type_checks:
2648 typecheck, typename = type_checks[self.subclass_of]
2649 return """
2650 if (!{typecheck}({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002651 _PyArg_BadArgument("{{name}}", {argnum}, "{typename}", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002652 goto exit;
2653 }}}}
2654 {paramname} = {cast}{argname};
2655 """.format(argname=argname, paramname=self.name,
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002656 argnum=argnum,
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002657 typecheck=typecheck, typename=typename, cast=cast)
2658 return """
2659 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002660 _PyArg_BadArgument("{{name}}", {argnum}, ({subclass_of})->tp_name, {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002661 goto exit;
2662 }}}}
2663 {paramname} = {cast}{argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002664 """.format(argname=argname, paramname=self.name, argnum=argnum,
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002665 subclass_of=self.subclass_of, cast=cast)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002666 if self.format_unit == 'O':
2667 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2668 return """
2669 {paramname} = {cast}{argname};
2670 """.format(argname=argname, paramname=self.name, cast=cast)
2671 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002672
2673type_checks = {
2674 '&PyLong_Type': ('PyLong_Check', 'int'),
2675 '&PyTuple_Type': ('PyTuple_Check', 'tuple'),
2676 '&PyList_Type': ('PyList_Check', 'list'),
2677 '&PySet_Type': ('PySet_Check', 'set'),
2678 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'),
2679 '&PyDict_Type': ('PyDict_Check', 'dict'),
2680 '&PyUnicode_Type': ('PyUnicode_Check', 'str'),
2681 '&PyBytes_Type': ('PyBytes_Check', 'bytes'),
2682 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'),
2683}
2684
Larry Hastings31826802013-10-19 00:09:25 -07002685
2686class bool_converter(CConverter):
2687 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002688 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002689 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002690 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002691
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002692 def converter_init(self, *, accept={object}):
2693 if accept == {int}:
2694 self.format_unit = 'i'
2695 elif accept != {object}:
2696 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002697 if self.default is not unspecified:
2698 self.default = bool(self.default)
2699 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002700
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002701 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002702 if self.format_unit == 'i':
Serhiy Storchaka6a44f6e2019-02-25 17:57:58 +02002703 # XXX PyFloat_Check can be removed after the end of the
2704 # deprecation in _PyLong_FromNbIndexOrNbInt.
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002705 return """
2706 if (PyFloat_Check({argname})) {{{{
2707 PyErr_SetString(PyExc_TypeError,
2708 "integer argument expected, got float" );
2709 goto exit;
2710 }}}}
2711 {paramname} = _PyLong_AsInt({argname});
2712 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2713 goto exit;
2714 }}}}
2715 """.format(argname=argname, paramname=self.name)
2716 elif self.format_unit == 'p':
2717 return """
2718 {paramname} = PyObject_IsTrue({argname});
2719 if ({paramname} < 0) {{{{
2720 goto exit;
2721 }}}}
2722 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002723 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002724
Larry Hastings31826802013-10-19 00:09:25 -07002725class char_converter(CConverter):
2726 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002727 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002728 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002729 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002730
Larry Hastings4a55fc52014-01-12 11:09:57 -08002731 def converter_init(self):
Tal Einatc929df32018-07-06 13:17:38 +03002732 if isinstance(self.default, self.default_type):
2733 if len(self.default) != 1:
2734 fail("char_converter: illegal default value " + repr(self.default))
2735
Serhiy Storchaka65ce60a2018-12-25 11:10:05 +02002736 self.c_default = repr(bytes(self.default))[1:]
2737 if self.c_default == '"\'"':
2738 self.c_default = r"'\''"
Larry Hastings4a55fc52014-01-12 11:09:57 -08002739
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002740 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002741 if self.format_unit == 'c':
2742 return """
2743 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
2744 {paramname} = PyBytes_AS_STRING({argname})[0];
2745 }}}}
2746 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{
2747 {paramname} = PyByteArray_AS_STRING({argname})[0];
2748 }}}}
2749 else {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002750 _PyArg_BadArgument("{{name}}", {argnum}, "a byte string of length 1", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002751 goto exit;
2752 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002753 """.format(argname=argname, paramname=self.name, argnum=argnum)
2754 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002755
Larry Hastings4a55fc52014-01-12 11:09:57 -08002756
Larry Hastings31826802013-10-19 00:09:25 -07002757@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002758class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002759 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002760 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002761 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002762 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002763
2764 def converter_init(self, *, bitwise=False):
2765 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002766 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002767
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002768 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002769 if self.format_unit == 'b':
2770 return """
2771 if (PyFloat_Check({argname})) {{{{
2772 PyErr_SetString(PyExc_TypeError,
2773 "integer argument expected, got float" );
2774 goto exit;
2775 }}}}
2776 {{{{
2777 long ival = PyLong_AsLong({argname});
2778 if (ival == -1 && PyErr_Occurred()) {{{{
2779 goto exit;
2780 }}}}
2781 else if (ival < 0) {{{{
2782 PyErr_SetString(PyExc_OverflowError,
2783 "unsigned byte integer is less than minimum");
2784 goto exit;
2785 }}}}
2786 else if (ival > UCHAR_MAX) {{{{
2787 PyErr_SetString(PyExc_OverflowError,
2788 "unsigned byte integer is greater than maximum");
2789 goto exit;
2790 }}}}
2791 else {{{{
2792 {paramname} = (unsigned char) ival;
2793 }}}}
2794 }}}}
2795 """.format(argname=argname, paramname=self.name)
2796 elif self.format_unit == 'B':
2797 return """
2798 if (PyFloat_Check({argname})) {{{{
2799 PyErr_SetString(PyExc_TypeError,
2800 "integer argument expected, got float" );
2801 goto exit;
2802 }}}}
2803 {{{{
2804 long ival = PyLong_AsUnsignedLongMask({argname});
2805 if (ival == -1 && PyErr_Occurred()) {{{{
2806 goto exit;
2807 }}}}
2808 else {{{{
2809 {paramname} = (unsigned char) ival;
2810 }}}}
2811 }}}}
2812 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002813 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002814
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002815class byte_converter(unsigned_char_converter): pass
2816
Larry Hastings31826802013-10-19 00:09:25 -07002817class short_converter(CConverter):
2818 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002819 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002820 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002821 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002822
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002823 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002824 if self.format_unit == 'h':
2825 return """
2826 if (PyFloat_Check({argname})) {{{{
2827 PyErr_SetString(PyExc_TypeError,
2828 "integer argument expected, got float" );
2829 goto exit;
2830 }}}}
2831 {{{{
2832 long ival = PyLong_AsLong({argname});
2833 if (ival == -1 && PyErr_Occurred()) {{{{
2834 goto exit;
2835 }}}}
2836 else if (ival < SHRT_MIN) {{{{
2837 PyErr_SetString(PyExc_OverflowError,
2838 "signed short integer is less than minimum");
2839 goto exit;
2840 }}}}
2841 else if (ival > SHRT_MAX) {{{{
2842 PyErr_SetString(PyExc_OverflowError,
2843 "signed short integer is greater than maximum");
2844 goto exit;
2845 }}}}
2846 else {{{{
2847 {paramname} = (short) ival;
2848 }}}}
2849 }}}}
2850 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002851 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002852
Larry Hastings31826802013-10-19 00:09:25 -07002853class unsigned_short_converter(CConverter):
2854 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002855 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002856 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002857
2858 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002859 if bitwise:
2860 self.format_unit = 'H'
2861 else:
2862 self.converter = '_PyLong_UnsignedShort_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002863
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002864 def parse_arg(self, argname, argnum):
2865 if self.format_unit == 'H':
2866 return """
2867 if (PyFloat_Check({argname})) {{{{
2868 PyErr_SetString(PyExc_TypeError,
2869 "integer argument expected, got float" );
2870 goto exit;
2871 }}}}
2872 {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname});
2873 if ({paramname} == (unsigned short)-1 && PyErr_Occurred()) {{{{
2874 goto exit;
2875 }}}}
2876 """.format(argname=argname, paramname=self.name)
2877 return super().parse_arg(argname, argnum)
2878
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002879@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002880class int_converter(CConverter):
2881 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002882 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002883 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002884 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002885
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002886 def converter_init(self, *, accept={int}, type=None):
2887 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002888 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002889 elif accept != {int}:
2890 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002891 if type != None:
2892 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002893
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002894 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002895 if self.format_unit == 'i':
2896 return """
2897 if (PyFloat_Check({argname})) {{{{
2898 PyErr_SetString(PyExc_TypeError,
2899 "integer argument expected, got float" );
2900 goto exit;
2901 }}}}
2902 {paramname} = _PyLong_AsInt({argname});
2903 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2904 goto exit;
2905 }}}}
2906 """.format(argname=argname, paramname=self.name)
2907 elif self.format_unit == 'C':
2908 return """
2909 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002910 _PyArg_BadArgument("{{name}}", {argnum}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002911 goto exit;
2912 }}}}
2913 if (PyUnicode_READY({argname})) {{{{
2914 goto exit;
2915 }}}}
2916 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002917 _PyArg_BadArgument("{{name}}", {argnum}, "a unicode character", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002918 goto exit;
2919 }}}}
2920 {paramname} = PyUnicode_READ_CHAR({argname}, 0);
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002921 """.format(argname=argname, paramname=self.name, argnum=argnum)
2922 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002923
Larry Hastings31826802013-10-19 00:09:25 -07002924class unsigned_int_converter(CConverter):
2925 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002926 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002927 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002928
2929 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002930 if bitwise:
2931 self.format_unit = 'I'
2932 else:
2933 self.converter = '_PyLong_UnsignedInt_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002934
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002935 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002936 if self.format_unit == 'I':
2937 return """
2938 if (PyFloat_Check({argname})) {{{{
2939 PyErr_SetString(PyExc_TypeError,
2940 "integer argument expected, got float" );
2941 goto exit;
2942 }}}}
2943 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
2944 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{
2945 goto exit;
2946 }}}}
2947 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002948 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002949
Larry Hastings31826802013-10-19 00:09:25 -07002950class long_converter(CConverter):
2951 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002952 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002953 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002954 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002955
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002956 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002957 if self.format_unit == 'l':
2958 return """
2959 if (PyFloat_Check({argname})) {{{{
2960 PyErr_SetString(PyExc_TypeError,
2961 "integer argument expected, got float" );
2962 goto exit;
2963 }}}}
2964 {paramname} = PyLong_AsLong({argname});
2965 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2966 goto exit;
2967 }}}}
2968 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002969 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002970
Larry Hastings31826802013-10-19 00:09:25 -07002971class unsigned_long_converter(CConverter):
2972 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002973 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002974 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002975
2976 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002977 if bitwise:
2978 self.format_unit = 'k'
2979 else:
2980 self.converter = '_PyLong_UnsignedLong_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002981
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002982 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002983 if self.format_unit == 'k':
2984 return """
2985 if (!PyLong_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002986 _PyArg_BadArgument("{{name}}", {argnum}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002987 goto exit;
2988 }}}}
2989 {paramname} = PyLong_AsUnsignedLongMask({argname});
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002990 """.format(argname=argname, paramname=self.name, argnum=argnum)
2991 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002992
Benjamin Petersoncc854492016-09-08 09:29:11 -07002993class long_long_converter(CConverter):
2994 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002995 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002996 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002997 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002998
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02002999 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003000 if self.format_unit == 'L':
3001 return """
3002 if (PyFloat_Check({argname})) {{{{
3003 PyErr_SetString(PyExc_TypeError,
3004 "integer argument expected, got float" );
3005 goto exit;
3006 }}}}
3007 {paramname} = PyLong_AsLongLong({argname});
3008 if ({paramname} == (PY_LONG_LONG)-1 && PyErr_Occurred()) {{{{
3009 goto exit;
3010 }}}}
3011 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003012 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003013
Benjamin Petersoncc854492016-09-08 09:29:11 -07003014class unsigned_long_long_converter(CConverter):
3015 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003016 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08003017 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003018
3019 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03003020 if bitwise:
3021 self.format_unit = 'K'
3022 else:
3023 self.converter = '_PyLong_UnsignedLongLong_Converter'
Serhiy Storchaka762bf402017-03-30 09:15:31 +03003024
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003025 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003026 if self.format_unit == 'K':
3027 return """
3028 if (!PyLong_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003029 _PyArg_BadArgument("{{name}}", {argnum}, "int", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003030 goto exit;
3031 }}}}
3032 {paramname} = PyLong_AsUnsignedLongLongMask({argname});
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003033 """.format(argname=argname, paramname=self.name, argnum=argnum)
3034 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003035
Larry Hastings31826802013-10-19 00:09:25 -07003036class Py_ssize_t_converter(CConverter):
3037 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003038 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07003039
Serhiy Storchaka762bf402017-03-30 09:15:31 +03003040 def converter_init(self, *, accept={int}):
3041 if accept == {int}:
3042 self.format_unit = 'n'
3043 self.default_type = int
3044 elif accept == {int, NoneType}:
3045 self.converter = '_Py_convert_optional_to_ssize_t'
3046 else:
3047 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
3048
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003049 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003050 if self.format_unit == 'n':
3051 return """
3052 if (PyFloat_Check({argname})) {{{{
3053 PyErr_SetString(PyExc_TypeError,
3054 "integer argument expected, got float" );
3055 goto exit;
3056 }}}}
3057 {{{{
3058 Py_ssize_t ival = -1;
3059 PyObject *iobj = PyNumber_Index({argname});
3060 if (iobj != NULL) {{{{
3061 ival = PyLong_AsSsize_t(iobj);
3062 Py_DECREF(iobj);
3063 }}}}
3064 if (ival == -1 && PyErr_Occurred()) {{{{
3065 goto exit;
3066 }}}}
3067 {paramname} = ival;
3068 }}}}
3069 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003070 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003071
Larry Hastings31826802013-10-19 00:09:25 -07003072
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003073class slice_index_converter(CConverter):
3074 type = 'Py_ssize_t'
3075
3076 def converter_init(self, *, accept={int, NoneType}):
3077 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03003078 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003079 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03003080 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003081 else:
3082 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
3083
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03003084class size_t_converter(CConverter):
3085 type = 'size_t'
3086 converter = '_PyLong_Size_t_Converter'
3087 c_ignored_default = "0"
3088
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003089 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003090 if self.format_unit == 'n':
3091 return """
3092 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
3093 if ({paramname} == -1 && PyErr_Occurred()) {{{{
3094 goto exit;
3095 }}}}
3096 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003097 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003098
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02003099
Larry Hastings31826802013-10-19 00:09:25 -07003100class float_converter(CConverter):
3101 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003102 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003103 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003104 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003105
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003106 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003107 if self.format_unit == 'f':
3108 return """
Raymond Hettingeraef9ad82019-08-24 19:10:39 -07003109 if (PyFloat_CheckExact({argname})) {{{{
3110 {paramname} = (float) (PyFloat_AS_DOUBLE({argname}));
3111 }}}}
3112 else
3113 {{{{
3114 {paramname} = (float) PyFloat_AsDouble({argname});
3115 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{
3116 goto exit;
3117 }}}}
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003118 }}}}
3119 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003120 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003121
Larry Hastings31826802013-10-19 00:09:25 -07003122class double_converter(CConverter):
3123 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003124 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003125 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003126 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003127
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003128 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003129 if self.format_unit == 'd':
3130 return """
Raymond Hettingeraef9ad82019-08-24 19:10:39 -07003131 if (PyFloat_CheckExact({argname})) {{{{
3132 {paramname} = PyFloat_AS_DOUBLE({argname});
3133 }}}}
3134 else
3135 {{{{
3136 {paramname} = PyFloat_AsDouble({argname});
3137 if ({paramname} == -1.0 && PyErr_Occurred()) {{{{
3138 goto exit;
3139 }}}}
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003140 }}}}
3141 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003142 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003143
Larry Hastings31826802013-10-19 00:09:25 -07003144
3145class Py_complex_converter(CConverter):
3146 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003147 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07003148 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003149 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07003150
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003151 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003152 if self.format_unit == 'D':
3153 return """
3154 {paramname} = PyComplex_AsCComplex({argname});
3155 if (PyErr_Occurred()) {{{{
3156 goto exit;
3157 }}}}
3158 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003159 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003160
Larry Hastings31826802013-10-19 00:09:25 -07003161
3162class object_converter(CConverter):
3163 type = 'PyObject *'
3164 format_unit = 'O'
3165
Larry Hastings4a55fc52014-01-12 11:09:57 -08003166 def converter_init(self, *, converter=None, type=None, subclass_of=None):
3167 if converter:
3168 if subclass_of:
3169 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
3170 self.format_unit = 'O&'
3171 self.converter = converter
3172 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07003173 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08003174 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08003175
Larry Hastings77561cc2014-01-07 12:13:13 -08003176 if type is not None:
3177 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07003178
3179
Larry Hastings7f90cba2015-04-15 23:02:12 -04003180#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003181# We define three conventions for buffer types in the 'accept' argument:
3182#
3183# buffer : any object supporting the buffer interface
3184# rwbuffer: any object supporting the buffer interface, but must be writeable
3185# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04003186#
3187
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003188class buffer: pass
3189class rwbuffer: pass
3190class robuffer: pass
3191
Larry Hastings38337d12015-05-07 23:30:09 -07003192def str_converter_key(types, encoding, zeroes):
3193 return (frozenset(types), bool(encoding), bool(zeroes))
3194
3195str_converter_argument_map = {}
3196
Larry Hastings31826802013-10-19 00:09:25 -07003197class str_converter(CConverter):
3198 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003199 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003200 format_unit = 's'
3201
Larry Hastings38337d12015-05-07 23:30:09 -07003202 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003203
Larry Hastings38337d12015-05-07 23:30:09 -07003204 key = str_converter_key(accept, encoding, zeroes)
3205 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003206 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07003207 fail("str_converter: illegal combination of arguments", key)
3208
Larry Hastingsebdcb502013-11-23 14:54:00 -08003209 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07003210 self.length = bool(zeroes)
3211 if encoding:
3212 if self.default not in (Null, None, unspecified):
3213 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
3214 self.encoding = encoding
3215 self.type = 'char *'
3216 # sorry, clinic can't support preallocated buffers
3217 # for es# and et#
3218 self.c_default = "NULL"
3219
3220 def cleanup(self):
3221 if self.encoding:
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003222 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003223 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07003224
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003225 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003226 if self.format_unit == 's':
3227 return """
3228 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003229 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003230 goto exit;
3231 }}}}
3232 Py_ssize_t {paramname}_length;
3233 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3234 if ({paramname} == NULL) {{{{
3235 goto exit;
3236 }}}}
3237 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3238 PyErr_SetString(PyExc_ValueError, "embedded null character");
3239 goto exit;
3240 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003241 """.format(argname=argname, paramname=self.name, argnum=argnum)
3242 if self.format_unit == 'z':
3243 return """
3244 if ({argname} == Py_None) {{{{
3245 {paramname} = NULL;
3246 }}}}
3247 else if (PyUnicode_Check({argname})) {{{{
3248 Py_ssize_t {paramname}_length;
3249 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3250 if ({paramname} == NULL) {{{{
3251 goto exit;
3252 }}}}
3253 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3254 PyErr_SetString(PyExc_ValueError, "embedded null character");
3255 goto exit;
3256 }}}}
3257 }}}}
3258 else {{{{
3259 _PyArg_BadArgument("{{name}}", {argnum}, "str or None", {argname});
3260 goto exit;
3261 }}}}
3262 """.format(argname=argname, paramname=self.name, argnum=argnum)
3263 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003264
Larry Hastings38337d12015-05-07 23:30:09 -07003265#
3266# This is the fourth or fifth rewrite of registering all the
Raymond Hettinger14010182018-09-13 21:17:40 -07003267# string converter format units. Previous approaches hid
Larry Hastings38337d12015-05-07 23:30:09 -07003268# bugs--generally mismatches between the semantics of the format
3269# unit and the arguments necessary to represent those semantics
3270# properly. Hopefully with this approach we'll get it 100% right.
3271#
3272# The r() function (short for "register") both registers the
3273# mapping from arguments to format unit *and* registers the
3274# legacy C converter for that format unit.
3275#
3276def r(format_unit, *, accept, encoding=False, zeroes=False):
3277 if not encoding and format_unit != 's':
3278 # add the legacy c converters here too.
3279 #
3280 # note: add_legacy_c_converter can't work for
3281 # es, es#, et, or et#
3282 # because of their extra encoding argument
3283 #
3284 # also don't add the converter for 's' because
3285 # the metaclass for CConverter adds it for us.
3286 kwargs = {}
3287 if accept != {str}:
3288 kwargs['accept'] = accept
3289 if zeroes:
3290 kwargs['zeroes'] = True
3291 added_f = functools.partial(str_converter, **kwargs)
3292 legacy_converters[format_unit] = added_f
3293
3294 d = str_converter_argument_map
3295 key = str_converter_key(accept, encoding, zeroes)
3296 if key in d:
3297 sys.exit("Duplicate keys specified for str_converter_argument_map!")
3298 d[key] = format_unit
3299
3300r('es', encoding=True, accept={str})
3301r('es#', encoding=True, zeroes=True, accept={str})
3302r('et', encoding=True, accept={bytes, bytearray, str})
3303r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
3304r('s', accept={str})
3305r('s#', zeroes=True, accept={robuffer, str})
3306r('y', accept={robuffer})
3307r('y#', zeroes=True, accept={robuffer})
3308r('z', accept={str, NoneType})
3309r('z#', zeroes=True, accept={robuffer, str, NoneType})
3310del r
Larry Hastings31826802013-10-19 00:09:25 -07003311
3312
3313class PyBytesObject_converter(CConverter):
3314 type = 'PyBytesObject *'
3315 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003316 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07003317
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003318 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003319 if self.format_unit == 'S':
3320 return """
3321 if (!PyBytes_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003322 _PyArg_BadArgument("{{name}}", {argnum}, "bytes", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003323 goto exit;
3324 }}}}
3325 {paramname} = ({type}){argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003326 """.format(argname=argname, paramname=self.name, argnum=argnum,
3327 type=self.type)
3328 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003329
Larry Hastings31826802013-10-19 00:09:25 -07003330class PyByteArrayObject_converter(CConverter):
3331 type = 'PyByteArrayObject *'
3332 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003333 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07003334
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003335 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003336 if self.format_unit == 'Y':
3337 return """
3338 if (!PyByteArray_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003339 _PyArg_BadArgument("{{name}}", {argnum}, "bytearray", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003340 goto exit;
3341 }}}}
3342 {paramname} = ({type}){argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003343 """.format(argname=argname, paramname=self.name, argnum=argnum,
3344 type=self.type)
3345 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003346
Larry Hastings31826802013-10-19 00:09:25 -07003347class unicode_converter(CConverter):
3348 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003349 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003350 format_unit = 'U'
3351
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003352 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003353 if self.format_unit == 'U':
3354 return """
3355 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003356 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003357 goto exit;
3358 }}}}
3359 if (PyUnicode_READY({argname}) == -1) {{{{
3360 goto exit;
3361 }}}}
3362 {paramname} = {argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003363 """.format(argname=argname, paramname=self.name, argnum=argnum)
3364 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003365
Larry Hastings38337d12015-05-07 23:30:09 -07003366@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003367@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07003368@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07003369class Py_UNICODE_converter(CConverter):
Serhiy Storchakaafb3e712018-12-14 11:19:51 +02003370 type = 'const Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003371 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003372 format_unit = 'u'
3373
Larry Hastings38337d12015-05-07 23:30:09 -07003374 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003375 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07003376 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003377 format_unit += '#'
3378 self.length = True
3379 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003380
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003381@add_legacy_c_converter('s*', accept={str, buffer})
3382@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
3383@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07003384class Py_buffer_converter(CConverter):
3385 type = 'Py_buffer'
3386 format_unit = 'y*'
3387 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08003388 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07003389
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003390 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08003391 if self.default not in (unspecified, None):
3392 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003393
Larry Hastings3f144c22014-01-06 10:34:00 -08003394 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08003395
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003396 if accept == {str, buffer, NoneType}:
3397 format_unit = 'z*'
3398 elif accept == {str, buffer}:
3399 format_unit = 's*'
3400 elif accept == {buffer}:
3401 format_unit = 'y*'
3402 elif accept == {rwbuffer}:
3403 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07003404 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003405 fail("Py_buffer_converter: illegal combination of arguments")
3406
3407 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003408
3409 def cleanup(self):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003410 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003411 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08003412
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003413 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003414 if self.format_unit == 'y*':
3415 return """
3416 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3417 goto exit;
3418 }}}}
3419 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003420 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003421 goto exit;
3422 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003423 """.format(argname=argname, paramname=self.name, argnum=argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003424 elif self.format_unit == 's*':
3425 return """
3426 if (PyUnicode_Check({argname})) {{{{
3427 Py_ssize_t len;
3428 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
3429 if (ptr == NULL) {{{{
3430 goto exit;
3431 }}}}
3432 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
3433 }}}}
3434 else {{{{ /* any bytes-like object */
3435 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3436 goto exit;
3437 }}}}
3438 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003439 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003440 goto exit;
3441 }}}}
3442 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003443 """.format(argname=argname, paramname=self.name, argnum=argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003444 elif self.format_unit == 'w*':
3445 return """
3446 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
3447 PyErr_Clear();
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003448 _PyArg_BadArgument("{{name}}", {argnum}, "read-write bytes-like object", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003449 goto exit;
3450 }}}}
3451 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003452 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003453 goto exit;
3454 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003455 """.format(argname=argname, paramname=self.name, argnum=argnum)
3456 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003457
Larry Hastingsebdcb502013-11-23 14:54:00 -08003458
Larry Hastings5c661892014-01-24 06:17:25 -08003459def correct_name_for_self(f):
3460 if f.kind in (CALLABLE, METHOD_INIT):
3461 if f.cls:
3462 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03003463 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08003464 if f.kind == STATIC_METHOD:
3465 return "void *", "null"
3466 if f.kind in (CLASS_METHOD, METHOD_NEW):
3467 return "PyTypeObject *", "type"
3468 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
3469
Larry Hastingsc2047262014-01-25 20:43:29 -08003470def required_type_for_self_for_parser(f):
3471 type, _ = correct_name_for_self(f)
3472 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
3473 return type
3474 return None
3475
Larry Hastings5c661892014-01-24 06:17:25 -08003476
Larry Hastingsebdcb502013-11-23 14:54:00 -08003477class self_converter(CConverter):
3478 """
3479 A special-case converter:
3480 this is the default converter used for "self".
3481 """
Larry Hastings5c661892014-01-24 06:17:25 -08003482 type = None
3483 format_unit = ''
3484
Larry Hastings78cf85c2014-01-04 12:44:57 -08003485 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08003486 self.specified_type = type
3487
3488 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003489 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08003490 default_type, default_name = correct_name_for_self(f)
3491 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08003492 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08003493
Larry Hastings5c661892014-01-24 06:17:25 -08003494 kind = self.function.kind
3495 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
3496
3497 if (kind == STATIC_METHOD) or new_or_init:
3498 self.show_in_signature = False
3499
3500 # tp_new (METHOD_NEW) functions are of type newfunc:
3501 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
3502 # PyTypeObject is a typedef for struct _typeobject.
3503 #
3504 # tp_init (METHOD_INIT) functions are of type initproc:
3505 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
3506 #
3507 # All other functions generated by Argument Clinic are stored in
3508 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
3509 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
3510 # However! We habitually cast these functions to PyCFunction,
3511 # since functions that accept keyword arguments don't fit this signature
3512 # but are stored there anyway. So strict type equality isn't important
3513 # for these functions.
3514 #
3515 # So:
3516 #
3517 # * The name of the first parameter to the impl and the parsing function will always
3518 # be self.name.
3519 #
3520 # * The type of the first parameter to the impl will always be of self.type.
3521 #
3522 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
3523 # * The type of the first parameter to the parsing function is also self.type.
3524 # This means that if you step into the parsing function, your "self" parameter
3525 # is of the correct type, which may make debugging more pleasant.
3526 #
3527 # * Else if the function is tp_new (METHOD_NEW):
3528 # * The type of the first parameter to the parsing function is "PyTypeObject *",
3529 # so the type signature of the function call is an exact match.
3530 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
3531 # in the impl call.
3532 #
3533 # * Else if the function is tp_init (METHOD_INIT):
3534 # * The type of the first parameter to the parsing function is "PyObject *",
3535 # so the type signature of the function call is an exact match.
3536 # * If self.type != "PyObject *", we cast the first parameter to self.type
3537 # in the impl call.
3538
3539 @property
3540 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08003541 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08003542
Larry Hastingsebdcb502013-11-23 14:54:00 -08003543 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08003544 """
3545 parameter is a clinic.Parameter instance.
3546 data is a CRenderData instance.
3547 """
3548 if self.function.kind == STATIC_METHOD:
3549 return
3550
3551 self._render_self(parameter, data)
3552
3553 if self.type != self.parser_type:
3554 # insert cast to impl_argument[0], aka self.
3555 # we know we're in the first slot in all the CRenderData lists,
3556 # because we render parameters in order, and self is always first.
3557 assert len(data.impl_arguments) == 1
3558 assert data.impl_arguments[0] == self.name
3559 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3560
3561 def set_template_dict(self, template_dict):
3562 template_dict['self_name'] = self.name
3563 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003564 kind = self.function.kind
3565 cls = self.function.cls
3566
3567 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3568 if kind == METHOD_NEW:
3569 passed_in_type = self.name
3570 else:
3571 passed_in_type = 'Py_TYPE({})'.format(self.name)
3572
3573 line = '({passed_in_type} == {type_object}) &&\n '
3574 d = {
3575 'type_object': self.function.cls.type_object,
3576 'passed_in_type': passed_in_type
3577 }
3578 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003579
Larry Hastings31826802013-10-19 00:09:25 -07003580
3581
3582def add_c_return_converter(f, name=None):
3583 if not name:
3584 name = f.__name__
3585 if not name.endswith('_return_converter'):
3586 return f
3587 name = name[:-len('_return_converter')]
3588 return_converters[name] = f
3589 return f
3590
3591
3592class CReturnConverterAutoRegister(type):
3593 def __init__(cls, name, bases, classdict):
3594 add_c_return_converter(cls)
3595
3596class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3597
Larry Hastings78cf85c2014-01-04 12:44:57 -08003598 # The C type to use for this variable.
3599 # 'type' should be a Python string specifying the type, e.g. "int".
3600 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003601 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003602
3603 # The Python default value for this parameter, as a Python value.
3604 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003605 default = None
3606
Larry Hastings2a727912014-01-16 11:32:01 -08003607 def __init__(self, *, py_default=None, **kwargs):
3608 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003609 try:
3610 self.return_converter_init(**kwargs)
3611 except TypeError as e:
3612 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3613 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3614
3615 def return_converter_init(self):
3616 pass
3617
3618 def declare(self, data, name="_return_value"):
3619 line = []
3620 add = line.append
3621 add(self.type)
3622 if not self.type.endswith('*'):
3623 add(' ')
3624 add(name + ';')
3625 data.declarations.append(''.join(line))
3626 data.return_value = name
3627
3628 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003629 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003630
3631 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003632 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003633
3634 def render(self, function, data):
3635 """
3636 function is a clinic.Function instance.
3637 data is a CRenderData instance.
3638 """
3639 pass
3640
3641add_c_return_converter(CReturnConverter, 'object')
3642
Larry Hastings78cf85c2014-01-04 12:44:57 -08003643class NoneType_return_converter(CReturnConverter):
3644 def render(self, function, data):
3645 self.declare(data)
3646 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003647if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003648 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003649}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003650return_value = Py_None;
3651Py_INCREF(Py_None);
3652'''.strip())
3653
Larry Hastings4a55fc52014-01-12 11:09:57 -08003654class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003655 type = 'int'
3656
3657 def render(self, function, data):
3658 self.declare(data)
3659 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003660 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003661
3662class long_return_converter(CReturnConverter):
3663 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003664 conversion_fn = 'PyLong_FromLong'
3665 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003666 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003667
3668 def render(self, function, data):
3669 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003670 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003671 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003672 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003673
Larry Hastings4a55fc52014-01-12 11:09:57 -08003674class int_return_converter(long_return_converter):
3675 type = 'int'
3676 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003677
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003678class init_return_converter(long_return_converter):
3679 """
3680 Special return converter for __init__ functions.
3681 """
3682 type = 'int'
3683 cast = '(long)'
3684
3685 def render(self, function, data):
3686 pass
3687
Larry Hastings4a55fc52014-01-12 11:09:57 -08003688class unsigned_long_return_converter(long_return_converter):
3689 type = 'unsigned long'
3690 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003691 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003692
3693class unsigned_int_return_converter(unsigned_long_return_converter):
3694 type = 'unsigned int'
3695 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003696 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003697
3698class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003699 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003700 conversion_fn = 'PyLong_FromSsize_t'
3701
3702class size_t_return_converter(long_return_converter):
3703 type = 'size_t'
3704 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003705 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003706
3707
3708class double_return_converter(CReturnConverter):
3709 type = 'double'
3710 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003711
3712 def render(self, function, data):
3713 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003714 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003715 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003716 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3717
3718class float_return_converter(double_return_converter):
3719 type = 'float'
3720 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003721
3722
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003723def eval_ast_expr(node, globals, *, filename='-'):
3724 """
3725 Takes an ast.Expr node. Compiles and evaluates it.
3726 Returns the result of the expression.
3727
3728 globals represents the globals dict the expression
3729 should see. (There's no equivalent for "locals" here.)
3730 """
3731
3732 if isinstance(node, ast.Expr):
3733 node = node.value
3734
3735 node = ast.Expression(node)
3736 co = compile(node, filename, 'eval')
3737 fn = types.FunctionType(co, globals)
3738 return fn()
3739
3740
Larry Hastings31826802013-10-19 00:09:25 -07003741class IndentStack:
3742 def __init__(self):
3743 self.indents = []
3744 self.margin = None
3745
3746 def _ensure(self):
3747 if not self.indents:
3748 fail('IndentStack expected indents, but none are defined.')
3749
3750 def measure(self, line):
3751 """
3752 Returns the length of the line's margin.
3753 """
3754 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003755 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003756 stripped = line.lstrip()
3757 if not len(stripped):
3758 # we can't tell anything from an empty line
3759 # so just pretend it's indented like our current indent
3760 self._ensure()
3761 return self.indents[-1]
3762 return len(line) - len(stripped)
3763
3764 def infer(self, line):
3765 """
3766 Infer what is now the current margin based on this line.
3767 Returns:
3768 1 if we have indented (or this is the first margin)
3769 0 if the margin has not changed
3770 -N if we have dedented N times
3771 """
3772 indent = self.measure(line)
3773 margin = ' ' * indent
3774 if not self.indents:
3775 self.indents.append(indent)
3776 self.margin = margin
3777 return 1
3778 current = self.indents[-1]
3779 if indent == current:
3780 return 0
3781 if indent > current:
3782 self.indents.append(indent)
3783 self.margin = margin
3784 return 1
3785 # indent < current
3786 if indent not in self.indents:
3787 fail("Illegal outdent.")
3788 outdent_count = 0
3789 while indent != current:
3790 self.indents.pop()
3791 current = self.indents[-1]
3792 outdent_count -= 1
3793 self.margin = margin
3794 return outdent_count
3795
3796 @property
3797 def depth(self):
3798 """
3799 Returns how many margins are currently defined.
3800 """
3801 return len(self.indents)
3802
3803 def indent(self, line):
3804 """
3805 Indents a line by the currently defined margin.
3806 """
3807 return self.margin + line
3808
3809 def dedent(self, line):
3810 """
3811 Dedents a line by the currently defined margin.
3812 (The inverse of 'indent'.)
3813 """
3814 margin = self.margin
3815 indent = self.indents[-1]
3816 if not line.startswith(margin):
3817 fail('Cannot dedent, line does not start with the previous margin:')
3818 return line[indent:]
3819
3820
3821class DSLParser:
3822 def __init__(self, clinic):
3823 self.clinic = clinic
3824
3825 self.directives = {}
3826 for name in dir(self):
3827 # functions that start with directive_ are added to directives
3828 _, s, key = name.partition("directive_")
3829 if s:
3830 self.directives[key] = getattr(self, name)
3831
3832 # functions that start with at_ are too, with an @ in front
3833 _, s, key = name.partition("at_")
3834 if s:
3835 self.directives['@' + key] = getattr(self, name)
3836
3837 self.reset()
3838
3839 def reset(self):
3840 self.function = None
3841 self.state = self.state_dsl_start
3842 self.parameter_indent = None
3843 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003844 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003845 self.group = 0
3846 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003847 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003848 self.indent = IndentStack()
3849 self.kind = CALLABLE
3850 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003851 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003852 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003853
Larry Hastingsebdcb502013-11-23 14:54:00 -08003854 def directive_version(self, required):
3855 global version
3856 if version_comparitor(version, required) < 0:
3857 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3858
Larry Hastings31826802013-10-19 00:09:25 -07003859 def directive_module(self, name):
3860 fields = name.split('.')
3861 new = fields.pop()
3862 module, cls = self.clinic._module_and_class(fields)
3863 if cls:
3864 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003865
3866 if name in module.classes:
3867 fail("Already defined module " + repr(name) + "!")
3868
Larry Hastings31826802013-10-19 00:09:25 -07003869 m = Module(name, module)
3870 module.modules[name] = m
3871 self.block.signatures.append(m)
3872
Larry Hastingsc2047262014-01-25 20:43:29 -08003873 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003874 fields = name.split('.')
3875 in_classes = False
3876 parent = self
3877 name = fields.pop()
3878 so_far = []
3879 module, cls = self.clinic._module_and_class(fields)
3880
Larry Hastingsc2047262014-01-25 20:43:29 -08003881 parent = cls or module
3882 if name in parent.classes:
3883 fail("Already defined class " + repr(name) + "!")
3884
3885 c = Class(name, module, cls, typedef, type_object)
3886 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003887 self.block.signatures.append(c)
3888
Larry Hastingsbebf7352014-01-17 17:47:17 -08003889 def directive_set(self, name, value):
3890 if name not in ("line_prefix", "line_suffix"):
3891 fail("unknown variable", repr(name))
3892
3893 value = value.format_map({
3894 'block comment start': '/*',
3895 'block comment end': '*/',
3896 })
3897
3898 self.clinic.__dict__[name] = value
3899
3900 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003901 if command == 'new':
3902 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003903 return
3904
Zachary Ware071baa62014-01-21 23:07:12 -06003905 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003906 self.clinic.get_destination(name).clear()
3907 fail("unknown destination command", repr(command))
3908
3909
Larry Hastings0759f842015-04-03 13:09:02 -07003910 def directive_output(self, command_or_name, destination=''):
3911 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003912
Larry Hastings0759f842015-04-03 13:09:02 -07003913 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003914 preset = self.clinic.presets.get(destination)
3915 if not preset:
3916 fail("Unknown preset " + repr(destination) + "!")
3917 fd.update(preset)
3918 return
3919
Larry Hastings0759f842015-04-03 13:09:02 -07003920 if command_or_name == "push":
3921 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003922 return
3923
Larry Hastings0759f842015-04-03 13:09:02 -07003924 if command_or_name == "pop":
3925 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003926 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003927 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003928 fd.update(previous_fd)
3929 return
3930
3931 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003932 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003933 self.block.output.append(pprint.pformat(fd))
3934 self.block.output.append('\n')
3935 return
3936
3937 d = self.clinic.get_destination(destination)
3938
Larry Hastings0759f842015-04-03 13:09:02 -07003939 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003940 for name in list(fd):
3941 fd[name] = d
3942 return
3943
Larry Hastings0759f842015-04-03 13:09:02 -07003944 if command_or_name not in fd:
3945 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3946 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003947
3948 def directive_dump(self, name):
3949 self.block.output.append(self.clinic.get_destination(name).dump())
3950
3951 def directive_print(self, *args):
3952 self.block.output.append(' '.join(args))
3953 self.block.output.append('\n')
3954
3955 def directive_preserve(self):
3956 if self.preserve_output:
3957 fail("Can't have preserve twice in one block!")
3958 self.preserve_output = True
3959
Larry Hastings31826802013-10-19 00:09:25 -07003960 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003961 if self.kind is not CALLABLE:
3962 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003963 self.kind = CLASS_METHOD
3964
3965 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003966 if self.kind is not CALLABLE:
3967 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003968 self.kind = STATIC_METHOD
3969
3970 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003971 if self.coexist:
3972 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003973 self.coexist = True
3974
3975 def parse(self, block):
3976 self.reset()
3977 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003978 self.saved_output = self.block.output
3979 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003980 block_start = self.clinic.block_parser.line_number
3981 lines = block.input.split('\n')
3982 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3983 if '\t' in line:
3984 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3985 self.state(line)
3986
3987 self.next(self.state_terminal)
3988 self.state(None)
3989
Larry Hastingsbebf7352014-01-17 17:47:17 -08003990 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3991
3992 if self.preserve_output:
3993 if block.output:
3994 fail("'preserve' only works for blocks that don't produce any output!")
3995 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003996
3997 @staticmethod
3998 def ignore_line(line):
3999 # ignore comment-only lines
4000 if line.lstrip().startswith('#'):
4001 return True
4002
4003 # Ignore empty lines too
4004 # (but not in docstring sections!)
4005 if not line.strip():
4006 return True
4007
4008 return False
4009
4010 @staticmethod
4011 def calculate_indent(line):
4012 return len(line) - len(line.strip())
4013
4014 def next(self, state, line=None):
4015 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
4016 self.state = state
4017 if line is not None:
4018 self.state(line)
4019
4020 def state_dsl_start(self, line):
4021 # self.block = self.ClinicOutputBlock(self)
4022 if self.ignore_line(line):
4023 return
Larry Hastings7726ac92014-01-31 22:03:12 -08004024
4025 # is it a directive?
4026 fields = shlex.split(line)
4027 directive_name = fields[0]
4028 directive = self.directives.get(directive_name, None)
4029 if directive:
4030 try:
4031 directive(*fields[1:])
4032 except TypeError as e:
4033 fail(str(e))
4034 return
4035
Larry Hastings31826802013-10-19 00:09:25 -07004036 self.next(self.state_modulename_name, line)
4037
4038 def state_modulename_name(self, line):
4039 # looking for declaration, which establishes the leftmost column
4040 # line should be
4041 # modulename.fnname [as c_basename] [-> return annotation]
4042 # square brackets denote optional syntax.
4043 #
Larry Hastings4a714d42014-01-14 22:22:41 -08004044 # alternatively:
4045 # modulename.fnname [as c_basename] = modulename.existing_fn_name
4046 # clones the parameters and return converter from that
4047 # function. you can't modify them. you must enter a
4048 # new docstring.
4049 #
Larry Hastings31826802013-10-19 00:09:25 -07004050 # (but we might find a directive first!)
4051 #
4052 # this line is permitted to start with whitespace.
4053 # we'll call this number of spaces F (for "function").
4054
4055 if not line.strip():
4056 return
4057
4058 self.indent.infer(line)
4059
Larry Hastings4a714d42014-01-14 22:22:41 -08004060 # are we cloning?
4061 before, equals, existing = line.rpartition('=')
4062 if equals:
4063 full_name, _, c_basename = before.partition(' as ')
4064 full_name = full_name.strip()
4065 c_basename = c_basename.strip()
4066 existing = existing.strip()
4067 if (is_legal_py_identifier(full_name) and
4068 (not c_basename or is_legal_c_identifier(c_basename)) and
4069 is_legal_py_identifier(existing)):
4070 # we're cloning!
4071 fields = [x.strip() for x in existing.split('.')]
4072 function_name = fields.pop()
4073 module, cls = self.clinic._module_and_class(fields)
4074
4075 for existing_function in (cls or module).functions:
4076 if existing_function.name == function_name:
4077 break
4078 else:
4079 existing_function = None
4080 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08004081 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08004082 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08004083 fail("Couldn't find existing function " + repr(existing) + "!")
4084
4085 fields = [x.strip() for x in full_name.split('.')]
4086 function_name = fields.pop()
4087 module, cls = self.clinic._module_and_class(fields)
4088
4089 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
4090 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08004091 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 -08004092
4093 self.block.signatures.append(self.function)
4094 (cls or module).functions.append(self.function)
4095 self.next(self.state_function_docstring)
4096 return
4097
Larry Hastings31826802013-10-19 00:09:25 -07004098 line, _, returns = line.partition('->')
4099
4100 full_name, _, c_basename = line.partition(' as ')
4101 full_name = full_name.strip()
4102 c_basename = c_basename.strip() or None
4103
Larry Hastingsdfcd4672013-10-27 02:49:39 -07004104 if not is_legal_py_identifier(full_name):
4105 fail("Illegal function name: {}".format(full_name))
4106 if c_basename and not is_legal_c_identifier(c_basename):
4107 fail("Illegal C basename: {}".format(c_basename))
4108
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004109 return_converter = None
4110 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07004111 ast_input = "def x() -> {}: pass".format(returns)
4112 module = None
4113 try:
4114 module = ast.parse(ast_input)
4115 except SyntaxError:
4116 pass
4117 if not module:
4118 fail("Badly-formed annotation for " + full_name + ": " + returns)
4119 try:
4120 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004121 if legacy:
4122 fail("Legacy converter {!r} not allowed as a return converter"
4123 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07004124 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004125 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07004126 return_converter = return_converters[name](**kwargs)
4127 except ValueError:
4128 fail("Badly-formed annotation for " + full_name + ": " + returns)
4129
4130 fields = [x.strip() for x in full_name.split('.')]
4131 function_name = fields.pop()
4132 module, cls = self.clinic._module_and_class(fields)
4133
Larry Hastings8666e652014-01-12 14:12:59 -08004134 fields = full_name.split('.')
4135 if fields[-1] == '__new__':
4136 if (self.kind != CLASS_METHOD) or (not cls):
4137 fail("__new__ must be a class method!")
4138 self.kind = METHOD_NEW
4139 elif fields[-1] == '__init__':
4140 if (self.kind != CALLABLE) or (not cls):
4141 fail("__init__ must be a normal method, not a class or static method!")
4142 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004143 if not return_converter:
4144 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08004145 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08004146 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08004147
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004148 if not return_converter:
4149 return_converter = CReturnConverter()
4150
Larry Hastings31826802013-10-19 00:09:25 -07004151 if not module:
4152 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
4153 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
4154 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
4155 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08004156
4157 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08004158 type, name = correct_name_for_self(self.function)
4159 kwargs = {}
4160 if cls and type == "PyObject *":
4161 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08004162 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08004163 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
4164 self.function.parameters[sc.name] = p_self
4165
Larry Hastings4a714d42014-01-14 22:22:41 -08004166 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07004167 self.next(self.state_parameters_start)
4168
4169 # Now entering the parameters section. The rules, formally stated:
4170 #
4171 # * All lines must be indented with spaces only.
4172 # * The first line must be a parameter declaration.
4173 # * The first line must be indented.
4174 # * This first line establishes the indent for parameters.
4175 # * We'll call this number of spaces P (for "parameter").
4176 # * Thenceforth:
4177 # * Lines indented with P spaces specify a parameter.
4178 # * Lines indented with > P spaces are docstrings for the previous
4179 # parameter.
4180 # * We'll call this number of spaces D (for "docstring").
4181 # * All subsequent lines indented with >= D spaces are stored as
4182 # part of the per-parameter docstring.
4183 # * All lines will have the first D spaces of the indent stripped
4184 # before they are stored.
4185 # * It's illegal to have a line starting with a number of spaces X
4186 # such that P < X < D.
4187 # * A line with < P spaces is the first line of the function
4188 # docstring, which ends processing for parameters and per-parameter
4189 # docstrings.
4190 # * The first line of the function docstring must be at the same
4191 # indent as the function declaration.
4192 # * It's illegal to have any line in the parameters section starting
4193 # with X spaces such that F < X < P. (As before, F is the indent
4194 # of the function declaration.)
4195 #
Larry Hastings31826802013-10-19 00:09:25 -07004196 # Also, currently Argument Clinic places the following restrictions on groups:
4197 # * Each group must contain at least one parameter.
4198 # * Each group may contain at most one group, which must be the furthest
4199 # thing in the group from the required parameters. (The nested group
4200 # must be the first in the group when it's before the required
4201 # parameters, and the last thing in the group when after the required
4202 # parameters.)
4203 # * There may be at most one (top-level) group to the left or right of
4204 # the required parameters.
4205 # * You must specify a slash, and it must be after all parameters.
4206 # (In other words: either all parameters are positional-only,
4207 # or none are.)
4208 #
4209 # Said another way:
4210 # * Each group must contain at least one parameter.
4211 # * All left square brackets before the required parameters must be
4212 # consecutive. (You can't have a left square bracket followed
4213 # by a parameter, then another left square bracket. You can't
4214 # have a left square bracket, a parameter, a right square bracket,
4215 # and then a left square bracket.)
4216 # * All right square brackets after the required parameters must be
4217 # consecutive.
4218 #
4219 # These rules are enforced with a single state variable:
4220 # "parameter_state". (Previously the code was a miasma of ifs and
4221 # separate boolean state variables.) The states are:
4222 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004223 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4224 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07004225 #
4226 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4227 # 1: ps_left_square_before. left square brackets before required parameters.
4228 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08004229 # 3: ps_required. required parameters, positional-or-keyword or positional-only
4230 # (we don't know yet). (renumber left groups!)
4231 # 4: ps_optional. positional-or-keyword or positional-only parameters that
4232 # now must have default values.
4233 # 5: ps_group_after. in a group, after required parameters.
4234 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07004235 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004236 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07004237
4238 def state_parameters_start(self, line):
4239 if self.ignore_line(line):
4240 return
4241
4242 # if this line is not indented, we have no parameters
4243 if not self.indent.infer(line):
4244 return self.next(self.state_function_docstring, line)
4245
Larry Hastings2a727912014-01-16 11:32:01 -08004246 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07004247 return self.next(self.state_parameter, line)
4248
4249
4250 def to_required(self):
4251 """
4252 Transition to the "required" parameter state.
4253 """
4254 if self.parameter_state != self.ps_required:
4255 self.parameter_state = self.ps_required
4256 for p in self.function.parameters.values():
4257 p.group = -p.group
4258
4259 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08004260 if self.parameter_continuation:
4261 line = self.parameter_continuation + ' ' + line.lstrip()
4262 self.parameter_continuation = ''
4263
Larry Hastings31826802013-10-19 00:09:25 -07004264 if self.ignore_line(line):
4265 return
4266
4267 assert self.indent.depth == 2
4268 indent = self.indent.infer(line)
4269 if indent == -1:
4270 # we outdented, must be to definition column
4271 return self.next(self.state_function_docstring, line)
4272
4273 if indent == 1:
4274 # we indented, must be to new parameter docstring column
4275 return self.next(self.state_parameter_docstring_start, line)
4276
Larry Hastings2a727912014-01-16 11:32:01 -08004277 line = line.rstrip()
4278 if line.endswith('\\'):
4279 self.parameter_continuation = line[:-1]
4280 return
4281
Larry Hastings31826802013-10-19 00:09:25 -07004282 line = line.lstrip()
4283
4284 if line in ('*', '/', '[', ']'):
4285 self.parse_special_symbol(line)
4286 return
4287
4288 if self.parameter_state in (self.ps_start, self.ps_required):
4289 self.to_required()
4290 elif self.parameter_state == self.ps_left_square_before:
4291 self.parameter_state = self.ps_group_before
4292 elif self.parameter_state == self.ps_group_before:
4293 if not self.group:
4294 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08004295 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07004296 pass
4297 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004298 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07004299
Larry Hastings7726ac92014-01-31 22:03:12 -08004300 # handle "as" for parameters too
4301 c_name = None
4302 name, have_as_token, trailing = line.partition(' as ')
4303 if have_as_token:
4304 name = name.strip()
4305 if ' ' not in name:
4306 fields = trailing.strip().split(' ')
4307 if not fields:
4308 fail("Invalid 'as' clause!")
4309 c_name = fields[0]
4310 if c_name.endswith(':'):
4311 name += ':'
4312 c_name = c_name[:-1]
4313 fields[0] = name
4314 line = ' '.join(fields)
4315
Larry Hastings2a727912014-01-16 11:32:01 -08004316 base, equals, default = line.rpartition('=')
4317 if not equals:
4318 base = default
4319 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08004320
Larry Hastings31826802013-10-19 00:09:25 -07004321 module = None
4322 try:
Larry Hastings2a727912014-01-16 11:32:01 -08004323 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07004324 module = ast.parse(ast_input)
4325 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08004326 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08004327 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004328 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08004329 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08004330 default = None
4331 ast_input = "def x({}): pass".format(line)
4332 module = ast.parse(ast_input)
4333 except SyntaxError:
4334 pass
Larry Hastings31826802013-10-19 00:09:25 -07004335 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07004336 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07004337
4338 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004339
4340 if len(function_args.args) > 1:
4341 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
4342 if function_args.defaults or function_args.kw_defaults:
4343 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
4344 if function_args.vararg or function_args.kwarg:
4345 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
4346
Larry Hastings31826802013-10-19 00:09:25 -07004347 parameter = function_args.args[0]
4348
Larry Hastings16c51912014-01-07 11:53:01 -08004349 parameter_name = parameter.arg
4350 name, legacy, kwargs = self.parse_converter(parameter.annotation)
4351
Larry Hastings2a727912014-01-16 11:32:01 -08004352 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08004353 if self.parameter_state == self.ps_optional:
4354 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 -08004355 value = unspecified
4356 if 'py_default' in kwargs:
4357 fail("You can't specify py_default without specifying a default value!")
4358 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004359 if self.parameter_state == self.ps_required:
4360 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08004361 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06004362 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004363 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08004364 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004365 try:
4366 module = ast.parse(ast_input)
4367
Larry Hastings5c661892014-01-24 06:17:25 -08004368 if 'c_default' not in kwargs:
4369 # we can only represent very simple data values in C.
4370 # detect whether default is okay, via a blacklist
4371 # of disallowed ast nodes.
4372 class DetectBadNodes(ast.NodeVisitor):
4373 bad = False
4374 def bad_node(self, node):
4375 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08004376
Larry Hastings5c661892014-01-24 06:17:25 -08004377 # inline function call
4378 visit_Call = bad_node
4379 # inline if statement ("x = 3 if y else z")
4380 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004381
Larry Hastings5c661892014-01-24 06:17:25 -08004382 # comprehensions and generator expressions
4383 visit_ListComp = visit_SetComp = bad_node
4384 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004385
Larry Hastings5c661892014-01-24 06:17:25 -08004386 # literals for advanced types
4387 visit_Dict = visit_Set = bad_node
4388 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004389
Larry Hastings5c661892014-01-24 06:17:25 -08004390 # "starred": "a = [1, 2, 3]; *a"
4391 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004392
Larry Hastings5c661892014-01-24 06:17:25 -08004393 blacklist = DetectBadNodes()
4394 blacklist.visit(module)
4395 bad = blacklist.bad
4396 else:
4397 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06004398 # but at least make an attempt at ensuring it's a valid expression.
4399 try:
4400 value = eval(default)
4401 if value == unspecified:
4402 fail("'unspecified' is not a legal default value!")
4403 except NameError:
4404 pass # probably a named constant
4405 except Exception as e:
4406 fail("Malformed expression given as default value\n"
4407 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08004408 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08004409 fail("Unsupported expression as default value: " + repr(default))
4410
4411 expr = module.body[0].value
4412 # mild hack: explicitly support NULL as a default value
4413 if isinstance(expr, ast.Name) and expr.id == 'NULL':
4414 value = NULL
4415 py_default = 'None'
4416 c_default = "NULL"
4417 elif (isinstance(expr, ast.BinOp) or
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004418 (isinstance(expr, ast.UnaryOp) and
4419 not (isinstance(expr.operand, ast.Num) or
4420 (hasattr(ast, 'Constant') and
4421 isinstance(expr.operand, ast.Constant) and
4422 type(expr.operand.value) in (int, float, complex)))
4423 )):
Larry Hastings2a727912014-01-16 11:32:01 -08004424 c_default = kwargs.get("c_default")
4425 if not (isinstance(c_default, str) and c_default):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004426 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 -08004427 py_default = default
4428 value = unknown
4429 elif isinstance(expr, ast.Attribute):
4430 a = []
4431 n = expr
4432 while isinstance(n, ast.Attribute):
4433 a.append(n.attr)
4434 n = n.value
4435 if not isinstance(n, ast.Name):
4436 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
4437 a.append(n.id)
4438 py_default = ".".join(reversed(a))
4439
4440 c_default = kwargs.get("c_default")
4441 if not (isinstance(c_default, str) and c_default):
4442 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4443
4444 try:
4445 value = eval(py_default)
4446 except NameError:
4447 value = unknown
4448 else:
4449 value = ast.literal_eval(expr)
4450 py_default = repr(value)
4451 if isinstance(value, (bool, None.__class__)):
4452 c_default = "Py_" + py_default
4453 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08004454 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08004455 else:
4456 c_default = py_default
4457
4458 except SyntaxError as e:
4459 fail("Syntax error: " + repr(e.text))
4460 except (ValueError, AttributeError):
4461 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08004462 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08004463 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08004464 if not (isinstance(c_default, str) and c_default):
4465 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4466
Larry Hastings2a727912014-01-16 11:32:01 -08004467 kwargs.setdefault('c_default', c_default)
4468 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004469
Larry Hastings31826802013-10-19 00:09:25 -07004470 dict = legacy_converters if legacy else converters
4471 legacy_str = "legacy " if legacy else ""
4472 if name not in dict:
4473 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08004474 # if you use a c_name for the parameter, we just give that name to the converter
4475 # but the parameter object gets the python name
4476 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07004477
4478 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08004479
4480 if isinstance(converter, self_converter):
4481 if len(self.function.parameters) == 1:
4482 if (self.parameter_state != self.ps_required):
4483 fail("A 'self' parameter cannot be marked optional.")
4484 if value is not unspecified:
4485 fail("A 'self' parameter cannot have a default value.")
4486 if self.group:
4487 fail("A 'self' parameter cannot be in an optional group.")
4488 kind = inspect.Parameter.POSITIONAL_ONLY
4489 self.parameter_state = self.ps_start
4490 self.function.parameters.clear()
4491 else:
4492 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
4493
Larry Hastings31826802013-10-19 00:09:25 -07004494 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08004495
4496 if parameter_name in self.function.parameters:
4497 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07004498 self.function.parameters[parameter_name] = p
4499
4500 def parse_converter(self, annotation):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004501 if (hasattr(ast, 'Constant') and
4502 isinstance(annotation, ast.Constant) and
4503 type(annotation.value) is str):
4504 return annotation.value, True, {}
4505
Larry Hastings31826802013-10-19 00:09:25 -07004506 if isinstance(annotation, ast.Str):
4507 return annotation.s, True, {}
4508
4509 if isinstance(annotation, ast.Name):
4510 return annotation.id, False, {}
4511
Larry Hastings4a55fc52014-01-12 11:09:57 -08004512 if not isinstance(annotation, ast.Call):
4513 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07004514
4515 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004516 symbols = globals()
4517
4518 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07004519 return name, False, kwargs
4520
4521 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07004522 if symbol == '*':
4523 if self.keyword_only:
4524 fail("Function " + self.function.name + " uses '*' more than once.")
4525 self.keyword_only = True
4526 elif symbol == '[':
4527 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
4528 self.parameter_state = self.ps_left_square_before
4529 elif self.parameter_state in (self.ps_required, self.ps_group_after):
4530 self.parameter_state = self.ps_group_after
4531 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004532 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07004533 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08004534 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07004535 elif symbol == ']':
4536 if not self.group:
4537 fail("Function " + self.function.name + " has a ] without a matching [.")
4538 if not any(p.group == self.group for p in self.function.parameters.values()):
4539 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
4540 self.group -= 1
4541 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
4542 self.parameter_state = self.ps_group_before
4543 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
4544 self.parameter_state = self.ps_right_square_after
4545 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004546 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07004547 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004548 if self.positional_only:
4549 fail("Function " + self.function.name + " uses '/' more than once.")
4550 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08004551 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07004552 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08004553 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
4554 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07004555 if self.keyword_only:
4556 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004557 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004558 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004559 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004560 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4561 p.kind = inspect.Parameter.POSITIONAL_ONLY
4562
4563 def state_parameter_docstring_start(self, line):
4564 self.parameter_docstring_indent = len(self.indent.margin)
4565 assert self.indent.depth == 3
4566 return self.next(self.state_parameter_docstring, line)
4567
4568 # every line of the docstring must start with at least F spaces,
4569 # where F > P.
4570 # these F spaces will be stripped.
4571 def state_parameter_docstring(self, line):
4572 stripped = line.strip()
4573 if stripped.startswith('#'):
4574 return
4575
4576 indent = self.indent.measure(line)
4577 if indent < self.parameter_docstring_indent:
4578 self.indent.infer(line)
4579 assert self.indent.depth < 3
4580 if self.indent.depth == 2:
4581 # back to a parameter
4582 return self.next(self.state_parameter, line)
4583 assert self.indent.depth == 1
4584 return self.next(self.state_function_docstring, line)
4585
4586 assert self.function.parameters
4587 last_parameter = next(reversed(list(self.function.parameters.values())))
4588
4589 new_docstring = last_parameter.docstring
4590
4591 if new_docstring:
4592 new_docstring += '\n'
4593 if stripped:
4594 new_docstring += self.indent.dedent(line)
4595
4596 last_parameter.docstring = new_docstring
4597
4598 # the final stanza of the DSL is the docstring.
4599 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004600 if self.group:
4601 fail("Function " + self.function.name + " has a ] without a matching [.")
4602
4603 stripped = line.strip()
4604 if stripped.startswith('#'):
4605 return
4606
4607 new_docstring = self.function.docstring
4608 if new_docstring:
4609 new_docstring += "\n"
4610 if stripped:
4611 line = self.indent.dedent(line).rstrip()
4612 else:
4613 line = ''
4614 new_docstring += line
4615 self.function.docstring = new_docstring
4616
4617 def format_docstring(self):
4618 f = self.function
4619
Larry Hastings5c661892014-01-24 06:17:25 -08004620 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4621 if new_or_init and not f.docstring:
4622 # don't render a docstring at all, no signature, nothing.
4623 return f.docstring
4624
Larry Hastings2623c8c2014-02-08 22:15:29 -08004625 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004626 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004627
4628 ##
4629 ## docstring first line
4630 ##
4631
Larry Hastings2623c8c2014-02-08 22:15:29 -08004632 if new_or_init:
4633 # classes get *just* the name of the class
4634 # not __new__, not __init__, and not module.classname
4635 assert f.cls
4636 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004637 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004638 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004639 add('(')
4640
4641 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004642 assert parameters, "We should always have a self parameter. " + repr(f)
4643 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004644 # self is always positional-only.
4645 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004646 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004647 positional_only = True
4648 for p in parameters[1:]:
4649 if not p.is_positional_only():
4650 positional_only = False
4651 else:
4652 assert positional_only
4653 if positional_only:
4654 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004655 else:
4656 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004657 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004658
4659 right_bracket_count = 0
4660
4661 def fix_right_bracket_count(desired):
4662 nonlocal right_bracket_count
4663 s = ''
4664 while right_bracket_count < desired:
4665 s += '['
4666 right_bracket_count += 1
4667 while right_bracket_count > desired:
4668 s += ']'
4669 right_bracket_count -= 1
4670 return s
4671
Larry Hastings2623c8c2014-02-08 22:15:29 -08004672 need_slash = False
4673 added_slash = False
4674 need_a_trailing_slash = False
4675
4676 # we only need a trailing slash:
4677 # * if this is not a "docstring_only" signature
4678 # * and if the last *shown* parameter is
4679 # positional only
4680 if not f.docstring_only:
4681 for p in reversed(parameters):
4682 if not p.converter.show_in_signature:
4683 continue
4684 if p.is_positional_only():
4685 need_a_trailing_slash = True
4686 break
4687
4688
Larry Hastings31826802013-10-19 00:09:25 -07004689 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004690
4691 first_parameter = True
4692 last_p = parameters[-1]
4693 line_length = len(''.join(text))
4694 indent = " " * line_length
4695 def add_parameter(text):
4696 nonlocal line_length
4697 nonlocal first_parameter
4698 if first_parameter:
4699 s = text
4700 first_parameter = False
4701 else:
4702 s = ' ' + text
4703 if line_length + len(s) >= 72:
4704 add('\n')
4705 add(indent)
4706 line_length = len(indent)
4707 s = text
4708 line_length += len(s)
4709 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004710
4711 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004712 if not p.converter.show_in_signature:
4713 continue
Larry Hastings31826802013-10-19 00:09:25 -07004714 assert p.name
4715
Larry Hastings2623c8c2014-02-08 22:15:29 -08004716 is_self = isinstance(p.converter, self_converter)
4717 if is_self and f.docstring_only:
4718 # this isn't a real machine-parsable signature,
4719 # so let's not print the "self" parameter
4720 continue
4721
4722 if p.is_positional_only():
4723 need_slash = not f.docstring_only
4724 elif need_slash and not (added_slash or p.is_positional_only()):
4725 added_slash = True
4726 add_parameter('/,')
4727
Larry Hastings31826802013-10-19 00:09:25 -07004728 if p.is_keyword_only() and not added_star:
4729 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004730 add_parameter('*,')
4731
4732 p_add, p_output = text_accumulator()
4733 p_add(fix_right_bracket_count(p.right_bracket_count))
4734
4735 if isinstance(p.converter, self_converter):
4736 # annotate first parameter as being a "self".
4737 #
4738 # if inspect.Signature gets this function,
4739 # and it's already bound, the self parameter
4740 # will be stripped off.
4741 #
4742 # if it's not bound, it should be marked
4743 # as positional-only.
4744 #
4745 # note: we don't print "self" for __init__,
4746 # because this isn't actually the signature
4747 # for __init__. (it can't be, __init__ doesn't
4748 # have a docstring.) if this is an __init__
4749 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004750 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004751 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004752
Larry Hastings5c661892014-01-24 06:17:25 -08004753 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004754 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004755
Larry Hastings31826802013-10-19 00:09:25 -07004756 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004757 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004758 value = p.converter.py_default
4759 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004760 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004761 p_add(value)
4762
4763 if (p != last_p) or need_a_trailing_slash:
4764 p_add(',')
4765
4766 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004767
4768 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004769 if need_a_trailing_slash:
4770 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004771 add(')')
4772
Larry Hastings2a727912014-01-16 11:32:01 -08004773 # PEP 8 says:
4774 #
4775 # The Python standard library will not use function annotations
4776 # as that would result in a premature commitment to a particular
4777 # annotation style. Instead, the annotations are left for users
4778 # to discover and experiment with useful annotation styles.
4779 #
4780 # therefore this is commented out:
4781 #
4782 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004783 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004784 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004785
Larry Hastings2623c8c2014-02-08 22:15:29 -08004786 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004787 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004788
Larry Hastings31826802013-10-19 00:09:25 -07004789 docstring_first_line = output()
4790
4791 # now fix up the places where the brackets look wrong
4792 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4793
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004794 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004795 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004796 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004797 for p in parameters:
4798 if not p.docstring.strip():
4799 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004800 if spacer_line:
4801 add('\n')
4802 else:
4803 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004804 add(" ")
4805 add(p.name)
4806 add('\n')
4807 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004808 parameters = output()
4809 if parameters:
4810 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004811
4812 ##
4813 ## docstring body
4814 ##
4815
4816 docstring = f.docstring.rstrip()
4817 lines = [line.rstrip() for line in docstring.split('\n')]
4818
4819 # Enforce the summary line!
4820 # The first line of a docstring should be a summary of the function.
4821 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4822 # by itself.
4823 #
4824 # Argument Clinic enforces the following rule:
4825 # * either the docstring is empty,
4826 # * or it must have a summary line.
4827 #
4828 # Guido said Clinic should enforce this:
4829 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4830
4831 if len(lines) >= 2:
4832 if lines[1]:
4833 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4834 "Every non-blank function docstring must start with\n" +
4835 "a single line summary followed by an empty line.")
4836 elif len(lines) == 1:
4837 # the docstring is only one line right now--the summary line.
4838 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004839 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004840 lines.append('')
4841
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004842 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4843 if parameters_marker_count > 1:
4844 fail('You may not specify {parameters} more than once in a docstring!')
4845
4846 if not parameters_marker_count:
4847 # insert after summary line
4848 lines.insert(2, '{parameters}')
4849
4850 # insert at front of docstring
4851 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004852
4853 docstring = "\n".join(lines)
4854
4855 add(docstring)
4856 docstring = output()
4857
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004858 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004859 docstring = docstring.rstrip()
4860
4861 return docstring
4862
4863 def state_terminal(self, line):
4864 """
4865 Called when processing the block is done.
4866 """
4867 assert not line
4868
4869 if not self.function:
4870 return
4871
4872 if self.keyword_only:
4873 values = self.function.parameters.values()
4874 if not values:
4875 no_parameter_after_star = True
4876 else:
4877 last_parameter = next(reversed(list(values)))
4878 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4879 if no_parameter_after_star:
4880 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4881
4882 # remove trailing whitespace from all parameter docstrings
4883 for name, value in self.function.parameters.items():
4884 if not value:
4885 continue
4886 value.docstring = value.docstring.rstrip()
4887
4888 self.function.docstring = self.format_docstring()
4889
4890
Larry Hastings5c661892014-01-24 06:17:25 -08004891
4892
Larry Hastings31826802013-10-19 00:09:25 -07004893# maps strings to callables.
4894# the callable should return an object
4895# that implements the clinic parser
4896# interface (__init__ and parse).
4897#
4898# example parsers:
4899# "clinic", handles the Clinic DSL
4900# "python", handles running Python code
4901#
4902parsers = {'clinic' : DSLParser, 'python': PythonParser}
4903
4904
4905clinic = None
4906
4907
4908def main(argv):
4909 import sys
4910
4911 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4912 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4913
4914 import argparse
Tim Hoffmann5df40252019-06-02 18:58:10 +02004915 cmdline = argparse.ArgumentParser(
4916 description="""Preprocessor for CPython C files.
4917
4918The purpose of the Argument Clinic is automating all the boilerplate involved
4919with writing argument parsing code for builtins and providing introspection
4920signatures ("docstrings") for CPython builtins.
4921
4922For more information see https://docs.python.org/3/howto/clinic.html""")
Larry Hastings31826802013-10-19 00:09:25 -07004923 cmdline.add_argument("-f", "--force", action='store_true')
4924 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004925 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004926 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004927 cmdline.add_argument("--make", action='store_true',
4928 help="Walk --srcdir to run over all relevant files.")
4929 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4930 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004931 cmdline.add_argument("filename", type=str, nargs="*")
4932 ns = cmdline.parse_args(argv)
4933
4934 if ns.converters:
4935 if ns.filename:
4936 print("Usage error: can't specify --converters and a filename at the same time.")
4937 print()
4938 cmdline.print_usage()
4939 sys.exit(-1)
4940 converters = []
4941 return_converters = []
4942 ignored = set("""
4943 add_c_converter
4944 add_c_return_converter
4945 add_default_legacy_c_converter
4946 add_legacy_c_converter
4947 """.strip().split())
4948 module = globals()
4949 for name in module:
4950 for suffix, ids in (
4951 ("_return_converter", return_converters),
4952 ("_converter", converters),
4953 ):
4954 if name in ignored:
4955 continue
4956 if name.endswith(suffix):
4957 ids.append((name, name[:-len(suffix)]))
4958 break
4959 print()
4960
4961 print("Legacy converters:")
4962 legacy = sorted(legacy_converters)
4963 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4964 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4965 print()
4966
4967 for title, attribute, ids in (
4968 ("Converters", 'converter_init', converters),
4969 ("Return converters", 'return_converter_init', return_converters),
4970 ):
4971 print(title + ":")
4972 longest = -1
4973 for name, short_name in ids:
4974 longest = max(longest, len(short_name))
4975 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4976 cls = module[name]
4977 callable = getattr(cls, attribute, None)
4978 if not callable:
4979 continue
4980 signature = inspect.signature(callable)
4981 parameters = []
4982 for parameter_name, parameter in signature.parameters.items():
4983 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4984 if parameter.default != inspect.Parameter.empty:
4985 s = '{}={!r}'.format(parameter_name, parameter.default)
4986 else:
4987 s = parameter_name
4988 parameters.append(s)
4989 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004990 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004991 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4992 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004993 sys.exit(0)
4994
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004995 if ns.make:
4996 if ns.output or ns.filename:
4997 print("Usage error: can't use -o or filenames with --make.")
4998 print()
4999 cmdline.print_usage()
5000 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07005001 if not ns.srcdir:
5002 print("Usage error: --srcdir must not be empty with --make.")
5003 print()
5004 cmdline.print_usage()
5005 sys.exit(-1)
5006 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05005007 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005008 if rcs_dir in dirs:
5009 dirs.remove(rcs_dir)
5010 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08005011 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005012 continue
5013 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08005014 if ns.verbose:
5015 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08005016 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005017 return
5018
Larry Hastings31826802013-10-19 00:09:25 -07005019 if not ns.filename:
5020 cmdline.print_usage()
5021 sys.exit(-1)
5022
5023 if ns.output and len(ns.filename) > 1:
5024 print("Usage error: can't use -o with multiple filenames.")
5025 print()
5026 cmdline.print_usage()
5027 sys.exit(-1)
5028
5029 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08005030 if ns.verbose:
5031 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08005032 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07005033
5034
5035if __name__ == "__main__":
5036 sys.exit(main(sys.argv[1:]))