blob: 653afbea5fc94f8862f1f41d0f03c9675e32b3e6 [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} \\
683 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
684 """)
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
810 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300811 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300812 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300813 }}
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300814 """ % argname, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700815
Larry Hastingsbebf7352014-01-17 17:47:17 -0800816 elif has_option_groups:
817 # positional parameters with option groups
818 # (we have to generate lots of PyArg_ParseTuple calls
819 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700820
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800821 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800822 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700823
Larry Hastings7726ac92014-01-31 22:03:12 -0800824 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700825
Larry Hastingsbebf7352014-01-17 17:47:17 -0800826 elif positional and all_boring_objects:
827 # positional-only, but no option groups,
828 # and nothing but normal objects:
829 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700830
Victor Stinner093119e2017-01-17 02:35:41 +0100831 if not new_or_init:
832 flags = "METH_FASTCALL"
833 parser_prototype = parser_prototype_fastcall
Larry Hastings31826802013-10-19 00:09:25 -0700834
Victor Stinner093119e2017-01-17 02:35:41 +0100835 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Sylvain74453812017-06-10 06:51:48 +0200836 if (!_PyArg_UnpackStack(args, nargs, "{name}",
837 {unpack_min}, {unpack_max},
838 {parse_arguments})) {{
Victor Stinner093119e2017-01-17 02:35:41 +0100839 goto exit;
840 }}
841 """, indent=4))
842 else:
843 flags = "METH_VARARGS"
844 parser_prototype = parser_prototype_varargs
845
846 parser_definition = parser_body(parser_prototype, normalize_snippet("""
847 if (!PyArg_UnpackTuple(args, "{name}",
848 {unpack_min}, {unpack_max},
849 {parse_arguments})) {{
850 goto exit;
851 }}
852 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800853
854 elif positional:
Victor Stinner0c8c3892017-01-17 01:42:54 +0100855 if not new_or_init:
856 # positional-only, but no option groups
857 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800858
Victor Stinner0c8c3892017-01-17 01:42:54 +0100859 flags = "METH_FASTCALL"
860 parser_prototype = parser_prototype_fastcall
Larry Hastingsbebf7352014-01-17 17:47:17 -0800861
Victor Stinner0c8c3892017-01-17 01:42:54 +0100862 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Sylvain74453812017-06-10 06:51:48 +0200863 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
864 {parse_arguments})) {{
Victor Stinner0c8c3892017-01-17 01:42:54 +0100865 goto exit;
866 }}
867 """, indent=4))
868 else:
869 # positional-only, but no option groups
870 # we only need one call to PyArg_ParseTuple
871
872 flags = "METH_VARARGS"
873 parser_prototype = parser_prototype_varargs
874
875 parser_definition = parser_body(parser_prototype, normalize_snippet("""
876 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
877 {parse_arguments})) {{
878 goto exit;
879 }}
880 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800881
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700882 elif not new_or_init:
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300883 flags = "METH_FASTCALL|METH_KEYWORDS"
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700884
Serhiy Storchaka6969eaf2017-07-03 21:20:15 +0300885 parser_prototype = parser_prototype_fastcall_keywords
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700886
887 body = normalize_snippet("""
Victor Stinner3e1fad62017-01-17 01:29:01 +0100888 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700889 {parse_arguments})) {{
890 goto exit;
891 }}
892 """, indent=4)
893 parser_definition = parser_body(parser_prototype, body)
894 parser_definition = insert_keywords(parser_definition)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800895 else:
896 # positional-or-keyword arguments
897 flags = "METH_VARARGS|METH_KEYWORDS"
898
Larry Hastings7726ac92014-01-31 22:03:12 -0800899 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800900
Larry Hastings7726ac92014-01-31 22:03:12 -0800901 body = normalize_snippet("""
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300902 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300903 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800904 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300905 }}
906 """, indent=4)
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300907 parser_definition = parser_body(parser_prototype, body)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800908 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700909
Larry Hastings31826802013-10-19 00:09:25 -0700910
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800911 if new_or_init:
912 methoddef_define = ''
913
914 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800915 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800916 else:
917 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800918 parser_prototype = normalize_snippet("""
919 static int
920 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
921 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800922
923 fields = list(parser_body_fields)
924 parses_positional = 'METH_NOARGS' not in flags
925 parses_keywords = 'METH_KEYWORDS' in flags
926 if parses_keywords:
927 assert parses_positional
928
929 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800930 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300931 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800932 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300933 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800934 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800935 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800936 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300937 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800938 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300939 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800940 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800941
942 parser_definition = parser_body(parser_prototype, *fields)
943 if parses_keywords:
944 parser_definition = insert_keywords(parser_definition)
945
Larry Hastings31826802013-10-19 00:09:25 -0700946
Larry Hastingsbebf7352014-01-17 17:47:17 -0800947 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800948 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700949
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800950 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700951
Larry Hastings7726ac92014-01-31 22:03:12 -0800952 methoddef_ifndef = ''
953 conditional = self.cpp.condition()
954 if not conditional:
955 cpp_if = cpp_endif = ''
956 else:
957 cpp_if = "#if " + conditional
958 cpp_endif = "#endif /* " + conditional + " */"
959
Tal Einat4f574092017-11-03 11:09:00 +0200960 if methoddef_define and f.full_name not in clinic.ifndef_symbols:
961 clinic.ifndef_symbols.add(f.full_name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800962 methoddef_ifndef = normalize_snippet("""
963 #ifndef {methoddef_name}
964 #define {methoddef_name}
965 #endif /* !defined({methoddef_name}) */
966 """)
967
968
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800969 # add ';' to the end of parser_prototype and impl_prototype
970 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800971 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800972 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800973 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800974 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700975
Larry Hastingsbebf7352014-01-17 17:47:17 -0800976 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800977 impl_prototype = impl_definition
978 if impl_prototype:
979 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700980
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800981 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800982
983 d = {
984 "docstring_prototype" : docstring_prototype,
985 "docstring_definition" : docstring_definition,
986 "impl_prototype" : impl_prototype,
987 "methoddef_define" : methoddef_define,
988 "parser_prototype" : parser_prototype,
989 "parser_definition" : parser_definition,
990 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800991 "cpp_if" : cpp_if,
992 "cpp_endif" : cpp_endif,
993 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800994 }
995
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800996 # make sure we didn't forget to assign something,
997 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -0800998 d2 = {}
999 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001000 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001001 if value:
1002 value = '\n' + value + '\n'
1003 d2[name] = value
1004 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001005
1006 @staticmethod
1007 def group_to_variable_name(group):
1008 adjective = "left_" if group < 0 else "right_"
1009 return "group_" + adjective + str(abs(group))
1010
1011 def render_option_group_parsing(self, f, template_dict):
1012 # positional only, grouped, optional arguments!
1013 # can be optional on the left or right.
1014 # here's an example:
1015 #
1016 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1017 #
1018 # Here group D are required, and all other groups are optional.
1019 # (Group D's "group" is actually None.)
1020 # We can figure out which sets of arguments we have based on
1021 # how many arguments are in the tuple.
1022 #
1023 # Note that you need to count up on both sides. For example,
1024 # you could have groups C+D, or C+D+E, or C+D+E+F.
1025 #
1026 # What if the number of arguments leads us to an ambiguous result?
1027 # Clinic prefers groups on the left. So in the above example,
1028 # five arguments would map to B+C, not C+D.
1029
1030 add, output = text_accumulator()
1031 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001032 if isinstance(parameters[0].converter, self_converter):
1033 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001034
1035 groups = []
1036 group = None
1037 left = []
1038 right = []
1039 required = []
1040 last = unspecified
1041
1042 for p in parameters:
1043 group_id = p.group
1044 if group_id != last:
1045 last = group_id
1046 group = []
1047 if group_id < 0:
1048 left.append(group)
1049 elif group_id == 0:
1050 group = required
1051 else:
1052 right.append(group)
1053 group.append(p)
1054
1055 count_min = sys.maxsize
1056 count_max = -1
1057
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001058 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001059 for subset in permute_optional_groups(left, required, right):
1060 count = len(subset)
1061 count_min = min(count_min, count)
1062 count_max = max(count_max, count)
1063
Larry Hastings583baa82014-01-12 08:49:30 -08001064 if count == 0:
1065 add(""" case 0:
1066 break;
1067""")
1068 continue
1069
Larry Hastings31826802013-10-19 00:09:25 -07001070 group_ids = {p.group for p in subset} # eliminate duplicates
1071 d = {}
1072 d['count'] = count
1073 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001074 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1075
1076 parse_arguments = []
1077 for p in subset:
1078 p.converter.parse_argument(parse_arguments)
1079 d['parse_arguments'] = ", ".join(parse_arguments)
1080
1081 group_ids.discard(0)
1082 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1083 lines = "\n".join(lines)
1084
1085 s = """
1086 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001087 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001088 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001089 }}
Larry Hastings31826802013-10-19 00:09:25 -07001090 {group_booleans}
1091 break;
1092"""[1:]
1093 s = linear_format(s, group_booleans=lines)
1094 s = s.format_map(d)
1095 add(s)
1096
1097 add(" default:\n")
1098 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1099 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001100 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001101 add("}")
1102 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001103
Larry Hastingsbebf7352014-01-17 17:47:17 -08001104 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001105 if not f:
1106 return ""
1107
1108 add, output = text_accumulator()
1109 data = CRenderData()
1110
Larry Hastings7726ac92014-01-31 22:03:12 -08001111 assert f.parameters, "We should always have a 'self' at this point!"
1112 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001113 converters = [p.converter for p in parameters]
1114
Larry Hastings5c661892014-01-24 06:17:25 -08001115 templates = self.output_templates(f)
1116
1117 f_self = parameters[0]
1118 selfless = parameters[1:]
1119 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1120
1121 last_group = 0
1122 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001123 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001124 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1125 default_return_converter = (not f.return_converter or
1126 f.return_converter.type == 'PyObject *')
1127 has_option_groups = False
1128
1129 # offset i by -1 because first_optional needs to ignore self
1130 for i, p in enumerate(parameters, -1):
1131 c = p.converter
1132
1133 if (i != -1) and (p.default is not unspecified):
1134 first_optional = min(first_optional, i)
1135
1136 # insert group variable
1137 group = p.group
1138 if last_group != group:
1139 last_group = group
1140 if group:
1141 group_name = self.group_to_variable_name(group)
1142 data.impl_arguments.append(group_name)
1143 data.declarations.append("int " + group_name + " = 0;")
1144 data.impl_parameters.append("int " + group_name)
1145 has_option_groups = True
1146
1147 c.render(p, data)
1148
1149 if has_option_groups and (not positional):
1150 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1151
1152 # HACK
1153 # when we're METH_O, but have a custom return converter,
1154 # we use "impl_parameters" for the parsing function
1155 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001156 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001157 # as variables in the parsing function. but since it's
1158 # METH_O, we have exactly one anyway, so we know exactly
1159 # where it is.
1160 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001161 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001162 data.declarations.pop(0)
1163
Larry Hastings31826802013-10-19 00:09:25 -07001164 template_dict = {}
1165
1166 full_name = f.full_name
1167 template_dict['full_name'] = full_name
1168
Larry Hastings5c661892014-01-24 06:17:25 -08001169 if new_or_init:
1170 name = f.cls.name
1171 else:
1172 name = f.name
1173
Larry Hastings31826802013-10-19 00:09:25 -07001174 template_dict['name'] = name
1175
Larry Hastings8666e652014-01-12 14:12:59 -08001176 if f.c_basename:
1177 c_basename = f.c_basename
1178 else:
1179 fields = full_name.split(".")
1180 if fields[-1] == '__new__':
1181 fields.pop()
1182 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001183
Larry Hastings31826802013-10-19 00:09:25 -07001184 template_dict['c_basename'] = c_basename
1185
1186 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1187 template_dict['methoddef_name'] = methoddef_name
1188
1189 template_dict['docstring'] = self.docstring_for_c_string(f)
1190
Larry Hastingsc2047262014-01-25 20:43:29 -08001191 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001192 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001193
Larry Hastings31826802013-10-19 00:09:25 -07001194 f.return_converter.render(f, data)
1195 template_dict['impl_return_type'] = f.return_converter.type
1196
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001197 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001198 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001199 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001200 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1201 template_dict['format_units'] = ''.join(data.format_units)
1202 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1203 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1204 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001205 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1206 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001207 template_dict['return_value'] = data.return_value
1208
Larry Hastings5c661892014-01-24 06:17:25 -08001209 # used by unpack tuple code generator
1210 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1211 unpack_min = first_optional
1212 unpack_max = len(selfless)
1213 template_dict['unpack_min'] = str(unpack_min)
1214 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001215
Larry Hastingsbebf7352014-01-17 17:47:17 -08001216 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001217 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001218
Larry Hastings0759f842015-04-03 13:09:02 -07001219 # buffers, not destination
1220 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001221 template = templates[name]
1222 if has_option_groups:
1223 template = linear_format(template,
1224 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001225 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001226 declarations=template_dict['declarations'],
1227 return_conversion=template_dict['return_conversion'],
1228 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001229 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001230 cleanup=template_dict['cleanup'],
1231 )
Larry Hastings31826802013-10-19 00:09:25 -07001232
Larry Hastingsbebf7352014-01-17 17:47:17 -08001233 # Only generate the "exit:" label
1234 # if we have any gotos
1235 need_exit_label = "goto exit;" in template
1236 template = linear_format(template,
1237 exit_label="exit:" if need_exit_label else ''
1238 )
Larry Hastings31826802013-10-19 00:09:25 -07001239
Larry Hastingsbebf7352014-01-17 17:47:17 -08001240 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001241
Larry Hastings89964c42015-04-14 18:07:59 -04001242 # mild hack:
1243 # reflow long impl declarations
1244 if name in {"impl_prototype", "impl_definition"}:
1245 s = wrap_declarations(s)
1246
Larry Hastingsbebf7352014-01-17 17:47:17 -08001247 if clinic.line_prefix:
1248 s = indent_all_lines(s, clinic.line_prefix)
1249 if clinic.line_suffix:
1250 s = suffix_all_lines(s, clinic.line_suffix)
1251
1252 destination.append(s)
1253
1254 return clinic.get_destination('block').dump()
1255
Larry Hastings31826802013-10-19 00:09:25 -07001256
1257
Larry Hastings5c661892014-01-24 06:17:25 -08001258
Larry Hastings31826802013-10-19 00:09:25 -07001259@contextlib.contextmanager
1260def OverrideStdioWith(stdout):
1261 saved_stdout = sys.stdout
1262 sys.stdout = stdout
1263 try:
1264 yield
1265 finally:
1266 assert sys.stdout is stdout
1267 sys.stdout = saved_stdout
1268
1269
Larry Hastings2623c8c2014-02-08 22:15:29 -08001270def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001271 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001272 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001273 pattern = r'{}({}){}'
1274 if whole_line:
1275 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001276 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1277 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001278
1279
1280class Block:
1281 r"""
1282 Represents a single block of text embedded in
1283 another file. If dsl_name is None, the block represents
1284 verbatim text, raw original text from the file, in
1285 which case "input" will be the only non-false member.
1286 If dsl_name is not None, the block represents a Clinic
1287 block.
1288
1289 input is always str, with embedded \n characters.
1290 input represents the original text from the file;
1291 if it's a Clinic block, it is the original text with
1292 the body_prefix and redundant leading whitespace removed.
1293
1294 dsl_name is either str or None. If str, it's the text
1295 found on the start line of the block between the square
1296 brackets.
1297
1298 signatures is either list or None. If it's a list,
1299 it may only contain clinic.Module, clinic.Class, and
1300 clinic.Function objects. At the moment it should
1301 contain at most one of each.
1302
1303 output is either str or None. If str, it's the output
1304 from this block, with embedded '\n' characters.
1305
1306 indent is either str or None. It's the leading whitespace
1307 that was found on every line of input. (If body_prefix is
1308 not empty, this is the indent *after* removing the
1309 body_prefix.)
1310
1311 preindent is either str or None. It's the whitespace that
1312 was found in front of every line of input *before* the
1313 "body_prefix" (see the Language object). If body_prefix
1314 is empty, preindent must always be empty too.
1315
1316 To illustrate indent and preindent: Assume that '_'
1317 represents whitespace. If the block processed was in a
1318 Python file, and looked like this:
1319 ____#/*[python]
1320 ____#__for a in range(20):
1321 ____#____print(a)
1322 ____#[python]*/
1323 "preindent" would be "____" and "indent" would be "__".
1324
1325 """
1326 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1327 assert isinstance(input, str)
1328 self.input = input
1329 self.dsl_name = dsl_name
1330 self.signatures = signatures or []
1331 self.output = output
1332 self.indent = indent
1333 self.preindent = preindent
1334
Larry Hastings581ee362014-01-28 05:00:08 -08001335 def __repr__(self):
1336 dsl_name = self.dsl_name or "text"
1337 def summarize(s):
1338 s = repr(s)
1339 if len(s) > 30:
1340 return s[:26] + "..." + s[0]
1341 return s
1342 return "".join((
1343 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1344
Larry Hastings31826802013-10-19 00:09:25 -07001345
1346class BlockParser:
1347 """
1348 Block-oriented parser for Argument Clinic.
1349 Iterator, yields Block objects.
1350 """
1351
1352 def __init__(self, input, language, *, verify=True):
1353 """
1354 "input" should be a str object
1355 with embedded \n characters.
1356
1357 "language" should be a Language object.
1358 """
1359 language.validate()
1360
1361 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1362 self.block_start_line_number = self.line_number = 0
1363
1364 self.language = language
1365 before, _, after = language.start_line.partition('{dsl_name}')
1366 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001367 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001368 self.start_re = create_regex(before, after)
1369 self.verify = verify
1370 self.last_checksum_re = None
1371 self.last_dsl_name = None
1372 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001373 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001374
1375 def __iter__(self):
1376 return self
1377
1378 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001379 while True:
1380 if not self.input:
1381 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001382
Larry Hastingsbebf7352014-01-17 17:47:17 -08001383 if self.dsl_name:
1384 return_value = self.parse_clinic_block(self.dsl_name)
1385 self.dsl_name = None
1386 self.first_block = False
1387 return return_value
1388 block = self.parse_verbatim_block()
1389 if self.first_block and not block.input:
1390 continue
1391 self.first_block = False
1392 return block
1393
Larry Hastings31826802013-10-19 00:09:25 -07001394
1395 def is_start_line(self, line):
1396 match = self.start_re.match(line.lstrip())
1397 return match.group(1) if match else None
1398
Larry Hastingse1b82532014-07-27 16:22:20 +02001399 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001400 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001401 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001402 if not lookahead:
1403 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001404 return line
Larry Hastings31826802013-10-19 00:09:25 -07001405
1406 def parse_verbatim_block(self):
1407 add, output = text_accumulator()
1408 self.block_start_line_number = self.line_number
1409
1410 while self.input:
1411 line = self._line()
1412 dsl_name = self.is_start_line(line)
1413 if dsl_name:
1414 self.dsl_name = dsl_name
1415 break
1416 add(line)
1417
1418 return Block(output())
1419
1420 def parse_clinic_block(self, dsl_name):
1421 input_add, input_output = text_accumulator()
1422 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001423 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001424 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1425
Larry Hastings90261132014-01-07 12:21:08 -08001426 def is_stop_line(line):
1427 # make sure to recognize stop line even if it
1428 # doesn't end with EOL (it could be the very end of the file)
1429 if not line.startswith(stop_line):
1430 return False
1431 remainder = line[len(stop_line):]
1432 return (not remainder) or remainder.isspace()
1433
Larry Hastings31826802013-10-19 00:09:25 -07001434 # consume body of program
1435 while self.input:
1436 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001437 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001438 break
1439 if body_prefix:
1440 line = line.lstrip()
1441 assert line.startswith(body_prefix)
1442 line = line[len(body_prefix):]
1443 input_add(line)
1444
1445 # consume output and checksum line, if present.
1446 if self.last_dsl_name == dsl_name:
1447 checksum_re = self.last_checksum_re
1448 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001449 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1450 assert _ == '{arguments}'
1451 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001452 self.last_dsl_name = dsl_name
1453 self.last_checksum_re = checksum_re
1454
1455 # scan forward for checksum line
1456 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001457 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001458 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001459 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001460 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001461 arguments = match.group(1) if match else None
1462 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001463 break
1464 output_add(line)
1465 if self.is_start_line(line):
1466 break
1467
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001468 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001469 if arguments:
1470 d = {}
1471 for field in shlex.split(arguments):
1472 name, equals, value = field.partition('=')
1473 if not equals:
1474 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1475 d[name.strip()] = value.strip()
1476
Larry Hastings31826802013-10-19 00:09:25 -07001477 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001478 if 'input' in d:
1479 checksum = d['output']
1480 input_checksum = d['input']
1481 else:
1482 checksum = d['checksum']
1483 input_checksum = None
1484
1485 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001486 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001487 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1488 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001489 "the end marker,\n"
1490 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001491 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001492 else:
1493 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001494 output_lines = output.splitlines(keepends=True)
1495 self.line_number -= len(output_lines)
1496 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001497 output = None
1498
1499 return Block(input_output(), dsl_name, output=output)
1500
1501
1502class BlockPrinter:
1503
1504 def __init__(self, language, f=None):
1505 self.language = language
1506 self.f = f or io.StringIO()
1507
1508 def print_block(self, block):
1509 input = block.input
1510 output = block.output
1511 dsl_name = block.dsl_name
1512 write = self.f.write
1513
Larry Hastings31826802013-10-19 00:09:25 -07001514 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1515
1516 if not dsl_name:
1517 write(input)
1518 return
1519
1520 write(self.language.start_line.format(dsl_name=dsl_name))
1521 write("\n")
1522
1523 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1524 if not body_prefix:
1525 write(input)
1526 else:
1527 for line in input.split('\n'):
1528 write(body_prefix)
1529 write(line)
1530 write("\n")
1531
1532 write(self.language.stop_line.format(dsl_name=dsl_name))
1533 write("\n")
1534
Larry Hastings581ee362014-01-28 05:00:08 -08001535 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001536 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001537 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001538 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001539 output += '\n'
1540 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001541
Larry Hastings581ee362014-01-28 05:00:08 -08001542 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1543 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001544 write("\n")
1545
Larry Hastingsbebf7352014-01-17 17:47:17 -08001546 def write(self, text):
1547 self.f.write(text)
1548
1549
Larry Hastings0759f842015-04-03 13:09:02 -07001550class BufferSeries:
1551 """
1552 Behaves like a "defaultlist".
1553 When you ask for an index that doesn't exist yet,
1554 the object grows the list until that item exists.
1555 So o[n] will always work.
1556
1557 Supports negative indices for actual items.
1558 e.g. o[-1] is an element immediately preceding o[0].
1559 """
1560
1561 def __init__(self):
1562 self._start = 0
1563 self._array = []
1564 self._constructor = _text_accumulator
1565
1566 def __getitem__(self, i):
1567 i -= self._start
1568 if i < 0:
1569 self._start += i
1570 prefix = [self._constructor() for x in range(-i)]
1571 self._array = prefix + self._array
1572 i = 0
1573 while i >= len(self._array):
1574 self._array.append(self._constructor())
1575 return self._array[i]
1576
1577 def clear(self):
1578 for ta in self._array:
1579 ta._text.clear()
1580
1581 def dump(self):
1582 texts = [ta.output() for ta in self._array]
1583 return "".join(texts)
1584
1585
Larry Hastingsbebf7352014-01-17 17:47:17 -08001586class Destination:
1587 def __init__(self, name, type, clinic, *args):
1588 self.name = name
1589 self.type = type
1590 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001591 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001592 if type not in valid_types:
1593 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1594 extra_arguments = 1 if type == "file" else 0
1595 if len(args) < extra_arguments:
1596 fail("Not enough arguments for destination " + name + " new " + type)
1597 if len(args) > extra_arguments:
1598 fail("Too many arguments for destination " + name + " new " + type)
1599 if type =='file':
1600 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001601 filename = clinic.filename
1602 d['path'] = filename
1603 dirname, basename = os.path.split(filename)
1604 if not dirname:
1605 dirname = '.'
1606 d['dirname'] = dirname
1607 d['basename'] = basename
1608 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001609 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001610
Larry Hastings0759f842015-04-03 13:09:02 -07001611 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001612
1613 def __repr__(self):
1614 if self.type == 'file':
1615 file_repr = " " + repr(self.filename)
1616 else:
1617 file_repr = ''
1618 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1619
1620 def clear(self):
1621 if self.type != 'buffer':
1622 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001623 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001624
1625 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001626 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001627
Larry Hastings31826802013-10-19 00:09:25 -07001628
1629# maps strings to Language objects.
1630# "languages" maps the name of the language ("C", "Python").
1631# "extensions" maps the file extension ("c", "py").
1632languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001633extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1634extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001635
1636
1637# maps strings to callables.
1638# these callables must be of the form:
1639# def foo(name, default, *, ...)
1640# The callable may have any number of keyword-only parameters.
1641# The callable must return a CConverter object.
1642# The callable should not call builtins.print.
1643converters = {}
1644
1645# maps strings to callables.
1646# these callables follow the same rules as those for "converters" above.
1647# note however that they will never be called with keyword-only parameters.
1648legacy_converters = {}
1649
1650
1651# maps strings to callables.
1652# these callables must be of the form:
1653# def foo(*, ...)
1654# The callable may have any number of keyword-only parameters.
1655# The callable must return a CConverter object.
1656# The callable should not call builtins.print.
1657return_converters = {}
1658
Larry Hastings7726ac92014-01-31 22:03:12 -08001659clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001660class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001661
1662 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001663preset block
1664everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001665methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001666docstring_prototype suppress
1667parser_prototype suppress
1668cpp_if suppress
1669cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001670
Larry Hastingsbebf7352014-01-17 17:47:17 -08001671preset original
1672everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001673methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001674docstring_prototype suppress
1675parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001676cpp_if suppress
1677cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001678
1679preset file
1680everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001681methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001682docstring_prototype suppress
1683parser_prototype suppress
1684impl_definition block
1685
1686preset buffer
1687everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001688methoddef_ifndef buffer 1
1689impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001690docstring_prototype suppress
1691impl_prototype suppress
1692parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001693
1694preset partial-buffer
1695everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001696methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001697docstring_prototype block
1698impl_prototype suppress
1699methoddef_define block
1700parser_prototype block
1701impl_definition block
1702
Larry Hastingsbebf7352014-01-17 17:47:17 -08001703"""
1704
Larry Hastings581ee362014-01-28 05:00:08 -08001705 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001706 # maps strings to Parser objects.
1707 # (instantiated from the "parsers" global.)
1708 self.parsers = {}
1709 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001710 if printer:
1711 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001712 self.printer = printer or BlockPrinter(language)
1713 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001714 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001715 self.filename = filename
1716 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001717 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001718 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001719
Larry Hastingsbebf7352014-01-17 17:47:17 -08001720 self.line_prefix = self.line_suffix = ''
1721
1722 self.destinations = {}
1723 self.add_destination("block", "buffer")
1724 self.add_destination("suppress", "suppress")
1725 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001726 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001727 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001728
Larry Hastings0759f842015-04-03 13:09:02 -07001729 d = self.get_destination_buffer
1730 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001731 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001732 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001733 ('docstring_definition', d('file')),
1734 ('methoddef_define', d('file')),
1735 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001736 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001737 ('parser_definition', d('file')),
1738 ('cpp_endif', d('file')),
1739 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001740 ('impl_definition', d('block')),
1741 ))
1742
Larry Hastings0759f842015-04-03 13:09:02 -07001743 self.destination_buffers_stack = []
1744 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001745
1746 self.presets = {}
1747 preset = None
1748 for line in self.presets_text.strip().split('\n'):
1749 line = line.strip()
1750 if not line:
1751 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001752 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001753 if name == 'preset':
1754 self.presets[value] = preset = collections.OrderedDict()
1755 continue
1756
Larry Hastings0759f842015-04-03 13:09:02 -07001757 if len(options):
1758 index = int(options[0])
1759 else:
1760 index = 0
1761 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001762
1763 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001764 for name in self.destination_buffers:
1765 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001766 continue
1767
Larry Hastings0759f842015-04-03 13:09:02 -07001768 assert name in self.destination_buffers
1769 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001770
Larry Hastings31826802013-10-19 00:09:25 -07001771 global clinic
1772 clinic = self
1773
Larry Hastingsbebf7352014-01-17 17:47:17 -08001774 def add_destination(self, name, type, *args):
1775 if name in self.destinations:
1776 fail("Destination already exists: " + repr(name))
1777 self.destinations[name] = Destination(name, type, self, *args)
1778
Larry Hastings0759f842015-04-03 13:09:02 -07001779 def get_destination(self, name):
1780 d = self.destinations.get(name)
1781 if not d:
1782 fail("Destination does not exist: " + repr(name))
1783 return d
1784
1785 def get_destination_buffer(self, name, item=0):
1786 d = self.get_destination(name)
1787 return d.buffers[item]
1788
Larry Hastings31826802013-10-19 00:09:25 -07001789 def parse(self, input):
1790 printer = self.printer
1791 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1792 for block in self.block_parser:
1793 dsl_name = block.dsl_name
1794 if dsl_name:
1795 if dsl_name not in self.parsers:
1796 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1797 self.parsers[dsl_name] = parsers[dsl_name](self)
1798 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001799 try:
1800 parser.parse(block)
1801 except Exception:
1802 fail('Exception raised during parsing:\n' +
1803 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001804 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001805
1806 second_pass_replacements = {}
1807
Larry Hastings0759f842015-04-03 13:09:02 -07001808 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001809 for name, destination in self.destinations.items():
1810 if destination.type == 'suppress':
1811 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001812 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001813
1814 if output:
1815
1816 block = Block("", dsl_name="clinic", output=output)
1817
1818 if destination.type == 'buffer':
1819 block.input = "dump " + name + "\n"
1820 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1821 printer.write("\n")
1822 printer.print_block(block)
1823 continue
1824
1825 if destination.type == 'file':
1826 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001827 dirname = os.path.dirname(destination.filename)
1828 try:
1829 os.makedirs(dirname)
1830 except FileExistsError:
1831 if not os.path.isdir(dirname):
1832 fail("Can't write to destination {}, "
1833 "can't make directory {}!".format(
1834 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001835 if self.verify:
1836 with open(destination.filename, "rt") as f:
1837 parser_2 = BlockParser(f.read(), language=self.language)
1838 blocks = list(parser_2)
1839 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1840 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001841 except FileNotFoundError:
1842 pass
1843
1844 block.input = 'preserve\n'
1845 printer_2 = BlockPrinter(self.language)
1846 printer_2.print_block(block)
1847 with open(destination.filename, "wt") as f:
1848 f.write(printer_2.f.getvalue())
1849 continue
1850 text = printer.f.getvalue()
1851
1852 if second_pass_replacements:
1853 printer_2 = BlockPrinter(self.language)
1854 parser_2 = BlockParser(text, self.language)
1855 changed = False
1856 for block in parser_2:
1857 if block.dsl_name:
1858 for id, replacement in second_pass_replacements.items():
1859 if id in block.output:
1860 changed = True
1861 block.output = block.output.replace(id, replacement)
1862 printer_2.print_block(block)
1863 if changed:
1864 text = printer_2.f.getvalue()
1865
1866 return text
1867
Larry Hastings31826802013-10-19 00:09:25 -07001868
1869 def _module_and_class(self, fields):
1870 """
1871 fields should be an iterable of field names.
1872 returns a tuple of (module, class).
1873 the module object could actually be self (a clinic object).
1874 this function is only ever used to find the parent of where
1875 a new class/module should go.
1876 """
1877 in_classes = False
1878 parent = module = self
1879 cls = None
1880 so_far = []
1881
1882 for field in fields:
1883 so_far.append(field)
1884 if not in_classes:
1885 child = parent.modules.get(field)
1886 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001887 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001888 continue
1889 in_classes = True
1890 if not hasattr(parent, 'classes'):
1891 return module, cls
1892 child = parent.classes.get(field)
1893 if not child:
1894 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1895 cls = parent = child
1896
1897 return module, cls
1898
1899
Larry Hastings581ee362014-01-28 05:00:08 -08001900def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001901 extension = os.path.splitext(filename)[1][1:]
1902 if not extension:
1903 fail("Can't extract file type for file " + repr(filename))
1904
1905 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001906 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001907 except KeyError:
1908 fail("Can't identify file type for file " + repr(filename))
1909
Larry Hastings31826802013-10-19 00:09:25 -07001910 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001911 raw = f.read()
1912
Larry Hastings2623c8c2014-02-08 22:15:29 -08001913 # exit quickly if there are no clinic markers in the file
1914 find_start_re = BlockParser("", language).find_start_re
1915 if not find_start_re.search(raw):
1916 return
1917
1918 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001919 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001920 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001921 return
Larry Hastings31826802013-10-19 00:09:25 -07001922
1923 directory = os.path.dirname(filename) or '.'
1924
1925 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001926 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001927 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1928 with open(tmpfilename, "wb") as f:
1929 f.write(bytes)
1930 os.replace(tmpfilename, output or filename)
1931
1932
Larry Hastings581ee362014-01-28 05:00:08 -08001933def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001934 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001935 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1936 if length:
1937 s = s[:length]
1938 return s
Larry Hastings31826802013-10-19 00:09:25 -07001939
1940
1941
1942
1943class PythonParser:
1944 def __init__(self, clinic):
1945 pass
1946
1947 def parse(self, block):
1948 s = io.StringIO()
1949 with OverrideStdioWith(s):
1950 exec(block.input)
1951 block.output = s.getvalue()
1952
1953
1954class Module:
1955 def __init__(self, name, module=None):
1956 self.name = name
1957 self.module = self.parent = module
1958
1959 self.modules = collections.OrderedDict()
1960 self.classes = collections.OrderedDict()
1961 self.functions = []
1962
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001963 def __repr__(self):
1964 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1965
Larry Hastings31826802013-10-19 00:09:25 -07001966class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001967 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001968 self.name = name
1969 self.module = module
1970 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001971 self.typedef = typedef
1972 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001973 self.parent = cls or module
1974
1975 self.classes = collections.OrderedDict()
1976 self.functions = []
1977
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001978 def __repr__(self):
1979 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1980
Larry Hastings8666e652014-01-12 14:12:59 -08001981unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001982
Larry Hastings8666e652014-01-12 14:12:59 -08001983__abs__
1984__add__
1985__and__
1986__bytes__
1987__call__
1988__complex__
1989__delitem__
1990__divmod__
1991__eq__
1992__float__
1993__floordiv__
1994__ge__
1995__getattr__
1996__getattribute__
1997__getitem__
1998__gt__
1999__hash__
2000__iadd__
2001__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002002__ifloordiv__
2003__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002004__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002005__imod__
2006__imul__
2007__index__
2008__int__
2009__invert__
2010__ior__
2011__ipow__
2012__irshift__
2013__isub__
2014__iter__
2015__itruediv__
2016__ixor__
2017__le__
2018__len__
2019__lshift__
2020__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002021__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002022__mod__
2023__mul__
2024__neg__
2025__new__
2026__next__
2027__or__
2028__pos__
2029__pow__
2030__radd__
2031__rand__
2032__rdivmod__
2033__repr__
2034__rfloordiv__
2035__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002036__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002037__rmod__
2038__rmul__
2039__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002040__rpow__
2041__rrshift__
2042__rshift__
2043__rsub__
2044__rtruediv__
2045__rxor__
2046__setattr__
2047__setitem__
2048__str__
2049__sub__
2050__truediv__
2051__xor__
2052
2053""".strip().split())
2054
2055
Larry Hastings5c661892014-01-24 06:17:25 -08002056INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2057INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2058""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002059
2060class Function:
2061 """
2062 Mutable duck type for inspect.Function.
2063
2064 docstring - a str containing
2065 * embedded line breaks
2066 * text outdented to the left margin
2067 * no trailing whitespace.
2068 It will always be true that
2069 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2070 """
2071
2072 def __init__(self, parameters=None, *, name,
2073 module, cls=None, c_basename=None,
2074 full_name=None,
2075 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002076 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002077 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002078 self.parameters = parameters or collections.OrderedDict()
2079 self.return_annotation = return_annotation
2080 self.name = name
2081 self.full_name = full_name
2082 self.module = module
2083 self.cls = cls
2084 self.parent = cls or module
2085 self.c_basename = c_basename
2086 self.return_converter = return_converter
2087 self.docstring = docstring or ''
2088 self.kind = kind
2089 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002090 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002091 # docstring_only means "don't generate a machine-readable
2092 # signature, just a normal docstring". it's True for
2093 # functions with optional groups because we can't represent
2094 # those accurately with inspect.Signature in 3.4.
2095 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002096
Larry Hastings7726ac92014-01-31 22:03:12 -08002097 self.rendered_parameters = None
2098
2099 __render_parameters__ = None
2100 @property
2101 def render_parameters(self):
2102 if not self.__render_parameters__:
2103 self.__render_parameters__ = l = []
2104 for p in self.parameters.values():
2105 p = p.copy()
2106 p.converter.pre_render()
2107 l.append(p)
2108 return self.__render_parameters__
2109
Larry Hastingsebdcb502013-11-23 14:54:00 -08002110 @property
2111 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002112 if self.kind in (METHOD_INIT, METHOD_NEW):
2113 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002114 flags = []
2115 if self.kind == CLASS_METHOD:
2116 flags.append('METH_CLASS')
2117 elif self.kind == STATIC_METHOD:
2118 flags.append('METH_STATIC')
2119 else:
2120 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2121 if self.coexist:
2122 flags.append('METH_COEXIST')
2123 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002124
2125 def __repr__(self):
2126 return '<clinic.Function ' + self.name + '>'
2127
Larry Hastings7726ac92014-01-31 22:03:12 -08002128 def copy(self, **overrides):
2129 kwargs = {
2130 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2131 'cls': self.cls, 'c_basename': self.c_basename,
2132 'full_name': self.full_name,
2133 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2134 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002135 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002136 }
2137 kwargs.update(overrides)
2138 f = Function(**kwargs)
2139
2140 parameters = collections.OrderedDict()
2141 for name, value in f.parameters.items():
2142 value = value.copy(function=f)
2143 parameters[name] = value
2144 f.parameters = parameters
2145 return f
2146
Larry Hastings31826802013-10-19 00:09:25 -07002147
2148class Parameter:
2149 """
2150 Mutable duck type of inspect.Parameter.
2151 """
2152
2153 def __init__(self, name, kind, *, default=_empty,
2154 function, converter, annotation=_empty,
2155 docstring=None, group=0):
2156 self.name = name
2157 self.kind = kind
2158 self.default = default
2159 self.function = function
2160 self.converter = converter
2161 self.annotation = annotation
2162 self.docstring = docstring or ''
2163 self.group = group
2164
2165 def __repr__(self):
2166 return '<clinic.Parameter ' + self.name + '>'
2167
2168 def is_keyword_only(self):
2169 return self.kind == inspect.Parameter.KEYWORD_ONLY
2170
Larry Hastings2623c8c2014-02-08 22:15:29 -08002171 def is_positional_only(self):
2172 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2173
Larry Hastings7726ac92014-01-31 22:03:12 -08002174 def copy(self, **overrides):
2175 kwargs = {
2176 'name': self.name, 'kind': self.kind, 'default':self.default,
2177 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2178 'docstring': self.docstring, 'group': self.group,
2179 }
2180 kwargs.update(overrides)
2181 if 'converter' not in overrides:
2182 converter = copy.copy(self.converter)
2183 converter.function = kwargs['function']
2184 kwargs['converter'] = converter
2185 return Parameter(**kwargs)
2186
2187
2188
2189class LandMine:
2190 # try to access any
2191 def __init__(self, message):
2192 self.__message__ = message
2193
2194 def __repr__(self):
2195 return '<LandMine ' + repr(self.__message__) + ">"
2196
2197 def __getattribute__(self, name):
2198 if name in ('__repr__', '__message__'):
2199 return super().__getattribute__(name)
2200 # raise RuntimeError(repr(name))
2201 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002202
Larry Hastings31826802013-10-19 00:09:25 -07002203
2204def add_c_converter(f, name=None):
2205 if not name:
2206 name = f.__name__
2207 if not name.endswith('_converter'):
2208 return f
2209 name = name[:-len('_converter')]
2210 converters[name] = f
2211 return f
2212
2213def add_default_legacy_c_converter(cls):
2214 # automatically add converter for default format unit
2215 # (but without stomping on the existing one if it's already
2216 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002217 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002218 (cls.format_unit not in legacy_converters)):
2219 legacy_converters[cls.format_unit] = cls
2220 return cls
2221
2222def add_legacy_c_converter(format_unit, **kwargs):
2223 """
2224 Adds a legacy converter.
2225 """
2226 def closure(f):
2227 if not kwargs:
2228 added_f = f
2229 else:
2230 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002231 if format_unit:
2232 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002233 return f
2234 return closure
2235
2236class CConverterAutoRegister(type):
2237 def __init__(cls, name, bases, classdict):
2238 add_c_converter(cls)
2239 add_default_legacy_c_converter(cls)
2240
2241class CConverter(metaclass=CConverterAutoRegister):
2242 """
2243 For the init function, self, name, function, and default
2244 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002245 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002246 """
2247
Larry Hastings7726ac92014-01-31 22:03:12 -08002248 # The C name to use for this variable.
2249 name = None
2250
2251 # The Python name to use for this variable.
2252 py_name = None
2253
Larry Hastings78cf85c2014-01-04 12:44:57 -08002254 # The C type to use for this variable.
2255 # 'type' should be a Python string specifying the type, e.g. "int".
2256 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002257 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002258
2259 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002260 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002261 # Or the magic value "unknown" if this value is a cannot be evaluated
2262 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2263 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002264 default = unspecified
2265
Larry Hastings4a55fc52014-01-12 11:09:57 -08002266 # If not None, default must be isinstance() of this type.
2267 # (You can also specify a tuple of types.)
2268 default_type = None
2269
Larry Hastings31826802013-10-19 00:09:25 -07002270 # "default" converted into a C value, as a string.
2271 # Or None if there is no default.
2272 c_default = None
2273
Larry Hastings2a727912014-01-16 11:32:01 -08002274 # "default" converted into a Python value, as a string.
2275 # Or None if there is no default.
2276 py_default = None
2277
Larry Hastingsabc716b2013-11-20 09:13:52 -08002278 # The default value used to initialize the C variable when
2279 # there is no default, but not specifying a default may
2280 # result in an "uninitialized variable" warning. This can
2281 # easily happen when using option groups--although
2282 # properly-written code won't actually use the variable,
2283 # the variable does get passed in to the _impl. (Ah, if
2284 # only dataflow analysis could inline the static function!)
2285 #
2286 # This value is specified as a string.
2287 # Every non-abstract subclass should supply a valid value.
2288 c_ignored_default = 'NULL'
2289
Larry Hastings31826802013-10-19 00:09:25 -07002290 # The C converter *function* to be used, if any.
2291 # (If this is not None, format_unit must be 'O&'.)
2292 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002293
Larry Hastings78cf85c2014-01-04 12:44:57 -08002294 # Should Argument Clinic add a '&' before the name of
2295 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002296 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002297
2298 # Should Argument Clinic add a '&' before the name of
2299 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002300 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002301
2302 #############################################################
2303 #############################################################
2304 ## You shouldn't need to read anything below this point to ##
2305 ## write your own converter functions. ##
2306 #############################################################
2307 #############################################################
2308
2309 # The "format unit" to specify for this variable when
2310 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2311 # Custom converters should always use the default value of 'O&'.
2312 format_unit = 'O&'
2313
2314 # What encoding do we want for this variable? Only used
2315 # by format units starting with 'e'.
2316 encoding = None
2317
Larry Hastings77561cc2014-01-07 12:13:13 -08002318 # Should this object be required to be a subclass of a specific type?
2319 # If not None, should be a string representing a pointer to a
2320 # PyTypeObject (e.g. "&PyUnicode_Type").
2321 # Only used by the 'O!' format unit (and the "object" converter).
2322 subclass_of = None
2323
Larry Hastings78cf85c2014-01-04 12:44:57 -08002324 # Do we want an adjacent '_length' variable for this variable?
2325 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002326 length = False
2327
Larry Hastings5c661892014-01-24 06:17:25 -08002328 # Should we show this parameter in the generated
2329 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002330 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002331 show_in_signature = True
2332
2333 # Overrides the name used in a text signature.
2334 # The name used for a "self" parameter must be one of
2335 # self, type, or module; however users can set their own.
2336 # This lets the self_converter overrule the user-settable
2337 # name, *just* for the text signature.
2338 # Only set by self_converter.
2339 signature_name = None
2340
2341 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002342 def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
Larry Hastings31826802013-10-19 00:09:25 -07002343 self.name = name
Larry Hastings7726ac92014-01-31 22:03:12 -08002344 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002345
2346 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002347 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002348 if isinstance(self.default_type, type):
2349 types_str = self.default_type.__name__
2350 else:
2351 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2352 fail("{}: default value {!r} for field {} is not of type {}".format(
2353 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002354 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002355
Larry Hastingsb4705752014-01-18 21:54:15 -08002356 if c_default:
2357 self.c_default = c_default
2358 if py_default:
2359 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002360
Larry Hastings31826802013-10-19 00:09:25 -07002361 if annotation != unspecified:
2362 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002363
2364 # this is deliberate, to prevent you from caching information
2365 # about the function in the init.
2366 # (that breaks if we get cloned.)
2367 # so after this change we will noisily fail.
2368 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002369 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002370 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002371
2372 def converter_init(self):
2373 pass
2374
2375 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002376 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002377
Larry Hastings5c661892014-01-24 06:17:25 -08002378 def _render_self(self, parameter, data):
2379 self.parameter = parameter
2380 original_name = self.name
2381 name = ensure_legal_c_identifier(original_name)
2382
2383 # impl_arguments
2384 s = ("&" if self.impl_by_reference else "") + name
2385 data.impl_arguments.append(s)
2386 if self.length:
2387 data.impl_arguments.append(self.length_name())
2388
2389 # impl_parameters
2390 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2391 if self.length:
2392 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2393
2394 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002395 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002396 original_name = self.name
2397 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002398
2399 # declarations
2400 d = self.declaration()
2401 data.declarations.append(d)
2402
2403 # initializers
2404 initializers = self.initialize()
2405 if initializers:
2406 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2407
Larry Hastingsc2047262014-01-25 20:43:29 -08002408 # modifications
2409 modifications = self.modify()
2410 if modifications:
2411 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2412
Larry Hastings31826802013-10-19 00:09:25 -07002413 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002414 if parameter.is_positional_only():
2415 data.keywords.append('')
2416 else:
2417 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002418
2419 # format_units
2420 if self.is_optional() and '|' not in data.format_units:
2421 data.format_units.append('|')
2422 if parameter.is_keyword_only() and '$' not in data.format_units:
2423 data.format_units.append('$')
2424 data.format_units.append(self.format_unit)
2425
2426 # parse_arguments
2427 self.parse_argument(data.parse_arguments)
2428
Larry Hastings31826802013-10-19 00:09:25 -07002429 # cleanup
2430 cleanup = self.cleanup()
2431 if cleanup:
2432 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2433
Larry Hastings5c661892014-01-24 06:17:25 -08002434 def render(self, parameter, data):
2435 """
2436 parameter is a clinic.Parameter instance.
2437 data is a CRenderData instance.
2438 """
2439 self._render_self(parameter, data)
2440 self._render_non_self(parameter, data)
2441
Larry Hastingsebdcb502013-11-23 14:54:00 -08002442 def length_name(self):
2443 """Computes the name of the associated "length" variable."""
2444 if not self.length:
2445 return None
2446 return ensure_legal_c_identifier(self.name) + "_length"
2447
Larry Hastings31826802013-10-19 00:09:25 -07002448 # Why is this one broken out separately?
2449 # For "positional-only" function parsing,
2450 # which generates a bunch of PyArg_ParseTuple calls.
2451 def parse_argument(self, list):
2452 assert not (self.converter and self.encoding)
2453 if self.format_unit == 'O&':
2454 assert self.converter
2455 list.append(self.converter)
2456
2457 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002458 list.append(c_repr(self.encoding))
2459 elif self.subclass_of:
2460 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002461
Larry Hastingsebdcb502013-11-23 14:54:00 -08002462 legal_name = ensure_legal_c_identifier(self.name)
2463 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002464 list.append(s)
2465
Larry Hastingsebdcb502013-11-23 14:54:00 -08002466 if self.length:
2467 list.append("&" + self.length_name())
2468
Larry Hastings31826802013-10-19 00:09:25 -07002469 #
2470 # All the functions after here are intended as extension points.
2471 #
2472
2473 def simple_declaration(self, by_reference=False):
2474 """
2475 Computes the basic declaration of the variable.
2476 Used in computing the prototype declaration and the
2477 variable declaration.
2478 """
2479 prototype = [self.type]
2480 if by_reference or not self.type.endswith('*'):
2481 prototype.append(" ")
2482 if by_reference:
2483 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002484 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002485 return "".join(prototype)
2486
2487 def declaration(self):
2488 """
2489 The C statement to declare this variable.
2490 """
2491 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002492 default = self.c_default
2493 if not default and self.parameter.group:
2494 default = self.c_ignored_default
2495 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002496 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002497 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002498 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002499 if self.length:
2500 declaration.append('\nPy_ssize_clean_t ')
2501 declaration.append(self.length_name())
2502 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002503 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002504
2505 def initialize(self):
2506 """
2507 The C statements required to set up this variable before parsing.
2508 Returns a string containing this code indented at column 0.
2509 If no initialization is necessary, returns an empty string.
2510 """
2511 return ""
2512
Larry Hastingsc2047262014-01-25 20:43:29 -08002513 def modify(self):
2514 """
2515 The C statements required to modify this variable after parsing.
2516 Returns a string containing this code indented at column 0.
2517 If no initialization is necessary, returns an empty string.
2518 """
2519 return ""
2520
Larry Hastings31826802013-10-19 00:09:25 -07002521 def cleanup(self):
2522 """
2523 The C statements required to clean up after this variable.
2524 Returns a string containing this code indented at column 0.
2525 If no cleanup is necessary, returns an empty string.
2526 """
2527 return ""
2528
Larry Hastings7726ac92014-01-31 22:03:12 -08002529 def pre_render(self):
2530 """
2531 A second initialization function, like converter_init,
2532 called just before rendering.
2533 You are permitted to examine self.function here.
2534 """
2535 pass
2536
Larry Hastings31826802013-10-19 00:09:25 -07002537
2538class bool_converter(CConverter):
2539 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002540 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002541 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002542 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002543
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002544 def converter_init(self, *, accept={object}):
2545 if accept == {int}:
2546 self.format_unit = 'i'
2547 elif accept != {object}:
2548 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002549 if self.default is not unspecified:
2550 self.default = bool(self.default)
2551 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002552
2553class char_converter(CConverter):
2554 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002555 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002556 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002557 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002558
Tal Einatc929df32018-07-06 13:17:38 +03002559 # characters which need to be escaped in C code
2560 _escapes = {x: r'\%d' % x for x in range(7)}
2561 _escapes.update({
2562 0x07: r'\a',
2563 0x08: r'\b',
2564 0x09: r'\t',
2565 0x0A: r'\n',
2566 0x0B: r'\v',
2567 0x0C: r'\f',
2568 0x0D: r'\r',
2569 0x22: r'\"',
2570 0x27: r'\'',
2571 0x3F: r'\?',
2572 0x5C: r'\\',
2573 })
2574
Larry Hastings4a55fc52014-01-12 11:09:57 -08002575 def converter_init(self):
Tal Einatc929df32018-07-06 13:17:38 +03002576 if isinstance(self.default, self.default_type):
2577 if len(self.default) != 1:
2578 fail("char_converter: illegal default value " + repr(self.default))
2579
2580 c_ord = self.default[0]
2581 self.c_default = "'%s'" % self._escapes.get(c_ord, chr(c_ord))
Larry Hastings4a55fc52014-01-12 11:09:57 -08002582
2583
Larry Hastings31826802013-10-19 00:09:25 -07002584@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002585class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002586 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002587 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002588 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002589 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002590
2591 def converter_init(self, *, bitwise=False):
2592 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002593 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002594
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002595class byte_converter(unsigned_char_converter): pass
2596
Larry Hastings31826802013-10-19 00:09:25 -07002597class short_converter(CConverter):
2598 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002599 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002600 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002601 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002602
2603class unsigned_short_converter(CConverter):
2604 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002605 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002606 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002607
2608 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002609 if bitwise:
2610 self.format_unit = 'H'
2611 else:
2612 self.converter = '_PyLong_UnsignedShort_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002613
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002614@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002615class int_converter(CConverter):
2616 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002617 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002618 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002619 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002620
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002621 def converter_init(self, *, accept={int}, type=None):
2622 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002623 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002624 elif accept != {int}:
2625 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002626 if type != None:
2627 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002628
2629class unsigned_int_converter(CConverter):
2630 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002631 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002632 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002633
2634 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002635 if bitwise:
2636 self.format_unit = 'I'
2637 else:
2638 self.converter = '_PyLong_UnsignedInt_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002639
2640class long_converter(CConverter):
2641 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002642 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002643 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002644 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002645
2646class unsigned_long_converter(CConverter):
2647 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002648 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002649 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002650
2651 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002652 if bitwise:
2653 self.format_unit = 'k'
2654 else:
2655 self.converter = '_PyLong_UnsignedLong_Converter'
Larry Hastings31826802013-10-19 00:09:25 -07002656
Benjamin Petersoncc854492016-09-08 09:29:11 -07002657class long_long_converter(CConverter):
2658 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002659 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002660 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002661 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002662
Benjamin Petersoncc854492016-09-08 09:29:11 -07002663class unsigned_long_long_converter(CConverter):
2664 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002665 default_type = int
Larry Hastingsabc716b2013-11-20 09:13:52 -08002666 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002667
2668 def converter_init(self, *, bitwise=False):
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002669 if bitwise:
2670 self.format_unit = 'K'
2671 else:
2672 self.converter = '_PyLong_UnsignedLongLong_Converter'
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002673
Larry Hastings31826802013-10-19 00:09:25 -07002674class Py_ssize_t_converter(CConverter):
2675 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002676 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002677
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002678 def converter_init(self, *, accept={int}):
2679 if accept == {int}:
2680 self.format_unit = 'n'
2681 self.default_type = int
2682 elif accept == {int, NoneType}:
2683 self.converter = '_Py_convert_optional_to_ssize_t'
2684 else:
2685 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
2686
Larry Hastings31826802013-10-19 00:09:25 -07002687
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002688class slice_index_converter(CConverter):
2689 type = 'Py_ssize_t'
2690
2691 def converter_init(self, *, accept={int, NoneType}):
2692 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002693 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002694 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002695 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002696 else:
2697 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
2698
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +03002699class size_t_converter(CConverter):
2700 type = 'size_t'
2701 converter = '_PyLong_Size_t_Converter'
2702 c_ignored_default = "0"
2703
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002704
Larry Hastings31826802013-10-19 00:09:25 -07002705class float_converter(CConverter):
2706 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002707 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002708 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002709 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002710
2711class double_converter(CConverter):
2712 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002713 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002714 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002715 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002716
2717
2718class Py_complex_converter(CConverter):
2719 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002720 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002721 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002722 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002723
2724
2725class object_converter(CConverter):
2726 type = 'PyObject *'
2727 format_unit = 'O'
2728
Larry Hastings4a55fc52014-01-12 11:09:57 -08002729 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2730 if converter:
2731 if subclass_of:
2732 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2733 self.format_unit = 'O&'
2734 self.converter = converter
2735 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002736 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002737 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002738
Larry Hastings77561cc2014-01-07 12:13:13 -08002739 if type is not None:
2740 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002741
2742
Larry Hastings7f90cba2015-04-15 23:02:12 -04002743#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002744# We define three conventions for buffer types in the 'accept' argument:
2745#
2746# buffer : any object supporting the buffer interface
2747# rwbuffer: any object supporting the buffer interface, but must be writeable
2748# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04002749#
2750
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002751class buffer: pass
2752class rwbuffer: pass
2753class robuffer: pass
2754
Larry Hastings38337d12015-05-07 23:30:09 -07002755def str_converter_key(types, encoding, zeroes):
2756 return (frozenset(types), bool(encoding), bool(zeroes))
2757
2758str_converter_argument_map = {}
2759
Larry Hastings31826802013-10-19 00:09:25 -07002760class str_converter(CConverter):
2761 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002762 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002763 format_unit = 's'
2764
Larry Hastings38337d12015-05-07 23:30:09 -07002765 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002766
Larry Hastings38337d12015-05-07 23:30:09 -07002767 key = str_converter_key(accept, encoding, zeroes)
2768 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002769 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07002770 fail("str_converter: illegal combination of arguments", key)
2771
Larry Hastingsebdcb502013-11-23 14:54:00 -08002772 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07002773 self.length = bool(zeroes)
2774 if encoding:
2775 if self.default not in (Null, None, unspecified):
2776 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
2777 self.encoding = encoding
2778 self.type = 'char *'
2779 # sorry, clinic can't support preallocated buffers
2780 # for es# and et#
2781 self.c_default = "NULL"
2782
2783 def cleanup(self):
2784 if self.encoding:
2785 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002786 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07002787
2788#
2789# This is the fourth or fifth rewrite of registering all the
2790# crazy string converter format units. Previous approaches hid
2791# bugs--generally mismatches between the semantics of the format
2792# unit and the arguments necessary to represent those semantics
2793# properly. Hopefully with this approach we'll get it 100% right.
2794#
2795# The r() function (short for "register") both registers the
2796# mapping from arguments to format unit *and* registers the
2797# legacy C converter for that format unit.
2798#
2799def r(format_unit, *, accept, encoding=False, zeroes=False):
2800 if not encoding and format_unit != 's':
2801 # add the legacy c converters here too.
2802 #
2803 # note: add_legacy_c_converter can't work for
2804 # es, es#, et, or et#
2805 # because of their extra encoding argument
2806 #
2807 # also don't add the converter for 's' because
2808 # the metaclass for CConverter adds it for us.
2809 kwargs = {}
2810 if accept != {str}:
2811 kwargs['accept'] = accept
2812 if zeroes:
2813 kwargs['zeroes'] = True
2814 added_f = functools.partial(str_converter, **kwargs)
2815 legacy_converters[format_unit] = added_f
2816
2817 d = str_converter_argument_map
2818 key = str_converter_key(accept, encoding, zeroes)
2819 if key in d:
2820 sys.exit("Duplicate keys specified for str_converter_argument_map!")
2821 d[key] = format_unit
2822
2823r('es', encoding=True, accept={str})
2824r('es#', encoding=True, zeroes=True, accept={str})
2825r('et', encoding=True, accept={bytes, bytearray, str})
2826r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
2827r('s', accept={str})
2828r('s#', zeroes=True, accept={robuffer, str})
2829r('y', accept={robuffer})
2830r('y#', zeroes=True, accept={robuffer})
2831r('z', accept={str, NoneType})
2832r('z#', zeroes=True, accept={robuffer, str, NoneType})
2833del r
Larry Hastings31826802013-10-19 00:09:25 -07002834
2835
2836class PyBytesObject_converter(CConverter):
2837 type = 'PyBytesObject *'
2838 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002839 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07002840
2841class PyByteArrayObject_converter(CConverter):
2842 type = 'PyByteArrayObject *'
2843 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002844 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07002845
2846class unicode_converter(CConverter):
2847 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002848 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002849 format_unit = 'U'
2850
Larry Hastings38337d12015-05-07 23:30:09 -07002851@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002852@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07002853@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07002854class Py_UNICODE_converter(CConverter):
2855 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002856 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002857 format_unit = 'u'
2858
Larry Hastings38337d12015-05-07 23:30:09 -07002859 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002860 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07002861 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002862 format_unit += '#'
2863 self.length = True
2864 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002865
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002866@add_legacy_c_converter('s*', accept={str, buffer})
2867@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
2868@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07002869class Py_buffer_converter(CConverter):
2870 type = 'Py_buffer'
2871 format_unit = 'y*'
2872 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002873 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002874
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002875 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002876 if self.default not in (unspecified, None):
2877 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002878
Larry Hastings3f144c22014-01-06 10:34:00 -08002879 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002880
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002881 if accept == {str, buffer, NoneType}:
2882 format_unit = 'z*'
2883 elif accept == {str, buffer}:
2884 format_unit = 's*'
2885 elif accept == {buffer}:
2886 format_unit = 'y*'
2887 elif accept == {rwbuffer}:
2888 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07002889 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002890 fail("Py_buffer_converter: illegal combination of arguments")
2891
2892 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002893
2894 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002895 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002896 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002897
2898
Larry Hastings5c661892014-01-24 06:17:25 -08002899def correct_name_for_self(f):
2900 if f.kind in (CALLABLE, METHOD_INIT):
2901 if f.cls:
2902 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03002903 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08002904 if f.kind == STATIC_METHOD:
2905 return "void *", "null"
2906 if f.kind in (CLASS_METHOD, METHOD_NEW):
2907 return "PyTypeObject *", "type"
2908 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
2909
Larry Hastingsc2047262014-01-25 20:43:29 -08002910def required_type_for_self_for_parser(f):
2911 type, _ = correct_name_for_self(f)
2912 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
2913 return type
2914 return None
2915
Larry Hastings5c661892014-01-24 06:17:25 -08002916
Larry Hastingsebdcb502013-11-23 14:54:00 -08002917class self_converter(CConverter):
2918 """
2919 A special-case converter:
2920 this is the default converter used for "self".
2921 """
Larry Hastings5c661892014-01-24 06:17:25 -08002922 type = None
2923 format_unit = ''
2924
Larry Hastings78cf85c2014-01-04 12:44:57 -08002925 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08002926 self.specified_type = type
2927
2928 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002929 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08002930 default_type, default_name = correct_name_for_self(f)
2931 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08002932 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002933
Larry Hastings5c661892014-01-24 06:17:25 -08002934 kind = self.function.kind
2935 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
2936
2937 if (kind == STATIC_METHOD) or new_or_init:
2938 self.show_in_signature = False
2939
2940 # tp_new (METHOD_NEW) functions are of type newfunc:
2941 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
2942 # PyTypeObject is a typedef for struct _typeobject.
2943 #
2944 # tp_init (METHOD_INIT) functions are of type initproc:
2945 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
2946 #
2947 # All other functions generated by Argument Clinic are stored in
2948 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
2949 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
2950 # However! We habitually cast these functions to PyCFunction,
2951 # since functions that accept keyword arguments don't fit this signature
2952 # but are stored there anyway. So strict type equality isn't important
2953 # for these functions.
2954 #
2955 # So:
2956 #
2957 # * The name of the first parameter to the impl and the parsing function will always
2958 # be self.name.
2959 #
2960 # * The type of the first parameter to the impl will always be of self.type.
2961 #
2962 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
2963 # * The type of the first parameter to the parsing function is also self.type.
2964 # This means that if you step into the parsing function, your "self" parameter
2965 # is of the correct type, which may make debugging more pleasant.
2966 #
2967 # * Else if the function is tp_new (METHOD_NEW):
2968 # * The type of the first parameter to the parsing function is "PyTypeObject *",
2969 # so the type signature of the function call is an exact match.
2970 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
2971 # in the impl call.
2972 #
2973 # * Else if the function is tp_init (METHOD_INIT):
2974 # * The type of the first parameter to the parsing function is "PyObject *",
2975 # so the type signature of the function call is an exact match.
2976 # * If self.type != "PyObject *", we cast the first parameter to self.type
2977 # in the impl call.
2978
2979 @property
2980 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08002981 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08002982
Larry Hastingsebdcb502013-11-23 14:54:00 -08002983 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08002984 """
2985 parameter is a clinic.Parameter instance.
2986 data is a CRenderData instance.
2987 """
2988 if self.function.kind == STATIC_METHOD:
2989 return
2990
2991 self._render_self(parameter, data)
2992
2993 if self.type != self.parser_type:
2994 # insert cast to impl_argument[0], aka self.
2995 # we know we're in the first slot in all the CRenderData lists,
2996 # because we render parameters in order, and self is always first.
2997 assert len(data.impl_arguments) == 1
2998 assert data.impl_arguments[0] == self.name
2999 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
3000
3001 def set_template_dict(self, template_dict):
3002 template_dict['self_name'] = self.name
3003 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08003004 kind = self.function.kind
3005 cls = self.function.cls
3006
3007 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
3008 if kind == METHOD_NEW:
3009 passed_in_type = self.name
3010 else:
3011 passed_in_type = 'Py_TYPE({})'.format(self.name)
3012
3013 line = '({passed_in_type} == {type_object}) &&\n '
3014 d = {
3015 'type_object': self.function.cls.type_object,
3016 'passed_in_type': passed_in_type
3017 }
3018 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08003019
Larry Hastings31826802013-10-19 00:09:25 -07003020
3021
3022def add_c_return_converter(f, name=None):
3023 if not name:
3024 name = f.__name__
3025 if not name.endswith('_return_converter'):
3026 return f
3027 name = name[:-len('_return_converter')]
3028 return_converters[name] = f
3029 return f
3030
3031
3032class CReturnConverterAutoRegister(type):
3033 def __init__(cls, name, bases, classdict):
3034 add_c_return_converter(cls)
3035
3036class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3037
Larry Hastings78cf85c2014-01-04 12:44:57 -08003038 # The C type to use for this variable.
3039 # 'type' should be a Python string specifying the type, e.g. "int".
3040 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003041 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003042
3043 # The Python default value for this parameter, as a Python value.
3044 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003045 default = None
3046
Larry Hastings2a727912014-01-16 11:32:01 -08003047 def __init__(self, *, py_default=None, **kwargs):
3048 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003049 try:
3050 self.return_converter_init(**kwargs)
3051 except TypeError as e:
3052 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3053 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3054
3055 def return_converter_init(self):
3056 pass
3057
3058 def declare(self, data, name="_return_value"):
3059 line = []
3060 add = line.append
3061 add(self.type)
3062 if not self.type.endswith('*'):
3063 add(' ')
3064 add(name + ';')
3065 data.declarations.append(''.join(line))
3066 data.return_value = name
3067
3068 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003069 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003070
3071 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003072 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003073
3074 def render(self, function, data):
3075 """
3076 function is a clinic.Function instance.
3077 data is a CRenderData instance.
3078 """
3079 pass
3080
3081add_c_return_converter(CReturnConverter, 'object')
3082
Larry Hastings78cf85c2014-01-04 12:44:57 -08003083class NoneType_return_converter(CReturnConverter):
3084 def render(self, function, data):
3085 self.declare(data)
3086 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003087if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003088 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003089}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003090return_value = Py_None;
3091Py_INCREF(Py_None);
3092'''.strip())
3093
Larry Hastings4a55fc52014-01-12 11:09:57 -08003094class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003095 type = 'int'
3096
3097 def render(self, function, data):
3098 self.declare(data)
3099 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003100 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003101
3102class long_return_converter(CReturnConverter):
3103 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003104 conversion_fn = 'PyLong_FromLong'
3105 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003106 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003107
3108 def render(self, function, data):
3109 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003110 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003111 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003112 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003113
Larry Hastings4a55fc52014-01-12 11:09:57 -08003114class int_return_converter(long_return_converter):
3115 type = 'int'
3116 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003117
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003118class init_return_converter(long_return_converter):
3119 """
3120 Special return converter for __init__ functions.
3121 """
3122 type = 'int'
3123 cast = '(long)'
3124
3125 def render(self, function, data):
3126 pass
3127
Larry Hastings4a55fc52014-01-12 11:09:57 -08003128class unsigned_long_return_converter(long_return_converter):
3129 type = 'unsigned long'
3130 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003131 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003132
3133class unsigned_int_return_converter(unsigned_long_return_converter):
3134 type = 'unsigned int'
3135 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003136 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003137
3138class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003139 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003140 conversion_fn = 'PyLong_FromSsize_t'
3141
3142class size_t_return_converter(long_return_converter):
3143 type = 'size_t'
3144 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003145 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003146
3147
3148class double_return_converter(CReturnConverter):
3149 type = 'double'
3150 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003151
3152 def render(self, function, data):
3153 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003154 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003155 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003156 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3157
3158class float_return_converter(double_return_converter):
3159 type = 'float'
3160 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003161
3162
3163class DecodeFSDefault_return_converter(CReturnConverter):
3164 type = 'char *'
3165
3166 def render(self, function, data):
3167 self.declare(data)
3168 self.err_occurred_if_null_pointer("_return_value", data)
3169 data.return_conversion.append(
3170 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
3171
3172
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003173def eval_ast_expr(node, globals, *, filename='-'):
3174 """
3175 Takes an ast.Expr node. Compiles and evaluates it.
3176 Returns the result of the expression.
3177
3178 globals represents the globals dict the expression
3179 should see. (There's no equivalent for "locals" here.)
3180 """
3181
3182 if isinstance(node, ast.Expr):
3183 node = node.value
3184
3185 node = ast.Expression(node)
3186 co = compile(node, filename, 'eval')
3187 fn = types.FunctionType(co, globals)
3188 return fn()
3189
3190
Larry Hastings31826802013-10-19 00:09:25 -07003191class IndentStack:
3192 def __init__(self):
3193 self.indents = []
3194 self.margin = None
3195
3196 def _ensure(self):
3197 if not self.indents:
3198 fail('IndentStack expected indents, but none are defined.')
3199
3200 def measure(self, line):
3201 """
3202 Returns the length of the line's margin.
3203 """
3204 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003205 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003206 stripped = line.lstrip()
3207 if not len(stripped):
3208 # we can't tell anything from an empty line
3209 # so just pretend it's indented like our current indent
3210 self._ensure()
3211 return self.indents[-1]
3212 return len(line) - len(stripped)
3213
3214 def infer(self, line):
3215 """
3216 Infer what is now the current margin based on this line.
3217 Returns:
3218 1 if we have indented (or this is the first margin)
3219 0 if the margin has not changed
3220 -N if we have dedented N times
3221 """
3222 indent = self.measure(line)
3223 margin = ' ' * indent
3224 if not self.indents:
3225 self.indents.append(indent)
3226 self.margin = margin
3227 return 1
3228 current = self.indents[-1]
3229 if indent == current:
3230 return 0
3231 if indent > current:
3232 self.indents.append(indent)
3233 self.margin = margin
3234 return 1
3235 # indent < current
3236 if indent not in self.indents:
3237 fail("Illegal outdent.")
3238 outdent_count = 0
3239 while indent != current:
3240 self.indents.pop()
3241 current = self.indents[-1]
3242 outdent_count -= 1
3243 self.margin = margin
3244 return outdent_count
3245
3246 @property
3247 def depth(self):
3248 """
3249 Returns how many margins are currently defined.
3250 """
3251 return len(self.indents)
3252
3253 def indent(self, line):
3254 """
3255 Indents a line by the currently defined margin.
3256 """
3257 return self.margin + line
3258
3259 def dedent(self, line):
3260 """
3261 Dedents a line by the currently defined margin.
3262 (The inverse of 'indent'.)
3263 """
3264 margin = self.margin
3265 indent = self.indents[-1]
3266 if not line.startswith(margin):
3267 fail('Cannot dedent, line does not start with the previous margin:')
3268 return line[indent:]
3269
3270
3271class DSLParser:
3272 def __init__(self, clinic):
3273 self.clinic = clinic
3274
3275 self.directives = {}
3276 for name in dir(self):
3277 # functions that start with directive_ are added to directives
3278 _, s, key = name.partition("directive_")
3279 if s:
3280 self.directives[key] = getattr(self, name)
3281
3282 # functions that start with at_ are too, with an @ in front
3283 _, s, key = name.partition("at_")
3284 if s:
3285 self.directives['@' + key] = getattr(self, name)
3286
3287 self.reset()
3288
3289 def reset(self):
3290 self.function = None
3291 self.state = self.state_dsl_start
3292 self.parameter_indent = None
3293 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003294 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003295 self.group = 0
3296 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003297 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003298 self.indent = IndentStack()
3299 self.kind = CALLABLE
3300 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003301 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003302 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003303
Larry Hastingsebdcb502013-11-23 14:54:00 -08003304 def directive_version(self, required):
3305 global version
3306 if version_comparitor(version, required) < 0:
3307 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3308
Larry Hastings31826802013-10-19 00:09:25 -07003309 def directive_module(self, name):
3310 fields = name.split('.')
3311 new = fields.pop()
3312 module, cls = self.clinic._module_and_class(fields)
3313 if cls:
3314 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003315
3316 if name in module.classes:
3317 fail("Already defined module " + repr(name) + "!")
3318
Larry Hastings31826802013-10-19 00:09:25 -07003319 m = Module(name, module)
3320 module.modules[name] = m
3321 self.block.signatures.append(m)
3322
Larry Hastingsc2047262014-01-25 20:43:29 -08003323 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003324 fields = name.split('.')
3325 in_classes = False
3326 parent = self
3327 name = fields.pop()
3328 so_far = []
3329 module, cls = self.clinic._module_and_class(fields)
3330
Larry Hastingsc2047262014-01-25 20:43:29 -08003331 parent = cls or module
3332 if name in parent.classes:
3333 fail("Already defined class " + repr(name) + "!")
3334
3335 c = Class(name, module, cls, typedef, type_object)
3336 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003337 self.block.signatures.append(c)
3338
Larry Hastingsbebf7352014-01-17 17:47:17 -08003339 def directive_set(self, name, value):
3340 if name not in ("line_prefix", "line_suffix"):
3341 fail("unknown variable", repr(name))
3342
3343 value = value.format_map({
3344 'block comment start': '/*',
3345 'block comment end': '*/',
3346 })
3347
3348 self.clinic.__dict__[name] = value
3349
3350 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003351 if command == 'new':
3352 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003353 return
3354
Zachary Ware071baa62014-01-21 23:07:12 -06003355 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003356 self.clinic.get_destination(name).clear()
3357 fail("unknown destination command", repr(command))
3358
3359
Larry Hastings0759f842015-04-03 13:09:02 -07003360 def directive_output(self, command_or_name, destination=''):
3361 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003362
Larry Hastings0759f842015-04-03 13:09:02 -07003363 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003364 preset = self.clinic.presets.get(destination)
3365 if not preset:
3366 fail("Unknown preset " + repr(destination) + "!")
3367 fd.update(preset)
3368 return
3369
Larry Hastings0759f842015-04-03 13:09:02 -07003370 if command_or_name == "push":
3371 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003372 return
3373
Larry Hastings0759f842015-04-03 13:09:02 -07003374 if command_or_name == "pop":
3375 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003376 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003377 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003378 fd.update(previous_fd)
3379 return
3380
3381 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003382 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003383 self.block.output.append(pprint.pformat(fd))
3384 self.block.output.append('\n')
3385 return
3386
3387 d = self.clinic.get_destination(destination)
3388
Larry Hastings0759f842015-04-03 13:09:02 -07003389 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003390 for name in list(fd):
3391 fd[name] = d
3392 return
3393
Larry Hastings0759f842015-04-03 13:09:02 -07003394 if command_or_name not in fd:
3395 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3396 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003397
3398 def directive_dump(self, name):
3399 self.block.output.append(self.clinic.get_destination(name).dump())
3400
3401 def directive_print(self, *args):
3402 self.block.output.append(' '.join(args))
3403 self.block.output.append('\n')
3404
3405 def directive_preserve(self):
3406 if self.preserve_output:
3407 fail("Can't have preserve twice in one block!")
3408 self.preserve_output = True
3409
Larry Hastings31826802013-10-19 00:09:25 -07003410 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003411 if self.kind is not CALLABLE:
3412 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003413 self.kind = CLASS_METHOD
3414
3415 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003416 if self.kind is not CALLABLE:
3417 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003418 self.kind = STATIC_METHOD
3419
3420 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003421 if self.coexist:
3422 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003423 self.coexist = True
3424
3425 def parse(self, block):
3426 self.reset()
3427 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003428 self.saved_output = self.block.output
3429 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003430 block_start = self.clinic.block_parser.line_number
3431 lines = block.input.split('\n')
3432 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3433 if '\t' in line:
3434 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3435 self.state(line)
3436
3437 self.next(self.state_terminal)
3438 self.state(None)
3439
Larry Hastingsbebf7352014-01-17 17:47:17 -08003440 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3441
3442 if self.preserve_output:
3443 if block.output:
3444 fail("'preserve' only works for blocks that don't produce any output!")
3445 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003446
3447 @staticmethod
3448 def ignore_line(line):
3449 # ignore comment-only lines
3450 if line.lstrip().startswith('#'):
3451 return True
3452
3453 # Ignore empty lines too
3454 # (but not in docstring sections!)
3455 if not line.strip():
3456 return True
3457
3458 return False
3459
3460 @staticmethod
3461 def calculate_indent(line):
3462 return len(line) - len(line.strip())
3463
3464 def next(self, state, line=None):
3465 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3466 self.state = state
3467 if line is not None:
3468 self.state(line)
3469
3470 def state_dsl_start(self, line):
3471 # self.block = self.ClinicOutputBlock(self)
3472 if self.ignore_line(line):
3473 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003474
3475 # is it a directive?
3476 fields = shlex.split(line)
3477 directive_name = fields[0]
3478 directive = self.directives.get(directive_name, None)
3479 if directive:
3480 try:
3481 directive(*fields[1:])
3482 except TypeError as e:
3483 fail(str(e))
3484 return
3485
Larry Hastings31826802013-10-19 00:09:25 -07003486 self.next(self.state_modulename_name, line)
3487
3488 def state_modulename_name(self, line):
3489 # looking for declaration, which establishes the leftmost column
3490 # line should be
3491 # modulename.fnname [as c_basename] [-> return annotation]
3492 # square brackets denote optional syntax.
3493 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003494 # alternatively:
3495 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3496 # clones the parameters and return converter from that
3497 # function. you can't modify them. you must enter a
3498 # new docstring.
3499 #
Larry Hastings31826802013-10-19 00:09:25 -07003500 # (but we might find a directive first!)
3501 #
3502 # this line is permitted to start with whitespace.
3503 # we'll call this number of spaces F (for "function").
3504
3505 if not line.strip():
3506 return
3507
3508 self.indent.infer(line)
3509
Larry Hastings4a714d42014-01-14 22:22:41 -08003510 # are we cloning?
3511 before, equals, existing = line.rpartition('=')
3512 if equals:
3513 full_name, _, c_basename = before.partition(' as ')
3514 full_name = full_name.strip()
3515 c_basename = c_basename.strip()
3516 existing = existing.strip()
3517 if (is_legal_py_identifier(full_name) and
3518 (not c_basename or is_legal_c_identifier(c_basename)) and
3519 is_legal_py_identifier(existing)):
3520 # we're cloning!
3521 fields = [x.strip() for x in existing.split('.')]
3522 function_name = fields.pop()
3523 module, cls = self.clinic._module_and_class(fields)
3524
3525 for existing_function in (cls or module).functions:
3526 if existing_function.name == function_name:
3527 break
3528 else:
3529 existing_function = None
3530 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003531 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003532 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003533 fail("Couldn't find existing function " + repr(existing) + "!")
3534
3535 fields = [x.strip() for x in full_name.split('.')]
3536 function_name = fields.pop()
3537 module, cls = self.clinic._module_and_class(fields)
3538
3539 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3540 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003541 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 -08003542
3543 self.block.signatures.append(self.function)
3544 (cls or module).functions.append(self.function)
3545 self.next(self.state_function_docstring)
3546 return
3547
Larry Hastings31826802013-10-19 00:09:25 -07003548 line, _, returns = line.partition('->')
3549
3550 full_name, _, c_basename = line.partition(' as ')
3551 full_name = full_name.strip()
3552 c_basename = c_basename.strip() or None
3553
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003554 if not is_legal_py_identifier(full_name):
3555 fail("Illegal function name: {}".format(full_name))
3556 if c_basename and not is_legal_c_identifier(c_basename):
3557 fail("Illegal C basename: {}".format(c_basename))
3558
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003559 return_converter = None
3560 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003561 ast_input = "def x() -> {}: pass".format(returns)
3562 module = None
3563 try:
3564 module = ast.parse(ast_input)
3565 except SyntaxError:
3566 pass
3567 if not module:
3568 fail("Badly-formed annotation for " + full_name + ": " + returns)
3569 try:
3570 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003571 if legacy:
3572 fail("Legacy converter {!r} not allowed as a return converter"
3573 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003574 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003575 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003576 return_converter = return_converters[name](**kwargs)
3577 except ValueError:
3578 fail("Badly-formed annotation for " + full_name + ": " + returns)
3579
3580 fields = [x.strip() for x in full_name.split('.')]
3581 function_name = fields.pop()
3582 module, cls = self.clinic._module_and_class(fields)
3583
Larry Hastings8666e652014-01-12 14:12:59 -08003584 fields = full_name.split('.')
3585 if fields[-1] == '__new__':
3586 if (self.kind != CLASS_METHOD) or (not cls):
3587 fail("__new__ must be a class method!")
3588 self.kind = METHOD_NEW
3589 elif fields[-1] == '__init__':
3590 if (self.kind != CALLABLE) or (not cls):
3591 fail("__init__ must be a normal method, not a class or static method!")
3592 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003593 if not return_converter:
3594 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003595 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003596 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003597
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003598 if not return_converter:
3599 return_converter = CReturnConverter()
3600
Larry Hastings31826802013-10-19 00:09:25 -07003601 if not module:
3602 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3603 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3604 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3605 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08003606
3607 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08003608 type, name = correct_name_for_self(self.function)
3609 kwargs = {}
3610 if cls and type == "PyObject *":
3611 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08003612 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08003613 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
3614 self.function.parameters[sc.name] = p_self
3615
Larry Hastings4a714d42014-01-14 22:22:41 -08003616 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003617 self.next(self.state_parameters_start)
3618
3619 # Now entering the parameters section. The rules, formally stated:
3620 #
3621 # * All lines must be indented with spaces only.
3622 # * The first line must be a parameter declaration.
3623 # * The first line must be indented.
3624 # * This first line establishes the indent for parameters.
3625 # * We'll call this number of spaces P (for "parameter").
3626 # * Thenceforth:
3627 # * Lines indented with P spaces specify a parameter.
3628 # * Lines indented with > P spaces are docstrings for the previous
3629 # parameter.
3630 # * We'll call this number of spaces D (for "docstring").
3631 # * All subsequent lines indented with >= D spaces are stored as
3632 # part of the per-parameter docstring.
3633 # * All lines will have the first D spaces of the indent stripped
3634 # before they are stored.
3635 # * It's illegal to have a line starting with a number of spaces X
3636 # such that P < X < D.
3637 # * A line with < P spaces is the first line of the function
3638 # docstring, which ends processing for parameters and per-parameter
3639 # docstrings.
3640 # * The first line of the function docstring must be at the same
3641 # indent as the function declaration.
3642 # * It's illegal to have any line in the parameters section starting
3643 # with X spaces such that F < X < P. (As before, F is the indent
3644 # of the function declaration.)
3645 #
Larry Hastings31826802013-10-19 00:09:25 -07003646 # Also, currently Argument Clinic places the following restrictions on groups:
3647 # * Each group must contain at least one parameter.
3648 # * Each group may contain at most one group, which must be the furthest
3649 # thing in the group from the required parameters. (The nested group
3650 # must be the first in the group when it's before the required
3651 # parameters, and the last thing in the group when after the required
3652 # parameters.)
3653 # * There may be at most one (top-level) group to the left or right of
3654 # the required parameters.
3655 # * You must specify a slash, and it must be after all parameters.
3656 # (In other words: either all parameters are positional-only,
3657 # or none are.)
3658 #
3659 # Said another way:
3660 # * Each group must contain at least one parameter.
3661 # * All left square brackets before the required parameters must be
3662 # consecutive. (You can't have a left square bracket followed
3663 # by a parameter, then another left square bracket. You can't
3664 # have a left square bracket, a parameter, a right square bracket,
3665 # and then a left square bracket.)
3666 # * All right square brackets after the required parameters must be
3667 # consecutive.
3668 #
3669 # These rules are enforced with a single state variable:
3670 # "parameter_state". (Previously the code was a miasma of ifs and
3671 # separate boolean state variables.) The states are:
3672 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003673 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
3674 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07003675 #
3676 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3677 # 1: ps_left_square_before. left square brackets before required parameters.
3678 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08003679 # 3: ps_required. required parameters, positional-or-keyword or positional-only
3680 # (we don't know yet). (renumber left groups!)
3681 # 4: ps_optional. positional-or-keyword or positional-only parameters that
3682 # now must have default values.
3683 # 5: ps_group_after. in a group, after required parameters.
3684 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07003685 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003686 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07003687
3688 def state_parameters_start(self, line):
3689 if self.ignore_line(line):
3690 return
3691
3692 # if this line is not indented, we have no parameters
3693 if not self.indent.infer(line):
3694 return self.next(self.state_function_docstring, line)
3695
Larry Hastings2a727912014-01-16 11:32:01 -08003696 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003697 return self.next(self.state_parameter, line)
3698
3699
3700 def to_required(self):
3701 """
3702 Transition to the "required" parameter state.
3703 """
3704 if self.parameter_state != self.ps_required:
3705 self.parameter_state = self.ps_required
3706 for p in self.function.parameters.values():
3707 p.group = -p.group
3708
3709 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003710 if self.parameter_continuation:
3711 line = self.parameter_continuation + ' ' + line.lstrip()
3712 self.parameter_continuation = ''
3713
Larry Hastings31826802013-10-19 00:09:25 -07003714 if self.ignore_line(line):
3715 return
3716
3717 assert self.indent.depth == 2
3718 indent = self.indent.infer(line)
3719 if indent == -1:
3720 # we outdented, must be to definition column
3721 return self.next(self.state_function_docstring, line)
3722
3723 if indent == 1:
3724 # we indented, must be to new parameter docstring column
3725 return self.next(self.state_parameter_docstring_start, line)
3726
Larry Hastings2a727912014-01-16 11:32:01 -08003727 line = line.rstrip()
3728 if line.endswith('\\'):
3729 self.parameter_continuation = line[:-1]
3730 return
3731
Larry Hastings31826802013-10-19 00:09:25 -07003732 line = line.lstrip()
3733
3734 if line in ('*', '/', '[', ']'):
3735 self.parse_special_symbol(line)
3736 return
3737
3738 if self.parameter_state in (self.ps_start, self.ps_required):
3739 self.to_required()
3740 elif self.parameter_state == self.ps_left_square_before:
3741 self.parameter_state = self.ps_group_before
3742 elif self.parameter_state == self.ps_group_before:
3743 if not self.group:
3744 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08003745 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07003746 pass
3747 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003748 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07003749
Larry Hastings7726ac92014-01-31 22:03:12 -08003750 # handle "as" for parameters too
3751 c_name = None
3752 name, have_as_token, trailing = line.partition(' as ')
3753 if have_as_token:
3754 name = name.strip()
3755 if ' ' not in name:
3756 fields = trailing.strip().split(' ')
3757 if not fields:
3758 fail("Invalid 'as' clause!")
3759 c_name = fields[0]
3760 if c_name.endswith(':'):
3761 name += ':'
3762 c_name = c_name[:-1]
3763 fields[0] = name
3764 line = ' '.join(fields)
3765
Larry Hastings2a727912014-01-16 11:32:01 -08003766 base, equals, default = line.rpartition('=')
3767 if not equals:
3768 base = default
3769 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08003770
Larry Hastings31826802013-10-19 00:09:25 -07003771 module = None
3772 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003773 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003774 module = ast.parse(ast_input)
3775 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003776 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08003777 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003778 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08003779 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08003780 default = None
3781 ast_input = "def x({}): pass".format(line)
3782 module = ast.parse(ast_input)
3783 except SyntaxError:
3784 pass
Larry Hastings31826802013-10-19 00:09:25 -07003785 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003786 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003787
3788 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003789
3790 if len(function_args.args) > 1:
3791 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
3792 if function_args.defaults or function_args.kw_defaults:
3793 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
3794 if function_args.vararg or function_args.kwarg:
3795 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
3796
Larry Hastings31826802013-10-19 00:09:25 -07003797 parameter = function_args.args[0]
3798
Larry Hastings16c51912014-01-07 11:53:01 -08003799 parameter_name = parameter.arg
3800 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3801
Larry Hastings2a727912014-01-16 11:32:01 -08003802 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08003803 if self.parameter_state == self.ps_optional:
3804 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 -08003805 value = unspecified
3806 if 'py_default' in kwargs:
3807 fail("You can't specify py_default without specifying a default value!")
3808 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003809 if self.parameter_state == self.ps_required:
3810 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08003811 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06003812 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003813 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08003814 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003815 try:
3816 module = ast.parse(ast_input)
3817
Larry Hastings5c661892014-01-24 06:17:25 -08003818 if 'c_default' not in kwargs:
3819 # we can only represent very simple data values in C.
3820 # detect whether default is okay, via a blacklist
3821 # of disallowed ast nodes.
3822 class DetectBadNodes(ast.NodeVisitor):
3823 bad = False
3824 def bad_node(self, node):
3825 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08003826
Larry Hastings5c661892014-01-24 06:17:25 -08003827 # inline function call
3828 visit_Call = bad_node
3829 # inline if statement ("x = 3 if y else z")
3830 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003831
Larry Hastings5c661892014-01-24 06:17:25 -08003832 # comprehensions and generator expressions
3833 visit_ListComp = visit_SetComp = bad_node
3834 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003835
Larry Hastings5c661892014-01-24 06:17:25 -08003836 # literals for advanced types
3837 visit_Dict = visit_Set = bad_node
3838 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003839
Larry Hastings5c661892014-01-24 06:17:25 -08003840 # "starred": "a = [1, 2, 3]; *a"
3841 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003842
Larry Hastings5c661892014-01-24 06:17:25 -08003843 # allow ellipsis, for now
3844 # visit_Ellipsis = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003845
Larry Hastings5c661892014-01-24 06:17:25 -08003846 blacklist = DetectBadNodes()
3847 blacklist.visit(module)
3848 bad = blacklist.bad
3849 else:
3850 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06003851 # but at least make an attempt at ensuring it's a valid expression.
3852 try:
3853 value = eval(default)
3854 if value == unspecified:
3855 fail("'unspecified' is not a legal default value!")
3856 except NameError:
3857 pass # probably a named constant
3858 except Exception as e:
3859 fail("Malformed expression given as default value\n"
3860 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08003861 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08003862 fail("Unsupported expression as default value: " + repr(default))
3863
3864 expr = module.body[0].value
3865 # mild hack: explicitly support NULL as a default value
3866 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3867 value = NULL
3868 py_default = 'None'
3869 c_default = "NULL"
3870 elif (isinstance(expr, ast.BinOp) or
3871 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3872 c_default = kwargs.get("c_default")
3873 if not (isinstance(c_default, str) and c_default):
3874 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3875 py_default = default
3876 value = unknown
3877 elif isinstance(expr, ast.Attribute):
3878 a = []
3879 n = expr
3880 while isinstance(n, ast.Attribute):
3881 a.append(n.attr)
3882 n = n.value
3883 if not isinstance(n, ast.Name):
3884 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3885 a.append(n.id)
3886 py_default = ".".join(reversed(a))
3887
3888 c_default = kwargs.get("c_default")
3889 if not (isinstance(c_default, str) and c_default):
3890 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3891
3892 try:
3893 value = eval(py_default)
3894 except NameError:
3895 value = unknown
3896 else:
3897 value = ast.literal_eval(expr)
3898 py_default = repr(value)
3899 if isinstance(value, (bool, None.__class__)):
3900 c_default = "Py_" + py_default
3901 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003902 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003903 else:
3904 c_default = py_default
3905
3906 except SyntaxError as e:
3907 fail("Syntax error: " + repr(e.text))
3908 except (ValueError, AttributeError):
3909 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003910 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003911 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003912 if not (isinstance(c_default, str) and c_default):
3913 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3914
Larry Hastings2a727912014-01-16 11:32:01 -08003915 kwargs.setdefault('c_default', c_default)
3916 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003917
Larry Hastings31826802013-10-19 00:09:25 -07003918 dict = legacy_converters if legacy else converters
3919 legacy_str = "legacy " if legacy else ""
3920 if name not in dict:
3921 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08003922 # if you use a c_name for the parameter, we just give that name to the converter
3923 # but the parameter object gets the python name
3924 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07003925
3926 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08003927
3928 if isinstance(converter, self_converter):
3929 if len(self.function.parameters) == 1:
3930 if (self.parameter_state != self.ps_required):
3931 fail("A 'self' parameter cannot be marked optional.")
3932 if value is not unspecified:
3933 fail("A 'self' parameter cannot have a default value.")
3934 if self.group:
3935 fail("A 'self' parameter cannot be in an optional group.")
3936 kind = inspect.Parameter.POSITIONAL_ONLY
3937 self.parameter_state = self.ps_start
3938 self.function.parameters.clear()
3939 else:
3940 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
3941
Larry Hastings31826802013-10-19 00:09:25 -07003942 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003943
3944 if parameter_name in self.function.parameters:
3945 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003946 self.function.parameters[parameter_name] = p
3947
3948 def parse_converter(self, annotation):
3949 if isinstance(annotation, ast.Str):
3950 return annotation.s, True, {}
3951
3952 if isinstance(annotation, ast.Name):
3953 return annotation.id, False, {}
3954
Larry Hastings4a55fc52014-01-12 11:09:57 -08003955 if not isinstance(annotation, ast.Call):
3956 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003957
3958 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003959 symbols = globals()
3960
3961 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07003962 return name, False, kwargs
3963
3964 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07003965 if symbol == '*':
3966 if self.keyword_only:
3967 fail("Function " + self.function.name + " uses '*' more than once.")
3968 self.keyword_only = True
3969 elif symbol == '[':
3970 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3971 self.parameter_state = self.ps_left_square_before
3972 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3973 self.parameter_state = self.ps_group_after
3974 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003975 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07003976 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08003977 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07003978 elif symbol == ']':
3979 if not self.group:
3980 fail("Function " + self.function.name + " has a ] without a matching [.")
3981 if not any(p.group == self.group for p in self.function.parameters.values()):
3982 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3983 self.group -= 1
3984 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3985 self.parameter_state = self.ps_group_before
3986 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3987 self.parameter_state = self.ps_right_square_after
3988 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003989 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07003990 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003991 if self.positional_only:
3992 fail("Function " + self.function.name + " uses '/' more than once.")
3993 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08003994 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07003995 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08003996 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
3997 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07003998 if self.keyword_only:
3999 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03004000 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07004001 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08004002 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07004003 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
4004 p.kind = inspect.Parameter.POSITIONAL_ONLY
4005
4006 def state_parameter_docstring_start(self, line):
4007 self.parameter_docstring_indent = len(self.indent.margin)
4008 assert self.indent.depth == 3
4009 return self.next(self.state_parameter_docstring, line)
4010
4011 # every line of the docstring must start with at least F spaces,
4012 # where F > P.
4013 # these F spaces will be stripped.
4014 def state_parameter_docstring(self, line):
4015 stripped = line.strip()
4016 if stripped.startswith('#'):
4017 return
4018
4019 indent = self.indent.measure(line)
4020 if indent < self.parameter_docstring_indent:
4021 self.indent.infer(line)
4022 assert self.indent.depth < 3
4023 if self.indent.depth == 2:
4024 # back to a parameter
4025 return self.next(self.state_parameter, line)
4026 assert self.indent.depth == 1
4027 return self.next(self.state_function_docstring, line)
4028
4029 assert self.function.parameters
4030 last_parameter = next(reversed(list(self.function.parameters.values())))
4031
4032 new_docstring = last_parameter.docstring
4033
4034 if new_docstring:
4035 new_docstring += '\n'
4036 if stripped:
4037 new_docstring += self.indent.dedent(line)
4038
4039 last_parameter.docstring = new_docstring
4040
4041 # the final stanza of the DSL is the docstring.
4042 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004043 if self.group:
4044 fail("Function " + self.function.name + " has a ] without a matching [.")
4045
4046 stripped = line.strip()
4047 if stripped.startswith('#'):
4048 return
4049
4050 new_docstring = self.function.docstring
4051 if new_docstring:
4052 new_docstring += "\n"
4053 if stripped:
4054 line = self.indent.dedent(line).rstrip()
4055 else:
4056 line = ''
4057 new_docstring += line
4058 self.function.docstring = new_docstring
4059
4060 def format_docstring(self):
4061 f = self.function
4062
Larry Hastings5c661892014-01-24 06:17:25 -08004063 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4064 if new_or_init and not f.docstring:
4065 # don't render a docstring at all, no signature, nothing.
4066 return f.docstring
4067
Larry Hastings2623c8c2014-02-08 22:15:29 -08004068 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004069 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004070
4071 ##
4072 ## docstring first line
4073 ##
4074
Larry Hastings2623c8c2014-02-08 22:15:29 -08004075 if new_or_init:
4076 # classes get *just* the name of the class
4077 # not __new__, not __init__, and not module.classname
4078 assert f.cls
4079 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004080 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004081 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004082 add('(')
4083
4084 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004085 assert parameters, "We should always have a self parameter. " + repr(f)
4086 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004087 # self is always positional-only.
4088 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004089 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004090 positional_only = True
4091 for p in parameters[1:]:
4092 if not p.is_positional_only():
4093 positional_only = False
4094 else:
4095 assert positional_only
4096 if positional_only:
4097 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004098 else:
4099 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004100 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004101
4102 right_bracket_count = 0
4103
4104 def fix_right_bracket_count(desired):
4105 nonlocal right_bracket_count
4106 s = ''
4107 while right_bracket_count < desired:
4108 s += '['
4109 right_bracket_count += 1
4110 while right_bracket_count > desired:
4111 s += ']'
4112 right_bracket_count -= 1
4113 return s
4114
Larry Hastings2623c8c2014-02-08 22:15:29 -08004115 need_slash = False
4116 added_slash = False
4117 need_a_trailing_slash = False
4118
4119 # we only need a trailing slash:
4120 # * if this is not a "docstring_only" signature
4121 # * and if the last *shown* parameter is
4122 # positional only
4123 if not f.docstring_only:
4124 for p in reversed(parameters):
4125 if not p.converter.show_in_signature:
4126 continue
4127 if p.is_positional_only():
4128 need_a_trailing_slash = True
4129 break
4130
4131
Larry Hastings31826802013-10-19 00:09:25 -07004132 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004133
4134 first_parameter = True
4135 last_p = parameters[-1]
4136 line_length = len(''.join(text))
4137 indent = " " * line_length
4138 def add_parameter(text):
4139 nonlocal line_length
4140 nonlocal first_parameter
4141 if first_parameter:
4142 s = text
4143 first_parameter = False
4144 else:
4145 s = ' ' + text
4146 if line_length + len(s) >= 72:
4147 add('\n')
4148 add(indent)
4149 line_length = len(indent)
4150 s = text
4151 line_length += len(s)
4152 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004153
4154 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004155 if not p.converter.show_in_signature:
4156 continue
Larry Hastings31826802013-10-19 00:09:25 -07004157 assert p.name
4158
Larry Hastings2623c8c2014-02-08 22:15:29 -08004159 is_self = isinstance(p.converter, self_converter)
4160 if is_self and f.docstring_only:
4161 # this isn't a real machine-parsable signature,
4162 # so let's not print the "self" parameter
4163 continue
4164
4165 if p.is_positional_only():
4166 need_slash = not f.docstring_only
4167 elif need_slash and not (added_slash or p.is_positional_only()):
4168 added_slash = True
4169 add_parameter('/,')
4170
Larry Hastings31826802013-10-19 00:09:25 -07004171 if p.is_keyword_only() and not added_star:
4172 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004173 add_parameter('*,')
4174
4175 p_add, p_output = text_accumulator()
4176 p_add(fix_right_bracket_count(p.right_bracket_count))
4177
4178 if isinstance(p.converter, self_converter):
4179 # annotate first parameter as being a "self".
4180 #
4181 # if inspect.Signature gets this function,
4182 # and it's already bound, the self parameter
4183 # will be stripped off.
4184 #
4185 # if it's not bound, it should be marked
4186 # as positional-only.
4187 #
4188 # note: we don't print "self" for __init__,
4189 # because this isn't actually the signature
4190 # for __init__. (it can't be, __init__ doesn't
4191 # have a docstring.) if this is an __init__
4192 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004193 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004194 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004195
Larry Hastings5c661892014-01-24 06:17:25 -08004196 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004197 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004198
Larry Hastings31826802013-10-19 00:09:25 -07004199 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004200 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004201 value = p.converter.py_default
4202 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004203 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004204 p_add(value)
4205
4206 if (p != last_p) or need_a_trailing_slash:
4207 p_add(',')
4208
4209 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004210
4211 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004212 if need_a_trailing_slash:
4213 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004214 add(')')
4215
Larry Hastings2a727912014-01-16 11:32:01 -08004216 # PEP 8 says:
4217 #
4218 # The Python standard library will not use function annotations
4219 # as that would result in a premature commitment to a particular
4220 # annotation style. Instead, the annotations are left for users
4221 # to discover and experiment with useful annotation styles.
4222 #
4223 # therefore this is commented out:
4224 #
4225 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004226 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004227 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004228
Larry Hastings2623c8c2014-02-08 22:15:29 -08004229 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004230 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004231
Larry Hastings31826802013-10-19 00:09:25 -07004232 docstring_first_line = output()
4233
4234 # now fix up the places where the brackets look wrong
4235 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4236
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004237 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004238 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004239 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004240 for p in parameters:
4241 if not p.docstring.strip():
4242 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004243 if spacer_line:
4244 add('\n')
4245 else:
4246 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004247 add(" ")
4248 add(p.name)
4249 add('\n')
4250 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004251 parameters = output()
4252 if parameters:
4253 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004254
4255 ##
4256 ## docstring body
4257 ##
4258
4259 docstring = f.docstring.rstrip()
4260 lines = [line.rstrip() for line in docstring.split('\n')]
4261
4262 # Enforce the summary line!
4263 # The first line of a docstring should be a summary of the function.
4264 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4265 # by itself.
4266 #
4267 # Argument Clinic enforces the following rule:
4268 # * either the docstring is empty,
4269 # * or it must have a summary line.
4270 #
4271 # Guido said Clinic should enforce this:
4272 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4273
4274 if len(lines) >= 2:
4275 if lines[1]:
4276 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4277 "Every non-blank function docstring must start with\n" +
4278 "a single line summary followed by an empty line.")
4279 elif len(lines) == 1:
4280 # the docstring is only one line right now--the summary line.
4281 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004282 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004283 lines.append('')
4284
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004285 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4286 if parameters_marker_count > 1:
4287 fail('You may not specify {parameters} more than once in a docstring!')
4288
4289 if not parameters_marker_count:
4290 # insert after summary line
4291 lines.insert(2, '{parameters}')
4292
4293 # insert at front of docstring
4294 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004295
4296 docstring = "\n".join(lines)
4297
4298 add(docstring)
4299 docstring = output()
4300
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004301 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004302 docstring = docstring.rstrip()
4303
4304 return docstring
4305
4306 def state_terminal(self, line):
4307 """
4308 Called when processing the block is done.
4309 """
4310 assert not line
4311
4312 if not self.function:
4313 return
4314
4315 if self.keyword_only:
4316 values = self.function.parameters.values()
4317 if not values:
4318 no_parameter_after_star = True
4319 else:
4320 last_parameter = next(reversed(list(values)))
4321 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4322 if no_parameter_after_star:
4323 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4324
4325 # remove trailing whitespace from all parameter docstrings
4326 for name, value in self.function.parameters.items():
4327 if not value:
4328 continue
4329 value.docstring = value.docstring.rstrip()
4330
4331 self.function.docstring = self.format_docstring()
4332
4333
Larry Hastings5c661892014-01-24 06:17:25 -08004334
4335
Larry Hastings31826802013-10-19 00:09:25 -07004336# maps strings to callables.
4337# the callable should return an object
4338# that implements the clinic parser
4339# interface (__init__ and parse).
4340#
4341# example parsers:
4342# "clinic", handles the Clinic DSL
4343# "python", handles running Python code
4344#
4345parsers = {'clinic' : DSLParser, 'python': PythonParser}
4346
4347
4348clinic = None
4349
4350
4351def main(argv):
4352 import sys
4353
4354 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4355 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4356
4357 import argparse
4358 cmdline = argparse.ArgumentParser()
4359 cmdline.add_argument("-f", "--force", action='store_true')
4360 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004361 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004362 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004363 cmdline.add_argument("--make", action='store_true',
4364 help="Walk --srcdir to run over all relevant files.")
4365 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4366 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004367 cmdline.add_argument("filename", type=str, nargs="*")
4368 ns = cmdline.parse_args(argv)
4369
4370 if ns.converters:
4371 if ns.filename:
4372 print("Usage error: can't specify --converters and a filename at the same time.")
4373 print()
4374 cmdline.print_usage()
4375 sys.exit(-1)
4376 converters = []
4377 return_converters = []
4378 ignored = set("""
4379 add_c_converter
4380 add_c_return_converter
4381 add_default_legacy_c_converter
4382 add_legacy_c_converter
4383 """.strip().split())
4384 module = globals()
4385 for name in module:
4386 for suffix, ids in (
4387 ("_return_converter", return_converters),
4388 ("_converter", converters),
4389 ):
4390 if name in ignored:
4391 continue
4392 if name.endswith(suffix):
4393 ids.append((name, name[:-len(suffix)]))
4394 break
4395 print()
4396
4397 print("Legacy converters:")
4398 legacy = sorted(legacy_converters)
4399 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4400 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4401 print()
4402
4403 for title, attribute, ids in (
4404 ("Converters", 'converter_init', converters),
4405 ("Return converters", 'return_converter_init', return_converters),
4406 ):
4407 print(title + ":")
4408 longest = -1
4409 for name, short_name in ids:
4410 longest = max(longest, len(short_name))
4411 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4412 cls = module[name]
4413 callable = getattr(cls, attribute, None)
4414 if not callable:
4415 continue
4416 signature = inspect.signature(callable)
4417 parameters = []
4418 for parameter_name, parameter in signature.parameters.items():
4419 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4420 if parameter.default != inspect.Parameter.empty:
4421 s = '{}={!r}'.format(parameter_name, parameter.default)
4422 else:
4423 s = parameter_name
4424 parameters.append(s)
4425 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004426 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004427 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4428 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004429 sys.exit(0)
4430
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004431 if ns.make:
4432 if ns.output or ns.filename:
4433 print("Usage error: can't use -o or filenames with --make.")
4434 print()
4435 cmdline.print_usage()
4436 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07004437 if not ns.srcdir:
4438 print("Usage error: --srcdir must not be empty with --make.")
4439 print()
4440 cmdline.print_usage()
4441 sys.exit(-1)
4442 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004443 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004444 if rcs_dir in dirs:
4445 dirs.remove(rcs_dir)
4446 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004447 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004448 continue
4449 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004450 if ns.verbose:
4451 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004452 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004453 return
4454
Larry Hastings31826802013-10-19 00:09:25 -07004455 if not ns.filename:
4456 cmdline.print_usage()
4457 sys.exit(-1)
4458
4459 if ns.output and len(ns.filename) > 1:
4460 print("Usage error: can't use -o with multiple filenames.")
4461 print()
4462 cmdline.print_usage()
4463 sys.exit(-1)
4464
4465 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004466 if ns.verbose:
4467 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004468 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004469
4470
4471if __name__ == "__main__":
4472 sys.exit(main(sys.argv[1:]))