blob: 9880b395133995be7ebe3ca6e1dd60bbffe457d8 [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 """
3109 {paramname} = (float) PyFloat_AsDouble({argname});
3110 if (PyErr_Occurred()) {{{{
3111 goto exit;
3112 }}}}
3113 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003114 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003115
Larry Hastings31826802013-10-19 00:09:25 -07003116class double_converter(CConverter):
3117 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003118 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003119 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003120 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003121
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003122 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003123 if self.format_unit == 'd':
3124 return """
3125 {paramname} = PyFloat_AsDouble({argname});
3126 if (PyErr_Occurred()) {{{{
3127 goto exit;
3128 }}}}
3129 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003130 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003131
Larry Hastings31826802013-10-19 00:09:25 -07003132
3133class Py_complex_converter(CConverter):
3134 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003135 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07003136 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003137 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07003138
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003139 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003140 if self.format_unit == 'D':
3141 return """
3142 {paramname} = PyComplex_AsCComplex({argname});
3143 if (PyErr_Occurred()) {{{{
3144 goto exit;
3145 }}}}
3146 """.format(argname=argname, paramname=self.name)
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003147 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003148
Larry Hastings31826802013-10-19 00:09:25 -07003149
3150class object_converter(CConverter):
3151 type = 'PyObject *'
3152 format_unit = 'O'
3153
Larry Hastings4a55fc52014-01-12 11:09:57 -08003154 def converter_init(self, *, converter=None, type=None, subclass_of=None):
3155 if converter:
3156 if subclass_of:
3157 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
3158 self.format_unit = 'O&'
3159 self.converter = converter
3160 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07003161 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08003162 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08003163
Larry Hastings77561cc2014-01-07 12:13:13 -08003164 if type is not None:
3165 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07003166
3167
Larry Hastings7f90cba2015-04-15 23:02:12 -04003168#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003169# We define three conventions for buffer types in the 'accept' argument:
3170#
3171# buffer : any object supporting the buffer interface
3172# rwbuffer: any object supporting the buffer interface, but must be writeable
3173# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04003174#
3175
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003176class buffer: pass
3177class rwbuffer: pass
3178class robuffer: pass
3179
Larry Hastings38337d12015-05-07 23:30:09 -07003180def str_converter_key(types, encoding, zeroes):
3181 return (frozenset(types), bool(encoding), bool(zeroes))
3182
3183str_converter_argument_map = {}
3184
Larry Hastings31826802013-10-19 00:09:25 -07003185class str_converter(CConverter):
3186 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003187 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003188 format_unit = 's'
3189
Larry Hastings38337d12015-05-07 23:30:09 -07003190 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003191
Larry Hastings38337d12015-05-07 23:30:09 -07003192 key = str_converter_key(accept, encoding, zeroes)
3193 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003194 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07003195 fail("str_converter: illegal combination of arguments", key)
3196
Larry Hastingsebdcb502013-11-23 14:54:00 -08003197 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07003198 self.length = bool(zeroes)
3199 if encoding:
3200 if self.default not in (Null, None, unspecified):
3201 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
3202 self.encoding = encoding
3203 self.type = 'char *'
3204 # sorry, clinic can't support preallocated buffers
3205 # for es# and et#
3206 self.c_default = "NULL"
3207
3208 def cleanup(self):
3209 if self.encoding:
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003210 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003211 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07003212
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003213 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003214 if self.format_unit == 's':
3215 return """
3216 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003217 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003218 goto exit;
3219 }}}}
3220 Py_ssize_t {paramname}_length;
3221 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3222 if ({paramname} == NULL) {{{{
3223 goto exit;
3224 }}}}
3225 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3226 PyErr_SetString(PyExc_ValueError, "embedded null character");
3227 goto exit;
3228 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003229 """.format(argname=argname, paramname=self.name, argnum=argnum)
3230 if self.format_unit == 'z':
3231 return """
3232 if ({argname} == Py_None) {{{{
3233 {paramname} = NULL;
3234 }}}}
3235 else if (PyUnicode_Check({argname})) {{{{
3236 Py_ssize_t {paramname}_length;
3237 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3238 if ({paramname} == NULL) {{{{
3239 goto exit;
3240 }}}}
3241 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3242 PyErr_SetString(PyExc_ValueError, "embedded null character");
3243 goto exit;
3244 }}}}
3245 }}}}
3246 else {{{{
3247 _PyArg_BadArgument("{{name}}", {argnum}, "str or None", {argname});
3248 goto exit;
3249 }}}}
3250 """.format(argname=argname, paramname=self.name, argnum=argnum)
3251 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003252
Larry Hastings38337d12015-05-07 23:30:09 -07003253#
3254# This is the fourth or fifth rewrite of registering all the
Raymond Hettinger14010182018-09-13 21:17:40 -07003255# string converter format units. Previous approaches hid
Larry Hastings38337d12015-05-07 23:30:09 -07003256# bugs--generally mismatches between the semantics of the format
3257# unit and the arguments necessary to represent those semantics
3258# properly. Hopefully with this approach we'll get it 100% right.
3259#
3260# The r() function (short for "register") both registers the
3261# mapping from arguments to format unit *and* registers the
3262# legacy C converter for that format unit.
3263#
3264def r(format_unit, *, accept, encoding=False, zeroes=False):
3265 if not encoding and format_unit != 's':
3266 # add the legacy c converters here too.
3267 #
3268 # note: add_legacy_c_converter can't work for
3269 # es, es#, et, or et#
3270 # because of their extra encoding argument
3271 #
3272 # also don't add the converter for 's' because
3273 # the metaclass for CConverter adds it for us.
3274 kwargs = {}
3275 if accept != {str}:
3276 kwargs['accept'] = accept
3277 if zeroes:
3278 kwargs['zeroes'] = True
3279 added_f = functools.partial(str_converter, **kwargs)
3280 legacy_converters[format_unit] = added_f
3281
3282 d = str_converter_argument_map
3283 key = str_converter_key(accept, encoding, zeroes)
3284 if key in d:
3285 sys.exit("Duplicate keys specified for str_converter_argument_map!")
3286 d[key] = format_unit
3287
3288r('es', encoding=True, accept={str})
3289r('es#', encoding=True, zeroes=True, accept={str})
3290r('et', encoding=True, accept={bytes, bytearray, str})
3291r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
3292r('s', accept={str})
3293r('s#', zeroes=True, accept={robuffer, str})
3294r('y', accept={robuffer})
3295r('y#', zeroes=True, accept={robuffer})
3296r('z', accept={str, NoneType})
3297r('z#', zeroes=True, accept={robuffer, str, NoneType})
3298del r
Larry Hastings31826802013-10-19 00:09:25 -07003299
3300
3301class PyBytesObject_converter(CConverter):
3302 type = 'PyBytesObject *'
3303 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003304 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07003305
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003306 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003307 if self.format_unit == 'S':
3308 return """
3309 if (!PyBytes_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003310 _PyArg_BadArgument("{{name}}", {argnum}, "bytes", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003311 goto exit;
3312 }}}}
3313 {paramname} = ({type}){argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003314 """.format(argname=argname, paramname=self.name, argnum=argnum,
3315 type=self.type)
3316 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003317
Larry Hastings31826802013-10-19 00:09:25 -07003318class PyByteArrayObject_converter(CConverter):
3319 type = 'PyByteArrayObject *'
3320 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003321 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07003322
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003323 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003324 if self.format_unit == 'Y':
3325 return """
3326 if (!PyByteArray_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003327 _PyArg_BadArgument("{{name}}", {argnum}, "bytearray", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003328 goto exit;
3329 }}}}
3330 {paramname} = ({type}){argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003331 """.format(argname=argname, paramname=self.name, argnum=argnum,
3332 type=self.type)
3333 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003334
Larry Hastings31826802013-10-19 00:09:25 -07003335class unicode_converter(CConverter):
3336 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003337 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003338 format_unit = 'U'
3339
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003340 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003341 if self.format_unit == 'U':
3342 return """
3343 if (!PyUnicode_Check({argname})) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003344 _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003345 goto exit;
3346 }}}}
3347 if (PyUnicode_READY({argname}) == -1) {{{{
3348 goto exit;
3349 }}}}
3350 {paramname} = {argname};
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003351 """.format(argname=argname, paramname=self.name, argnum=argnum)
3352 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003353
Larry Hastings38337d12015-05-07 23:30:09 -07003354@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003355@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07003356@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07003357class Py_UNICODE_converter(CConverter):
Serhiy Storchakaafb3e712018-12-14 11:19:51 +02003358 type = 'const Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003359 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003360 format_unit = 'u'
3361
Larry Hastings38337d12015-05-07 23:30:09 -07003362 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003363 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07003364 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003365 format_unit += '#'
3366 self.length = True
3367 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003368
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003369@add_legacy_c_converter('s*', accept={str, buffer})
3370@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
3371@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07003372class Py_buffer_converter(CConverter):
3373 type = 'Py_buffer'
3374 format_unit = 'y*'
3375 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08003376 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07003377
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003378 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08003379 if self.default not in (unspecified, None):
3380 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003381
Larry Hastings3f144c22014-01-06 10:34:00 -08003382 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08003383
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003384 if accept == {str, buffer, NoneType}:
3385 format_unit = 'z*'
3386 elif accept == {str, buffer}:
3387 format_unit = 's*'
3388 elif accept == {buffer}:
3389 format_unit = 'y*'
3390 elif accept == {rwbuffer}:
3391 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07003392 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003393 fail("Py_buffer_converter: illegal combination of arguments")
3394
3395 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003396
3397 def cleanup(self):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003398 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003399 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08003400
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003401 def parse_arg(self, argname, argnum):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003402 if self.format_unit == 'y*':
3403 return """
3404 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3405 goto exit;
3406 }}}}
3407 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003408 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003409 goto exit;
3410 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003411 """.format(argname=argname, paramname=self.name, argnum=argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003412 elif self.format_unit == 's*':
3413 return """
3414 if (PyUnicode_Check({argname})) {{{{
3415 Py_ssize_t len;
3416 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
3417 if (ptr == NULL) {{{{
3418 goto exit;
3419 }}}}
3420 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
3421 }}}}
3422 else {{{{ /* any bytes-like object */
3423 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3424 goto exit;
3425 }}}}
3426 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003427 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003428 goto exit;
3429 }}}}
3430 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003431 """.format(argname=argname, paramname=self.name, argnum=argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003432 elif self.format_unit == 'w*':
3433 return """
3434 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
3435 PyErr_Clear();
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003436 _PyArg_BadArgument("{{name}}", {argnum}, "read-write bytes-like object", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003437 goto exit;
3438 }}}}
3439 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003440 _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname});
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003441 goto exit;
3442 }}}}
Serhiy Storchaka4fa95912019-01-11 16:01:14 +02003443 """.format(argname=argname, paramname=self.name, argnum=argnum)
3444 return super().parse_arg(argname, argnum)
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003445
Larry Hastingsebdcb502013-11-23 14:54:00 -08003446
Larry Hastings5c661892014-01-24 06:17:25 -08003447def correct_name_for_self(f):
3448 if f.kind in (CALLABLE, METHOD_INIT):
3449 if f.cls:
3450 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03003451 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08003452 if f.kind == STATIC_METHOD:
3453 return "void *", "null"
3454 if f.kind in (CLASS_METHOD, METHOD_NEW):
3455 return "PyTypeObject *", "type"
3456 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
3457
Larry Hastingsc2047262014-01-25 20:43:29 -08003458def required_type_for_self_for_parser(f):
3459 type, _ = correct_name_for_self(f)
3460 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
3461 return type
3462 return None
3463
Larry Hastings5c661892014-01-24 06:17:25 -08003464
Larry Hastingsebdcb502013-11-23 14:54:00 -08003465class self_converter(CConverter):
3466 """
3467 A special-case converter:
3468 this is the default converter used for "self".
3469 """
Larry Hastings5c661892014-01-24 06:17:25 -08003470 type = None
3471 format_unit = ''
3472
Larry Hastings78cf85c2014-01-04 12:44:57 -08003473 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08003474 self.specified_type = type
3475
3476 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003477 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08003478 default_type, default_name = correct_name_for_self(f)
3479 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08003480 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08003481
Larry Hastings5c661892014-01-24 06:17:25 -08003482 kind = self.function.kind
3483 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
3484
3485 if (kind == STATIC_METHOD) or new_or_init:
3486 self.show_in_signature = False
3487
3488 # tp_new (METHOD_NEW) functions are of type newfunc:
3489 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
3490 # PyTypeObject is a typedef for struct _typeobject.
3491 #
3492 # tp_init (METHOD_INIT) functions are of type initproc:
3493 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
3494 #
3495 # All other functions generated by Argument Clinic are stored in
3496 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
3497 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
3498 # However! We habitually cast these functions to PyCFunction,
3499 # since functions that accept keyword arguments don't fit this signature
3500 # but are stored there anyway. So strict type equality isn't important
3501 # for these functions.
3502 #
3503 # So:
3504 #
3505 # * The name of the first parameter to the impl and the parsing function will always
3506 # be self.name.
3507 #
3508 # * The type of the first parameter to the impl will always be of self.type.
3509 #
3510 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
3511 # * The type of the first parameter to the parsing function is also self.type.
3512 # This means that if you step into the parsing function, your "self" parameter
3513 # is of the correct type, which may make debugging more pleasant.
3514 #
3515 # * Else if the function is tp_new (METHOD_NEW):
3516 # * The type of the first parameter to the parsing function is "PyTypeObject *",
3517 # so the type signature of the function call is an exact match.
3518 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
3519 # in the impl call.
3520 #
3521 # * Else if the function is tp_init (METHOD_INIT):
3522 # * The type of the first parameter to the parsing function is "PyObject *",
3523 # so the type signature of the function call is an exact match.
3524 # * If self.type != "PyObject *", we cast the first parameter to self.type
3525 # in the impl call.
3526
3527 @property
3528 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08003529 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08003530
Larry Hastingsebdcb502013-11-23 14:54:00 -08003531 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08003532 """
3533 parameter is a clinic.Parameter instance.
3534 data is a CRenderData instance.
3535 """
3536 if self.function.kind == STATIC_METHOD:
3537 return
3538
3539 self._render_self(parameter, data)
3540
3541 if self.type != self.parser_type:
3542 # insert cast to impl_argument[0], aka self.
3543 # we know we're in the first slot in all the CRenderData lists,
3544 # because we render parameters in order, and self is always first.
3545 assert len(data.impl_arguments) == 1
3546 assert data.impl_arguments[0] == self.name
3547 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3548
3549 def set_template_dict(self, template_dict):
3550 template_dict['self_name'] = self.name
3551 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003552 kind = self.function.kind
3553 cls = self.function.cls
3554
3555 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3556 if kind == METHOD_NEW:
3557 passed_in_type = self.name
3558 else:
3559 passed_in_type = 'Py_TYPE({})'.format(self.name)
3560
3561 line = '({passed_in_type} == {type_object}) &&\n '
3562 d = {
3563 'type_object': self.function.cls.type_object,
3564 'passed_in_type': passed_in_type
3565 }
3566 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003567
Larry Hastings31826802013-10-19 00:09:25 -07003568
3569
3570def add_c_return_converter(f, name=None):
3571 if not name:
3572 name = f.__name__
3573 if not name.endswith('_return_converter'):
3574 return f
3575 name = name[:-len('_return_converter')]
3576 return_converters[name] = f
3577 return f
3578
3579
3580class CReturnConverterAutoRegister(type):
3581 def __init__(cls, name, bases, classdict):
3582 add_c_return_converter(cls)
3583
3584class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3585
Larry Hastings78cf85c2014-01-04 12:44:57 -08003586 # The C type to use for this variable.
3587 # 'type' should be a Python string specifying the type, e.g. "int".
3588 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003589 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003590
3591 # The Python default value for this parameter, as a Python value.
3592 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003593 default = None
3594
Larry Hastings2a727912014-01-16 11:32:01 -08003595 def __init__(self, *, py_default=None, **kwargs):
3596 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003597 try:
3598 self.return_converter_init(**kwargs)
3599 except TypeError as e:
3600 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3601 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3602
3603 def return_converter_init(self):
3604 pass
3605
3606 def declare(self, data, name="_return_value"):
3607 line = []
3608 add = line.append
3609 add(self.type)
3610 if not self.type.endswith('*'):
3611 add(' ')
3612 add(name + ';')
3613 data.declarations.append(''.join(line))
3614 data.return_value = name
3615
3616 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003617 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003618
3619 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003620 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003621
3622 def render(self, function, data):
3623 """
3624 function is a clinic.Function instance.
3625 data is a CRenderData instance.
3626 """
3627 pass
3628
3629add_c_return_converter(CReturnConverter, 'object')
3630
Larry Hastings78cf85c2014-01-04 12:44:57 -08003631class NoneType_return_converter(CReturnConverter):
3632 def render(self, function, data):
3633 self.declare(data)
3634 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003635if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003636 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003637}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003638return_value = Py_None;
3639Py_INCREF(Py_None);
3640'''.strip())
3641
Larry Hastings4a55fc52014-01-12 11:09:57 -08003642class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003643 type = 'int'
3644
3645 def render(self, function, data):
3646 self.declare(data)
3647 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003648 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003649
3650class long_return_converter(CReturnConverter):
3651 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003652 conversion_fn = 'PyLong_FromLong'
3653 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003654 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003655
3656 def render(self, function, data):
3657 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003658 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003659 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003660 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003661
Larry Hastings4a55fc52014-01-12 11:09:57 -08003662class int_return_converter(long_return_converter):
3663 type = 'int'
3664 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003665
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003666class init_return_converter(long_return_converter):
3667 """
3668 Special return converter for __init__ functions.
3669 """
3670 type = 'int'
3671 cast = '(long)'
3672
3673 def render(self, function, data):
3674 pass
3675
Larry Hastings4a55fc52014-01-12 11:09:57 -08003676class unsigned_long_return_converter(long_return_converter):
3677 type = 'unsigned long'
3678 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003679 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003680
3681class unsigned_int_return_converter(unsigned_long_return_converter):
3682 type = 'unsigned int'
3683 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003684 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003685
3686class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003687 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003688 conversion_fn = 'PyLong_FromSsize_t'
3689
3690class size_t_return_converter(long_return_converter):
3691 type = 'size_t'
3692 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003693 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003694
3695
3696class double_return_converter(CReturnConverter):
3697 type = 'double'
3698 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003699
3700 def render(self, function, data):
3701 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003702 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003703 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003704 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3705
3706class float_return_converter(double_return_converter):
3707 type = 'float'
3708 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003709
3710
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003711def eval_ast_expr(node, globals, *, filename='-'):
3712 """
3713 Takes an ast.Expr node. Compiles and evaluates it.
3714 Returns the result of the expression.
3715
3716 globals represents the globals dict the expression
3717 should see. (There's no equivalent for "locals" here.)
3718 """
3719
3720 if isinstance(node, ast.Expr):
3721 node = node.value
3722
3723 node = ast.Expression(node)
3724 co = compile(node, filename, 'eval')
3725 fn = types.FunctionType(co, globals)
3726 return fn()
3727
3728
Larry Hastings31826802013-10-19 00:09:25 -07003729class IndentStack:
3730 def __init__(self):
3731 self.indents = []
3732 self.margin = None
3733
3734 def _ensure(self):
3735 if not self.indents:
3736 fail('IndentStack expected indents, but none are defined.')
3737
3738 def measure(self, line):
3739 """
3740 Returns the length of the line's margin.
3741 """
3742 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003743 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003744 stripped = line.lstrip()
3745 if not len(stripped):
3746 # we can't tell anything from an empty line
3747 # so just pretend it's indented like our current indent
3748 self._ensure()
3749 return self.indents[-1]
3750 return len(line) - len(stripped)
3751
3752 def infer(self, line):
3753 """
3754 Infer what is now the current margin based on this line.
3755 Returns:
3756 1 if we have indented (or this is the first margin)
3757 0 if the margin has not changed
3758 -N if we have dedented N times
3759 """
3760 indent = self.measure(line)
3761 margin = ' ' * indent
3762 if not self.indents:
3763 self.indents.append(indent)
3764 self.margin = margin
3765 return 1
3766 current = self.indents[-1]
3767 if indent == current:
3768 return 0
3769 if indent > current:
3770 self.indents.append(indent)
3771 self.margin = margin
3772 return 1
3773 # indent < current
3774 if indent not in self.indents:
3775 fail("Illegal outdent.")
3776 outdent_count = 0
3777 while indent != current:
3778 self.indents.pop()
3779 current = self.indents[-1]
3780 outdent_count -= 1
3781 self.margin = margin
3782 return outdent_count
3783
3784 @property
3785 def depth(self):
3786 """
3787 Returns how many margins are currently defined.
3788 """
3789 return len(self.indents)
3790
3791 def indent(self, line):
3792 """
3793 Indents a line by the currently defined margin.
3794 """
3795 return self.margin + line
3796
3797 def dedent(self, line):
3798 """
3799 Dedents a line by the currently defined margin.
3800 (The inverse of 'indent'.)
3801 """
3802 margin = self.margin
3803 indent = self.indents[-1]
3804 if not line.startswith(margin):
3805 fail('Cannot dedent, line does not start with the previous margin:')
3806 return line[indent:]
3807
3808
3809class DSLParser:
3810 def __init__(self, clinic):
3811 self.clinic = clinic
3812
3813 self.directives = {}
3814 for name in dir(self):
3815 # functions that start with directive_ are added to directives
3816 _, s, key = name.partition("directive_")
3817 if s:
3818 self.directives[key] = getattr(self, name)
3819
3820 # functions that start with at_ are too, with an @ in front
3821 _, s, key = name.partition("at_")
3822 if s:
3823 self.directives['@' + key] = getattr(self, name)
3824
3825 self.reset()
3826
3827 def reset(self):
3828 self.function = None
3829 self.state = self.state_dsl_start
3830 self.parameter_indent = None
3831 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003832 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003833 self.group = 0
3834 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003835 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003836 self.indent = IndentStack()
3837 self.kind = CALLABLE
3838 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003839 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003840 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003841
Larry Hastingsebdcb502013-11-23 14:54:00 -08003842 def directive_version(self, required):
3843 global version
3844 if version_comparitor(version, required) < 0:
3845 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3846
Larry Hastings31826802013-10-19 00:09:25 -07003847 def directive_module(self, name):
3848 fields = name.split('.')
3849 new = fields.pop()
3850 module, cls = self.clinic._module_and_class(fields)
3851 if cls:
3852 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003853
3854 if name in module.classes:
3855 fail("Already defined module " + repr(name) + "!")
3856
Larry Hastings31826802013-10-19 00:09:25 -07003857 m = Module(name, module)
3858 module.modules[name] = m
3859 self.block.signatures.append(m)
3860
Larry Hastingsc2047262014-01-25 20:43:29 -08003861 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003862 fields = name.split('.')
3863 in_classes = False
3864 parent = self
3865 name = fields.pop()
3866 so_far = []
3867 module, cls = self.clinic._module_and_class(fields)
3868
Larry Hastingsc2047262014-01-25 20:43:29 -08003869 parent = cls or module
3870 if name in parent.classes:
3871 fail("Already defined class " + repr(name) + "!")
3872
3873 c = Class(name, module, cls, typedef, type_object)
3874 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003875 self.block.signatures.append(c)
3876
Larry Hastingsbebf7352014-01-17 17:47:17 -08003877 def directive_set(self, name, value):
3878 if name not in ("line_prefix", "line_suffix"):
3879 fail("unknown variable", repr(name))
3880
3881 value = value.format_map({
3882 'block comment start': '/*',
3883 'block comment end': '*/',
3884 })
3885
3886 self.clinic.__dict__[name] = value
3887
3888 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003889 if command == 'new':
3890 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003891 return
3892
Zachary Ware071baa62014-01-21 23:07:12 -06003893 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003894 self.clinic.get_destination(name).clear()
3895 fail("unknown destination command", repr(command))
3896
3897
Larry Hastings0759f842015-04-03 13:09:02 -07003898 def directive_output(self, command_or_name, destination=''):
3899 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003900
Larry Hastings0759f842015-04-03 13:09:02 -07003901 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003902 preset = self.clinic.presets.get(destination)
3903 if not preset:
3904 fail("Unknown preset " + repr(destination) + "!")
3905 fd.update(preset)
3906 return
3907
Larry Hastings0759f842015-04-03 13:09:02 -07003908 if command_or_name == "push":
3909 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003910 return
3911
Larry Hastings0759f842015-04-03 13:09:02 -07003912 if command_or_name == "pop":
3913 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003914 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003915 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003916 fd.update(previous_fd)
3917 return
3918
3919 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003920 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003921 self.block.output.append(pprint.pformat(fd))
3922 self.block.output.append('\n')
3923 return
3924
3925 d = self.clinic.get_destination(destination)
3926
Larry Hastings0759f842015-04-03 13:09:02 -07003927 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003928 for name in list(fd):
3929 fd[name] = d
3930 return
3931
Larry Hastings0759f842015-04-03 13:09:02 -07003932 if command_or_name not in fd:
3933 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3934 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003935
3936 def directive_dump(self, name):
3937 self.block.output.append(self.clinic.get_destination(name).dump())
3938
3939 def directive_print(self, *args):
3940 self.block.output.append(' '.join(args))
3941 self.block.output.append('\n')
3942
3943 def directive_preserve(self):
3944 if self.preserve_output:
3945 fail("Can't have preserve twice in one block!")
3946 self.preserve_output = True
3947
Larry Hastings31826802013-10-19 00:09:25 -07003948 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003949 if self.kind is not CALLABLE:
3950 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003951 self.kind = CLASS_METHOD
3952
3953 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003954 if self.kind is not CALLABLE:
3955 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003956 self.kind = STATIC_METHOD
3957
3958 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003959 if self.coexist:
3960 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003961 self.coexist = True
3962
3963 def parse(self, block):
3964 self.reset()
3965 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003966 self.saved_output = self.block.output
3967 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003968 block_start = self.clinic.block_parser.line_number
3969 lines = block.input.split('\n')
3970 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3971 if '\t' in line:
3972 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3973 self.state(line)
3974
3975 self.next(self.state_terminal)
3976 self.state(None)
3977
Larry Hastingsbebf7352014-01-17 17:47:17 -08003978 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3979
3980 if self.preserve_output:
3981 if block.output:
3982 fail("'preserve' only works for blocks that don't produce any output!")
3983 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003984
3985 @staticmethod
3986 def ignore_line(line):
3987 # ignore comment-only lines
3988 if line.lstrip().startswith('#'):
3989 return True
3990
3991 # Ignore empty lines too
3992 # (but not in docstring sections!)
3993 if not line.strip():
3994 return True
3995
3996 return False
3997
3998 @staticmethod
3999 def calculate_indent(line):
4000 return len(line) - len(line.strip())
4001
4002 def next(self, state, line=None):
4003 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
4004 self.state = state
4005 if line is not None:
4006 self.state(line)
4007
4008 def state_dsl_start(self, line):
4009 # self.block = self.ClinicOutputBlock(self)
4010 if self.ignore_line(line):
4011 return
Larry Hastings7726ac92014-01-31 22:03:12 -08004012
4013 # is it a directive?
4014 fields = shlex.split(line)
4015 directive_name = fields[0]
4016 directive = self.directives.get(directive_name, None)
4017 if directive:
4018 try:
4019 directive(*fields[1:])
4020 except TypeError as e:
4021 fail(str(e))
4022 return
4023
Larry Hastings31826802013-10-19 00:09:25 -07004024 self.next(self.state_modulename_name, line)
4025
4026 def state_modulename_name(self, line):
4027 # looking for declaration, which establishes the leftmost column
4028 # line should be
4029 # modulename.fnname [as c_basename] [-> return annotation]
4030 # square brackets denote optional syntax.
4031 #
Larry Hastings4a714d42014-01-14 22:22:41 -08004032 # alternatively:
4033 # modulename.fnname [as c_basename] = modulename.existing_fn_name
4034 # clones the parameters and return converter from that
4035 # function. you can't modify them. you must enter a
4036 # new docstring.
4037 #
Larry Hastings31826802013-10-19 00:09:25 -07004038 # (but we might find a directive first!)
4039 #
4040 # this line is permitted to start with whitespace.
4041 # we'll call this number of spaces F (for "function").
4042
4043 if not line.strip():
4044 return
4045
4046 self.indent.infer(line)
4047
Larry Hastings4a714d42014-01-14 22:22:41 -08004048 # are we cloning?
4049 before, equals, existing = line.rpartition('=')
4050 if equals:
4051 full_name, _, c_basename = before.partition(' as ')
4052 full_name = full_name.strip()
4053 c_basename = c_basename.strip()
4054 existing = existing.strip()
4055 if (is_legal_py_identifier(full_name) and
4056 (not c_basename or is_legal_c_identifier(c_basename)) and
4057 is_legal_py_identifier(existing)):
4058 # we're cloning!
4059 fields = [x.strip() for x in existing.split('.')]
4060 function_name = fields.pop()
4061 module, cls = self.clinic._module_and_class(fields)
4062
4063 for existing_function in (cls or module).functions:
4064 if existing_function.name == function_name:
4065 break
4066 else:
4067 existing_function = None
4068 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08004069 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08004070 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08004071 fail("Couldn't find existing function " + repr(existing) + "!")
4072
4073 fields = [x.strip() for x in full_name.split('.')]
4074 function_name = fields.pop()
4075 module, cls = self.clinic._module_and_class(fields)
4076
4077 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
4078 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08004079 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 -08004080
4081 self.block.signatures.append(self.function)
4082 (cls or module).functions.append(self.function)
4083 self.next(self.state_function_docstring)
4084 return
4085
Larry Hastings31826802013-10-19 00:09:25 -07004086 line, _, returns = line.partition('->')
4087
4088 full_name, _, c_basename = line.partition(' as ')
4089 full_name = full_name.strip()
4090 c_basename = c_basename.strip() or None
4091
Larry Hastingsdfcd4672013-10-27 02:49:39 -07004092 if not is_legal_py_identifier(full_name):
4093 fail("Illegal function name: {}".format(full_name))
4094 if c_basename and not is_legal_c_identifier(c_basename):
4095 fail("Illegal C basename: {}".format(c_basename))
4096
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004097 return_converter = None
4098 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07004099 ast_input = "def x() -> {}: pass".format(returns)
4100 module = None
4101 try:
4102 module = ast.parse(ast_input)
4103 except SyntaxError:
4104 pass
4105 if not module:
4106 fail("Badly-formed annotation for " + full_name + ": " + returns)
4107 try:
4108 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004109 if legacy:
4110 fail("Legacy converter {!r} not allowed as a return converter"
4111 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07004112 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01004113 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07004114 return_converter = return_converters[name](**kwargs)
4115 except ValueError:
4116 fail("Badly-formed annotation for " + full_name + ": " + returns)
4117
4118 fields = [x.strip() for x in full_name.split('.')]
4119 function_name = fields.pop()
4120 module, cls = self.clinic._module_and_class(fields)
4121
Larry Hastings8666e652014-01-12 14:12:59 -08004122 fields = full_name.split('.')
4123 if fields[-1] == '__new__':
4124 if (self.kind != CLASS_METHOD) or (not cls):
4125 fail("__new__ must be a class method!")
4126 self.kind = METHOD_NEW
4127 elif fields[-1] == '__init__':
4128 if (self.kind != CALLABLE) or (not cls):
4129 fail("__init__ must be a normal method, not a class or static method!")
4130 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004131 if not return_converter:
4132 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08004133 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08004134 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08004135
Larry Hastingsb7ccb202014-01-18 23:50:21 -08004136 if not return_converter:
4137 return_converter = CReturnConverter()
4138
Larry Hastings31826802013-10-19 00:09:25 -07004139 if not module:
4140 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
4141 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
4142 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
4143 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08004144
4145 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08004146 type, name = correct_name_for_self(self.function)
4147 kwargs = {}
4148 if cls and type == "PyObject *":
4149 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08004150 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08004151 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
4152 self.function.parameters[sc.name] = p_self
4153
Larry Hastings4a714d42014-01-14 22:22:41 -08004154 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07004155 self.next(self.state_parameters_start)
4156
4157 # Now entering the parameters section. The rules, formally stated:
4158 #
4159 # * All lines must be indented with spaces only.
4160 # * The first line must be a parameter declaration.
4161 # * The first line must be indented.
4162 # * This first line establishes the indent for parameters.
4163 # * We'll call this number of spaces P (for "parameter").
4164 # * Thenceforth:
4165 # * Lines indented with P spaces specify a parameter.
4166 # * Lines indented with > P spaces are docstrings for the previous
4167 # parameter.
4168 # * We'll call this number of spaces D (for "docstring").
4169 # * All subsequent lines indented with >= D spaces are stored as
4170 # part of the per-parameter docstring.
4171 # * All lines will have the first D spaces of the indent stripped
4172 # before they are stored.
4173 # * It's illegal to have a line starting with a number of spaces X
4174 # such that P < X < D.
4175 # * A line with < P spaces is the first line of the function
4176 # docstring, which ends processing for parameters and per-parameter
4177 # docstrings.
4178 # * The first line of the function docstring must be at the same
4179 # indent as the function declaration.
4180 # * It's illegal to have any line in the parameters section starting
4181 # with X spaces such that F < X < P. (As before, F is the indent
4182 # of the function declaration.)
4183 #
Larry Hastings31826802013-10-19 00:09:25 -07004184 # Also, currently Argument Clinic places the following restrictions on groups:
4185 # * Each group must contain at least one parameter.
4186 # * Each group may contain at most one group, which must be the furthest
4187 # thing in the group from the required parameters. (The nested group
4188 # must be the first in the group when it's before the required
4189 # parameters, and the last thing in the group when after the required
4190 # parameters.)
4191 # * There may be at most one (top-level) group to the left or right of
4192 # the required parameters.
4193 # * You must specify a slash, and it must be after all parameters.
4194 # (In other words: either all parameters are positional-only,
4195 # or none are.)
4196 #
4197 # Said another way:
4198 # * Each group must contain at least one parameter.
4199 # * All left square brackets before the required parameters must be
4200 # consecutive. (You can't have a left square bracket followed
4201 # by a parameter, then another left square bracket. You can't
4202 # have a left square bracket, a parameter, a right square bracket,
4203 # and then a left square bracket.)
4204 # * All right square brackets after the required parameters must be
4205 # consecutive.
4206 #
4207 # These rules are enforced with a single state variable:
4208 # "parameter_state". (Previously the code was a miasma of ifs and
4209 # separate boolean state variables.) The states are:
4210 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004211 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4212 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07004213 #
4214 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4215 # 1: ps_left_square_before. left square brackets before required parameters.
4216 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08004217 # 3: ps_required. required parameters, positional-or-keyword or positional-only
4218 # (we don't know yet). (renumber left groups!)
4219 # 4: ps_optional. positional-or-keyword or positional-only parameters that
4220 # now must have default values.
4221 # 5: ps_group_after. in a group, after required parameters.
4222 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07004223 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004224 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07004225
4226 def state_parameters_start(self, line):
4227 if self.ignore_line(line):
4228 return
4229
4230 # if this line is not indented, we have no parameters
4231 if not self.indent.infer(line):
4232 return self.next(self.state_function_docstring, line)
4233
Larry Hastings2a727912014-01-16 11:32:01 -08004234 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07004235 return self.next(self.state_parameter, line)
4236
4237
4238 def to_required(self):
4239 """
4240 Transition to the "required" parameter state.
4241 """
4242 if self.parameter_state != self.ps_required:
4243 self.parameter_state = self.ps_required
4244 for p in self.function.parameters.values():
4245 p.group = -p.group
4246
4247 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08004248 if self.parameter_continuation:
4249 line = self.parameter_continuation + ' ' + line.lstrip()
4250 self.parameter_continuation = ''
4251
Larry Hastings31826802013-10-19 00:09:25 -07004252 if self.ignore_line(line):
4253 return
4254
4255 assert self.indent.depth == 2
4256 indent = self.indent.infer(line)
4257 if indent == -1:
4258 # we outdented, must be to definition column
4259 return self.next(self.state_function_docstring, line)
4260
4261 if indent == 1:
4262 # we indented, must be to new parameter docstring column
4263 return self.next(self.state_parameter_docstring_start, line)
4264
Larry Hastings2a727912014-01-16 11:32:01 -08004265 line = line.rstrip()
4266 if line.endswith('\\'):
4267 self.parameter_continuation = line[:-1]
4268 return
4269
Larry Hastings31826802013-10-19 00:09:25 -07004270 line = line.lstrip()
4271
4272 if line in ('*', '/', '[', ']'):
4273 self.parse_special_symbol(line)
4274 return
4275
4276 if self.parameter_state in (self.ps_start, self.ps_required):
4277 self.to_required()
4278 elif self.parameter_state == self.ps_left_square_before:
4279 self.parameter_state = self.ps_group_before
4280 elif self.parameter_state == self.ps_group_before:
4281 if not self.group:
4282 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08004283 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07004284 pass
4285 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004286 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07004287
Larry Hastings7726ac92014-01-31 22:03:12 -08004288 # handle "as" for parameters too
4289 c_name = None
4290 name, have_as_token, trailing = line.partition(' as ')
4291 if have_as_token:
4292 name = name.strip()
4293 if ' ' not in name:
4294 fields = trailing.strip().split(' ')
4295 if not fields:
4296 fail("Invalid 'as' clause!")
4297 c_name = fields[0]
4298 if c_name.endswith(':'):
4299 name += ':'
4300 c_name = c_name[:-1]
4301 fields[0] = name
4302 line = ' '.join(fields)
4303
Larry Hastings2a727912014-01-16 11:32:01 -08004304 base, equals, default = line.rpartition('=')
4305 if not equals:
4306 base = default
4307 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08004308
Larry Hastings31826802013-10-19 00:09:25 -07004309 module = None
4310 try:
Larry Hastings2a727912014-01-16 11:32:01 -08004311 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07004312 module = ast.parse(ast_input)
4313 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08004314 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08004315 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004316 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08004317 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08004318 default = None
4319 ast_input = "def x({}): pass".format(line)
4320 module = ast.parse(ast_input)
4321 except SyntaxError:
4322 pass
Larry Hastings31826802013-10-19 00:09:25 -07004323 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07004324 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07004325
4326 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004327
4328 if len(function_args.args) > 1:
4329 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
4330 if function_args.defaults or function_args.kw_defaults:
4331 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
4332 if function_args.vararg or function_args.kwarg:
4333 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
4334
Larry Hastings31826802013-10-19 00:09:25 -07004335 parameter = function_args.args[0]
4336
Larry Hastings16c51912014-01-07 11:53:01 -08004337 parameter_name = parameter.arg
4338 name, legacy, kwargs = self.parse_converter(parameter.annotation)
4339
Larry Hastings2a727912014-01-16 11:32:01 -08004340 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08004341 if self.parameter_state == self.ps_optional:
4342 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 -08004343 value = unspecified
4344 if 'py_default' in kwargs:
4345 fail("You can't specify py_default without specifying a default value!")
4346 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004347 if self.parameter_state == self.ps_required:
4348 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08004349 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06004350 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004351 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08004352 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004353 try:
4354 module = ast.parse(ast_input)
4355
Larry Hastings5c661892014-01-24 06:17:25 -08004356 if 'c_default' not in kwargs:
4357 # we can only represent very simple data values in C.
4358 # detect whether default is okay, via a blacklist
4359 # of disallowed ast nodes.
4360 class DetectBadNodes(ast.NodeVisitor):
4361 bad = False
4362 def bad_node(self, node):
4363 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08004364
Larry Hastings5c661892014-01-24 06:17:25 -08004365 # inline function call
4366 visit_Call = bad_node
4367 # inline if statement ("x = 3 if y else z")
4368 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004369
Larry Hastings5c661892014-01-24 06:17:25 -08004370 # comprehensions and generator expressions
4371 visit_ListComp = visit_SetComp = bad_node
4372 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004373
Larry Hastings5c661892014-01-24 06:17:25 -08004374 # literals for advanced types
4375 visit_Dict = visit_Set = bad_node
4376 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004377
Larry Hastings5c661892014-01-24 06:17:25 -08004378 # "starred": "a = [1, 2, 3]; *a"
4379 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004380
Larry Hastings5c661892014-01-24 06:17:25 -08004381 blacklist = DetectBadNodes()
4382 blacklist.visit(module)
4383 bad = blacklist.bad
4384 else:
4385 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06004386 # but at least make an attempt at ensuring it's a valid expression.
4387 try:
4388 value = eval(default)
4389 if value == unspecified:
4390 fail("'unspecified' is not a legal default value!")
4391 except NameError:
4392 pass # probably a named constant
4393 except Exception as e:
4394 fail("Malformed expression given as default value\n"
4395 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08004396 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08004397 fail("Unsupported expression as default value: " + repr(default))
4398
4399 expr = module.body[0].value
4400 # mild hack: explicitly support NULL as a default value
4401 if isinstance(expr, ast.Name) and expr.id == 'NULL':
4402 value = NULL
4403 py_default = 'None'
4404 c_default = "NULL"
4405 elif (isinstance(expr, ast.BinOp) or
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004406 (isinstance(expr, ast.UnaryOp) and
4407 not (isinstance(expr.operand, ast.Num) or
4408 (hasattr(ast, 'Constant') and
4409 isinstance(expr.operand, ast.Constant) and
4410 type(expr.operand.value) in (int, float, complex)))
4411 )):
Larry Hastings2a727912014-01-16 11:32:01 -08004412 c_default = kwargs.get("c_default")
4413 if not (isinstance(c_default, str) and c_default):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004414 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 -08004415 py_default = default
4416 value = unknown
4417 elif isinstance(expr, ast.Attribute):
4418 a = []
4419 n = expr
4420 while isinstance(n, ast.Attribute):
4421 a.append(n.attr)
4422 n = n.value
4423 if not isinstance(n, ast.Name):
4424 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
4425 a.append(n.id)
4426 py_default = ".".join(reversed(a))
4427
4428 c_default = kwargs.get("c_default")
4429 if not (isinstance(c_default, str) and c_default):
4430 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4431
4432 try:
4433 value = eval(py_default)
4434 except NameError:
4435 value = unknown
4436 else:
4437 value = ast.literal_eval(expr)
4438 py_default = repr(value)
4439 if isinstance(value, (bool, None.__class__)):
4440 c_default = "Py_" + py_default
4441 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08004442 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08004443 else:
4444 c_default = py_default
4445
4446 except SyntaxError as e:
4447 fail("Syntax error: " + repr(e.text))
4448 except (ValueError, AttributeError):
4449 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08004450 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08004451 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08004452 if not (isinstance(c_default, str) and c_default):
4453 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4454
Larry Hastings2a727912014-01-16 11:32:01 -08004455 kwargs.setdefault('c_default', c_default)
4456 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004457
Larry Hastings31826802013-10-19 00:09:25 -07004458 dict = legacy_converters if legacy else converters
4459 legacy_str = "legacy " if legacy else ""
4460 if name not in dict:
4461 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08004462 # if you use a c_name for the parameter, we just give that name to the converter
4463 # but the parameter object gets the python name
4464 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07004465
4466 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08004467
4468 if isinstance(converter, self_converter):
4469 if len(self.function.parameters) == 1:
4470 if (self.parameter_state != self.ps_required):
4471 fail("A 'self' parameter cannot be marked optional.")
4472 if value is not unspecified:
4473 fail("A 'self' parameter cannot have a default value.")
4474 if self.group:
4475 fail("A 'self' parameter cannot be in an optional group.")
4476 kind = inspect.Parameter.POSITIONAL_ONLY
4477 self.parameter_state = self.ps_start
4478 self.function.parameters.clear()
4479 else:
4480 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
4481
Larry Hastings31826802013-10-19 00:09:25 -07004482 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08004483
4484 if parameter_name in self.function.parameters:
4485 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07004486 self.function.parameters[parameter_name] = p
4487
4488 def parse_converter(self, annotation):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004489 if (hasattr(ast, 'Constant') and
4490 isinstance(annotation, ast.Constant) and
4491 type(annotation.value) is str):
4492 return annotation.value, True, {}
4493
Larry Hastings31826802013-10-19 00:09:25 -07004494 if isinstance(annotation, ast.Str):
4495 return annotation.s, True, {}
4496
4497 if isinstance(annotation, ast.Name):
4498 return annotation.id, False, {}
4499
Larry Hastings4a55fc52014-01-12 11:09:57 -08004500 if not isinstance(annotation, ast.Call):
4501 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07004502
4503 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004504 symbols = globals()
4505
4506 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07004507 return name, False, kwargs
4508
4509 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07004510 if symbol == '*':
4511 if self.keyword_only:
4512 fail("Function " + self.function.name + " uses '*' more than once.")
4513 self.keyword_only = True
4514 elif symbol == '[':
4515 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
4516 self.parameter_state = self.ps_left_square_before
4517 elif self.parameter_state in (self.ps_required, self.ps_group_after):
4518 self.parameter_state = self.ps_group_after
4519 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004520 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07004521 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08004522 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07004523 elif symbol == ']':
4524 if not self.group:
4525 fail("Function " + self.function.name + " has a ] without a matching [.")
4526 if not any(p.group == self.group for p in self.function.parameters.values()):
4527 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
4528 self.group -= 1
4529 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
4530 self.parameter_state = self.ps_group_before
4531 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
4532 self.parameter_state = self.ps_right_square_after
4533 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004534 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07004535 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004536 if self.positional_only:
4537 fail("Function " + self.function.name + " uses '/' more than once.")
4538 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08004539 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07004540 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08004541 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
4542 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07004543 if self.keyword_only:
4544 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004545 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004546 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004547 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004548 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4549 p.kind = inspect.Parameter.POSITIONAL_ONLY
4550
4551 def state_parameter_docstring_start(self, line):
4552 self.parameter_docstring_indent = len(self.indent.margin)
4553 assert self.indent.depth == 3
4554 return self.next(self.state_parameter_docstring, line)
4555
4556 # every line of the docstring must start with at least F spaces,
4557 # where F > P.
4558 # these F spaces will be stripped.
4559 def state_parameter_docstring(self, line):
4560 stripped = line.strip()
4561 if stripped.startswith('#'):
4562 return
4563
4564 indent = self.indent.measure(line)
4565 if indent < self.parameter_docstring_indent:
4566 self.indent.infer(line)
4567 assert self.indent.depth < 3
4568 if self.indent.depth == 2:
4569 # back to a parameter
4570 return self.next(self.state_parameter, line)
4571 assert self.indent.depth == 1
4572 return self.next(self.state_function_docstring, line)
4573
4574 assert self.function.parameters
4575 last_parameter = next(reversed(list(self.function.parameters.values())))
4576
4577 new_docstring = last_parameter.docstring
4578
4579 if new_docstring:
4580 new_docstring += '\n'
4581 if stripped:
4582 new_docstring += self.indent.dedent(line)
4583
4584 last_parameter.docstring = new_docstring
4585
4586 # the final stanza of the DSL is the docstring.
4587 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004588 if self.group:
4589 fail("Function " + self.function.name + " has a ] without a matching [.")
4590
4591 stripped = line.strip()
4592 if stripped.startswith('#'):
4593 return
4594
4595 new_docstring = self.function.docstring
4596 if new_docstring:
4597 new_docstring += "\n"
4598 if stripped:
4599 line = self.indent.dedent(line).rstrip()
4600 else:
4601 line = ''
4602 new_docstring += line
4603 self.function.docstring = new_docstring
4604
4605 def format_docstring(self):
4606 f = self.function
4607
Larry Hastings5c661892014-01-24 06:17:25 -08004608 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4609 if new_or_init and not f.docstring:
4610 # don't render a docstring at all, no signature, nothing.
4611 return f.docstring
4612
Larry Hastings2623c8c2014-02-08 22:15:29 -08004613 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004614 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004615
4616 ##
4617 ## docstring first line
4618 ##
4619
Larry Hastings2623c8c2014-02-08 22:15:29 -08004620 if new_or_init:
4621 # classes get *just* the name of the class
4622 # not __new__, not __init__, and not module.classname
4623 assert f.cls
4624 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004625 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004626 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004627 add('(')
4628
4629 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004630 assert parameters, "We should always have a self parameter. " + repr(f)
4631 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004632 # self is always positional-only.
4633 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004634 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004635 positional_only = True
4636 for p in parameters[1:]:
4637 if not p.is_positional_only():
4638 positional_only = False
4639 else:
4640 assert positional_only
4641 if positional_only:
4642 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004643 else:
4644 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004645 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004646
4647 right_bracket_count = 0
4648
4649 def fix_right_bracket_count(desired):
4650 nonlocal right_bracket_count
4651 s = ''
4652 while right_bracket_count < desired:
4653 s += '['
4654 right_bracket_count += 1
4655 while right_bracket_count > desired:
4656 s += ']'
4657 right_bracket_count -= 1
4658 return s
4659
Larry Hastings2623c8c2014-02-08 22:15:29 -08004660 need_slash = False
4661 added_slash = False
4662 need_a_trailing_slash = False
4663
4664 # we only need a trailing slash:
4665 # * if this is not a "docstring_only" signature
4666 # * and if the last *shown* parameter is
4667 # positional only
4668 if not f.docstring_only:
4669 for p in reversed(parameters):
4670 if not p.converter.show_in_signature:
4671 continue
4672 if p.is_positional_only():
4673 need_a_trailing_slash = True
4674 break
4675
4676
Larry Hastings31826802013-10-19 00:09:25 -07004677 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004678
4679 first_parameter = True
4680 last_p = parameters[-1]
4681 line_length = len(''.join(text))
4682 indent = " " * line_length
4683 def add_parameter(text):
4684 nonlocal line_length
4685 nonlocal first_parameter
4686 if first_parameter:
4687 s = text
4688 first_parameter = False
4689 else:
4690 s = ' ' + text
4691 if line_length + len(s) >= 72:
4692 add('\n')
4693 add(indent)
4694 line_length = len(indent)
4695 s = text
4696 line_length += len(s)
4697 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004698
4699 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004700 if not p.converter.show_in_signature:
4701 continue
Larry Hastings31826802013-10-19 00:09:25 -07004702 assert p.name
4703
Larry Hastings2623c8c2014-02-08 22:15:29 -08004704 is_self = isinstance(p.converter, self_converter)
4705 if is_self and f.docstring_only:
4706 # this isn't a real machine-parsable signature,
4707 # so let's not print the "self" parameter
4708 continue
4709
4710 if p.is_positional_only():
4711 need_slash = not f.docstring_only
4712 elif need_slash and not (added_slash or p.is_positional_only()):
4713 added_slash = True
4714 add_parameter('/,')
4715
Larry Hastings31826802013-10-19 00:09:25 -07004716 if p.is_keyword_only() and not added_star:
4717 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004718 add_parameter('*,')
4719
4720 p_add, p_output = text_accumulator()
4721 p_add(fix_right_bracket_count(p.right_bracket_count))
4722
4723 if isinstance(p.converter, self_converter):
4724 # annotate first parameter as being a "self".
4725 #
4726 # if inspect.Signature gets this function,
4727 # and it's already bound, the self parameter
4728 # will be stripped off.
4729 #
4730 # if it's not bound, it should be marked
4731 # as positional-only.
4732 #
4733 # note: we don't print "self" for __init__,
4734 # because this isn't actually the signature
4735 # for __init__. (it can't be, __init__ doesn't
4736 # have a docstring.) if this is an __init__
4737 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004738 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004739 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004740
Larry Hastings5c661892014-01-24 06:17:25 -08004741 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004742 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004743
Larry Hastings31826802013-10-19 00:09:25 -07004744 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004745 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004746 value = p.converter.py_default
4747 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004748 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004749 p_add(value)
4750
4751 if (p != last_p) or need_a_trailing_slash:
4752 p_add(',')
4753
4754 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004755
4756 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004757 if need_a_trailing_slash:
4758 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004759 add(')')
4760
Larry Hastings2a727912014-01-16 11:32:01 -08004761 # PEP 8 says:
4762 #
4763 # The Python standard library will not use function annotations
4764 # as that would result in a premature commitment to a particular
4765 # annotation style. Instead, the annotations are left for users
4766 # to discover and experiment with useful annotation styles.
4767 #
4768 # therefore this is commented out:
4769 #
4770 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004771 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004772 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004773
Larry Hastings2623c8c2014-02-08 22:15:29 -08004774 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004775 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004776
Larry Hastings31826802013-10-19 00:09:25 -07004777 docstring_first_line = output()
4778
4779 # now fix up the places where the brackets look wrong
4780 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4781
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004782 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004783 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004784 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004785 for p in parameters:
4786 if not p.docstring.strip():
4787 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004788 if spacer_line:
4789 add('\n')
4790 else:
4791 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004792 add(" ")
4793 add(p.name)
4794 add('\n')
4795 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004796 parameters = output()
4797 if parameters:
4798 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004799
4800 ##
4801 ## docstring body
4802 ##
4803
4804 docstring = f.docstring.rstrip()
4805 lines = [line.rstrip() for line in docstring.split('\n')]
4806
4807 # Enforce the summary line!
4808 # The first line of a docstring should be a summary of the function.
4809 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4810 # by itself.
4811 #
4812 # Argument Clinic enforces the following rule:
4813 # * either the docstring is empty,
4814 # * or it must have a summary line.
4815 #
4816 # Guido said Clinic should enforce this:
4817 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4818
4819 if len(lines) >= 2:
4820 if lines[1]:
4821 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4822 "Every non-blank function docstring must start with\n" +
4823 "a single line summary followed by an empty line.")
4824 elif len(lines) == 1:
4825 # the docstring is only one line right now--the summary line.
4826 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004827 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004828 lines.append('')
4829
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004830 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4831 if parameters_marker_count > 1:
4832 fail('You may not specify {parameters} more than once in a docstring!')
4833
4834 if not parameters_marker_count:
4835 # insert after summary line
4836 lines.insert(2, '{parameters}')
4837
4838 # insert at front of docstring
4839 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004840
4841 docstring = "\n".join(lines)
4842
4843 add(docstring)
4844 docstring = output()
4845
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004846 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004847 docstring = docstring.rstrip()
4848
4849 return docstring
4850
4851 def state_terminal(self, line):
4852 """
4853 Called when processing the block is done.
4854 """
4855 assert not line
4856
4857 if not self.function:
4858 return
4859
4860 if self.keyword_only:
4861 values = self.function.parameters.values()
4862 if not values:
4863 no_parameter_after_star = True
4864 else:
4865 last_parameter = next(reversed(list(values)))
4866 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4867 if no_parameter_after_star:
4868 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4869
4870 # remove trailing whitespace from all parameter docstrings
4871 for name, value in self.function.parameters.items():
4872 if not value:
4873 continue
4874 value.docstring = value.docstring.rstrip()
4875
4876 self.function.docstring = self.format_docstring()
4877
4878
Larry Hastings5c661892014-01-24 06:17:25 -08004879
4880
Larry Hastings31826802013-10-19 00:09:25 -07004881# maps strings to callables.
4882# the callable should return an object
4883# that implements the clinic parser
4884# interface (__init__ and parse).
4885#
4886# example parsers:
4887# "clinic", handles the Clinic DSL
4888# "python", handles running Python code
4889#
4890parsers = {'clinic' : DSLParser, 'python': PythonParser}
4891
4892
4893clinic = None
4894
4895
4896def main(argv):
4897 import sys
4898
4899 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4900 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4901
4902 import argparse
Tim Hoffmann5df40252019-06-02 18:58:10 +02004903 cmdline = argparse.ArgumentParser(
4904 description="""Preprocessor for CPython C files.
4905
4906The purpose of the Argument Clinic is automating all the boilerplate involved
4907with writing argument parsing code for builtins and providing introspection
4908signatures ("docstrings") for CPython builtins.
4909
4910For more information see https://docs.python.org/3/howto/clinic.html""")
Larry Hastings31826802013-10-19 00:09:25 -07004911 cmdline.add_argument("-f", "--force", action='store_true')
4912 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004913 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004914 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004915 cmdline.add_argument("--make", action='store_true',
4916 help="Walk --srcdir to run over all relevant files.")
4917 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4918 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004919 cmdline.add_argument("filename", type=str, nargs="*")
4920 ns = cmdline.parse_args(argv)
4921
4922 if ns.converters:
4923 if ns.filename:
4924 print("Usage error: can't specify --converters and a filename at the same time.")
4925 print()
4926 cmdline.print_usage()
4927 sys.exit(-1)
4928 converters = []
4929 return_converters = []
4930 ignored = set("""
4931 add_c_converter
4932 add_c_return_converter
4933 add_default_legacy_c_converter
4934 add_legacy_c_converter
4935 """.strip().split())
4936 module = globals()
4937 for name in module:
4938 for suffix, ids in (
4939 ("_return_converter", return_converters),
4940 ("_converter", converters),
4941 ):
4942 if name in ignored:
4943 continue
4944 if name.endswith(suffix):
4945 ids.append((name, name[:-len(suffix)]))
4946 break
4947 print()
4948
4949 print("Legacy converters:")
4950 legacy = sorted(legacy_converters)
4951 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4952 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4953 print()
4954
4955 for title, attribute, ids in (
4956 ("Converters", 'converter_init', converters),
4957 ("Return converters", 'return_converter_init', return_converters),
4958 ):
4959 print(title + ":")
4960 longest = -1
4961 for name, short_name in ids:
4962 longest = max(longest, len(short_name))
4963 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4964 cls = module[name]
4965 callable = getattr(cls, attribute, None)
4966 if not callable:
4967 continue
4968 signature = inspect.signature(callable)
4969 parameters = []
4970 for parameter_name, parameter in signature.parameters.items():
4971 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4972 if parameter.default != inspect.Parameter.empty:
4973 s = '{}={!r}'.format(parameter_name, parameter.default)
4974 else:
4975 s = parameter_name
4976 parameters.append(s)
4977 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004978 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004979 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4980 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004981 sys.exit(0)
4982
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004983 if ns.make:
4984 if ns.output or ns.filename:
4985 print("Usage error: can't use -o or filenames with --make.")
4986 print()
4987 cmdline.print_usage()
4988 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07004989 if not ns.srcdir:
4990 print("Usage error: --srcdir must not be empty with --make.")
4991 print()
4992 cmdline.print_usage()
4993 sys.exit(-1)
4994 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004995 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004996 if rcs_dir in dirs:
4997 dirs.remove(rcs_dir)
4998 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004999 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005000 continue
5001 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08005002 if ns.verbose:
5003 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08005004 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08005005 return
5006
Larry Hastings31826802013-10-19 00:09:25 -07005007 if not ns.filename:
5008 cmdline.print_usage()
5009 sys.exit(-1)
5010
5011 if ns.output and len(ns.filename) > 1:
5012 print("Usage error: can't use -o with multiple filenames.")
5013 print()
5014 cmdline.print_usage()
5015 sys.exit(-1)
5016
5017 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08005018 if ns.verbose:
5019 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08005020 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07005021
5022
5023if __name__ == "__main__":
5024 sys.exit(main(sys.argv[1:]))