blob: 3627725eecec93980c5cc610f3c2ed45f53fd7e9 [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):
618 text, add, output = _text_accumulator()
619 # turn docstring into a properly quoted C string
620 for line in f.docstring.split('\n'):
621 add('"')
622 add(quoted_for_c_string(line))
623 add('\\n"\n')
624
Zachary Ware8ef887c2015-04-13 18:22:35 -0500625 if text[-2] == sig_end_marker:
626 # If we only have a signature, add the blank line that the
627 # __text_signature__ getter expects to be there.
628 add('"\\n"')
629 else:
630 text.pop()
631 add('"')
Larry Hastings31826802013-10-19 00:09:25 -0700632 return ''.join(text)
633
Larry Hastingsbebf7352014-01-17 17:47:17 -0800634 def output_templates(self, f):
635 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800636 assert parameters
637 assert isinstance(parameters[0].converter, self_converter)
638 del parameters[0]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800639 converters = [p.converter for p in parameters]
640
641 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
642 default_return_converter = (not f.return_converter or
643 f.return_converter.type == 'PyObject *')
644
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300645 positional = parameters and parameters[-1].is_positional_only()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800646 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
647 first_optional = len(parameters)
648 for i, p in enumerate(parameters):
649 c = p.converter
650 if type(c) != object_converter:
651 break
652 if c.format_unit != 'O':
653 break
654 if p.default is not unspecified:
655 first_optional = min(first_optional, i)
656 else:
657 all_boring_objects = True
658
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800659 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
660
Larry Hastingsbebf7352014-01-17 17:47:17 -0800661 meth_o = (len(parameters) == 1 and
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300662 parameters[0].is_positional_only() and
Larry Hastingsbebf7352014-01-17 17:47:17 -0800663 not converters[0].is_optional() and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800664 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800665
Larry Hastings7726ac92014-01-31 22:03:12 -0800666 # we have to set these things before we're done:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800667 #
668 # docstring_prototype
669 # docstring_definition
670 # impl_prototype
671 # methoddef_define
672 # parser_prototype
673 # parser_definition
674 # impl_definition
Larry Hastings7726ac92014-01-31 22:03:12 -0800675 # cpp_if
676 # cpp_endif
677 # methoddef_ifndef
Larry Hastingsbebf7352014-01-17 17:47:17 -0800678
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800679 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700680
Larry Hastings7726ac92014-01-31 22:03:12 -0800681 methoddef_define = normalize_snippet("""
682 #define {methoddef_name} \\
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200683 {{"{name}", {methoddef_cast}{c_basename}, {methoddef_flags}, {c_basename}__doc__}},
Larry Hastings7726ac92014-01-31 22:03:12 -0800684 """)
Larry Hastings5c661892014-01-24 06:17:25 -0800685 if new_or_init and not f.docstring:
686 docstring_prototype = docstring_definition = ''
687 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800688 docstring_prototype = normalize_snippet("""
689 PyDoc_VAR({c_basename}__doc__);
690 """)
691 docstring_definition = normalize_snippet("""
692 PyDoc_STRVAR({c_basename}__doc__,
693 {docstring});
694 """)
695 impl_definition = normalize_snippet("""
696 static {impl_return_type}
697 {c_basename}_impl({impl_parameters})
698 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800699 impl_prototype = parser_prototype = parser_definition = None
700
Larry Hastings7726ac92014-01-31 22:03:12 -0800701 parser_prototype_keyword = normalize_snippet("""
702 static PyObject *
703 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
704 """)
705
706 parser_prototype_varargs = normalize_snippet("""
707 static PyObject *
708 {c_basename}({self_type}{self_name}, PyObject *args)
709 """)
710
Victor Stinner0c8c3892017-01-17 01:42:54 +0100711 parser_prototype_fastcall = normalize_snippet("""
712 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200713 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300714 """)
715
716 parser_prototype_fastcall_keywords = normalize_snippet("""
717 static PyObject *
Serhiy Storchakaa5552f02017-12-15 13:11:11 +0200718 {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
Victor Stinner0c8c3892017-01-17 01:42:54 +0100719 """)
720
Larry Hastings7726ac92014-01-31 22:03:12 -0800721 # parser_body_fields remembers the fields passed in to the
722 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800723 parser_body_fields = ()
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800724 def parser_body(prototype, *fields):
725 nonlocal parser_body_fields
726 add, output = text_accumulator()
727 add(prototype)
728 parser_body_fields = fields
Larry Hastings7726ac92014-01-31 22:03:12 -0800729
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800730 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800731 fields.insert(0, normalize_snippet("""
732 {{
733 {return_value_declaration}
734 {declarations}
735 {initializers}
736 """) + "\n")
737 # just imagine--your code is here in the middle
738 fields.append(normalize_snippet("""
739 {modifications}
740 {return_value} = {c_basename}_impl({impl_arguments});
741 {return_conversion}
742
743 {exit_label}
744 {cleanup}
745 return return_value;
746 }}
747 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800748 for field in fields:
749 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800750 add(field)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800751 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800752
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800753 def insert_keywords(s):
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300754 return linear_format(s, declarations=
755 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
756 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};\n'
757 '{declarations}')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800758
759 if not parameters:
760 # no parameters, METH_NOARGS
761
762 flags = "METH_NOARGS"
763
Larry Hastings7726ac92014-01-31 22:03:12 -0800764 parser_prototype = normalize_snippet("""
765 static PyObject *
766 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
767 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800768 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800769
770 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800771 parser_definition = parser_prototype + '\n' + normalize_snippet("""
772 {{
773 return {c_basename}_impl({impl_arguments});
774 }}
775 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800776 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800777 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700778
Larry Hastingsbebf7352014-01-17 17:47:17 -0800779 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800780 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800781
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300782 if (isinstance(converters[0], object_converter) and
783 converters[0].format_unit == 'O'):
784 meth_o_prototype = normalize_snippet("""
785 static PyObject *
786 {c_basename}({impl_parameters})
787 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800788
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300789 if default_return_converter:
790 # maps perfectly to METH_O, doesn't need a return converter.
791 # so we skip making a parse function
792 # and call directly into the impl function.
793 impl_prototype = parser_prototype = parser_definition = ''
794 impl_definition = meth_o_prototype
795 else:
796 # SLIGHT HACK
797 # use impl_parameters for the parser here!
798 parser_prototype = meth_o_prototype
799 parser_definition = parser_body(parser_prototype)
800
Larry Hastingsbebf7352014-01-17 17:47:17 -0800801 else:
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300802 argname = 'arg'
803 if parameters[0].name == argname:
804 argname += '_'
805 parser_prototype = normalize_snippet("""
806 static PyObject *
807 {c_basename}({self_type}{self_name}, PyObject *%s)
808 """ % argname)
809
Serhiy Storchaka32d96a22018-12-25 13:23:47 +0200810 parsearg = converters[0].parse_arg(argname)
811 assert parsearg is not None
812 parser_definition = parser_body(parser_prototype,
813 normalize_snippet(parsearg, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700814
Larry Hastingsbebf7352014-01-17 17:47:17 -0800815 elif has_option_groups:
816 # positional parameters with option groups
817 # (we have to generate lots of PyArg_ParseTuple calls
818 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700819
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800820 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800821 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700822
Larry Hastings7726ac92014-01-31 22:03:12 -0800823 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700824
Larry Hastingsbebf7352014-01-17 17:47:17 -0800825 elif positional and all_boring_objects:
826 # positional-only, but no option groups,
827 # and nothing but normal objects:
828 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700829
Victor Stinner093119e2017-01-17 02:35:41 +0100830 if not new_or_init:
831 flags = "METH_FASTCALL"
832 parser_prototype = parser_prototype_fastcall
Larry Hastings31826802013-10-19 00:09:25 -0700833
Victor Stinner093119e2017-01-17 02:35:41 +0100834 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Sylvain74453812017-06-10 06:51:48 +0200835 if (!_PyArg_UnpackStack(args, nargs, "{name}",
836 {unpack_min}, {unpack_max},
837 {parse_arguments})) {{
Victor Stinner093119e2017-01-17 02:35:41 +0100838 goto exit;
839 }}
840 """, indent=4))
841 else:
842 flags = "METH_VARARGS"
843 parser_prototype = parser_prototype_varargs
844
845 parser_definition = parser_body(parser_prototype, normalize_snippet("""
846 if (!PyArg_UnpackTuple(args, "{name}",
847 {unpack_min}, {unpack_max},
848 {parse_arguments})) {{
849 goto exit;
850 }}
851 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800852
853 elif positional:
Victor Stinner0c8c3892017-01-17 01:42:54 +0100854 if not new_or_init:
855 # positional-only, but no option groups
856 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800857
Victor Stinner0c8c3892017-01-17 01:42:54 +0100858 flags = "METH_FASTCALL"
859 parser_prototype = parser_prototype_fastcall
Larry Hastingsbebf7352014-01-17 17:47:17 -0800860
Victor Stinner0c8c3892017-01-17 01:42:54 +0100861 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Sylvain74453812017-06-10 06:51:48 +0200862 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
863 {parse_arguments})) {{
Victor Stinner0c8c3892017-01-17 01:42:54 +0100864 goto exit;
865 }}
866 """, indent=4))
867 else:
868 # positional-only, but no option groups
869 # we only need one call to PyArg_ParseTuple
870
871 flags = "METH_VARARGS"
872 parser_prototype = parser_prototype_varargs
873
874 parser_definition = parser_body(parser_prototype, normalize_snippet("""
875 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
876 {parse_arguments})) {{
877 goto exit;
878 }}
879 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800880
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700881 elif not new_or_init:
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300882 flags = "METH_FASTCALL|METH_KEYWORDS"
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700883
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300884 parser_prototype = parser_prototype_fastcall_keywords
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700885
886 body = normalize_snippet("""
Victor Stinner3e1fad62017-01-17 01:29:01 +0100887 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700888 {parse_arguments})) {{
889 goto exit;
890 }}
891 """, indent=4)
892 parser_definition = parser_body(parser_prototype, body)
893 parser_definition = insert_keywords(parser_definition)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800894 else:
895 # positional-or-keyword arguments
896 flags = "METH_VARARGS|METH_KEYWORDS"
897
Larry Hastings7726ac92014-01-31 22:03:12 -0800898 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800899
Larry Hastings7726ac92014-01-31 22:03:12 -0800900 body = normalize_snippet("""
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300901 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300902 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800903 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300904 }}
905 """, indent=4)
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300906 parser_definition = parser_body(parser_prototype, body)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800907 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700908
Larry Hastings31826802013-10-19 00:09:25 -0700909
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800910 if new_or_init:
911 methoddef_define = ''
912
913 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800914 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800915 else:
916 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800917 parser_prototype = normalize_snippet("""
918 static int
919 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
920 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800921
922 fields = list(parser_body_fields)
923 parses_positional = 'METH_NOARGS' not in flags
924 parses_keywords = 'METH_KEYWORDS' in flags
925 if parses_keywords:
926 assert parses_positional
927
928 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800929 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300930 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800931 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300932 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800933 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800934 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800935 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300936 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800937 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300938 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800939 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800940
941 parser_definition = parser_body(parser_prototype, *fields)
942 if parses_keywords:
943 parser_definition = insert_keywords(parser_definition)
944
Larry Hastings31826802013-10-19 00:09:25 -0700945
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200946 if flags in ('METH_NOARGS', 'METH_O', 'METH_VARARGS'):
947 methoddef_cast = "(PyCFunction)"
948 else:
949 methoddef_cast = "(PyCFunction)(void(*)(void))"
950
Larry Hastingsbebf7352014-01-17 17:47:17 -0800951 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800952 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700953
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800954 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Serhiy Storchaka4a934d42018-11-27 11:27:36 +0200955 methoddef_define = methoddef_define.replace('{methoddef_cast}', methoddef_cast)
Larry Hastings31826802013-10-19 00:09:25 -0700956
Larry Hastings7726ac92014-01-31 22:03:12 -0800957 methoddef_ifndef = ''
958 conditional = self.cpp.condition()
959 if not conditional:
960 cpp_if = cpp_endif = ''
961 else:
962 cpp_if = "#if " + conditional
963 cpp_endif = "#endif /* " + conditional + " */"
964
Tal Einat4f574092017-11-03 11:09:00 +0200965 if methoddef_define and f.full_name not in clinic.ifndef_symbols:
966 clinic.ifndef_symbols.add(f.full_name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800967 methoddef_ifndef = normalize_snippet("""
968 #ifndef {methoddef_name}
969 #define {methoddef_name}
970 #endif /* !defined({methoddef_name}) */
971 """)
972
973
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800974 # add ';' to the end of parser_prototype and impl_prototype
975 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800976 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800977 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800978 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800979 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700980
Larry Hastingsbebf7352014-01-17 17:47:17 -0800981 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800982 impl_prototype = impl_definition
983 if impl_prototype:
984 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700985
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800986 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800987
988 d = {
989 "docstring_prototype" : docstring_prototype,
990 "docstring_definition" : docstring_definition,
991 "impl_prototype" : impl_prototype,
992 "methoddef_define" : methoddef_define,
993 "parser_prototype" : parser_prototype,
994 "parser_definition" : parser_definition,
995 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800996 "cpp_if" : cpp_if,
997 "cpp_endif" : cpp_endif,
998 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800999 }
1000
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001001 # make sure we didn't forget to assign something,
1002 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001003 d2 = {}
1004 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001005 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001006 if value:
1007 value = '\n' + value + '\n'
1008 d2[name] = value
1009 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001010
1011 @staticmethod
1012 def group_to_variable_name(group):
1013 adjective = "left_" if group < 0 else "right_"
1014 return "group_" + adjective + str(abs(group))
1015
1016 def render_option_group_parsing(self, f, template_dict):
1017 # positional only, grouped, optional arguments!
1018 # can be optional on the left or right.
1019 # here's an example:
1020 #
1021 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1022 #
1023 # Here group D are required, and all other groups are optional.
1024 # (Group D's "group" is actually None.)
1025 # We can figure out which sets of arguments we have based on
1026 # how many arguments are in the tuple.
1027 #
1028 # Note that you need to count up on both sides. For example,
1029 # you could have groups C+D, or C+D+E, or C+D+E+F.
1030 #
1031 # What if the number of arguments leads us to an ambiguous result?
1032 # Clinic prefers groups on the left. So in the above example,
1033 # five arguments would map to B+C, not C+D.
1034
1035 add, output = text_accumulator()
1036 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001037 if isinstance(parameters[0].converter, self_converter):
1038 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001039
1040 groups = []
1041 group = None
1042 left = []
1043 right = []
1044 required = []
1045 last = unspecified
1046
1047 for p in parameters:
1048 group_id = p.group
1049 if group_id != last:
1050 last = group_id
1051 group = []
1052 if group_id < 0:
1053 left.append(group)
1054 elif group_id == 0:
1055 group = required
1056 else:
1057 right.append(group)
1058 group.append(p)
1059
1060 count_min = sys.maxsize
1061 count_max = -1
1062
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001063 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001064 for subset in permute_optional_groups(left, required, right):
1065 count = len(subset)
1066 count_min = min(count_min, count)
1067 count_max = max(count_max, count)
1068
Larry Hastings583baa82014-01-12 08:49:30 -08001069 if count == 0:
1070 add(""" case 0:
1071 break;
1072""")
1073 continue
1074
Larry Hastings31826802013-10-19 00:09:25 -07001075 group_ids = {p.group for p in subset} # eliminate duplicates
1076 d = {}
1077 d['count'] = count
1078 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001079 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1080
1081 parse_arguments = []
1082 for p in subset:
1083 p.converter.parse_argument(parse_arguments)
1084 d['parse_arguments'] = ", ".join(parse_arguments)
1085
1086 group_ids.discard(0)
1087 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1088 lines = "\n".join(lines)
1089
1090 s = """
1091 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001092 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001093 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001094 }}
Larry Hastings31826802013-10-19 00:09:25 -07001095 {group_booleans}
1096 break;
1097"""[1:]
1098 s = linear_format(s, group_booleans=lines)
1099 s = s.format_map(d)
1100 add(s)
1101
1102 add(" default:\n")
1103 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1104 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001105 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001106 add("}")
1107 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001108
Larry Hastingsbebf7352014-01-17 17:47:17 -08001109 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001110 if not f:
1111 return ""
1112
1113 add, output = text_accumulator()
1114 data = CRenderData()
1115
Larry Hastings7726ac92014-01-31 22:03:12 -08001116 assert f.parameters, "We should always have a 'self' at this point!"
1117 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001118 converters = [p.converter for p in parameters]
1119
Larry Hastings5c661892014-01-24 06:17:25 -08001120 templates = self.output_templates(f)
1121
1122 f_self = parameters[0]
1123 selfless = parameters[1:]
1124 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1125
1126 last_group = 0
1127 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001128 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001129 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1130 default_return_converter = (not f.return_converter or
1131 f.return_converter.type == 'PyObject *')
1132 has_option_groups = False
1133
1134 # offset i by -1 because first_optional needs to ignore self
1135 for i, p in enumerate(parameters, -1):
1136 c = p.converter
1137
1138 if (i != -1) and (p.default is not unspecified):
1139 first_optional = min(first_optional, i)
1140
1141 # insert group variable
1142 group = p.group
1143 if last_group != group:
1144 last_group = group
1145 if group:
1146 group_name = self.group_to_variable_name(group)
1147 data.impl_arguments.append(group_name)
1148 data.declarations.append("int " + group_name + " = 0;")
1149 data.impl_parameters.append("int " + group_name)
1150 has_option_groups = True
1151
1152 c.render(p, data)
1153
1154 if has_option_groups and (not positional):
1155 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1156
1157 # HACK
1158 # when we're METH_O, but have a custom return converter,
1159 # we use "impl_parameters" for the parsing function
1160 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001161 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001162 # as variables in the parsing function. but since it's
1163 # METH_O, we have exactly one anyway, so we know exactly
1164 # where it is.
1165 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001166 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001167 data.declarations.pop(0)
1168
Larry Hastings31826802013-10-19 00:09:25 -07001169 template_dict = {}
1170
1171 full_name = f.full_name
1172 template_dict['full_name'] = full_name
1173
Larry Hastings5c661892014-01-24 06:17:25 -08001174 if new_or_init:
1175 name = f.cls.name
1176 else:
1177 name = f.name
1178
Larry Hastings31826802013-10-19 00:09:25 -07001179 template_dict['name'] = name
1180
Larry Hastings8666e652014-01-12 14:12:59 -08001181 if f.c_basename:
1182 c_basename = f.c_basename
1183 else:
1184 fields = full_name.split(".")
1185 if fields[-1] == '__new__':
1186 fields.pop()
1187 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001188
Larry Hastings31826802013-10-19 00:09:25 -07001189 template_dict['c_basename'] = c_basename
1190
1191 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1192 template_dict['methoddef_name'] = methoddef_name
1193
1194 template_dict['docstring'] = self.docstring_for_c_string(f)
1195
Larry Hastingsc2047262014-01-25 20:43:29 -08001196 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001197 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001198
Larry Hastings31826802013-10-19 00:09:25 -07001199 f.return_converter.render(f, data)
1200 template_dict['impl_return_type'] = f.return_converter.type
1201
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001202 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001203 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001204 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001205 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1206 template_dict['format_units'] = ''.join(data.format_units)
1207 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1208 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1209 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001210 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1211 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001212 template_dict['return_value'] = data.return_value
1213
Larry Hastings5c661892014-01-24 06:17:25 -08001214 # used by unpack tuple code generator
1215 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1216 unpack_min = first_optional
1217 unpack_max = len(selfless)
1218 template_dict['unpack_min'] = str(unpack_min)
1219 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001220
Larry Hastingsbebf7352014-01-17 17:47:17 -08001221 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001222 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001223
Larry Hastings0759f842015-04-03 13:09:02 -07001224 # buffers, not destination
1225 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001226 template = templates[name]
1227 if has_option_groups:
1228 template = linear_format(template,
1229 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001230 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001231 declarations=template_dict['declarations'],
1232 return_conversion=template_dict['return_conversion'],
1233 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001234 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001235 cleanup=template_dict['cleanup'],
1236 )
Larry Hastings31826802013-10-19 00:09:25 -07001237
Larry Hastingsbebf7352014-01-17 17:47:17 -08001238 # Only generate the "exit:" label
1239 # if we have any gotos
1240 need_exit_label = "goto exit;" in template
1241 template = linear_format(template,
1242 exit_label="exit:" if need_exit_label else ''
1243 )
Larry Hastings31826802013-10-19 00:09:25 -07001244
Larry Hastingsbebf7352014-01-17 17:47:17 -08001245 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001246
Larry Hastings89964c42015-04-14 18:07:59 -04001247 # mild hack:
1248 # reflow long impl declarations
1249 if name in {"impl_prototype", "impl_definition"}:
1250 s = wrap_declarations(s)
1251
Larry Hastingsbebf7352014-01-17 17:47:17 -08001252 if clinic.line_prefix:
1253 s = indent_all_lines(s, clinic.line_prefix)
1254 if clinic.line_suffix:
1255 s = suffix_all_lines(s, clinic.line_suffix)
1256
1257 destination.append(s)
1258
1259 return clinic.get_destination('block').dump()
1260
Larry Hastings31826802013-10-19 00:09:25 -07001261
1262
Larry Hastings5c661892014-01-24 06:17:25 -08001263
Larry Hastings31826802013-10-19 00:09:25 -07001264@contextlib.contextmanager
1265def OverrideStdioWith(stdout):
1266 saved_stdout = sys.stdout
1267 sys.stdout = stdout
1268 try:
1269 yield
1270 finally:
1271 assert sys.stdout is stdout
1272 sys.stdout = saved_stdout
1273
1274
Larry Hastings2623c8c2014-02-08 22:15:29 -08001275def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001276 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001277 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001278 pattern = r'{}({}){}'
1279 if whole_line:
1280 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001281 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1282 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001283
1284
1285class Block:
1286 r"""
1287 Represents a single block of text embedded in
1288 another file. If dsl_name is None, the block represents
1289 verbatim text, raw original text from the file, in
1290 which case "input" will be the only non-false member.
1291 If dsl_name is not None, the block represents a Clinic
1292 block.
1293
1294 input is always str, with embedded \n characters.
1295 input represents the original text from the file;
1296 if it's a Clinic block, it is the original text with
1297 the body_prefix and redundant leading whitespace removed.
1298
1299 dsl_name is either str or None. If str, it's the text
1300 found on the start line of the block between the square
1301 brackets.
1302
1303 signatures is either list or None. If it's a list,
1304 it may only contain clinic.Module, clinic.Class, and
1305 clinic.Function objects. At the moment it should
1306 contain at most one of each.
1307
1308 output is either str or None. If str, it's the output
1309 from this block, with embedded '\n' characters.
1310
1311 indent is either str or None. It's the leading whitespace
1312 that was found on every line of input. (If body_prefix is
1313 not empty, this is the indent *after* removing the
1314 body_prefix.)
1315
1316 preindent is either str or None. It's the whitespace that
1317 was found in front of every line of input *before* the
1318 "body_prefix" (see the Language object). If body_prefix
1319 is empty, preindent must always be empty too.
1320
1321 To illustrate indent and preindent: Assume that '_'
1322 represents whitespace. If the block processed was in a
1323 Python file, and looked like this:
1324 ____#/*[python]
1325 ____#__for a in range(20):
1326 ____#____print(a)
1327 ____#[python]*/
1328 "preindent" would be "____" and "indent" would be "__".
1329
1330 """
1331 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1332 assert isinstance(input, str)
1333 self.input = input
1334 self.dsl_name = dsl_name
1335 self.signatures = signatures or []
1336 self.output = output
1337 self.indent = indent
1338 self.preindent = preindent
1339
Larry Hastings581ee362014-01-28 05:00:08 -08001340 def __repr__(self):
1341 dsl_name = self.dsl_name or "text"
1342 def summarize(s):
1343 s = repr(s)
1344 if len(s) > 30:
1345 return s[:26] + "..." + s[0]
1346 return s
1347 return "".join((
1348 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1349
Larry Hastings31826802013-10-19 00:09:25 -07001350
1351class BlockParser:
1352 """
1353 Block-oriented parser for Argument Clinic.
1354 Iterator, yields Block objects.
1355 """
1356
1357 def __init__(self, input, language, *, verify=True):
1358 """
1359 "input" should be a str object
1360 with embedded \n characters.
1361
1362 "language" should be a Language object.
1363 """
1364 language.validate()
1365
1366 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1367 self.block_start_line_number = self.line_number = 0
1368
1369 self.language = language
1370 before, _, after = language.start_line.partition('{dsl_name}')
1371 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001372 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001373 self.start_re = create_regex(before, after)
1374 self.verify = verify
1375 self.last_checksum_re = None
1376 self.last_dsl_name = None
1377 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001378 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001379
1380 def __iter__(self):
1381 return self
1382
1383 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001384 while True:
1385 if not self.input:
1386 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001387
Larry Hastingsbebf7352014-01-17 17:47:17 -08001388 if self.dsl_name:
1389 return_value = self.parse_clinic_block(self.dsl_name)
1390 self.dsl_name = None
1391 self.first_block = False
1392 return return_value
1393 block = self.parse_verbatim_block()
1394 if self.first_block and not block.input:
1395 continue
1396 self.first_block = False
1397 return block
1398
Larry Hastings31826802013-10-19 00:09:25 -07001399
1400 def is_start_line(self, line):
1401 match = self.start_re.match(line.lstrip())
1402 return match.group(1) if match else None
1403
Larry Hastingse1b82532014-07-27 16:22:20 +02001404 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001405 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001406 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001407 if not lookahead:
1408 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001409 return line
Larry Hastings31826802013-10-19 00:09:25 -07001410
1411 def parse_verbatim_block(self):
1412 add, output = text_accumulator()
1413 self.block_start_line_number = self.line_number
1414
1415 while self.input:
1416 line = self._line()
1417 dsl_name = self.is_start_line(line)
1418 if dsl_name:
1419 self.dsl_name = dsl_name
1420 break
1421 add(line)
1422
1423 return Block(output())
1424
1425 def parse_clinic_block(self, dsl_name):
1426 input_add, input_output = text_accumulator()
1427 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001428 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001429 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1430
Larry Hastings90261132014-01-07 12:21:08 -08001431 def is_stop_line(line):
1432 # make sure to recognize stop line even if it
1433 # doesn't end with EOL (it could be the very end of the file)
1434 if not line.startswith(stop_line):
1435 return False
1436 remainder = line[len(stop_line):]
1437 return (not remainder) or remainder.isspace()
1438
Larry Hastings31826802013-10-19 00:09:25 -07001439 # consume body of program
1440 while self.input:
1441 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001442 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001443 break
1444 if body_prefix:
1445 line = line.lstrip()
1446 assert line.startswith(body_prefix)
1447 line = line[len(body_prefix):]
1448 input_add(line)
1449
1450 # consume output and checksum line, if present.
1451 if self.last_dsl_name == dsl_name:
1452 checksum_re = self.last_checksum_re
1453 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001454 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1455 assert _ == '{arguments}'
1456 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001457 self.last_dsl_name = dsl_name
1458 self.last_checksum_re = checksum_re
1459
1460 # scan forward for checksum line
1461 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001462 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001463 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001464 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001465 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001466 arguments = match.group(1) if match else None
1467 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001468 break
1469 output_add(line)
1470 if self.is_start_line(line):
1471 break
1472
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001473 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001474 if arguments:
1475 d = {}
1476 for field in shlex.split(arguments):
1477 name, equals, value = field.partition('=')
1478 if not equals:
1479 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1480 d[name.strip()] = value.strip()
1481
Larry Hastings31826802013-10-19 00:09:25 -07001482 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001483 if 'input' in d:
1484 checksum = d['output']
1485 input_checksum = d['input']
1486 else:
1487 checksum = d['checksum']
1488 input_checksum = None
1489
1490 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001491 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001492 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1493 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001494 "the end marker,\n"
1495 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001496 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001497 else:
1498 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001499 output_lines = output.splitlines(keepends=True)
1500 self.line_number -= len(output_lines)
1501 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001502 output = None
1503
1504 return Block(input_output(), dsl_name, output=output)
1505
1506
1507class BlockPrinter:
1508
1509 def __init__(self, language, f=None):
1510 self.language = language
1511 self.f = f or io.StringIO()
1512
1513 def print_block(self, block):
1514 input = block.input
1515 output = block.output
1516 dsl_name = block.dsl_name
1517 write = self.f.write
1518
Larry Hastings31826802013-10-19 00:09:25 -07001519 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1520
1521 if not dsl_name:
1522 write(input)
1523 return
1524
1525 write(self.language.start_line.format(dsl_name=dsl_name))
1526 write("\n")
1527
1528 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1529 if not body_prefix:
1530 write(input)
1531 else:
1532 for line in input.split('\n'):
1533 write(body_prefix)
1534 write(line)
1535 write("\n")
1536
1537 write(self.language.stop_line.format(dsl_name=dsl_name))
1538 write("\n")
1539
Larry Hastings581ee362014-01-28 05:00:08 -08001540 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001541 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001542 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001543 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001544 output += '\n'
1545 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001546
Larry Hastings581ee362014-01-28 05:00:08 -08001547 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1548 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001549 write("\n")
1550
Larry Hastingsbebf7352014-01-17 17:47:17 -08001551 def write(self, text):
1552 self.f.write(text)
1553
1554
Larry Hastings0759f842015-04-03 13:09:02 -07001555class BufferSeries:
1556 """
1557 Behaves like a "defaultlist".
1558 When you ask for an index that doesn't exist yet,
1559 the object grows the list until that item exists.
1560 So o[n] will always work.
1561
1562 Supports negative indices for actual items.
1563 e.g. o[-1] is an element immediately preceding o[0].
1564 """
1565
1566 def __init__(self):
1567 self._start = 0
1568 self._array = []
1569 self._constructor = _text_accumulator
1570
1571 def __getitem__(self, i):
1572 i -= self._start
1573 if i < 0:
1574 self._start += i
1575 prefix = [self._constructor() for x in range(-i)]
1576 self._array = prefix + self._array
1577 i = 0
1578 while i >= len(self._array):
1579 self._array.append(self._constructor())
1580 return self._array[i]
1581
1582 def clear(self):
1583 for ta in self._array:
1584 ta._text.clear()
1585
1586 def dump(self):
1587 texts = [ta.output() for ta in self._array]
1588 return "".join(texts)
1589
1590
Larry Hastingsbebf7352014-01-17 17:47:17 -08001591class Destination:
1592 def __init__(self, name, type, clinic, *args):
1593 self.name = name
1594 self.type = type
1595 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001596 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001597 if type not in valid_types:
1598 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1599 extra_arguments = 1 if type == "file" else 0
1600 if len(args) < extra_arguments:
1601 fail("Not enough arguments for destination " + name + " new " + type)
1602 if len(args) > extra_arguments:
1603 fail("Too many arguments for destination " + name + " new " + type)
1604 if type =='file':
1605 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001606 filename = clinic.filename
1607 d['path'] = filename
1608 dirname, basename = os.path.split(filename)
1609 if not dirname:
1610 dirname = '.'
1611 d['dirname'] = dirname
1612 d['basename'] = basename
1613 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001614 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001615
Larry Hastings0759f842015-04-03 13:09:02 -07001616 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001617
1618 def __repr__(self):
1619 if self.type == 'file':
1620 file_repr = " " + repr(self.filename)
1621 else:
1622 file_repr = ''
1623 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1624
1625 def clear(self):
1626 if self.type != 'buffer':
1627 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001628 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001629
1630 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001631 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001632
Larry Hastings31826802013-10-19 00:09:25 -07001633
1634# maps strings to Language objects.
1635# "languages" maps the name of the language ("C", "Python").
1636# "extensions" maps the file extension ("c", "py").
1637languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001638extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1639extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001640
1641
1642# maps strings to callables.
1643# these callables must be of the form:
1644# def foo(name, default, *, ...)
1645# The callable may have any number of keyword-only parameters.
1646# The callable must return a CConverter object.
1647# The callable should not call builtins.print.
1648converters = {}
1649
1650# maps strings to callables.
1651# these callables follow the same rules as those for "converters" above.
1652# note however that they will never be called with keyword-only parameters.
1653legacy_converters = {}
1654
1655
1656# maps strings to callables.
1657# these callables must be of the form:
1658# def foo(*, ...)
1659# The callable may have any number of keyword-only parameters.
1660# The callable must return a CConverter object.
1661# The callable should not call builtins.print.
1662return_converters = {}
1663
Larry Hastings7726ac92014-01-31 22:03:12 -08001664clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001665class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001666
1667 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001668preset block
1669everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001670methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001671docstring_prototype suppress
1672parser_prototype suppress
1673cpp_if suppress
1674cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001675
Larry Hastingsbebf7352014-01-17 17:47:17 -08001676preset original
1677everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001678methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001679docstring_prototype suppress
1680parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001681cpp_if suppress
1682cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001683
1684preset file
1685everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001686methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001687docstring_prototype suppress
1688parser_prototype suppress
1689impl_definition block
1690
1691preset buffer
1692everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001693methoddef_ifndef buffer 1
1694impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001695docstring_prototype suppress
1696impl_prototype suppress
1697parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001698
1699preset partial-buffer
1700everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001701methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001702docstring_prototype block
1703impl_prototype suppress
1704methoddef_define block
1705parser_prototype block
1706impl_definition block
1707
Larry Hastingsbebf7352014-01-17 17:47:17 -08001708"""
1709
Larry Hastings581ee362014-01-28 05:00:08 -08001710 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001711 # maps strings to Parser objects.
1712 # (instantiated from the "parsers" global.)
1713 self.parsers = {}
1714 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001715 if printer:
1716 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001717 self.printer = printer or BlockPrinter(language)
1718 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001719 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001720 self.filename = filename
1721 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001722 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001723 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001724
Larry Hastingsbebf7352014-01-17 17:47:17 -08001725 self.line_prefix = self.line_suffix = ''
1726
1727 self.destinations = {}
1728 self.add_destination("block", "buffer")
1729 self.add_destination("suppress", "suppress")
1730 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001731 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001732 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001733
Larry Hastings0759f842015-04-03 13:09:02 -07001734 d = self.get_destination_buffer
1735 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001736 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001737 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001738 ('docstring_definition', d('file')),
1739 ('methoddef_define', d('file')),
1740 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001741 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001742 ('parser_definition', d('file')),
1743 ('cpp_endif', d('file')),
1744 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001745 ('impl_definition', d('block')),
1746 ))
1747
Larry Hastings0759f842015-04-03 13:09:02 -07001748 self.destination_buffers_stack = []
1749 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001750
1751 self.presets = {}
1752 preset = None
1753 for line in self.presets_text.strip().split('\n'):
1754 line = line.strip()
1755 if not line:
1756 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001757 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001758 if name == 'preset':
1759 self.presets[value] = preset = collections.OrderedDict()
1760 continue
1761
Larry Hastings0759f842015-04-03 13:09:02 -07001762 if len(options):
1763 index = int(options[0])
1764 else:
1765 index = 0
1766 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001767
1768 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001769 for name in self.destination_buffers:
1770 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001771 continue
1772
Larry Hastings0759f842015-04-03 13:09:02 -07001773 assert name in self.destination_buffers
1774 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001775
Larry Hastings31826802013-10-19 00:09:25 -07001776 global clinic
1777 clinic = self
1778
Larry Hastingsbebf7352014-01-17 17:47:17 -08001779 def add_destination(self, name, type, *args):
1780 if name in self.destinations:
1781 fail("Destination already exists: " + repr(name))
1782 self.destinations[name] = Destination(name, type, self, *args)
1783
Larry Hastings0759f842015-04-03 13:09:02 -07001784 def get_destination(self, name):
1785 d = self.destinations.get(name)
1786 if not d:
1787 fail("Destination does not exist: " + repr(name))
1788 return d
1789
1790 def get_destination_buffer(self, name, item=0):
1791 d = self.get_destination(name)
1792 return d.buffers[item]
1793
Larry Hastings31826802013-10-19 00:09:25 -07001794 def parse(self, input):
1795 printer = self.printer
1796 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1797 for block in self.block_parser:
1798 dsl_name = block.dsl_name
1799 if dsl_name:
1800 if dsl_name not in self.parsers:
1801 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1802 self.parsers[dsl_name] = parsers[dsl_name](self)
1803 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001804 try:
1805 parser.parse(block)
1806 except Exception:
1807 fail('Exception raised during parsing:\n' +
1808 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001809 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001810
1811 second_pass_replacements = {}
1812
Larry Hastings0759f842015-04-03 13:09:02 -07001813 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001814 for name, destination in self.destinations.items():
1815 if destination.type == 'suppress':
1816 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001817 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001818
1819 if output:
1820
1821 block = Block("", dsl_name="clinic", output=output)
1822
1823 if destination.type == 'buffer':
1824 block.input = "dump " + name + "\n"
1825 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1826 printer.write("\n")
1827 printer.print_block(block)
1828 continue
1829
1830 if destination.type == 'file':
1831 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001832 dirname = os.path.dirname(destination.filename)
1833 try:
1834 os.makedirs(dirname)
1835 except FileExistsError:
1836 if not os.path.isdir(dirname):
1837 fail("Can't write to destination {}, "
1838 "can't make directory {}!".format(
1839 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001840 if self.verify:
1841 with open(destination.filename, "rt") as f:
1842 parser_2 = BlockParser(f.read(), language=self.language)
1843 blocks = list(parser_2)
1844 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1845 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001846 except FileNotFoundError:
1847 pass
1848
1849 block.input = 'preserve\n'
1850 printer_2 = BlockPrinter(self.language)
1851 printer_2.print_block(block)
1852 with open(destination.filename, "wt") as f:
1853 f.write(printer_2.f.getvalue())
1854 continue
1855 text = printer.f.getvalue()
1856
1857 if second_pass_replacements:
1858 printer_2 = BlockPrinter(self.language)
1859 parser_2 = BlockParser(text, self.language)
1860 changed = False
1861 for block in parser_2:
1862 if block.dsl_name:
1863 for id, replacement in second_pass_replacements.items():
1864 if id in block.output:
1865 changed = True
1866 block.output = block.output.replace(id, replacement)
1867 printer_2.print_block(block)
1868 if changed:
1869 text = printer_2.f.getvalue()
1870
1871 return text
1872
Larry Hastings31826802013-10-19 00:09:25 -07001873
1874 def _module_and_class(self, fields):
1875 """
1876 fields should be an iterable of field names.
1877 returns a tuple of (module, class).
1878 the module object could actually be self (a clinic object).
1879 this function is only ever used to find the parent of where
1880 a new class/module should go.
1881 """
1882 in_classes = False
1883 parent = module = self
1884 cls = None
1885 so_far = []
1886
1887 for field in fields:
1888 so_far.append(field)
1889 if not in_classes:
1890 child = parent.modules.get(field)
1891 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001892 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001893 continue
1894 in_classes = True
1895 if not hasattr(parent, 'classes'):
1896 return module, cls
1897 child = parent.classes.get(field)
1898 if not child:
1899 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1900 cls = parent = child
1901
1902 return module, cls
1903
1904
Larry Hastings581ee362014-01-28 05:00:08 -08001905def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001906 extension = os.path.splitext(filename)[1][1:]
1907 if not extension:
1908 fail("Can't extract file type for file " + repr(filename))
1909
1910 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001911 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001912 except KeyError:
1913 fail("Can't identify file type for file " + repr(filename))
1914
Larry Hastings31826802013-10-19 00:09:25 -07001915 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001916 raw = f.read()
1917
Larry Hastings2623c8c2014-02-08 22:15:29 -08001918 # exit quickly if there are no clinic markers in the file
1919 find_start_re = BlockParser("", language).find_start_re
1920 if not find_start_re.search(raw):
1921 return
1922
1923 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001924 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001925 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001926 return
Larry Hastings31826802013-10-19 00:09:25 -07001927
1928 directory = os.path.dirname(filename) or '.'
1929
1930 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001931 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001932 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1933 with open(tmpfilename, "wb") as f:
1934 f.write(bytes)
1935 os.replace(tmpfilename, output or filename)
1936
1937
Larry Hastings581ee362014-01-28 05:00:08 -08001938def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001939 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001940 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1941 if length:
1942 s = s[:length]
1943 return s
Larry Hastings31826802013-10-19 00:09:25 -07001944
1945
1946
1947
1948class PythonParser:
1949 def __init__(self, clinic):
1950 pass
1951
1952 def parse(self, block):
1953 s = io.StringIO()
1954 with OverrideStdioWith(s):
1955 exec(block.input)
1956 block.output = s.getvalue()
1957
1958
1959class Module:
1960 def __init__(self, name, module=None):
1961 self.name = name
1962 self.module = self.parent = module
1963
1964 self.modules = collections.OrderedDict()
1965 self.classes = collections.OrderedDict()
1966 self.functions = []
1967
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001968 def __repr__(self):
1969 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1970
Larry Hastings31826802013-10-19 00:09:25 -07001971class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001972 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001973 self.name = name
1974 self.module = module
1975 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001976 self.typedef = typedef
1977 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001978 self.parent = cls or module
1979
1980 self.classes = collections.OrderedDict()
1981 self.functions = []
1982
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001983 def __repr__(self):
1984 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1985
Larry Hastings8666e652014-01-12 14:12:59 -08001986unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001987
Larry Hastings8666e652014-01-12 14:12:59 -08001988__abs__
1989__add__
1990__and__
1991__bytes__
1992__call__
1993__complex__
1994__delitem__
1995__divmod__
1996__eq__
1997__float__
1998__floordiv__
1999__ge__
2000__getattr__
2001__getattribute__
2002__getitem__
2003__gt__
2004__hash__
2005__iadd__
2006__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002007__ifloordiv__
2008__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002009__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002010__imod__
2011__imul__
2012__index__
2013__int__
2014__invert__
2015__ior__
2016__ipow__
2017__irshift__
2018__isub__
2019__iter__
2020__itruediv__
2021__ixor__
2022__le__
2023__len__
2024__lshift__
2025__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002026__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002027__mod__
2028__mul__
2029__neg__
2030__new__
2031__next__
2032__or__
2033__pos__
2034__pow__
2035__radd__
2036__rand__
2037__rdivmod__
2038__repr__
2039__rfloordiv__
2040__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002041__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002042__rmod__
2043__rmul__
2044__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002045__rpow__
2046__rrshift__
2047__rshift__
2048__rsub__
2049__rtruediv__
2050__rxor__
2051__setattr__
2052__setitem__
2053__str__
2054__sub__
2055__truediv__
2056__xor__
2057
2058""".strip().split())
2059
2060
Larry Hastings5c661892014-01-24 06:17:25 -08002061INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2062INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2063""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002064
2065class Function:
2066 """
2067 Mutable duck type for inspect.Function.
2068
2069 docstring - a str containing
2070 * embedded line breaks
2071 * text outdented to the left margin
2072 * no trailing whitespace.
2073 It will always be true that
2074 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2075 """
2076
2077 def __init__(self, parameters=None, *, name,
2078 module, cls=None, c_basename=None,
2079 full_name=None,
2080 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002081 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002082 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002083 self.parameters = parameters or collections.OrderedDict()
2084 self.return_annotation = return_annotation
2085 self.name = name
2086 self.full_name = full_name
2087 self.module = module
2088 self.cls = cls
2089 self.parent = cls or module
2090 self.c_basename = c_basename
2091 self.return_converter = return_converter
2092 self.docstring = docstring or ''
2093 self.kind = kind
2094 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002095 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002096 # docstring_only means "don't generate a machine-readable
2097 # signature, just a normal docstring". it's True for
2098 # functions with optional groups because we can't represent
2099 # those accurately with inspect.Signature in 3.4.
2100 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002101
Larry Hastings7726ac92014-01-31 22:03:12 -08002102 self.rendered_parameters = None
2103
2104 __render_parameters__ = None
2105 @property
2106 def render_parameters(self):
2107 if not self.__render_parameters__:
2108 self.__render_parameters__ = l = []
2109 for p in self.parameters.values():
2110 p = p.copy()
2111 p.converter.pre_render()
2112 l.append(p)
2113 return self.__render_parameters__
2114
Larry Hastingsebdcb502013-11-23 14:54:00 -08002115 @property
2116 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002117 if self.kind in (METHOD_INIT, METHOD_NEW):
2118 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002119 flags = []
2120 if self.kind == CLASS_METHOD:
2121 flags.append('METH_CLASS')
2122 elif self.kind == STATIC_METHOD:
2123 flags.append('METH_STATIC')
2124 else:
2125 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2126 if self.coexist:
2127 flags.append('METH_COEXIST')
2128 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002129
2130 def __repr__(self):
2131 return '<clinic.Function ' + self.name + '>'
2132
Larry Hastings7726ac92014-01-31 22:03:12 -08002133 def copy(self, **overrides):
2134 kwargs = {
2135 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2136 'cls': self.cls, 'c_basename': self.c_basename,
2137 'full_name': self.full_name,
2138 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2139 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002140 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002141 }
2142 kwargs.update(overrides)
2143 f = Function(**kwargs)
2144
2145 parameters = collections.OrderedDict()
2146 for name, value in f.parameters.items():
2147 value = value.copy(function=f)
2148 parameters[name] = value
2149 f.parameters = parameters
2150 return f
2151
Larry Hastings31826802013-10-19 00:09:25 -07002152
2153class Parameter:
2154 """
2155 Mutable duck type of inspect.Parameter.
2156 """
2157
2158 def __init__(self, name, kind, *, default=_empty,
2159 function, converter, annotation=_empty,
2160 docstring=None, group=0):
2161 self.name = name
2162 self.kind = kind
2163 self.default = default
2164 self.function = function
2165 self.converter = converter
2166 self.annotation = annotation
2167 self.docstring = docstring or ''
2168 self.group = group
2169
2170 def __repr__(self):
2171 return '<clinic.Parameter ' + self.name + '>'
2172
2173 def is_keyword_only(self):
2174 return self.kind == inspect.Parameter.KEYWORD_ONLY
2175
Larry Hastings2623c8c2014-02-08 22:15:29 -08002176 def is_positional_only(self):
2177 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2178
Larry Hastings7726ac92014-01-31 22:03:12 -08002179 def copy(self, **overrides):
2180 kwargs = {
2181 'name': self.name, 'kind': self.kind, 'default':self.default,
2182 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2183 'docstring': self.docstring, 'group': self.group,
2184 }
2185 kwargs.update(overrides)
2186 if 'converter' not in overrides:
2187 converter = copy.copy(self.converter)
2188 converter.function = kwargs['function']
2189 kwargs['converter'] = converter
2190 return Parameter(**kwargs)
2191
2192
2193
2194class LandMine:
2195 # try to access any
2196 def __init__(self, message):
2197 self.__message__ = message
2198
2199 def __repr__(self):
2200 return '<LandMine ' + repr(self.__message__) + ">"
2201
2202 def __getattribute__(self, name):
2203 if name in ('__repr__', '__message__'):
2204 return super().__getattribute__(name)
2205 # raise RuntimeError(repr(name))
2206 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002207
Larry Hastings31826802013-10-19 00:09:25 -07002208
2209def add_c_converter(f, name=None):
2210 if not name:
2211 name = f.__name__
2212 if not name.endswith('_converter'):
2213 return f
2214 name = name[:-len('_converter')]
2215 converters[name] = f
2216 return f
2217
2218def add_default_legacy_c_converter(cls):
2219 # automatically add converter for default format unit
2220 # (but without stomping on the existing one if it's already
2221 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002222 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002223 (cls.format_unit not in legacy_converters)):
2224 legacy_converters[cls.format_unit] = cls
2225 return cls
2226
2227def add_legacy_c_converter(format_unit, **kwargs):
2228 """
2229 Adds a legacy converter.
2230 """
2231 def closure(f):
2232 if not kwargs:
2233 added_f = f
2234 else:
2235 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002236 if format_unit:
2237 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002238 return f
2239 return closure
2240
2241class CConverterAutoRegister(type):
2242 def __init__(cls, name, bases, classdict):
2243 add_c_converter(cls)
2244 add_default_legacy_c_converter(cls)
2245
2246class CConverter(metaclass=CConverterAutoRegister):
2247 """
2248 For the init function, self, name, function, and default
2249 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002250 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002251 """
2252
Larry Hastings7726ac92014-01-31 22:03:12 -08002253 # The C name to use for this variable.
2254 name = None
2255
2256 # The Python name to use for this variable.
2257 py_name = None
2258
Larry Hastings78cf85c2014-01-04 12:44:57 -08002259 # The C type to use for this variable.
2260 # 'type' should be a Python string specifying the type, e.g. "int".
2261 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002262 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002263
2264 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002265 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002266 # Or the magic value "unknown" if this value is a cannot be evaluated
2267 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2268 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002269 default = unspecified
2270
Larry Hastings4a55fc52014-01-12 11:09:57 -08002271 # If not None, default must be isinstance() of this type.
2272 # (You can also specify a tuple of types.)
2273 default_type = None
2274
Larry Hastings31826802013-10-19 00:09:25 -07002275 # "default" converted into a C value, as a string.
2276 # Or None if there is no default.
2277 c_default = None
2278
Larry Hastings2a727912014-01-16 11:32:01 -08002279 # "default" converted into a Python value, as a string.
2280 # Or None if there is no default.
2281 py_default = None
2282
Larry Hastingsabc716b2013-11-20 09:13:52 -08002283 # The default value used to initialize the C variable when
2284 # there is no default, but not specifying a default may
2285 # result in an "uninitialized variable" warning. This can
2286 # easily happen when using option groups--although
2287 # properly-written code won't actually use the variable,
2288 # the variable does get passed in to the _impl. (Ah, if
2289 # only dataflow analysis could inline the static function!)
2290 #
2291 # This value is specified as a string.
2292 # Every non-abstract subclass should supply a valid value.
2293 c_ignored_default = 'NULL'
2294
Larry Hastings31826802013-10-19 00:09:25 -07002295 # The C converter *function* to be used, if any.
2296 # (If this is not None, format_unit must be 'O&'.)
2297 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002298
Larry Hastings78cf85c2014-01-04 12:44:57 -08002299 # Should Argument Clinic add a '&' before the name of
2300 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002301 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002302
2303 # Should Argument Clinic add a '&' before the name of
2304 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002305 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002306
2307 #############################################################
2308 #############################################################
2309 ## You shouldn't need to read anything below this point to ##
2310 ## write your own converter functions. ##
2311 #############################################################
2312 #############################################################
2313
2314 # The "format unit" to specify for this variable when
2315 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2316 # Custom converters should always use the default value of 'O&'.
2317 format_unit = 'O&'
2318
2319 # What encoding do we want for this variable? Only used
2320 # by format units starting with 'e'.
2321 encoding = None
2322
Larry Hastings77561cc2014-01-07 12:13:13 -08002323 # Should this object be required to be a subclass of a specific type?
2324 # If not None, should be a string representing a pointer to a
2325 # PyTypeObject (e.g. "&PyUnicode_Type").
2326 # Only used by the 'O!' format unit (and the "object" converter).
2327 subclass_of = None
2328
Larry Hastings78cf85c2014-01-04 12:44:57 -08002329 # Do we want an adjacent '_length' variable for this variable?
2330 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002331 length = False
2332
Larry Hastings5c661892014-01-24 06:17:25 -08002333 # Should we show this parameter in the generated
2334 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002335 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002336 show_in_signature = True
2337
2338 # Overrides the name used in a text signature.
2339 # The name used for a "self" parameter must be one of
2340 # self, type, or module; however users can set their own.
2341 # This lets the self_converter overrule the user-settable
2342 # name, *just* for the text signature.
2343 # Only set by self_converter.
2344 signature_name = None
2345
2346 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002347 def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002348 self.name = ensure_legal_c_identifier(name)
Larry Hastings7726ac92014-01-31 22:03:12 -08002349 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002350
2351 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002352 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002353 if isinstance(self.default_type, type):
2354 types_str = self.default_type.__name__
2355 else:
2356 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2357 fail("{}: default value {!r} for field {} is not of type {}".format(
2358 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002359 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002360
Larry Hastingsb4705752014-01-18 21:54:15 -08002361 if c_default:
2362 self.c_default = c_default
2363 if py_default:
2364 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002365
Larry Hastings31826802013-10-19 00:09:25 -07002366 if annotation != unspecified:
2367 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002368
2369 # this is deliberate, to prevent you from caching information
2370 # about the function in the init.
2371 # (that breaks if we get cloned.)
2372 # so after this change we will noisily fail.
2373 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002374 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002375 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002376
2377 def converter_init(self):
2378 pass
2379
2380 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002381 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002382
Larry Hastings5c661892014-01-24 06:17:25 -08002383 def _render_self(self, parameter, data):
2384 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002385 name = self.name
Larry Hastings5c661892014-01-24 06:17:25 -08002386
2387 # impl_arguments
2388 s = ("&" if self.impl_by_reference else "") + name
2389 data.impl_arguments.append(s)
2390 if self.length:
2391 data.impl_arguments.append(self.length_name())
2392
2393 # impl_parameters
2394 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2395 if self.length:
2396 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2397
2398 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002399 self.parameter = parameter
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002400 name = self.name
Larry Hastings31826802013-10-19 00:09:25 -07002401
2402 # declarations
2403 d = self.declaration()
2404 data.declarations.append(d)
2405
2406 # initializers
2407 initializers = self.initialize()
2408 if initializers:
2409 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2410
Larry Hastingsc2047262014-01-25 20:43:29 -08002411 # modifications
2412 modifications = self.modify()
2413 if modifications:
2414 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2415
Larry Hastings31826802013-10-19 00:09:25 -07002416 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002417 if parameter.is_positional_only():
2418 data.keywords.append('')
2419 else:
2420 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002421
2422 # format_units
2423 if self.is_optional() and '|' not in data.format_units:
2424 data.format_units.append('|')
2425 if parameter.is_keyword_only() and '$' not in data.format_units:
2426 data.format_units.append('$')
2427 data.format_units.append(self.format_unit)
2428
2429 # parse_arguments
2430 self.parse_argument(data.parse_arguments)
2431
Larry Hastings31826802013-10-19 00:09:25 -07002432 # cleanup
2433 cleanup = self.cleanup()
2434 if cleanup:
2435 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2436
Larry Hastings5c661892014-01-24 06:17:25 -08002437 def render(self, parameter, data):
2438 """
2439 parameter is a clinic.Parameter instance.
2440 data is a CRenderData instance.
2441 """
2442 self._render_self(parameter, data)
2443 self._render_non_self(parameter, data)
2444
Larry Hastingsebdcb502013-11-23 14:54:00 -08002445 def length_name(self):
2446 """Computes the name of the associated "length" variable."""
2447 if not self.length:
2448 return None
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002449 return self.name + "_length"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002450
Larry Hastings31826802013-10-19 00:09:25 -07002451 # Why is this one broken out separately?
2452 # For "positional-only" function parsing,
2453 # which generates a bunch of PyArg_ParseTuple calls.
2454 def parse_argument(self, list):
2455 assert not (self.converter and self.encoding)
2456 if self.format_unit == 'O&':
2457 assert self.converter
2458 list.append(self.converter)
2459
2460 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002461 list.append(c_repr(self.encoding))
2462 elif self.subclass_of:
2463 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002464
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002465 s = ("&" if self.parse_by_reference else "") + self.name
Larry Hastings31826802013-10-19 00:09:25 -07002466 list.append(s)
2467
Larry Hastingsebdcb502013-11-23 14:54:00 -08002468 if self.length:
2469 list.append("&" + self.length_name())
2470
Larry Hastings31826802013-10-19 00:09:25 -07002471 #
2472 # All the functions after here are intended as extension points.
2473 #
2474
2475 def simple_declaration(self, by_reference=False):
2476 """
2477 Computes the basic declaration of the variable.
2478 Used in computing the prototype declaration and the
2479 variable declaration.
2480 """
2481 prototype = [self.type]
2482 if by_reference or not self.type.endswith('*'):
2483 prototype.append(" ")
2484 if by_reference:
2485 prototype.append('*')
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002486 prototype.append(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07002487 return "".join(prototype)
2488
2489 def declaration(self):
2490 """
2491 The C statement to declare this variable.
2492 """
2493 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002494 default = self.c_default
2495 if not default and self.parameter.group:
2496 default = self.c_ignored_default
2497 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002498 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002499 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002500 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002501 if self.length:
2502 declaration.append('\nPy_ssize_clean_t ')
2503 declaration.append(self.length_name())
2504 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002505 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002506
2507 def initialize(self):
2508 """
2509 The C statements required to set up this variable before parsing.
2510 Returns a string containing this code indented at column 0.
2511 If no initialization is necessary, returns an empty string.
2512 """
2513 return ""
2514
Larry Hastingsc2047262014-01-25 20:43:29 -08002515 def modify(self):
2516 """
2517 The C statements required to modify this variable after parsing.
2518 Returns a string containing this code indented at column 0.
2519 If no initialization is necessary, returns an empty string.
2520 """
2521 return ""
2522
Larry Hastings31826802013-10-19 00:09:25 -07002523 def cleanup(self):
2524 """
2525 The C statements required to clean up after this variable.
2526 Returns a string containing this code indented at column 0.
2527 If no cleanup is necessary, returns an empty string.
2528 """
2529 return ""
2530
Larry Hastings7726ac92014-01-31 22:03:12 -08002531 def pre_render(self):
2532 """
2533 A second initialization function, like converter_init,
2534 called just before rendering.
2535 You are permitted to examine self.function here.
2536 """
2537 pass
2538
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002539 def parse_arg(self, argname):
2540 if self.format_unit == 'O&':
2541 return """
2542 if (!{converter}({argname}, &{paramname})) {{{{
2543 goto exit;
2544 }}}}
2545 """.format(argname=argname, paramname=self.name,
2546 converter=self.converter)
2547 if self.format_unit == 'O!':
2548 cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
2549 if self.subclass_of in type_checks:
2550 typecheck, typename = type_checks[self.subclass_of]
2551 return """
2552 if (!{typecheck}({argname})) {{{{
2553 _PyArg_BadArgument("{{name}}", "{typename}", {argname});
2554 goto exit;
2555 }}}}
2556 {paramname} = {cast}{argname};
2557 """.format(argname=argname, paramname=self.name,
2558 typecheck=typecheck, typename=typename, cast=cast)
2559 return """
2560 if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{
2561 _PyArg_BadArgument("{{name}}", ({subclass_of})->tp_name, {argname});
2562 goto exit;
2563 }}}}
2564 {paramname} = {cast}{argname};
2565 """.format(argname=argname, paramname=self.name,
2566 subclass_of=self.subclass_of, cast=cast)
2567 return """
2568 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
2569 goto exit;
2570 }}
2571 """ % argname
2572
2573type_checks = {
2574 '&PyLong_Type': ('PyLong_Check', 'int'),
2575 '&PyTuple_Type': ('PyTuple_Check', 'tuple'),
2576 '&PyList_Type': ('PyList_Check', 'list'),
2577 '&PySet_Type': ('PySet_Check', 'set'),
2578 '&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'),
2579 '&PyDict_Type': ('PyDict_Check', 'dict'),
2580 '&PyUnicode_Type': ('PyUnicode_Check', 'str'),
2581 '&PyBytes_Type': ('PyBytes_Check', 'bytes'),
2582 '&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'),
2583}
2584
Larry Hastings31826802013-10-19 00:09:25 -07002585
2586class bool_converter(CConverter):
2587 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002588 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002589 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002590 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002591
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002592 def converter_init(self, *, accept={object}):
2593 if accept == {int}:
2594 self.format_unit = 'i'
2595 elif accept != {object}:
2596 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002597 if self.default is not unspecified:
2598 self.default = bool(self.default)
2599 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002600
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002601 def parse_arg(self, argname):
2602 if self.format_unit == 'i':
2603 return """
2604 if (PyFloat_Check({argname})) {{{{
2605 PyErr_SetString(PyExc_TypeError,
2606 "integer argument expected, got float" );
2607 goto exit;
2608 }}}}
2609 {paramname} = _PyLong_AsInt({argname});
2610 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2611 goto exit;
2612 }}}}
2613 """.format(argname=argname, paramname=self.name)
2614 elif self.format_unit == 'p':
2615 return """
2616 {paramname} = PyObject_IsTrue({argname});
2617 if ({paramname} < 0) {{{{
2618 goto exit;
2619 }}}}
2620 """.format(argname=argname, paramname=self.name)
2621 return super().parse_arg(argname)
2622
Larry Hastings31826802013-10-19 00:09:25 -07002623class char_converter(CConverter):
2624 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002625 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002626 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002627 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002628
Larry Hastings4a55fc52014-01-12 11:09:57 -08002629 def converter_init(self):
Tal Einatc929df32018-07-06 13:17:38 +03002630 if isinstance(self.default, self.default_type):
2631 if len(self.default) != 1:
2632 fail("char_converter: illegal default value " + repr(self.default))
2633
Serhiy Storchaka65ce60a2018-12-25 11:10:05 +02002634 self.c_default = repr(bytes(self.default))[1:]
2635 if self.c_default == '"\'"':
2636 self.c_default = r"'\''"
Larry Hastings4a55fc52014-01-12 11:09:57 -08002637
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002638 def parse_arg(self, argname):
2639 if self.format_unit == 'c':
2640 return """
2641 if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
2642 {paramname} = PyBytes_AS_STRING({argname})[0];
2643 }}}}
2644 else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{
2645 {paramname} = PyByteArray_AS_STRING({argname})[0];
2646 }}}}
2647 else {{{{
2648 _PyArg_BadArgument("{{name}}", "a byte string of length 1", {argname});
2649 goto exit;
2650 }}}}
2651 """.format(argname=argname, paramname=self.name)
2652 return super().parse_arg(argname)
2653
Larry Hastings4a55fc52014-01-12 11:09:57 -08002654
Larry Hastings31826802013-10-19 00:09:25 -07002655@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002656class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002657 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002658 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002659 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002660 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002661
2662 def converter_init(self, *, bitwise=False):
2663 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002664 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002665
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002666 def parse_arg(self, argname):
2667 if self.format_unit == 'b':
2668 return """
2669 if (PyFloat_Check({argname})) {{{{
2670 PyErr_SetString(PyExc_TypeError,
2671 "integer argument expected, got float" );
2672 goto exit;
2673 }}}}
2674 {{{{
2675 long ival = PyLong_AsLong({argname});
2676 if (ival == -1 && PyErr_Occurred()) {{{{
2677 goto exit;
2678 }}}}
2679 else if (ival < 0) {{{{
2680 PyErr_SetString(PyExc_OverflowError,
2681 "unsigned byte integer is less than minimum");
2682 goto exit;
2683 }}}}
2684 else if (ival > UCHAR_MAX) {{{{
2685 PyErr_SetString(PyExc_OverflowError,
2686 "unsigned byte integer is greater than maximum");
2687 goto exit;
2688 }}}}
2689 else {{{{
2690 {paramname} = (unsigned char) ival;
2691 }}}}
2692 }}}}
2693 """.format(argname=argname, paramname=self.name)
2694 elif self.format_unit == 'B':
2695 return """
2696 if (PyFloat_Check({argname})) {{{{
2697 PyErr_SetString(PyExc_TypeError,
2698 "integer argument expected, got float" );
2699 goto exit;
2700 }}}}
2701 {{{{
2702 long ival = PyLong_AsUnsignedLongMask({argname});
2703 if (ival == -1 && PyErr_Occurred()) {{{{
2704 goto exit;
2705 }}}}
2706 else {{{{
2707 {paramname} = (unsigned char) ival;
2708 }}}}
2709 }}}}
2710 """.format(argname=argname, paramname=self.name)
2711 return super().parse_arg(argname)
2712
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002713class byte_converter(unsigned_char_converter): pass
2714
Larry Hastings31826802013-10-19 00:09:25 -07002715class short_converter(CConverter):
2716 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002717 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002718 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002719 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002720
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002721 def parse_arg(self, argname):
2722 if self.format_unit == 'h':
2723 return """
2724 if (PyFloat_Check({argname})) {{{{
2725 PyErr_SetString(PyExc_TypeError,
2726 "integer argument expected, got float" );
2727 goto exit;
2728 }}}}
2729 {{{{
2730 long ival = PyLong_AsLong({argname});
2731 if (ival == -1 && PyErr_Occurred()) {{{{
2732 goto exit;
2733 }}}}
2734 else if (ival < SHRT_MIN) {{{{
2735 PyErr_SetString(PyExc_OverflowError,
2736 "signed short integer is less than minimum");
2737 goto exit;
2738 }}}}
2739 else if (ival > SHRT_MAX) {{{{
2740 PyErr_SetString(PyExc_OverflowError,
2741 "signed short integer is greater than maximum");
2742 goto exit;
2743 }}}}
2744 else {{{{
2745 {paramname} = (short) ival;
2746 }}}}
2747 }}}}
2748 """.format(argname=argname, paramname=self.name)
2749 return super().parse_arg(argname)
2750
Larry Hastings31826802013-10-19 00:09:25 -07002751class unsigned_short_converter(CConverter):
2752 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002753 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002754 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002755
2756 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002757 if bitwise:
2758 self.format_unit = 'H'
2759 else:
2760 self.converter = '_PyLong_UnsignedShort_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002761
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002762@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002763class int_converter(CConverter):
2764 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002765 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002766 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002767 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002768
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002769 def converter_init(self, *, accept={int}, type=None):
2770 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002771 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002772 elif accept != {int}:
2773 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002774 if type != None:
2775 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002776
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002777 def parse_arg(self, argname):
2778 if self.format_unit == 'i':
2779 return """
2780 if (PyFloat_Check({argname})) {{{{
2781 PyErr_SetString(PyExc_TypeError,
2782 "integer argument expected, got float" );
2783 goto exit;
2784 }}}}
2785 {paramname} = _PyLong_AsInt({argname});
2786 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2787 goto exit;
2788 }}}}
2789 """.format(argname=argname, paramname=self.name)
2790 elif self.format_unit == 'C':
2791 return """
2792 if (!PyUnicode_Check({argname})) {{{{
2793 _PyArg_BadArgument("{{name}}", "a unicode character", {argname});
2794 goto exit;
2795 }}}}
2796 if (PyUnicode_READY({argname})) {{{{
2797 goto exit;
2798 }}}}
2799 if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{
2800 _PyArg_BadArgument("{{name}}", "a unicode character", {argname});
2801 goto exit;
2802 }}}}
2803 {paramname} = PyUnicode_READ_CHAR({argname}, 0);
2804 """.format(argname=argname, paramname=self.name)
2805 return super().parse_arg(argname)
2806
Larry Hastings31826802013-10-19 00:09:25 -07002807class unsigned_int_converter(CConverter):
2808 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002809 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002810 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002811
2812 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002813 if bitwise:
2814 self.format_unit = 'I'
2815 else:
2816 self.converter = '_PyLong_UnsignedInt_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002817
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002818 def parse_arg(self, argname):
2819 if self.format_unit == 'I':
2820 return """
2821 if (PyFloat_Check({argname})) {{{{
2822 PyErr_SetString(PyExc_TypeError,
2823 "integer argument expected, got float" );
2824 goto exit;
2825 }}}}
2826 {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
2827 if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{
2828 goto exit;
2829 }}}}
2830 """.format(argname=argname, paramname=self.name)
2831 return super().parse_arg(argname)
2832
Larry Hastings31826802013-10-19 00:09:25 -07002833class long_converter(CConverter):
2834 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002835 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002836 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002837 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002838
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002839 def parse_arg(self, argname):
2840 if self.format_unit == 'l':
2841 return """
2842 if (PyFloat_Check({argname})) {{{{
2843 PyErr_SetString(PyExc_TypeError,
2844 "integer argument expected, got float" );
2845 goto exit;
2846 }}}}
2847 {paramname} = PyLong_AsLong({argname});
2848 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2849 goto exit;
2850 }}}}
2851 """.format(argname=argname, paramname=self.name)
2852 return super().parse_arg(argname)
2853
Larry Hastings31826802013-10-19 00:09:25 -07002854class unsigned_long_converter(CConverter):
2855 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002856 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002857 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002858
2859 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002860 if bitwise:
2861 self.format_unit = 'k'
2862 else:
2863 self.converter = '_PyLong_UnsignedLong_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002864
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002865 def parse_arg(self, argname):
2866 if self.format_unit == 'k':
2867 return """
2868 if (!PyLong_Check({argname})) {{{{
2869 _PyArg_BadArgument("{{name}}", "int", {argname});
2870 goto exit;
2871 }}}}
2872 {paramname} = PyLong_AsUnsignedLongMask({argname});
2873 """.format(argname=argname, paramname=self.name)
2874 return super().parse_arg(argname)
2875
Benjamin Petersoncc854492016-09-08 09:29:11 -07002876class long_long_converter(CConverter):
2877 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002878 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002879 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002880 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002881
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002882 def parse_arg(self, argname):
2883 if self.format_unit == 'L':
2884 return """
2885 if (PyFloat_Check({argname})) {{{{
2886 PyErr_SetString(PyExc_TypeError,
2887 "integer argument expected, got float" );
2888 goto exit;
2889 }}}}
2890 {paramname} = PyLong_AsLongLong({argname});
2891 if ({paramname} == (PY_LONG_LONG)-1 && PyErr_Occurred()) {{{{
2892 goto exit;
2893 }}}}
2894 """.format(argname=argname, paramname=self.name)
2895 return super().parse_arg(argname)
2896
Benjamin Petersoncc854492016-09-08 09:29:11 -07002897class unsigned_long_long_converter(CConverter):
2898 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002899 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002900 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002901
2902 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002903 if bitwise:
2904 self.format_unit = 'K'
2905 else:
2906 self.converter = '_PyLong_UnsignedLongLong_Converter'
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002907
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002908 def parse_arg(self, argname):
2909 if self.format_unit == 'K':
2910 return """
2911 if (!PyLong_Check({argname})) {{{{
2912 _PyArg_BadArgument("{{name}}", "int", {argname});
2913 goto exit;
2914 }}}}
2915 {paramname} = PyLong_AsUnsignedLongLongMask({argname});
2916 """.format(argname=argname, paramname=self.name)
2917 return super().parse_arg(argname)
2918
Larry Hastings31826802013-10-19 00:09:25 -07002919class Py_ssize_t_converter(CConverter):
2920 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002921 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002922
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002923 def converter_init(self, *, accept={int}):
2924 if accept == {int}:
2925 self.format_unit = 'n'
2926 self.default_type = int
2927 elif accept == {int, NoneType}:
2928 self.converter = '_Py_convert_optional_to_ssize_t'
2929 else:
2930 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
2931
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002932 def parse_arg(self, argname):
2933 if self.format_unit == 'n':
2934 return """
2935 if (PyFloat_Check({argname})) {{{{
2936 PyErr_SetString(PyExc_TypeError,
2937 "integer argument expected, got float" );
2938 goto exit;
2939 }}}}
2940 {{{{
2941 Py_ssize_t ival = -1;
2942 PyObject *iobj = PyNumber_Index({argname});
2943 if (iobj != NULL) {{{{
2944 ival = PyLong_AsSsize_t(iobj);
2945 Py_DECREF(iobj);
2946 }}}}
2947 if (ival == -1 && PyErr_Occurred()) {{{{
2948 goto exit;
2949 }}}}
2950 {paramname} = ival;
2951 }}}}
2952 """.format(argname=argname, paramname=self.name)
2953 return super().parse_arg(argname)
2954
Larry Hastings31826802013-10-19 00:09:25 -07002955
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002956class slice_index_converter(CConverter):
2957 type = 'Py_ssize_t'
2958
2959 def converter_init(self, *, accept={int, NoneType}):
2960 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002961 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002962 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002963 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002964 else:
2965 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
2966
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002967class size_t_converter(CConverter):
2968 type = 'size_t'
2969 converter = '_PyLong_Size_t_Converter'
2970 c_ignored_default = "0"
2971
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002972 def parse_arg(self, argname):
2973 if self.format_unit == 'n':
2974 return """
2975 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
2976 if ({paramname} == -1 && PyErr_Occurred()) {{{{
2977 goto exit;
2978 }}}}
2979 """.format(argname=argname, paramname=self.name)
2980 return super().parse_arg(argname)
2981
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002982
Larry Hastings31826802013-10-19 00:09:25 -07002983class float_converter(CConverter):
2984 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002985 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002986 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002987 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002988
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02002989 def parse_arg(self, argname):
2990 if self.format_unit == 'f':
2991 return """
2992 {paramname} = (float) PyFloat_AsDouble({argname});
2993 if (PyErr_Occurred()) {{{{
2994 goto exit;
2995 }}}}
2996 """.format(argname=argname, paramname=self.name)
2997 return super().parse_arg(argname)
2998
Larry Hastings31826802013-10-19 00:09:25 -07002999class double_converter(CConverter):
3000 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003001 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07003002 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003003 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07003004
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003005 def parse_arg(self, argname):
3006 if self.format_unit == 'd':
3007 return """
3008 {paramname} = PyFloat_AsDouble({argname});
3009 if (PyErr_Occurred()) {{{{
3010 goto exit;
3011 }}}}
3012 """.format(argname=argname, paramname=self.name)
3013 return super().parse_arg(argname)
3014
Larry Hastings31826802013-10-19 00:09:25 -07003015
3016class Py_complex_converter(CConverter):
3017 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003018 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07003019 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08003020 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07003021
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003022 def parse_arg(self, argname):
3023 if self.format_unit == 'D':
3024 return """
3025 {paramname} = PyComplex_AsCComplex({argname});
3026 if (PyErr_Occurred()) {{{{
3027 goto exit;
3028 }}}}
3029 """.format(argname=argname, paramname=self.name)
3030 return super().parse_arg(argname)
3031
Larry Hastings31826802013-10-19 00:09:25 -07003032
3033class object_converter(CConverter):
3034 type = 'PyObject *'
3035 format_unit = 'O'
3036
Larry Hastings4a55fc52014-01-12 11:09:57 -08003037 def converter_init(self, *, converter=None, type=None, subclass_of=None):
3038 if converter:
3039 if subclass_of:
3040 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
3041 self.format_unit = 'O&'
3042 self.converter = converter
3043 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07003044 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08003045 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08003046
Larry Hastings77561cc2014-01-07 12:13:13 -08003047 if type is not None:
3048 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07003049
3050
Larry Hastings7f90cba2015-04-15 23:02:12 -04003051#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003052# We define three conventions for buffer types in the 'accept' argument:
3053#
3054# buffer : any object supporting the buffer interface
3055# rwbuffer: any object supporting the buffer interface, but must be writeable
3056# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04003057#
3058
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003059class buffer: pass
3060class rwbuffer: pass
3061class robuffer: pass
3062
Larry Hastings38337d12015-05-07 23:30:09 -07003063def str_converter_key(types, encoding, zeroes):
3064 return (frozenset(types), bool(encoding), bool(zeroes))
3065
3066str_converter_argument_map = {}
3067
Larry Hastings31826802013-10-19 00:09:25 -07003068class str_converter(CConverter):
3069 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003070 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003071 format_unit = 's'
3072
Larry Hastings38337d12015-05-07 23:30:09 -07003073 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003074
Larry Hastings38337d12015-05-07 23:30:09 -07003075 key = str_converter_key(accept, encoding, zeroes)
3076 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003077 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07003078 fail("str_converter: illegal combination of arguments", key)
3079
Larry Hastingsebdcb502013-11-23 14:54:00 -08003080 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07003081 self.length = bool(zeroes)
3082 if encoding:
3083 if self.default not in (Null, None, unspecified):
3084 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
3085 self.encoding = encoding
3086 self.type = 'char *'
3087 # sorry, clinic can't support preallocated buffers
3088 # for es# and et#
3089 self.c_default = "NULL"
3090
3091 def cleanup(self):
3092 if self.encoding:
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003093 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003094 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07003095
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003096 def parse_arg(self, argname):
3097 if self.format_unit == 's':
3098 return """
3099 if (!PyUnicode_Check({argname})) {{{{
3100 _PyArg_BadArgument("{{name}}", "str", {argname});
3101 goto exit;
3102 }}}}
3103 Py_ssize_t {paramname}_length;
3104 {paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
3105 if ({paramname} == NULL) {{{{
3106 goto exit;
3107 }}}}
3108 if (strlen({paramname}) != (size_t){paramname}_length) {{{{
3109 PyErr_SetString(PyExc_ValueError, "embedded null character");
3110 goto exit;
3111 }}}}
3112 """.format(argname=argname, paramname=self.name)
3113 return super().parse_arg(argname)
3114
Larry Hastings38337d12015-05-07 23:30:09 -07003115#
3116# This is the fourth or fifth rewrite of registering all the
Raymond Hettinger14010182018-09-13 21:17:40 -07003117# string converter format units. Previous approaches hid
Larry Hastings38337d12015-05-07 23:30:09 -07003118# bugs--generally mismatches between the semantics of the format
3119# unit and the arguments necessary to represent those semantics
3120# properly. Hopefully with this approach we'll get it 100% right.
3121#
3122# The r() function (short for "register") both registers the
3123# mapping from arguments to format unit *and* registers the
3124# legacy C converter for that format unit.
3125#
3126def r(format_unit, *, accept, encoding=False, zeroes=False):
3127 if not encoding and format_unit != 's':
3128 # add the legacy c converters here too.
3129 #
3130 # note: add_legacy_c_converter can't work for
3131 # es, es#, et, or et#
3132 # because of their extra encoding argument
3133 #
3134 # also don't add the converter for 's' because
3135 # the metaclass for CConverter adds it for us.
3136 kwargs = {}
3137 if accept != {str}:
3138 kwargs['accept'] = accept
3139 if zeroes:
3140 kwargs['zeroes'] = True
3141 added_f = functools.partial(str_converter, **kwargs)
3142 legacy_converters[format_unit] = added_f
3143
3144 d = str_converter_argument_map
3145 key = str_converter_key(accept, encoding, zeroes)
3146 if key in d:
3147 sys.exit("Duplicate keys specified for str_converter_argument_map!")
3148 d[key] = format_unit
3149
3150r('es', encoding=True, accept={str})
3151r('es#', encoding=True, zeroes=True, accept={str})
3152r('et', encoding=True, accept={bytes, bytearray, str})
3153r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
3154r('s', accept={str})
3155r('s#', zeroes=True, accept={robuffer, str})
3156r('y', accept={robuffer})
3157r('y#', zeroes=True, accept={robuffer})
3158r('z', accept={str, NoneType})
3159r('z#', zeroes=True, accept={robuffer, str, NoneType})
3160del r
Larry Hastings31826802013-10-19 00:09:25 -07003161
3162
3163class PyBytesObject_converter(CConverter):
3164 type = 'PyBytesObject *'
3165 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003166 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07003167
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003168 def parse_arg(self, argname):
3169 if self.format_unit == 'S':
3170 return """
3171 if (!PyBytes_Check({argname})) {{{{
3172 _PyArg_BadArgument("{{name}}", "bytes", {argname});
3173 goto exit;
3174 }}}}
3175 {paramname} = ({type}){argname};
3176 """.format(argname=argname, paramname=self.name, type=self.type)
3177 return super().parse_arg(argname)
3178
Larry Hastings31826802013-10-19 00:09:25 -07003179class PyByteArrayObject_converter(CConverter):
3180 type = 'PyByteArrayObject *'
3181 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003182 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07003183
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003184 def parse_arg(self, argname):
3185 if self.format_unit == 'Y':
3186 return """
3187 if (!PyByteArray_Check({argname})) {{{{
3188 _PyArg_BadArgument("{{name}}", "bytearray", {argname});
3189 goto exit;
3190 }}}}
3191 {paramname} = ({type}){argname};
3192 """.format(argname=argname, paramname=self.name, type=self.type)
3193 return super().parse_arg(argname)
3194
Larry Hastings31826802013-10-19 00:09:25 -07003195class unicode_converter(CConverter):
3196 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003197 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003198 format_unit = 'U'
3199
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003200 def parse_arg(self, argname):
3201 if self.format_unit == 'U':
3202 return """
3203 if (!PyUnicode_Check({argname})) {{{{
3204 _PyArg_BadArgument("{{name}}", "str", {argname});
3205 goto exit;
3206 }}}}
3207 if (PyUnicode_READY({argname}) == -1) {{{{
3208 goto exit;
3209 }}}}
3210 {paramname} = {argname};
3211 """.format(argname=argname, paramname=self.name)
3212 return super().parse_arg(argname)
3213
Larry Hastings38337d12015-05-07 23:30:09 -07003214@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003215@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07003216@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07003217class Py_UNICODE_converter(CConverter):
Serhiy Storchakaafb3e712018-12-14 11:19:51 +02003218 type = 'const Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003219 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07003220 format_unit = 'u'
3221
Larry Hastings38337d12015-05-07 23:30:09 -07003222 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003223 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07003224 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003225 format_unit += '#'
3226 self.length = True
3227 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003228
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003229@add_legacy_c_converter('s*', accept={str, buffer})
3230@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
3231@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07003232class Py_buffer_converter(CConverter):
3233 type = 'Py_buffer'
3234 format_unit = 'y*'
3235 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08003236 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07003237
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003238 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08003239 if self.default not in (unspecified, None):
3240 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003241
Larry Hastings3f144c22014-01-06 10:34:00 -08003242 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08003243
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003244 if accept == {str, buffer, NoneType}:
3245 format_unit = 'z*'
3246 elif accept == {str, buffer}:
3247 format_unit = 's*'
3248 elif accept == {buffer}:
3249 format_unit = 'y*'
3250 elif accept == {rwbuffer}:
3251 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07003252 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08003253 fail("Py_buffer_converter: illegal combination of arguments")
3254
3255 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07003256
3257 def cleanup(self):
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003258 name = self.name
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003259 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08003260
Serhiy Storchaka32d96a22018-12-25 13:23:47 +02003261 def parse_arg(self, argname):
3262 if self.format_unit == 'y*':
3263 return """
3264 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3265 goto exit;
3266 }}}}
3267 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
3268 _PyArg_BadArgument("{{name}}", "contiguous buffer", {argname});
3269 goto exit;
3270 }}}}
3271 """.format(argname=argname, paramname=self.name)
3272 elif self.format_unit == 's*':
3273 return """
3274 if (PyUnicode_Check({argname})) {{{{
3275 Py_ssize_t len;
3276 const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
3277 if (ptr == NULL) {{{{
3278 goto exit;
3279 }}}}
3280 PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
3281 }}}}
3282 else {{{{ /* any bytes-like object */
3283 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
3284 goto exit;
3285 }}}}
3286 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
3287 _PyArg_BadArgument("{{name}}", "contiguous buffer", {argname});
3288 goto exit;
3289 }}}}
3290 }}}}
3291 """.format(argname=argname, paramname=self.name)
3292 elif self.format_unit == 'w*':
3293 return """
3294 if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
3295 PyErr_Clear();
3296 _PyArg_BadArgument("{{name}}", "read-write bytes-like object", {argname});
3297 goto exit;
3298 }}}}
3299 if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
3300 _PyArg_BadArgument("{{name}}", "contiguous buffer", {argname});
3301 goto exit;
3302 }}}}
3303 """.format(argname=argname, paramname=self.name)
3304 return super().parse_arg(argname)
3305
Larry Hastingsebdcb502013-11-23 14:54:00 -08003306
Larry Hastings5c661892014-01-24 06:17:25 -08003307def correct_name_for_self(f):
3308 if f.kind in (CALLABLE, METHOD_INIT):
3309 if f.cls:
3310 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03003311 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08003312 if f.kind == STATIC_METHOD:
3313 return "void *", "null"
3314 if f.kind in (CLASS_METHOD, METHOD_NEW):
3315 return "PyTypeObject *", "type"
3316 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
3317
Larry Hastingsc2047262014-01-25 20:43:29 -08003318def required_type_for_self_for_parser(f):
3319 type, _ = correct_name_for_self(f)
3320 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
3321 return type
3322 return None
3323
Larry Hastings5c661892014-01-24 06:17:25 -08003324
Larry Hastingsebdcb502013-11-23 14:54:00 -08003325class self_converter(CConverter):
3326 """
3327 A special-case converter:
3328 this is the default converter used for "self".
3329 """
Larry Hastings5c661892014-01-24 06:17:25 -08003330 type = None
3331 format_unit = ''
3332
Larry Hastings78cf85c2014-01-04 12:44:57 -08003333 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08003334 self.specified_type = type
3335
3336 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08003337 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08003338 default_type, default_name = correct_name_for_self(f)
3339 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08003340 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08003341
Larry Hastings5c661892014-01-24 06:17:25 -08003342 kind = self.function.kind
3343 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
3344
3345 if (kind == STATIC_METHOD) or new_or_init:
3346 self.show_in_signature = False
3347
3348 # tp_new (METHOD_NEW) functions are of type newfunc:
3349 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
3350 # PyTypeObject is a typedef for struct _typeobject.
3351 #
3352 # tp_init (METHOD_INIT) functions are of type initproc:
3353 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
3354 #
3355 # All other functions generated by Argument Clinic are stored in
3356 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
3357 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
3358 # However! We habitually cast these functions to PyCFunction,
3359 # since functions that accept keyword arguments don't fit this signature
3360 # but are stored there anyway. So strict type equality isn't important
3361 # for these functions.
3362 #
3363 # So:
3364 #
3365 # * The name of the first parameter to the impl and the parsing function will always
3366 # be self.name.
3367 #
3368 # * The type of the first parameter to the impl will always be of self.type.
3369 #
3370 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
3371 # * The type of the first parameter to the parsing function is also self.type.
3372 # This means that if you step into the parsing function, your "self" parameter
3373 # is of the correct type, which may make debugging more pleasant.
3374 #
3375 # * Else if the function is tp_new (METHOD_NEW):
3376 # * The type of the first parameter to the parsing function is "PyTypeObject *",
3377 # so the type signature of the function call is an exact match.
3378 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
3379 # in the impl call.
3380 #
3381 # * Else if the function is tp_init (METHOD_INIT):
3382 # * The type of the first parameter to the parsing function is "PyObject *",
3383 # so the type signature of the function call is an exact match.
3384 # * If self.type != "PyObject *", we cast the first parameter to self.type
3385 # in the impl call.
3386
3387 @property
3388 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08003389 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08003390
Larry Hastingsebdcb502013-11-23 14:54:00 -08003391 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08003392 """
3393 parameter is a clinic.Parameter instance.
3394 data is a CRenderData instance.
3395 """
3396 if self.function.kind == STATIC_METHOD:
3397 return
3398
3399 self._render_self(parameter, data)
3400
3401 if self.type != self.parser_type:
3402 # insert cast to impl_argument[0], aka self.
3403 # we know we're in the first slot in all the CRenderData lists,
3404 # because we render parameters in order, and self is always first.
3405 assert len(data.impl_arguments) == 1
3406 assert data.impl_arguments[0] == self.name
3407 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3408
3409 def set_template_dict(self, template_dict):
3410 template_dict['self_name'] = self.name
3411 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003412 kind = self.function.kind
3413 cls = self.function.cls
3414
3415 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3416 if kind == METHOD_NEW:
3417 passed_in_type = self.name
3418 else:
3419 passed_in_type = 'Py_TYPE({})'.format(self.name)
3420
3421 line = '({passed_in_type} == {type_object}) &&\n '
3422 d = {
3423 'type_object': self.function.cls.type_object,
3424 'passed_in_type': passed_in_type
3425 }
3426 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003427
Larry Hastings31826802013-10-19 00:09:25 -07003428
3429
3430def add_c_return_converter(f, name=None):
3431 if not name:
3432 name = f.__name__
3433 if not name.endswith('_return_converter'):
3434 return f
3435 name = name[:-len('_return_converter')]
3436 return_converters[name] = f
3437 return f
3438
3439
3440class CReturnConverterAutoRegister(type):
3441 def __init__(cls, name, bases, classdict):
3442 add_c_return_converter(cls)
3443
3444class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3445
Larry Hastings78cf85c2014-01-04 12:44:57 -08003446 # The C type to use for this variable.
3447 # 'type' should be a Python string specifying the type, e.g. "int".
3448 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003449 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003450
3451 # The Python default value for this parameter, as a Python value.
3452 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003453 default = None
3454
Larry Hastings2a727912014-01-16 11:32:01 -08003455 def __init__(self, *, py_default=None, **kwargs):
3456 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003457 try:
3458 self.return_converter_init(**kwargs)
3459 except TypeError as e:
3460 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3461 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3462
3463 def return_converter_init(self):
3464 pass
3465
3466 def declare(self, data, name="_return_value"):
3467 line = []
3468 add = line.append
3469 add(self.type)
3470 if not self.type.endswith('*'):
3471 add(' ')
3472 add(name + ';')
3473 data.declarations.append(''.join(line))
3474 data.return_value = name
3475
3476 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003477 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003478
3479 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003480 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003481
3482 def render(self, function, data):
3483 """
3484 function is a clinic.Function instance.
3485 data is a CRenderData instance.
3486 """
3487 pass
3488
3489add_c_return_converter(CReturnConverter, 'object')
3490
Larry Hastings78cf85c2014-01-04 12:44:57 -08003491class NoneType_return_converter(CReturnConverter):
3492 def render(self, function, data):
3493 self.declare(data)
3494 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003495if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003496 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003497}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003498return_value = Py_None;
3499Py_INCREF(Py_None);
3500'''.strip())
3501
Larry Hastings4a55fc52014-01-12 11:09:57 -08003502class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003503 type = 'int'
3504
3505 def render(self, function, data):
3506 self.declare(data)
3507 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003508 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003509
3510class long_return_converter(CReturnConverter):
3511 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003512 conversion_fn = 'PyLong_FromLong'
3513 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003514 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003515
3516 def render(self, function, data):
3517 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003518 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003519 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003520 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003521
Larry Hastings4a55fc52014-01-12 11:09:57 -08003522class int_return_converter(long_return_converter):
3523 type = 'int'
3524 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003525
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003526class init_return_converter(long_return_converter):
3527 """
3528 Special return converter for __init__ functions.
3529 """
3530 type = 'int'
3531 cast = '(long)'
3532
3533 def render(self, function, data):
3534 pass
3535
Larry Hastings4a55fc52014-01-12 11:09:57 -08003536class unsigned_long_return_converter(long_return_converter):
3537 type = 'unsigned long'
3538 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003539 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003540
3541class unsigned_int_return_converter(unsigned_long_return_converter):
3542 type = 'unsigned int'
3543 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003544 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003545
3546class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003547 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003548 conversion_fn = 'PyLong_FromSsize_t'
3549
3550class size_t_return_converter(long_return_converter):
3551 type = 'size_t'
3552 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003553 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003554
3555
3556class double_return_converter(CReturnConverter):
3557 type = 'double'
3558 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003559
3560 def render(self, function, data):
3561 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003562 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003563 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003564 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3565
3566class float_return_converter(double_return_converter):
3567 type = 'float'
3568 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003569
3570
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003571def eval_ast_expr(node, globals, *, filename='-'):
3572 """
3573 Takes an ast.Expr node. Compiles and evaluates it.
3574 Returns the result of the expression.
3575
3576 globals represents the globals dict the expression
3577 should see. (There's no equivalent for "locals" here.)
3578 """
3579
3580 if isinstance(node, ast.Expr):
3581 node = node.value
3582
3583 node = ast.Expression(node)
3584 co = compile(node, filename, 'eval')
3585 fn = types.FunctionType(co, globals)
3586 return fn()
3587
3588
Larry Hastings31826802013-10-19 00:09:25 -07003589class IndentStack:
3590 def __init__(self):
3591 self.indents = []
3592 self.margin = None
3593
3594 def _ensure(self):
3595 if not self.indents:
3596 fail('IndentStack expected indents, but none are defined.')
3597
3598 def measure(self, line):
3599 """
3600 Returns the length of the line's margin.
3601 """
3602 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003603 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003604 stripped = line.lstrip()
3605 if not len(stripped):
3606 # we can't tell anything from an empty line
3607 # so just pretend it's indented like our current indent
3608 self._ensure()
3609 return self.indents[-1]
3610 return len(line) - len(stripped)
3611
3612 def infer(self, line):
3613 """
3614 Infer what is now the current margin based on this line.
3615 Returns:
3616 1 if we have indented (or this is the first margin)
3617 0 if the margin has not changed
3618 -N if we have dedented N times
3619 """
3620 indent = self.measure(line)
3621 margin = ' ' * indent
3622 if not self.indents:
3623 self.indents.append(indent)
3624 self.margin = margin
3625 return 1
3626 current = self.indents[-1]
3627 if indent == current:
3628 return 0
3629 if indent > current:
3630 self.indents.append(indent)
3631 self.margin = margin
3632 return 1
3633 # indent < current
3634 if indent not in self.indents:
3635 fail("Illegal outdent.")
3636 outdent_count = 0
3637 while indent != current:
3638 self.indents.pop()
3639 current = self.indents[-1]
3640 outdent_count -= 1
3641 self.margin = margin
3642 return outdent_count
3643
3644 @property
3645 def depth(self):
3646 """
3647 Returns how many margins are currently defined.
3648 """
3649 return len(self.indents)
3650
3651 def indent(self, line):
3652 """
3653 Indents a line by the currently defined margin.
3654 """
3655 return self.margin + line
3656
3657 def dedent(self, line):
3658 """
3659 Dedents a line by the currently defined margin.
3660 (The inverse of 'indent'.)
3661 """
3662 margin = self.margin
3663 indent = self.indents[-1]
3664 if not line.startswith(margin):
3665 fail('Cannot dedent, line does not start with the previous margin:')
3666 return line[indent:]
3667
3668
3669class DSLParser:
3670 def __init__(self, clinic):
3671 self.clinic = clinic
3672
3673 self.directives = {}
3674 for name in dir(self):
3675 # functions that start with directive_ are added to directives
3676 _, s, key = name.partition("directive_")
3677 if s:
3678 self.directives[key] = getattr(self, name)
3679
3680 # functions that start with at_ are too, with an @ in front
3681 _, s, key = name.partition("at_")
3682 if s:
3683 self.directives['@' + key] = getattr(self, name)
3684
3685 self.reset()
3686
3687 def reset(self):
3688 self.function = None
3689 self.state = self.state_dsl_start
3690 self.parameter_indent = None
3691 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003692 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003693 self.group = 0
3694 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003695 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003696 self.indent = IndentStack()
3697 self.kind = CALLABLE
3698 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003699 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003700 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003701
Larry Hastingsebdcb502013-11-23 14:54:00 -08003702 def directive_version(self, required):
3703 global version
3704 if version_comparitor(version, required) < 0:
3705 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3706
Larry Hastings31826802013-10-19 00:09:25 -07003707 def directive_module(self, name):
3708 fields = name.split('.')
3709 new = fields.pop()
3710 module, cls = self.clinic._module_and_class(fields)
3711 if cls:
3712 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003713
3714 if name in module.classes:
3715 fail("Already defined module " + repr(name) + "!")
3716
Larry Hastings31826802013-10-19 00:09:25 -07003717 m = Module(name, module)
3718 module.modules[name] = m
3719 self.block.signatures.append(m)
3720
Larry Hastingsc2047262014-01-25 20:43:29 -08003721 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003722 fields = name.split('.')
3723 in_classes = False
3724 parent = self
3725 name = fields.pop()
3726 so_far = []
3727 module, cls = self.clinic._module_and_class(fields)
3728
Larry Hastingsc2047262014-01-25 20:43:29 -08003729 parent = cls or module
3730 if name in parent.classes:
3731 fail("Already defined class " + repr(name) + "!")
3732
3733 c = Class(name, module, cls, typedef, type_object)
3734 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003735 self.block.signatures.append(c)
3736
Larry Hastingsbebf7352014-01-17 17:47:17 -08003737 def directive_set(self, name, value):
3738 if name not in ("line_prefix", "line_suffix"):
3739 fail("unknown variable", repr(name))
3740
3741 value = value.format_map({
3742 'block comment start': '/*',
3743 'block comment end': '*/',
3744 })
3745
3746 self.clinic.__dict__[name] = value
3747
3748 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003749 if command == 'new':
3750 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003751 return
3752
Zachary Ware071baa62014-01-21 23:07:12 -06003753 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003754 self.clinic.get_destination(name).clear()
3755 fail("unknown destination command", repr(command))
3756
3757
Larry Hastings0759f842015-04-03 13:09:02 -07003758 def directive_output(self, command_or_name, destination=''):
3759 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003760
Larry Hastings0759f842015-04-03 13:09:02 -07003761 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003762 preset = self.clinic.presets.get(destination)
3763 if not preset:
3764 fail("Unknown preset " + repr(destination) + "!")
3765 fd.update(preset)
3766 return
3767
Larry Hastings0759f842015-04-03 13:09:02 -07003768 if command_or_name == "push":
3769 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003770 return
3771
Larry Hastings0759f842015-04-03 13:09:02 -07003772 if command_or_name == "pop":
3773 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003774 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003775 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003776 fd.update(previous_fd)
3777 return
3778
3779 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003780 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003781 self.block.output.append(pprint.pformat(fd))
3782 self.block.output.append('\n')
3783 return
3784
3785 d = self.clinic.get_destination(destination)
3786
Larry Hastings0759f842015-04-03 13:09:02 -07003787 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003788 for name in list(fd):
3789 fd[name] = d
3790 return
3791
Larry Hastings0759f842015-04-03 13:09:02 -07003792 if command_or_name not in fd:
3793 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3794 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003795
3796 def directive_dump(self, name):
3797 self.block.output.append(self.clinic.get_destination(name).dump())
3798
3799 def directive_print(self, *args):
3800 self.block.output.append(' '.join(args))
3801 self.block.output.append('\n')
3802
3803 def directive_preserve(self):
3804 if self.preserve_output:
3805 fail("Can't have preserve twice in one block!")
3806 self.preserve_output = True
3807
Larry Hastings31826802013-10-19 00:09:25 -07003808 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003809 if self.kind is not CALLABLE:
3810 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003811 self.kind = CLASS_METHOD
3812
3813 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003814 if self.kind is not CALLABLE:
3815 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003816 self.kind = STATIC_METHOD
3817
3818 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003819 if self.coexist:
3820 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003821 self.coexist = True
3822
3823 def parse(self, block):
3824 self.reset()
3825 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003826 self.saved_output = self.block.output
3827 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003828 block_start = self.clinic.block_parser.line_number
3829 lines = block.input.split('\n')
3830 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3831 if '\t' in line:
3832 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3833 self.state(line)
3834
3835 self.next(self.state_terminal)
3836 self.state(None)
3837
Larry Hastingsbebf7352014-01-17 17:47:17 -08003838 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3839
3840 if self.preserve_output:
3841 if block.output:
3842 fail("'preserve' only works for blocks that don't produce any output!")
3843 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003844
3845 @staticmethod
3846 def ignore_line(line):
3847 # ignore comment-only lines
3848 if line.lstrip().startswith('#'):
3849 return True
3850
3851 # Ignore empty lines too
3852 # (but not in docstring sections!)
3853 if not line.strip():
3854 return True
3855
3856 return False
3857
3858 @staticmethod
3859 def calculate_indent(line):
3860 return len(line) - len(line.strip())
3861
3862 def next(self, state, line=None):
3863 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3864 self.state = state
3865 if line is not None:
3866 self.state(line)
3867
3868 def state_dsl_start(self, line):
3869 # self.block = self.ClinicOutputBlock(self)
3870 if self.ignore_line(line):
3871 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003872
3873 # is it a directive?
3874 fields = shlex.split(line)
3875 directive_name = fields[0]
3876 directive = self.directives.get(directive_name, None)
3877 if directive:
3878 try:
3879 directive(*fields[1:])
3880 except TypeError as e:
3881 fail(str(e))
3882 return
3883
Larry Hastings31826802013-10-19 00:09:25 -07003884 self.next(self.state_modulename_name, line)
3885
3886 def state_modulename_name(self, line):
3887 # looking for declaration, which establishes the leftmost column
3888 # line should be
3889 # modulename.fnname [as c_basename] [-> return annotation]
3890 # square brackets denote optional syntax.
3891 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003892 # alternatively:
3893 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3894 # clones the parameters and return converter from that
3895 # function. you can't modify them. you must enter a
3896 # new docstring.
3897 #
Larry Hastings31826802013-10-19 00:09:25 -07003898 # (but we might find a directive first!)
3899 #
3900 # this line is permitted to start with whitespace.
3901 # we'll call this number of spaces F (for "function").
3902
3903 if not line.strip():
3904 return
3905
3906 self.indent.infer(line)
3907
Larry Hastings4a714d42014-01-14 22:22:41 -08003908 # are we cloning?
3909 before, equals, existing = line.rpartition('=')
3910 if equals:
3911 full_name, _, c_basename = before.partition(' as ')
3912 full_name = full_name.strip()
3913 c_basename = c_basename.strip()
3914 existing = existing.strip()
3915 if (is_legal_py_identifier(full_name) and
3916 (not c_basename or is_legal_c_identifier(c_basename)) and
3917 is_legal_py_identifier(existing)):
3918 # we're cloning!
3919 fields = [x.strip() for x in existing.split('.')]
3920 function_name = fields.pop()
3921 module, cls = self.clinic._module_and_class(fields)
3922
3923 for existing_function in (cls or module).functions:
3924 if existing_function.name == function_name:
3925 break
3926 else:
3927 existing_function = None
3928 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003929 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003930 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003931 fail("Couldn't find existing function " + repr(existing) + "!")
3932
3933 fields = [x.strip() for x in full_name.split('.')]
3934 function_name = fields.pop()
3935 module, cls = self.clinic._module_and_class(fields)
3936
3937 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3938 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003939 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 -08003940
3941 self.block.signatures.append(self.function)
3942 (cls or module).functions.append(self.function)
3943 self.next(self.state_function_docstring)
3944 return
3945
Larry Hastings31826802013-10-19 00:09:25 -07003946 line, _, returns = line.partition('->')
3947
3948 full_name, _, c_basename = line.partition(' as ')
3949 full_name = full_name.strip()
3950 c_basename = c_basename.strip() or None
3951
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003952 if not is_legal_py_identifier(full_name):
3953 fail("Illegal function name: {}".format(full_name))
3954 if c_basename and not is_legal_c_identifier(c_basename):
3955 fail("Illegal C basename: {}".format(c_basename))
3956
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003957 return_converter = None
3958 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003959 ast_input = "def x() -> {}: pass".format(returns)
3960 module = None
3961 try:
3962 module = ast.parse(ast_input)
3963 except SyntaxError:
3964 pass
3965 if not module:
3966 fail("Badly-formed annotation for " + full_name + ": " + returns)
3967 try:
3968 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003969 if legacy:
3970 fail("Legacy converter {!r} not allowed as a return converter"
3971 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003972 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003973 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003974 return_converter = return_converters[name](**kwargs)
3975 except ValueError:
3976 fail("Badly-formed annotation for " + full_name + ": " + returns)
3977
3978 fields = [x.strip() for x in full_name.split('.')]
3979 function_name = fields.pop()
3980 module, cls = self.clinic._module_and_class(fields)
3981
Larry Hastings8666e652014-01-12 14:12:59 -08003982 fields = full_name.split('.')
3983 if fields[-1] == '__new__':
3984 if (self.kind != CLASS_METHOD) or (not cls):
3985 fail("__new__ must be a class method!")
3986 self.kind = METHOD_NEW
3987 elif fields[-1] == '__init__':
3988 if (self.kind != CALLABLE) or (not cls):
3989 fail("__init__ must be a normal method, not a class or static method!")
3990 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003991 if not return_converter:
3992 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003993 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003994 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003995
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003996 if not return_converter:
3997 return_converter = CReturnConverter()
3998
Larry Hastings31826802013-10-19 00:09:25 -07003999 if not module:
4000 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
4001 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
4002 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
4003 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08004004
4005 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08004006 type, name = correct_name_for_self(self.function)
4007 kwargs = {}
4008 if cls and type == "PyObject *":
4009 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08004010 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08004011 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
4012 self.function.parameters[sc.name] = p_self
4013
Larry Hastings4a714d42014-01-14 22:22:41 -08004014 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07004015 self.next(self.state_parameters_start)
4016
4017 # Now entering the parameters section. The rules, formally stated:
4018 #
4019 # * All lines must be indented with spaces only.
4020 # * The first line must be a parameter declaration.
4021 # * The first line must be indented.
4022 # * This first line establishes the indent for parameters.
4023 # * We'll call this number of spaces P (for "parameter").
4024 # * Thenceforth:
4025 # * Lines indented with P spaces specify a parameter.
4026 # * Lines indented with > P spaces are docstrings for the previous
4027 # parameter.
4028 # * We'll call this number of spaces D (for "docstring").
4029 # * All subsequent lines indented with >= D spaces are stored as
4030 # part of the per-parameter docstring.
4031 # * All lines will have the first D spaces of the indent stripped
4032 # before they are stored.
4033 # * It's illegal to have a line starting with a number of spaces X
4034 # such that P < X < D.
4035 # * A line with < P spaces is the first line of the function
4036 # docstring, which ends processing for parameters and per-parameter
4037 # docstrings.
4038 # * The first line of the function docstring must be at the same
4039 # indent as the function declaration.
4040 # * It's illegal to have any line in the parameters section starting
4041 # with X spaces such that F < X < P. (As before, F is the indent
4042 # of the function declaration.)
4043 #
Larry Hastings31826802013-10-19 00:09:25 -07004044 # Also, currently Argument Clinic places the following restrictions on groups:
4045 # * Each group must contain at least one parameter.
4046 # * Each group may contain at most one group, which must be the furthest
4047 # thing in the group from the required parameters. (The nested group
4048 # must be the first in the group when it's before the required
4049 # parameters, and the last thing in the group when after the required
4050 # parameters.)
4051 # * There may be at most one (top-level) group to the left or right of
4052 # the required parameters.
4053 # * You must specify a slash, and it must be after all parameters.
4054 # (In other words: either all parameters are positional-only,
4055 # or none are.)
4056 #
4057 # Said another way:
4058 # * Each group must contain at least one parameter.
4059 # * All left square brackets before the required parameters must be
4060 # consecutive. (You can't have a left square bracket followed
4061 # by a parameter, then another left square bracket. You can't
4062 # have a left square bracket, a parameter, a right square bracket,
4063 # and then a left square bracket.)
4064 # * All right square brackets after the required parameters must be
4065 # consecutive.
4066 #
4067 # These rules are enforced with a single state variable:
4068 # "parameter_state". (Previously the code was a miasma of ifs and
4069 # separate boolean state variables.) The states are:
4070 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004071 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4072 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07004073 #
4074 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4075 # 1: ps_left_square_before. left square brackets before required parameters.
4076 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08004077 # 3: ps_required. required parameters, positional-or-keyword or positional-only
4078 # (we don't know yet). (renumber left groups!)
4079 # 4: ps_optional. positional-or-keyword or positional-only parameters that
4080 # now must have default values.
4081 # 5: ps_group_after. in a group, after required parameters.
4082 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07004083 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004084 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07004085
4086 def state_parameters_start(self, line):
4087 if self.ignore_line(line):
4088 return
4089
4090 # if this line is not indented, we have no parameters
4091 if not self.indent.infer(line):
4092 return self.next(self.state_function_docstring, line)
4093
Larry Hastings2a727912014-01-16 11:32:01 -08004094 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07004095 return self.next(self.state_parameter, line)
4096
4097
4098 def to_required(self):
4099 """
4100 Transition to the "required" parameter state.
4101 """
4102 if self.parameter_state != self.ps_required:
4103 self.parameter_state = self.ps_required
4104 for p in self.function.parameters.values():
4105 p.group = -p.group
4106
4107 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08004108 if self.parameter_continuation:
4109 line = self.parameter_continuation + ' ' + line.lstrip()
4110 self.parameter_continuation = ''
4111
Larry Hastings31826802013-10-19 00:09:25 -07004112 if self.ignore_line(line):
4113 return
4114
4115 assert self.indent.depth == 2
4116 indent = self.indent.infer(line)
4117 if indent == -1:
4118 # we outdented, must be to definition column
4119 return self.next(self.state_function_docstring, line)
4120
4121 if indent == 1:
4122 # we indented, must be to new parameter docstring column
4123 return self.next(self.state_parameter_docstring_start, line)
4124
Larry Hastings2a727912014-01-16 11:32:01 -08004125 line = line.rstrip()
4126 if line.endswith('\\'):
4127 self.parameter_continuation = line[:-1]
4128 return
4129
Larry Hastings31826802013-10-19 00:09:25 -07004130 line = line.lstrip()
4131
4132 if line in ('*', '/', '[', ']'):
4133 self.parse_special_symbol(line)
4134 return
4135
4136 if self.parameter_state in (self.ps_start, self.ps_required):
4137 self.to_required()
4138 elif self.parameter_state == self.ps_left_square_before:
4139 self.parameter_state = self.ps_group_before
4140 elif self.parameter_state == self.ps_group_before:
4141 if not self.group:
4142 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08004143 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07004144 pass
4145 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004146 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07004147
Larry Hastings7726ac92014-01-31 22:03:12 -08004148 # handle "as" for parameters too
4149 c_name = None
4150 name, have_as_token, trailing = line.partition(' as ')
4151 if have_as_token:
4152 name = name.strip()
4153 if ' ' not in name:
4154 fields = trailing.strip().split(' ')
4155 if not fields:
4156 fail("Invalid 'as' clause!")
4157 c_name = fields[0]
4158 if c_name.endswith(':'):
4159 name += ':'
4160 c_name = c_name[:-1]
4161 fields[0] = name
4162 line = ' '.join(fields)
4163
Larry Hastings2a727912014-01-16 11:32:01 -08004164 base, equals, default = line.rpartition('=')
4165 if not equals:
4166 base = default
4167 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08004168
Larry Hastings31826802013-10-19 00:09:25 -07004169 module = None
4170 try:
Larry Hastings2a727912014-01-16 11:32:01 -08004171 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07004172 module = ast.parse(ast_input)
4173 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08004174 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08004175 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004176 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08004177 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08004178 default = None
4179 ast_input = "def x({}): pass".format(line)
4180 module = ast.parse(ast_input)
4181 except SyntaxError:
4182 pass
Larry Hastings31826802013-10-19 00:09:25 -07004183 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07004184 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07004185
4186 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004187
4188 if len(function_args.args) > 1:
4189 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
4190 if function_args.defaults or function_args.kw_defaults:
4191 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
4192 if function_args.vararg or function_args.kwarg:
4193 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
4194
Larry Hastings31826802013-10-19 00:09:25 -07004195 parameter = function_args.args[0]
4196
Larry Hastings16c51912014-01-07 11:53:01 -08004197 parameter_name = parameter.arg
4198 name, legacy, kwargs = self.parse_converter(parameter.annotation)
4199
Larry Hastings2a727912014-01-16 11:32:01 -08004200 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08004201 if self.parameter_state == self.ps_optional:
4202 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 -08004203 value = unspecified
4204 if 'py_default' in kwargs:
4205 fail("You can't specify py_default without specifying a default value!")
4206 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004207 if self.parameter_state == self.ps_required:
4208 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08004209 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06004210 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004211 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08004212 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08004213 try:
4214 module = ast.parse(ast_input)
4215
Larry Hastings5c661892014-01-24 06:17:25 -08004216 if 'c_default' not in kwargs:
4217 # we can only represent very simple data values in C.
4218 # detect whether default is okay, via a blacklist
4219 # of disallowed ast nodes.
4220 class DetectBadNodes(ast.NodeVisitor):
4221 bad = False
4222 def bad_node(self, node):
4223 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08004224
Larry Hastings5c661892014-01-24 06:17:25 -08004225 # inline function call
4226 visit_Call = bad_node
4227 # inline if statement ("x = 3 if y else z")
4228 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004229
Larry Hastings5c661892014-01-24 06:17:25 -08004230 # comprehensions and generator expressions
4231 visit_ListComp = visit_SetComp = bad_node
4232 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004233
Larry Hastings5c661892014-01-24 06:17:25 -08004234 # literals for advanced types
4235 visit_Dict = visit_Set = bad_node
4236 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004237
Larry Hastings5c661892014-01-24 06:17:25 -08004238 # "starred": "a = [1, 2, 3]; *a"
4239 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08004240
Larry Hastings5c661892014-01-24 06:17:25 -08004241 blacklist = DetectBadNodes()
4242 blacklist.visit(module)
4243 bad = blacklist.bad
4244 else:
4245 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06004246 # but at least make an attempt at ensuring it's a valid expression.
4247 try:
4248 value = eval(default)
4249 if value == unspecified:
4250 fail("'unspecified' is not a legal default value!")
4251 except NameError:
4252 pass # probably a named constant
4253 except Exception as e:
4254 fail("Malformed expression given as default value\n"
4255 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08004256 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08004257 fail("Unsupported expression as default value: " + repr(default))
4258
4259 expr = module.body[0].value
4260 # mild hack: explicitly support NULL as a default value
4261 if isinstance(expr, ast.Name) and expr.id == 'NULL':
4262 value = NULL
4263 py_default = 'None'
4264 c_default = "NULL"
4265 elif (isinstance(expr, ast.BinOp) or
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004266 (isinstance(expr, ast.UnaryOp) and
4267 not (isinstance(expr.operand, ast.Num) or
4268 (hasattr(ast, 'Constant') and
4269 isinstance(expr.operand, ast.Constant) and
4270 type(expr.operand.value) in (int, float, complex)))
4271 )):
Larry Hastings2a727912014-01-16 11:32:01 -08004272 c_default = kwargs.get("c_default")
4273 if not (isinstance(c_default, str) and c_default):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004274 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 -08004275 py_default = default
4276 value = unknown
4277 elif isinstance(expr, ast.Attribute):
4278 a = []
4279 n = expr
4280 while isinstance(n, ast.Attribute):
4281 a.append(n.attr)
4282 n = n.value
4283 if not isinstance(n, ast.Name):
4284 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
4285 a.append(n.id)
4286 py_default = ".".join(reversed(a))
4287
4288 c_default = kwargs.get("c_default")
4289 if not (isinstance(c_default, str) and c_default):
4290 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4291
4292 try:
4293 value = eval(py_default)
4294 except NameError:
4295 value = unknown
4296 else:
4297 value = ast.literal_eval(expr)
4298 py_default = repr(value)
4299 if isinstance(value, (bool, None.__class__)):
4300 c_default = "Py_" + py_default
4301 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08004302 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08004303 else:
4304 c_default = py_default
4305
4306 except SyntaxError as e:
4307 fail("Syntax error: " + repr(e.text))
4308 except (ValueError, AttributeError):
4309 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08004310 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08004311 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08004312 if not (isinstance(c_default, str) and c_default):
4313 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
4314
Larry Hastings2a727912014-01-16 11:32:01 -08004315 kwargs.setdefault('c_default', c_default)
4316 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004317
Larry Hastings31826802013-10-19 00:09:25 -07004318 dict = legacy_converters if legacy else converters
4319 legacy_str = "legacy " if legacy else ""
4320 if name not in dict:
4321 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08004322 # if you use a c_name for the parameter, we just give that name to the converter
4323 # but the parameter object gets the python name
4324 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07004325
4326 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08004327
4328 if isinstance(converter, self_converter):
4329 if len(self.function.parameters) == 1:
4330 if (self.parameter_state != self.ps_required):
4331 fail("A 'self' parameter cannot be marked optional.")
4332 if value is not unspecified:
4333 fail("A 'self' parameter cannot have a default value.")
4334 if self.group:
4335 fail("A 'self' parameter cannot be in an optional group.")
4336 kind = inspect.Parameter.POSITIONAL_ONLY
4337 self.parameter_state = self.ps_start
4338 self.function.parameters.clear()
4339 else:
4340 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
4341
Larry Hastings31826802013-10-19 00:09:25 -07004342 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08004343
4344 if parameter_name in self.function.parameters:
4345 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07004346 self.function.parameters[parameter_name] = p
4347
4348 def parse_converter(self, annotation):
Serhiy Storchaka3f228112018-09-27 17:42:37 +03004349 if (hasattr(ast, 'Constant') and
4350 isinstance(annotation, ast.Constant) and
4351 type(annotation.value) is str):
4352 return annotation.value, True, {}
4353
Larry Hastings31826802013-10-19 00:09:25 -07004354 if isinstance(annotation, ast.Str):
4355 return annotation.s, True, {}
4356
4357 if isinstance(annotation, ast.Name):
4358 return annotation.id, False, {}
4359
Larry Hastings4a55fc52014-01-12 11:09:57 -08004360 if not isinstance(annotation, ast.Call):
4361 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07004362
4363 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07004364 symbols = globals()
4365
4366 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07004367 return name, False, kwargs
4368
4369 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07004370 if symbol == '*':
4371 if self.keyword_only:
4372 fail("Function " + self.function.name + " uses '*' more than once.")
4373 self.keyword_only = True
4374 elif symbol == '[':
4375 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
4376 self.parameter_state = self.ps_left_square_before
4377 elif self.parameter_state in (self.ps_required, self.ps_group_after):
4378 self.parameter_state = self.ps_group_after
4379 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004380 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07004381 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08004382 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07004383 elif symbol == ']':
4384 if not self.group:
4385 fail("Function " + self.function.name + " has a ] without a matching [.")
4386 if not any(p.group == self.group for p in self.function.parameters.values()):
4387 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
4388 self.group -= 1
4389 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
4390 self.parameter_state = self.ps_group_before
4391 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
4392 self.parameter_state = self.ps_right_square_after
4393 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08004394 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07004395 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004396 if self.positional_only:
4397 fail("Function " + self.function.name + " uses '/' more than once.")
4398 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08004399 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07004400 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08004401 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
4402 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07004403 if self.keyword_only:
4404 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004405 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004406 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004407 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004408 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4409 p.kind = inspect.Parameter.POSITIONAL_ONLY
4410
4411 def state_parameter_docstring_start(self, line):
4412 self.parameter_docstring_indent = len(self.indent.margin)
4413 assert self.indent.depth == 3
4414 return self.next(self.state_parameter_docstring, line)
4415
4416 # every line of the docstring must start with at least F spaces,
4417 # where F > P.
4418 # these F spaces will be stripped.
4419 def state_parameter_docstring(self, line):
4420 stripped = line.strip()
4421 if stripped.startswith('#'):
4422 return
4423
4424 indent = self.indent.measure(line)
4425 if indent < self.parameter_docstring_indent:
4426 self.indent.infer(line)
4427 assert self.indent.depth < 3
4428 if self.indent.depth == 2:
4429 # back to a parameter
4430 return self.next(self.state_parameter, line)
4431 assert self.indent.depth == 1
4432 return self.next(self.state_function_docstring, line)
4433
4434 assert self.function.parameters
4435 last_parameter = next(reversed(list(self.function.parameters.values())))
4436
4437 new_docstring = last_parameter.docstring
4438
4439 if new_docstring:
4440 new_docstring += '\n'
4441 if stripped:
4442 new_docstring += self.indent.dedent(line)
4443
4444 last_parameter.docstring = new_docstring
4445
4446 # the final stanza of the DSL is the docstring.
4447 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004448 if self.group:
4449 fail("Function " + self.function.name + " has a ] without a matching [.")
4450
4451 stripped = line.strip()
4452 if stripped.startswith('#'):
4453 return
4454
4455 new_docstring = self.function.docstring
4456 if new_docstring:
4457 new_docstring += "\n"
4458 if stripped:
4459 line = self.indent.dedent(line).rstrip()
4460 else:
4461 line = ''
4462 new_docstring += line
4463 self.function.docstring = new_docstring
4464
4465 def format_docstring(self):
4466 f = self.function
4467
Larry Hastings5c661892014-01-24 06:17:25 -08004468 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4469 if new_or_init and not f.docstring:
4470 # don't render a docstring at all, no signature, nothing.
4471 return f.docstring
4472
Larry Hastings2623c8c2014-02-08 22:15:29 -08004473 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004474 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004475
4476 ##
4477 ## docstring first line
4478 ##
4479
Larry Hastings2623c8c2014-02-08 22:15:29 -08004480 if new_or_init:
4481 # classes get *just* the name of the class
4482 # not __new__, not __init__, and not module.classname
4483 assert f.cls
4484 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004485 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004486 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004487 add('(')
4488
4489 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004490 assert parameters, "We should always have a self parameter. " + repr(f)
4491 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004492 # self is always positional-only.
4493 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004494 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004495 positional_only = True
4496 for p in parameters[1:]:
4497 if not p.is_positional_only():
4498 positional_only = False
4499 else:
4500 assert positional_only
4501 if positional_only:
4502 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004503 else:
4504 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004505 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004506
4507 right_bracket_count = 0
4508
4509 def fix_right_bracket_count(desired):
4510 nonlocal right_bracket_count
4511 s = ''
4512 while right_bracket_count < desired:
4513 s += '['
4514 right_bracket_count += 1
4515 while right_bracket_count > desired:
4516 s += ']'
4517 right_bracket_count -= 1
4518 return s
4519
Larry Hastings2623c8c2014-02-08 22:15:29 -08004520 need_slash = False
4521 added_slash = False
4522 need_a_trailing_slash = False
4523
4524 # we only need a trailing slash:
4525 # * if this is not a "docstring_only" signature
4526 # * and if the last *shown* parameter is
4527 # positional only
4528 if not f.docstring_only:
4529 for p in reversed(parameters):
4530 if not p.converter.show_in_signature:
4531 continue
4532 if p.is_positional_only():
4533 need_a_trailing_slash = True
4534 break
4535
4536
Larry Hastings31826802013-10-19 00:09:25 -07004537 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004538
4539 first_parameter = True
4540 last_p = parameters[-1]
4541 line_length = len(''.join(text))
4542 indent = " " * line_length
4543 def add_parameter(text):
4544 nonlocal line_length
4545 nonlocal first_parameter
4546 if first_parameter:
4547 s = text
4548 first_parameter = False
4549 else:
4550 s = ' ' + text
4551 if line_length + len(s) >= 72:
4552 add('\n')
4553 add(indent)
4554 line_length = len(indent)
4555 s = text
4556 line_length += len(s)
4557 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004558
4559 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004560 if not p.converter.show_in_signature:
4561 continue
Larry Hastings31826802013-10-19 00:09:25 -07004562 assert p.name
4563
Larry Hastings2623c8c2014-02-08 22:15:29 -08004564 is_self = isinstance(p.converter, self_converter)
4565 if is_self and f.docstring_only:
4566 # this isn't a real machine-parsable signature,
4567 # so let's not print the "self" parameter
4568 continue
4569
4570 if p.is_positional_only():
4571 need_slash = not f.docstring_only
4572 elif need_slash and not (added_slash or p.is_positional_only()):
4573 added_slash = True
4574 add_parameter('/,')
4575
Larry Hastings31826802013-10-19 00:09:25 -07004576 if p.is_keyword_only() and not added_star:
4577 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004578 add_parameter('*,')
4579
4580 p_add, p_output = text_accumulator()
4581 p_add(fix_right_bracket_count(p.right_bracket_count))
4582
4583 if isinstance(p.converter, self_converter):
4584 # annotate first parameter as being a "self".
4585 #
4586 # if inspect.Signature gets this function,
4587 # and it's already bound, the self parameter
4588 # will be stripped off.
4589 #
4590 # if it's not bound, it should be marked
4591 # as positional-only.
4592 #
4593 # note: we don't print "self" for __init__,
4594 # because this isn't actually the signature
4595 # for __init__. (it can't be, __init__ doesn't
4596 # have a docstring.) if this is an __init__
4597 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004598 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004599 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004600
Larry Hastings5c661892014-01-24 06:17:25 -08004601 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004602 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004603
Larry Hastings31826802013-10-19 00:09:25 -07004604 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004605 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004606 value = p.converter.py_default
4607 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004608 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004609 p_add(value)
4610
4611 if (p != last_p) or need_a_trailing_slash:
4612 p_add(',')
4613
4614 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004615
4616 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004617 if need_a_trailing_slash:
4618 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004619 add(')')
4620
Larry Hastings2a727912014-01-16 11:32:01 -08004621 # PEP 8 says:
4622 #
4623 # The Python standard library will not use function annotations
4624 # as that would result in a premature commitment to a particular
4625 # annotation style. Instead, the annotations are left for users
4626 # to discover and experiment with useful annotation styles.
4627 #
4628 # therefore this is commented out:
4629 #
4630 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004631 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004632 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004633
Larry Hastings2623c8c2014-02-08 22:15:29 -08004634 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004635 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004636
Larry Hastings31826802013-10-19 00:09:25 -07004637 docstring_first_line = output()
4638
4639 # now fix up the places where the brackets look wrong
4640 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4641
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004642 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004643 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004644 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004645 for p in parameters:
4646 if not p.docstring.strip():
4647 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004648 if spacer_line:
4649 add('\n')
4650 else:
4651 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004652 add(" ")
4653 add(p.name)
4654 add('\n')
4655 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004656 parameters = output()
4657 if parameters:
4658 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004659
4660 ##
4661 ## docstring body
4662 ##
4663
4664 docstring = f.docstring.rstrip()
4665 lines = [line.rstrip() for line in docstring.split('\n')]
4666
4667 # Enforce the summary line!
4668 # The first line of a docstring should be a summary of the function.
4669 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4670 # by itself.
4671 #
4672 # Argument Clinic enforces the following rule:
4673 # * either the docstring is empty,
4674 # * or it must have a summary line.
4675 #
4676 # Guido said Clinic should enforce this:
4677 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4678
4679 if len(lines) >= 2:
4680 if lines[1]:
4681 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4682 "Every non-blank function docstring must start with\n" +
4683 "a single line summary followed by an empty line.")
4684 elif len(lines) == 1:
4685 # the docstring is only one line right now--the summary line.
4686 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004687 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004688 lines.append('')
4689
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004690 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4691 if parameters_marker_count > 1:
4692 fail('You may not specify {parameters} more than once in a docstring!')
4693
4694 if not parameters_marker_count:
4695 # insert after summary line
4696 lines.insert(2, '{parameters}')
4697
4698 # insert at front of docstring
4699 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004700
4701 docstring = "\n".join(lines)
4702
4703 add(docstring)
4704 docstring = output()
4705
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004706 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004707 docstring = docstring.rstrip()
4708
4709 return docstring
4710
4711 def state_terminal(self, line):
4712 """
4713 Called when processing the block is done.
4714 """
4715 assert not line
4716
4717 if not self.function:
4718 return
4719
4720 if self.keyword_only:
4721 values = self.function.parameters.values()
4722 if not values:
4723 no_parameter_after_star = True
4724 else:
4725 last_parameter = next(reversed(list(values)))
4726 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4727 if no_parameter_after_star:
4728 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4729
4730 # remove trailing whitespace from all parameter docstrings
4731 for name, value in self.function.parameters.items():
4732 if not value:
4733 continue
4734 value.docstring = value.docstring.rstrip()
4735
4736 self.function.docstring = self.format_docstring()
4737
4738
Larry Hastings5c661892014-01-24 06:17:25 -08004739
4740
Larry Hastings31826802013-10-19 00:09:25 -07004741# maps strings to callables.
4742# the callable should return an object
4743# that implements the clinic parser
4744# interface (__init__ and parse).
4745#
4746# example parsers:
4747# "clinic", handles the Clinic DSL
4748# "python", handles running Python code
4749#
4750parsers = {'clinic' : DSLParser, 'python': PythonParser}
4751
4752
4753clinic = None
4754
4755
4756def main(argv):
4757 import sys
4758
4759 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4760 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4761
4762 import argparse
4763 cmdline = argparse.ArgumentParser()
4764 cmdline.add_argument("-f", "--force", action='store_true')
4765 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004766 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004767 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004768 cmdline.add_argument("--make", action='store_true',
4769 help="Walk --srcdir to run over all relevant files.")
4770 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4771 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004772 cmdline.add_argument("filename", type=str, nargs="*")
4773 ns = cmdline.parse_args(argv)
4774
4775 if ns.converters:
4776 if ns.filename:
4777 print("Usage error: can't specify --converters and a filename at the same time.")
4778 print()
4779 cmdline.print_usage()
4780 sys.exit(-1)
4781 converters = []
4782 return_converters = []
4783 ignored = set("""
4784 add_c_converter
4785 add_c_return_converter
4786 add_default_legacy_c_converter
4787 add_legacy_c_converter
4788 """.strip().split())
4789 module = globals()
4790 for name in module:
4791 for suffix, ids in (
4792 ("_return_converter", return_converters),
4793 ("_converter", converters),
4794 ):
4795 if name in ignored:
4796 continue
4797 if name.endswith(suffix):
4798 ids.append((name, name[:-len(suffix)]))
4799 break
4800 print()
4801
4802 print("Legacy converters:")
4803 legacy = sorted(legacy_converters)
4804 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4805 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4806 print()
4807
4808 for title, attribute, ids in (
4809 ("Converters", 'converter_init', converters),
4810 ("Return converters", 'return_converter_init', return_converters),
4811 ):
4812 print(title + ":")
4813 longest = -1
4814 for name, short_name in ids:
4815 longest = max(longest, len(short_name))
4816 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4817 cls = module[name]
4818 callable = getattr(cls, attribute, None)
4819 if not callable:
4820 continue
4821 signature = inspect.signature(callable)
4822 parameters = []
4823 for parameter_name, parameter in signature.parameters.items():
4824 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4825 if parameter.default != inspect.Parameter.empty:
4826 s = '{}={!r}'.format(parameter_name, parameter.default)
4827 else:
4828 s = parameter_name
4829 parameters.append(s)
4830 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004831 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004832 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4833 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004834 sys.exit(0)
4835
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004836 if ns.make:
4837 if ns.output or ns.filename:
4838 print("Usage error: can't use -o or filenames with --make.")
4839 print()
4840 cmdline.print_usage()
4841 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07004842 if not ns.srcdir:
4843 print("Usage error: --srcdir must not be empty with --make.")
4844 print()
4845 cmdline.print_usage()
4846 sys.exit(-1)
4847 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004848 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004849 if rcs_dir in dirs:
4850 dirs.remove(rcs_dir)
4851 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004852 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004853 continue
4854 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004855 if ns.verbose:
4856 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004857 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004858 return
4859
Larry Hastings31826802013-10-19 00:09:25 -07004860 if not ns.filename:
4861 cmdline.print_usage()
4862 sys.exit(-1)
4863
4864 if ns.output and len(ns.filename) > 1:
4865 print("Usage error: can't use -o with multiple filenames.")
4866 print()
4867 cmdline.print_usage()
4868 sys.exit(-1)
4869
4870 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004871 if ns.verbose:
4872 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004873 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004874
4875
4876if __name__ == "__main__":
4877 sys.exit(main(sys.argv[1:]))