blob: 22cde144f37f38482e5b0c0d7fa2e343595ea97a [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 *
713 {c_basename}({self_type}{self_name}, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
714 """)
715
Larry Hastings7726ac92014-01-31 22:03:12 -0800716 # parser_body_fields remembers the fields passed in to the
717 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800718 parser_body_fields = ()
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800719 def parser_body(prototype, *fields):
720 nonlocal parser_body_fields
721 add, output = text_accumulator()
722 add(prototype)
723 parser_body_fields = fields
Larry Hastings7726ac92014-01-31 22:03:12 -0800724
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800725 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800726 fields.insert(0, normalize_snippet("""
727 {{
728 {return_value_declaration}
729 {declarations}
730 {initializers}
731 """) + "\n")
732 # just imagine--your code is here in the middle
733 fields.append(normalize_snippet("""
734 {modifications}
735 {return_value} = {c_basename}_impl({impl_arguments});
736 {return_conversion}
737
738 {exit_label}
739 {cleanup}
740 return return_value;
741 }}
742 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800743 for field in fields:
744 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800745 add(field)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800746 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800747
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800748 def insert_keywords(s):
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300749 return linear_format(s, declarations=
750 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
751 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};\n'
752 '{declarations}')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800753
754 if not parameters:
755 # no parameters, METH_NOARGS
756
757 flags = "METH_NOARGS"
758
Larry Hastings7726ac92014-01-31 22:03:12 -0800759 parser_prototype = normalize_snippet("""
760 static PyObject *
761 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
762 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800763 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800764
765 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800766 parser_definition = parser_prototype + '\n' + normalize_snippet("""
767 {{
768 return {c_basename}_impl({impl_arguments});
769 }}
770 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800771 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800772 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700773
Larry Hastingsbebf7352014-01-17 17:47:17 -0800774 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800775 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800776
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300777 if (isinstance(converters[0], object_converter) and
778 converters[0].format_unit == 'O'):
779 meth_o_prototype = normalize_snippet("""
780 static PyObject *
781 {c_basename}({impl_parameters})
782 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800783
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300784 if default_return_converter:
785 # maps perfectly to METH_O, doesn't need a return converter.
786 # so we skip making a parse function
787 # and call directly into the impl function.
788 impl_prototype = parser_prototype = parser_definition = ''
789 impl_definition = meth_o_prototype
790 else:
791 # SLIGHT HACK
792 # use impl_parameters for the parser here!
793 parser_prototype = meth_o_prototype
794 parser_definition = parser_body(parser_prototype)
795
Larry Hastingsbebf7352014-01-17 17:47:17 -0800796 else:
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300797 argname = 'arg'
798 if parameters[0].name == argname:
799 argname += '_'
800 parser_prototype = normalize_snippet("""
801 static PyObject *
802 {c_basename}({self_type}{self_name}, PyObject *%s)
803 """ % argname)
804
805 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300806 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300807 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300808 }}
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300809 """ % argname, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700810
Larry Hastingsbebf7352014-01-17 17:47:17 -0800811 elif has_option_groups:
812 # positional parameters with option groups
813 # (we have to generate lots of PyArg_ParseTuple calls
814 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700815
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800816 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800817 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700818
Larry Hastings7726ac92014-01-31 22:03:12 -0800819 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700820
Larry Hastingsbebf7352014-01-17 17:47:17 -0800821 elif positional and all_boring_objects:
822 # positional-only, but no option groups,
823 # and nothing but normal objects:
824 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700825
Victor Stinner093119e2017-01-17 02:35:41 +0100826 if not new_or_init:
827 flags = "METH_FASTCALL"
828 parser_prototype = parser_prototype_fastcall
Larry Hastings31826802013-10-19 00:09:25 -0700829
Victor Stinner093119e2017-01-17 02:35:41 +0100830 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Sylvain74453812017-06-10 06:51:48 +0200831 if ({self_type_check}!_PyArg_NoStackKeywords("{name}", kwnames)) {{
Victor Stinner093119e2017-01-17 02:35:41 +0100832 goto exit;
833 }}
834
Sylvain74453812017-06-10 06:51:48 +0200835 if (!_PyArg_UnpackStack(args, nargs, "{name}",
836 {unpack_min}, {unpack_max},
837 {parse_arguments})) {{
Victor Stinner093119e2017-01-17 02:35:41 +0100838 goto exit;
839 }}
840 """, indent=4))
841 else:
842 flags = "METH_VARARGS"
843 parser_prototype = parser_prototype_varargs
844
845 parser_definition = parser_body(parser_prototype, normalize_snippet("""
846 if (!PyArg_UnpackTuple(args, "{name}",
847 {unpack_min}, {unpack_max},
848 {parse_arguments})) {{
849 goto exit;
850 }}
851 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800852
853 elif positional:
Victor Stinner0c8c3892017-01-17 01:42:54 +0100854 if not new_or_init:
855 # positional-only, but no option groups
856 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800857
Victor Stinner0c8c3892017-01-17 01:42:54 +0100858 flags = "METH_FASTCALL"
859 parser_prototype = parser_prototype_fastcall
Larry Hastingsbebf7352014-01-17 17:47:17 -0800860
Victor Stinner0c8c3892017-01-17 01:42:54 +0100861 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Sylvain74453812017-06-10 06:51:48 +0200862 if ({self_type_check}!_PyArg_NoStackKeywords("{name}", kwnames)) {{
Victor Stinner0c8c3892017-01-17 01:42:54 +0100863 goto exit;
864 }}
865
Sylvain74453812017-06-10 06:51:48 +0200866 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
867 {parse_arguments})) {{
Victor Stinner0c8c3892017-01-17 01:42:54 +0100868 goto exit;
869 }}
870 """, indent=4))
871 else:
872 # positional-only, but no option groups
873 # we only need one call to PyArg_ParseTuple
874
875 flags = "METH_VARARGS"
876 parser_prototype = parser_prototype_varargs
877
878 parser_definition = parser_body(parser_prototype, normalize_snippet("""
879 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
880 {parse_arguments})) {{
881 goto exit;
882 }}
883 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800884
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700885 elif not new_or_init:
886 flags = "METH_FASTCALL"
887
888 parser_prototype = parser_prototype_fastcall
889
890 body = normalize_snippet("""
Victor Stinner3e1fad62017-01-17 01:29:01 +0100891 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700892 {parse_arguments})) {{
893 goto exit;
894 }}
895 """, indent=4)
896 parser_definition = parser_body(parser_prototype, body)
897 parser_definition = insert_keywords(parser_definition)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800898 else:
899 # positional-or-keyword arguments
900 flags = "METH_VARARGS|METH_KEYWORDS"
901
Larry Hastings7726ac92014-01-31 22:03:12 -0800902 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800903
Larry Hastings7726ac92014-01-31 22:03:12 -0800904 body = normalize_snippet("""
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300905 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300906 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800907 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300908 }}
909 """, indent=4)
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300910 parser_definition = parser_body(parser_prototype, body)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800911 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700912
Larry Hastings31826802013-10-19 00:09:25 -0700913
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800914 if new_or_init:
915 methoddef_define = ''
916
917 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800918 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800919 else:
920 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800921 parser_prototype = normalize_snippet("""
922 static int
923 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
924 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800925
926 fields = list(parser_body_fields)
927 parses_positional = 'METH_NOARGS' not in flags
928 parses_keywords = 'METH_KEYWORDS' in flags
929 if parses_keywords:
930 assert parses_positional
931
932 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800933 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300934 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800935 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300936 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800937 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800938 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800939 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300940 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800941 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300942 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800943 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800944
945 parser_definition = parser_body(parser_prototype, *fields)
946 if parses_keywords:
947 parser_definition = insert_keywords(parser_definition)
948
Larry Hastings31826802013-10-19 00:09:25 -0700949
Larry Hastingsbebf7352014-01-17 17:47:17 -0800950 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800951 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700952
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800953 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700954
Larry Hastings7726ac92014-01-31 22:03:12 -0800955 methoddef_ifndef = ''
956 conditional = self.cpp.condition()
957 if not conditional:
958 cpp_if = cpp_endif = ''
959 else:
960 cpp_if = "#if " + conditional
961 cpp_endif = "#endif /* " + conditional + " */"
962
Larry Hastings0759f842015-04-03 13:09:02 -0700963 if methoddef_define and f.name not in clinic.ifndef_symbols:
964 clinic.ifndef_symbols.add(f.name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800965 methoddef_ifndef = normalize_snippet("""
966 #ifndef {methoddef_name}
967 #define {methoddef_name}
968 #endif /* !defined({methoddef_name}) */
969 """)
970
971
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800972 # add ';' to the end of parser_prototype and impl_prototype
973 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800974 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800975 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800976 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800977 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700978
Larry Hastingsbebf7352014-01-17 17:47:17 -0800979 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800980 impl_prototype = impl_definition
981 if impl_prototype:
982 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700983
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800984 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800985
986 d = {
987 "docstring_prototype" : docstring_prototype,
988 "docstring_definition" : docstring_definition,
989 "impl_prototype" : impl_prototype,
990 "methoddef_define" : methoddef_define,
991 "parser_prototype" : parser_prototype,
992 "parser_definition" : parser_definition,
993 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800994 "cpp_if" : cpp_if,
995 "cpp_endif" : cpp_endif,
996 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800997 }
998
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800999 # make sure we didn't forget to assign something,
1000 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001001 d2 = {}
1002 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001003 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001004 if value:
1005 value = '\n' + value + '\n'
1006 d2[name] = value
1007 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001008
1009 @staticmethod
1010 def group_to_variable_name(group):
1011 adjective = "left_" if group < 0 else "right_"
1012 return "group_" + adjective + str(abs(group))
1013
1014 def render_option_group_parsing(self, f, template_dict):
1015 # positional only, grouped, optional arguments!
1016 # can be optional on the left or right.
1017 # here's an example:
1018 #
1019 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1020 #
1021 # Here group D are required, and all other groups are optional.
1022 # (Group D's "group" is actually None.)
1023 # We can figure out which sets of arguments we have based on
1024 # how many arguments are in the tuple.
1025 #
1026 # Note that you need to count up on both sides. For example,
1027 # you could have groups C+D, or C+D+E, or C+D+E+F.
1028 #
1029 # What if the number of arguments leads us to an ambiguous result?
1030 # Clinic prefers groups on the left. So in the above example,
1031 # five arguments would map to B+C, not C+D.
1032
1033 add, output = text_accumulator()
1034 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001035 if isinstance(parameters[0].converter, self_converter):
1036 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001037
1038 groups = []
1039 group = None
1040 left = []
1041 right = []
1042 required = []
1043 last = unspecified
1044
1045 for p in parameters:
1046 group_id = p.group
1047 if group_id != last:
1048 last = group_id
1049 group = []
1050 if group_id < 0:
1051 left.append(group)
1052 elif group_id == 0:
1053 group = required
1054 else:
1055 right.append(group)
1056 group.append(p)
1057
1058 count_min = sys.maxsize
1059 count_max = -1
1060
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001061 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001062 for subset in permute_optional_groups(left, required, right):
1063 count = len(subset)
1064 count_min = min(count_min, count)
1065 count_max = max(count_max, count)
1066
Larry Hastings583baa82014-01-12 08:49:30 -08001067 if count == 0:
1068 add(""" case 0:
1069 break;
1070""")
1071 continue
1072
Larry Hastings31826802013-10-19 00:09:25 -07001073 group_ids = {p.group for p in subset} # eliminate duplicates
1074 d = {}
1075 d['count'] = count
1076 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001077 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1078
1079 parse_arguments = []
1080 for p in subset:
1081 p.converter.parse_argument(parse_arguments)
1082 d['parse_arguments'] = ", ".join(parse_arguments)
1083
1084 group_ids.discard(0)
1085 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1086 lines = "\n".join(lines)
1087
1088 s = """
1089 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001090 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001091 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001092 }}
Larry Hastings31826802013-10-19 00:09:25 -07001093 {group_booleans}
1094 break;
1095"""[1:]
1096 s = linear_format(s, group_booleans=lines)
1097 s = s.format_map(d)
1098 add(s)
1099
1100 add(" default:\n")
1101 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1102 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001103 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001104 add("}")
1105 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001106
Larry Hastingsbebf7352014-01-17 17:47:17 -08001107 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001108 if not f:
1109 return ""
1110
1111 add, output = text_accumulator()
1112 data = CRenderData()
1113
Larry Hastings7726ac92014-01-31 22:03:12 -08001114 assert f.parameters, "We should always have a 'self' at this point!"
1115 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001116 converters = [p.converter for p in parameters]
1117
Larry Hastings5c661892014-01-24 06:17:25 -08001118 templates = self.output_templates(f)
1119
1120 f_self = parameters[0]
1121 selfless = parameters[1:]
1122 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1123
1124 last_group = 0
1125 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001126 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001127 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1128 default_return_converter = (not f.return_converter or
1129 f.return_converter.type == 'PyObject *')
1130 has_option_groups = False
1131
1132 # offset i by -1 because first_optional needs to ignore self
1133 for i, p in enumerate(parameters, -1):
1134 c = p.converter
1135
1136 if (i != -1) and (p.default is not unspecified):
1137 first_optional = min(first_optional, i)
1138
1139 # insert group variable
1140 group = p.group
1141 if last_group != group:
1142 last_group = group
1143 if group:
1144 group_name = self.group_to_variable_name(group)
1145 data.impl_arguments.append(group_name)
1146 data.declarations.append("int " + group_name + " = 0;")
1147 data.impl_parameters.append("int " + group_name)
1148 has_option_groups = True
1149
1150 c.render(p, data)
1151
1152 if has_option_groups and (not positional):
1153 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1154
1155 # HACK
1156 # when we're METH_O, but have a custom return converter,
1157 # we use "impl_parameters" for the parsing function
1158 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001159 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001160 # as variables in the parsing function. but since it's
1161 # METH_O, we have exactly one anyway, so we know exactly
1162 # where it is.
1163 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001164 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001165 data.declarations.pop(0)
1166
Larry Hastings31826802013-10-19 00:09:25 -07001167 template_dict = {}
1168
1169 full_name = f.full_name
1170 template_dict['full_name'] = full_name
1171
Larry Hastings5c661892014-01-24 06:17:25 -08001172 if new_or_init:
1173 name = f.cls.name
1174 else:
1175 name = f.name
1176
Larry Hastings31826802013-10-19 00:09:25 -07001177 template_dict['name'] = name
1178
Larry Hastings8666e652014-01-12 14:12:59 -08001179 if f.c_basename:
1180 c_basename = f.c_basename
1181 else:
1182 fields = full_name.split(".")
1183 if fields[-1] == '__new__':
1184 fields.pop()
1185 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001186
Larry Hastings31826802013-10-19 00:09:25 -07001187 template_dict['c_basename'] = c_basename
1188
1189 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1190 template_dict['methoddef_name'] = methoddef_name
1191
1192 template_dict['docstring'] = self.docstring_for_c_string(f)
1193
Larry Hastingsc2047262014-01-25 20:43:29 -08001194 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001195 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001196
Larry Hastings31826802013-10-19 00:09:25 -07001197 f.return_converter.render(f, data)
1198 template_dict['impl_return_type'] = f.return_converter.type
1199
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001200 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001201 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001202 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001203 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1204 template_dict['format_units'] = ''.join(data.format_units)
1205 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1206 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1207 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001208 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1209 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001210 template_dict['return_value'] = data.return_value
1211
Larry Hastings5c661892014-01-24 06:17:25 -08001212 # used by unpack tuple code generator
1213 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1214 unpack_min = first_optional
1215 unpack_max = len(selfless)
1216 template_dict['unpack_min'] = str(unpack_min)
1217 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001218
Larry Hastingsbebf7352014-01-17 17:47:17 -08001219 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001220 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001221
Larry Hastings0759f842015-04-03 13:09:02 -07001222 # buffers, not destination
1223 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001224 template = templates[name]
1225 if has_option_groups:
1226 template = linear_format(template,
1227 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001228 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001229 declarations=template_dict['declarations'],
1230 return_conversion=template_dict['return_conversion'],
1231 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001232 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001233 cleanup=template_dict['cleanup'],
1234 )
Larry Hastings31826802013-10-19 00:09:25 -07001235
Larry Hastingsbebf7352014-01-17 17:47:17 -08001236 # Only generate the "exit:" label
1237 # if we have any gotos
1238 need_exit_label = "goto exit;" in template
1239 template = linear_format(template,
1240 exit_label="exit:" if need_exit_label else ''
1241 )
Larry Hastings31826802013-10-19 00:09:25 -07001242
Larry Hastingsbebf7352014-01-17 17:47:17 -08001243 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001244
Larry Hastings89964c42015-04-14 18:07:59 -04001245 # mild hack:
1246 # reflow long impl declarations
1247 if name in {"impl_prototype", "impl_definition"}:
1248 s = wrap_declarations(s)
1249
Larry Hastingsbebf7352014-01-17 17:47:17 -08001250 if clinic.line_prefix:
1251 s = indent_all_lines(s, clinic.line_prefix)
1252 if clinic.line_suffix:
1253 s = suffix_all_lines(s, clinic.line_suffix)
1254
1255 destination.append(s)
1256
1257 return clinic.get_destination('block').dump()
1258
Larry Hastings31826802013-10-19 00:09:25 -07001259
1260
Larry Hastings5c661892014-01-24 06:17:25 -08001261
Larry Hastings31826802013-10-19 00:09:25 -07001262@contextlib.contextmanager
1263def OverrideStdioWith(stdout):
1264 saved_stdout = sys.stdout
1265 sys.stdout = stdout
1266 try:
1267 yield
1268 finally:
1269 assert sys.stdout is stdout
1270 sys.stdout = saved_stdout
1271
1272
Larry Hastings2623c8c2014-02-08 22:15:29 -08001273def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001274 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001275 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001276 pattern = r'{}({}){}'
1277 if whole_line:
1278 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001279 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1280 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001281
1282
1283class Block:
1284 r"""
1285 Represents a single block of text embedded in
1286 another file. If dsl_name is None, the block represents
1287 verbatim text, raw original text from the file, in
1288 which case "input" will be the only non-false member.
1289 If dsl_name is not None, the block represents a Clinic
1290 block.
1291
1292 input is always str, with embedded \n characters.
1293 input represents the original text from the file;
1294 if it's a Clinic block, it is the original text with
1295 the body_prefix and redundant leading whitespace removed.
1296
1297 dsl_name is either str or None. If str, it's the text
1298 found on the start line of the block between the square
1299 brackets.
1300
1301 signatures is either list or None. If it's a list,
1302 it may only contain clinic.Module, clinic.Class, and
1303 clinic.Function objects. At the moment it should
1304 contain at most one of each.
1305
1306 output is either str or None. If str, it's the output
1307 from this block, with embedded '\n' characters.
1308
1309 indent is either str or None. It's the leading whitespace
1310 that was found on every line of input. (If body_prefix is
1311 not empty, this is the indent *after* removing the
1312 body_prefix.)
1313
1314 preindent is either str or None. It's the whitespace that
1315 was found in front of every line of input *before* the
1316 "body_prefix" (see the Language object). If body_prefix
1317 is empty, preindent must always be empty too.
1318
1319 To illustrate indent and preindent: Assume that '_'
1320 represents whitespace. If the block processed was in a
1321 Python file, and looked like this:
1322 ____#/*[python]
1323 ____#__for a in range(20):
1324 ____#____print(a)
1325 ____#[python]*/
1326 "preindent" would be "____" and "indent" would be "__".
1327
1328 """
1329 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1330 assert isinstance(input, str)
1331 self.input = input
1332 self.dsl_name = dsl_name
1333 self.signatures = signatures or []
1334 self.output = output
1335 self.indent = indent
1336 self.preindent = preindent
1337
Larry Hastings581ee362014-01-28 05:00:08 -08001338 def __repr__(self):
1339 dsl_name = self.dsl_name or "text"
1340 def summarize(s):
1341 s = repr(s)
1342 if len(s) > 30:
1343 return s[:26] + "..." + s[0]
1344 return s
1345 return "".join((
1346 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1347
Larry Hastings31826802013-10-19 00:09:25 -07001348
1349class BlockParser:
1350 """
1351 Block-oriented parser for Argument Clinic.
1352 Iterator, yields Block objects.
1353 """
1354
1355 def __init__(self, input, language, *, verify=True):
1356 """
1357 "input" should be a str object
1358 with embedded \n characters.
1359
1360 "language" should be a Language object.
1361 """
1362 language.validate()
1363
1364 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1365 self.block_start_line_number = self.line_number = 0
1366
1367 self.language = language
1368 before, _, after = language.start_line.partition('{dsl_name}')
1369 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001370 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001371 self.start_re = create_regex(before, after)
1372 self.verify = verify
1373 self.last_checksum_re = None
1374 self.last_dsl_name = None
1375 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001376 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001377
1378 def __iter__(self):
1379 return self
1380
1381 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001382 while True:
1383 if not self.input:
1384 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001385
Larry Hastingsbebf7352014-01-17 17:47:17 -08001386 if self.dsl_name:
1387 return_value = self.parse_clinic_block(self.dsl_name)
1388 self.dsl_name = None
1389 self.first_block = False
1390 return return_value
1391 block = self.parse_verbatim_block()
1392 if self.first_block and not block.input:
1393 continue
1394 self.first_block = False
1395 return block
1396
Larry Hastings31826802013-10-19 00:09:25 -07001397
1398 def is_start_line(self, line):
1399 match = self.start_re.match(line.lstrip())
1400 return match.group(1) if match else None
1401
Larry Hastingse1b82532014-07-27 16:22:20 +02001402 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001403 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001404 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001405 if not lookahead:
1406 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001407 return line
Larry Hastings31826802013-10-19 00:09:25 -07001408
1409 def parse_verbatim_block(self):
1410 add, output = text_accumulator()
1411 self.block_start_line_number = self.line_number
1412
1413 while self.input:
1414 line = self._line()
1415 dsl_name = self.is_start_line(line)
1416 if dsl_name:
1417 self.dsl_name = dsl_name
1418 break
1419 add(line)
1420
1421 return Block(output())
1422
1423 def parse_clinic_block(self, dsl_name):
1424 input_add, input_output = text_accumulator()
1425 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001426 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001427 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1428
Larry Hastings90261132014-01-07 12:21:08 -08001429 def is_stop_line(line):
1430 # make sure to recognize stop line even if it
1431 # doesn't end with EOL (it could be the very end of the file)
1432 if not line.startswith(stop_line):
1433 return False
1434 remainder = line[len(stop_line):]
1435 return (not remainder) or remainder.isspace()
1436
Larry Hastings31826802013-10-19 00:09:25 -07001437 # consume body of program
1438 while self.input:
1439 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001440 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001441 break
1442 if body_prefix:
1443 line = line.lstrip()
1444 assert line.startswith(body_prefix)
1445 line = line[len(body_prefix):]
1446 input_add(line)
1447
1448 # consume output and checksum line, if present.
1449 if self.last_dsl_name == dsl_name:
1450 checksum_re = self.last_checksum_re
1451 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001452 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1453 assert _ == '{arguments}'
1454 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001455 self.last_dsl_name = dsl_name
1456 self.last_checksum_re = checksum_re
1457
1458 # scan forward for checksum line
1459 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001460 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001461 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001462 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001463 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001464 arguments = match.group(1) if match else None
1465 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001466 break
1467 output_add(line)
1468 if self.is_start_line(line):
1469 break
1470
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001471 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001472 if arguments:
1473 d = {}
1474 for field in shlex.split(arguments):
1475 name, equals, value = field.partition('=')
1476 if not equals:
1477 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1478 d[name.strip()] = value.strip()
1479
Larry Hastings31826802013-10-19 00:09:25 -07001480 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001481 if 'input' in d:
1482 checksum = d['output']
1483 input_checksum = d['input']
1484 else:
1485 checksum = d['checksum']
1486 input_checksum = None
1487
1488 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001489 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001490 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1491 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001492 "the end marker,\n"
1493 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001494 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001495 else:
1496 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001497 output_lines = output.splitlines(keepends=True)
1498 self.line_number -= len(output_lines)
1499 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001500 output = None
1501
1502 return Block(input_output(), dsl_name, output=output)
1503
1504
1505class BlockPrinter:
1506
1507 def __init__(self, language, f=None):
1508 self.language = language
1509 self.f = f or io.StringIO()
1510
1511 def print_block(self, block):
1512 input = block.input
1513 output = block.output
1514 dsl_name = block.dsl_name
1515 write = self.f.write
1516
Larry Hastings31826802013-10-19 00:09:25 -07001517 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1518
1519 if not dsl_name:
1520 write(input)
1521 return
1522
1523 write(self.language.start_line.format(dsl_name=dsl_name))
1524 write("\n")
1525
1526 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1527 if not body_prefix:
1528 write(input)
1529 else:
1530 for line in input.split('\n'):
1531 write(body_prefix)
1532 write(line)
1533 write("\n")
1534
1535 write(self.language.stop_line.format(dsl_name=dsl_name))
1536 write("\n")
1537
Larry Hastings581ee362014-01-28 05:00:08 -08001538 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001539 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001540 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001541 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001542 output += '\n'
1543 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001544
Larry Hastings581ee362014-01-28 05:00:08 -08001545 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1546 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001547 write("\n")
1548
Larry Hastingsbebf7352014-01-17 17:47:17 -08001549 def write(self, text):
1550 self.f.write(text)
1551
1552
Larry Hastings0759f842015-04-03 13:09:02 -07001553class BufferSeries:
1554 """
1555 Behaves like a "defaultlist".
1556 When you ask for an index that doesn't exist yet,
1557 the object grows the list until that item exists.
1558 So o[n] will always work.
1559
1560 Supports negative indices for actual items.
1561 e.g. o[-1] is an element immediately preceding o[0].
1562 """
1563
1564 def __init__(self):
1565 self._start = 0
1566 self._array = []
1567 self._constructor = _text_accumulator
1568
1569 def __getitem__(self, i):
1570 i -= self._start
1571 if i < 0:
1572 self._start += i
1573 prefix = [self._constructor() for x in range(-i)]
1574 self._array = prefix + self._array
1575 i = 0
1576 while i >= len(self._array):
1577 self._array.append(self._constructor())
1578 return self._array[i]
1579
1580 def clear(self):
1581 for ta in self._array:
1582 ta._text.clear()
1583
1584 def dump(self):
1585 texts = [ta.output() for ta in self._array]
1586 return "".join(texts)
1587
1588
Larry Hastingsbebf7352014-01-17 17:47:17 -08001589class Destination:
1590 def __init__(self, name, type, clinic, *args):
1591 self.name = name
1592 self.type = type
1593 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001594 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001595 if type not in valid_types:
1596 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1597 extra_arguments = 1 if type == "file" else 0
1598 if len(args) < extra_arguments:
1599 fail("Not enough arguments for destination " + name + " new " + type)
1600 if len(args) > extra_arguments:
1601 fail("Too many arguments for destination " + name + " new " + type)
1602 if type =='file':
1603 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001604 filename = clinic.filename
1605 d['path'] = filename
1606 dirname, basename = os.path.split(filename)
1607 if not dirname:
1608 dirname = '.'
1609 d['dirname'] = dirname
1610 d['basename'] = basename
1611 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001612 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001613
Larry Hastings0759f842015-04-03 13:09:02 -07001614 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001615
1616 def __repr__(self):
1617 if self.type == 'file':
1618 file_repr = " " + repr(self.filename)
1619 else:
1620 file_repr = ''
1621 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1622
1623 def clear(self):
1624 if self.type != 'buffer':
1625 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001626 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001627
1628 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001629 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001630
Larry Hastings31826802013-10-19 00:09:25 -07001631
1632# maps strings to Language objects.
1633# "languages" maps the name of the language ("C", "Python").
1634# "extensions" maps the file extension ("c", "py").
1635languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001636extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1637extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001638
1639
1640# maps strings to callables.
1641# these callables must be of the form:
1642# def foo(name, default, *, ...)
1643# The callable may have any number of keyword-only parameters.
1644# The callable must return a CConverter object.
1645# The callable should not call builtins.print.
1646converters = {}
1647
1648# maps strings to callables.
1649# these callables follow the same rules as those for "converters" above.
1650# note however that they will never be called with keyword-only parameters.
1651legacy_converters = {}
1652
1653
1654# maps strings to callables.
1655# these callables must be of the form:
1656# def foo(*, ...)
1657# The callable may have any number of keyword-only parameters.
1658# The callable must return a CConverter object.
1659# The callable should not call builtins.print.
1660return_converters = {}
1661
Larry Hastings7726ac92014-01-31 22:03:12 -08001662clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001663class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001664
1665 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001666preset block
1667everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001668methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001669docstring_prototype suppress
1670parser_prototype suppress
1671cpp_if suppress
1672cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001673
Larry Hastingsbebf7352014-01-17 17:47:17 -08001674preset original
1675everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001676methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001677docstring_prototype suppress
1678parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001679cpp_if suppress
1680cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001681
1682preset file
1683everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001684methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001685docstring_prototype suppress
1686parser_prototype suppress
1687impl_definition block
1688
1689preset buffer
1690everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001691methoddef_ifndef buffer 1
1692impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001693docstring_prototype suppress
1694impl_prototype suppress
1695parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001696
1697preset partial-buffer
1698everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001699methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001700docstring_prototype block
1701impl_prototype suppress
1702methoddef_define block
1703parser_prototype block
1704impl_definition block
1705
Larry Hastingsbebf7352014-01-17 17:47:17 -08001706"""
1707
Larry Hastings581ee362014-01-28 05:00:08 -08001708 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001709 # maps strings to Parser objects.
1710 # (instantiated from the "parsers" global.)
1711 self.parsers = {}
1712 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001713 if printer:
1714 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001715 self.printer = printer or BlockPrinter(language)
1716 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001717 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001718 self.filename = filename
1719 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001720 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001721 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001722
Larry Hastingsbebf7352014-01-17 17:47:17 -08001723 self.line_prefix = self.line_suffix = ''
1724
1725 self.destinations = {}
1726 self.add_destination("block", "buffer")
1727 self.add_destination("suppress", "suppress")
1728 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001729 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001730 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001731
Larry Hastings0759f842015-04-03 13:09:02 -07001732 d = self.get_destination_buffer
1733 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001734 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001735 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001736 ('docstring_definition', d('file')),
1737 ('methoddef_define', d('file')),
1738 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001739 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001740 ('parser_definition', d('file')),
1741 ('cpp_endif', d('file')),
1742 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001743 ('impl_definition', d('block')),
1744 ))
1745
Larry Hastings0759f842015-04-03 13:09:02 -07001746 self.destination_buffers_stack = []
1747 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001748
1749 self.presets = {}
1750 preset = None
1751 for line in self.presets_text.strip().split('\n'):
1752 line = line.strip()
1753 if not line:
1754 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001755 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001756 if name == 'preset':
1757 self.presets[value] = preset = collections.OrderedDict()
1758 continue
1759
Larry Hastings0759f842015-04-03 13:09:02 -07001760 if len(options):
1761 index = int(options[0])
1762 else:
1763 index = 0
1764 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001765
1766 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001767 for name in self.destination_buffers:
1768 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001769 continue
1770
Larry Hastings0759f842015-04-03 13:09:02 -07001771 assert name in self.destination_buffers
1772 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001773
Larry Hastings31826802013-10-19 00:09:25 -07001774 global clinic
1775 clinic = self
1776
Larry Hastingsbebf7352014-01-17 17:47:17 -08001777 def add_destination(self, name, type, *args):
1778 if name in self.destinations:
1779 fail("Destination already exists: " + repr(name))
1780 self.destinations[name] = Destination(name, type, self, *args)
1781
Larry Hastings0759f842015-04-03 13:09:02 -07001782 def get_destination(self, name):
1783 d = self.destinations.get(name)
1784 if not d:
1785 fail("Destination does not exist: " + repr(name))
1786 return d
1787
1788 def get_destination_buffer(self, name, item=0):
1789 d = self.get_destination(name)
1790 return d.buffers[item]
1791
Larry Hastings31826802013-10-19 00:09:25 -07001792 def parse(self, input):
1793 printer = self.printer
1794 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1795 for block in self.block_parser:
1796 dsl_name = block.dsl_name
1797 if dsl_name:
1798 if dsl_name not in self.parsers:
1799 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1800 self.parsers[dsl_name] = parsers[dsl_name](self)
1801 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001802 try:
1803 parser.parse(block)
1804 except Exception:
1805 fail('Exception raised during parsing:\n' +
1806 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001807 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001808
1809 second_pass_replacements = {}
1810
Larry Hastings0759f842015-04-03 13:09:02 -07001811 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001812 for name, destination in self.destinations.items():
1813 if destination.type == 'suppress':
1814 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001815 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001816
1817 if output:
1818
1819 block = Block("", dsl_name="clinic", output=output)
1820
1821 if destination.type == 'buffer':
1822 block.input = "dump " + name + "\n"
1823 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1824 printer.write("\n")
1825 printer.print_block(block)
1826 continue
1827
1828 if destination.type == 'file':
1829 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001830 dirname = os.path.dirname(destination.filename)
1831 try:
1832 os.makedirs(dirname)
1833 except FileExistsError:
1834 if not os.path.isdir(dirname):
1835 fail("Can't write to destination {}, "
1836 "can't make directory {}!".format(
1837 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001838 if self.verify:
1839 with open(destination.filename, "rt") as f:
1840 parser_2 = BlockParser(f.read(), language=self.language)
1841 blocks = list(parser_2)
1842 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1843 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001844 except FileNotFoundError:
1845 pass
1846
1847 block.input = 'preserve\n'
1848 printer_2 = BlockPrinter(self.language)
1849 printer_2.print_block(block)
1850 with open(destination.filename, "wt") as f:
1851 f.write(printer_2.f.getvalue())
1852 continue
1853 text = printer.f.getvalue()
1854
1855 if second_pass_replacements:
1856 printer_2 = BlockPrinter(self.language)
1857 parser_2 = BlockParser(text, self.language)
1858 changed = False
1859 for block in parser_2:
1860 if block.dsl_name:
1861 for id, replacement in second_pass_replacements.items():
1862 if id in block.output:
1863 changed = True
1864 block.output = block.output.replace(id, replacement)
1865 printer_2.print_block(block)
1866 if changed:
1867 text = printer_2.f.getvalue()
1868
1869 return text
1870
Larry Hastings31826802013-10-19 00:09:25 -07001871
1872 def _module_and_class(self, fields):
1873 """
1874 fields should be an iterable of field names.
1875 returns a tuple of (module, class).
1876 the module object could actually be self (a clinic object).
1877 this function is only ever used to find the parent of where
1878 a new class/module should go.
1879 """
1880 in_classes = False
1881 parent = module = self
1882 cls = None
1883 so_far = []
1884
1885 for field in fields:
1886 so_far.append(field)
1887 if not in_classes:
1888 child = parent.modules.get(field)
1889 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001890 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001891 continue
1892 in_classes = True
1893 if not hasattr(parent, 'classes'):
1894 return module, cls
1895 child = parent.classes.get(field)
1896 if not child:
1897 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1898 cls = parent = child
1899
1900 return module, cls
1901
1902
Larry Hastings581ee362014-01-28 05:00:08 -08001903def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001904 extension = os.path.splitext(filename)[1][1:]
1905 if not extension:
1906 fail("Can't extract file type for file " + repr(filename))
1907
1908 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001909 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001910 except KeyError:
1911 fail("Can't identify file type for file " + repr(filename))
1912
Larry Hastings31826802013-10-19 00:09:25 -07001913 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001914 raw = f.read()
1915
Larry Hastings2623c8c2014-02-08 22:15:29 -08001916 # exit quickly if there are no clinic markers in the file
1917 find_start_re = BlockParser("", language).find_start_re
1918 if not find_start_re.search(raw):
1919 return
1920
1921 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001922 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001923 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001924 return
Larry Hastings31826802013-10-19 00:09:25 -07001925
1926 directory = os.path.dirname(filename) or '.'
1927
1928 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001929 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001930 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1931 with open(tmpfilename, "wb") as f:
1932 f.write(bytes)
1933 os.replace(tmpfilename, output or filename)
1934
1935
Larry Hastings581ee362014-01-28 05:00:08 -08001936def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001937 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001938 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1939 if length:
1940 s = s[:length]
1941 return s
Larry Hastings31826802013-10-19 00:09:25 -07001942
1943
1944
1945
1946class PythonParser:
1947 def __init__(self, clinic):
1948 pass
1949
1950 def parse(self, block):
1951 s = io.StringIO()
1952 with OverrideStdioWith(s):
1953 exec(block.input)
1954 block.output = s.getvalue()
1955
1956
1957class Module:
1958 def __init__(self, name, module=None):
1959 self.name = name
1960 self.module = self.parent = module
1961
1962 self.modules = collections.OrderedDict()
1963 self.classes = collections.OrderedDict()
1964 self.functions = []
1965
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001966 def __repr__(self):
1967 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1968
Larry Hastings31826802013-10-19 00:09:25 -07001969class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001970 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001971 self.name = name
1972 self.module = module
1973 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001974 self.typedef = typedef
1975 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001976 self.parent = cls or module
1977
1978 self.classes = collections.OrderedDict()
1979 self.functions = []
1980
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001981 def __repr__(self):
1982 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1983
Larry Hastings8666e652014-01-12 14:12:59 -08001984unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001985
Larry Hastings8666e652014-01-12 14:12:59 -08001986__abs__
1987__add__
1988__and__
1989__bytes__
1990__call__
1991__complex__
1992__delitem__
1993__divmod__
1994__eq__
1995__float__
1996__floordiv__
1997__ge__
1998__getattr__
1999__getattribute__
2000__getitem__
2001__gt__
2002__hash__
2003__iadd__
2004__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002005__ifloordiv__
2006__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002007__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002008__imod__
2009__imul__
2010__index__
2011__int__
2012__invert__
2013__ior__
2014__ipow__
2015__irshift__
2016__isub__
2017__iter__
2018__itruediv__
2019__ixor__
2020__le__
2021__len__
2022__lshift__
2023__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002024__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002025__mod__
2026__mul__
2027__neg__
2028__new__
2029__next__
2030__or__
2031__pos__
2032__pow__
2033__radd__
2034__rand__
2035__rdivmod__
2036__repr__
2037__rfloordiv__
2038__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002039__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002040__rmod__
2041__rmul__
2042__ror__
Larry Hastings8666e652014-01-12 14:12:59 -08002043__rpow__
2044__rrshift__
2045__rshift__
2046__rsub__
2047__rtruediv__
2048__rxor__
2049__setattr__
2050__setitem__
2051__str__
2052__sub__
2053__truediv__
2054__xor__
2055
2056""".strip().split())
2057
2058
Larry Hastings5c661892014-01-24 06:17:25 -08002059INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2060INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2061""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002062
2063class Function:
2064 """
2065 Mutable duck type for inspect.Function.
2066
2067 docstring - a str containing
2068 * embedded line breaks
2069 * text outdented to the left margin
2070 * no trailing whitespace.
2071 It will always be true that
2072 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2073 """
2074
2075 def __init__(self, parameters=None, *, name,
2076 module, cls=None, c_basename=None,
2077 full_name=None,
2078 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002079 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002080 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002081 self.parameters = parameters or collections.OrderedDict()
2082 self.return_annotation = return_annotation
2083 self.name = name
2084 self.full_name = full_name
2085 self.module = module
2086 self.cls = cls
2087 self.parent = cls or module
2088 self.c_basename = c_basename
2089 self.return_converter = return_converter
2090 self.docstring = docstring or ''
2091 self.kind = kind
2092 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002093 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002094 # docstring_only means "don't generate a machine-readable
2095 # signature, just a normal docstring". it's True for
2096 # functions with optional groups because we can't represent
2097 # those accurately with inspect.Signature in 3.4.
2098 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002099
Larry Hastings7726ac92014-01-31 22:03:12 -08002100 self.rendered_parameters = None
2101
2102 __render_parameters__ = None
2103 @property
2104 def render_parameters(self):
2105 if not self.__render_parameters__:
2106 self.__render_parameters__ = l = []
2107 for p in self.parameters.values():
2108 p = p.copy()
2109 p.converter.pre_render()
2110 l.append(p)
2111 return self.__render_parameters__
2112
Larry Hastingsebdcb502013-11-23 14:54:00 -08002113 @property
2114 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002115 if self.kind in (METHOD_INIT, METHOD_NEW):
2116 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002117 flags = []
2118 if self.kind == CLASS_METHOD:
2119 flags.append('METH_CLASS')
2120 elif self.kind == STATIC_METHOD:
2121 flags.append('METH_STATIC')
2122 else:
2123 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2124 if self.coexist:
2125 flags.append('METH_COEXIST')
2126 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002127
2128 def __repr__(self):
2129 return '<clinic.Function ' + self.name + '>'
2130
Larry Hastings7726ac92014-01-31 22:03:12 -08002131 def copy(self, **overrides):
2132 kwargs = {
2133 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2134 'cls': self.cls, 'c_basename': self.c_basename,
2135 'full_name': self.full_name,
2136 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2137 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002138 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002139 }
2140 kwargs.update(overrides)
2141 f = Function(**kwargs)
2142
2143 parameters = collections.OrderedDict()
2144 for name, value in f.parameters.items():
2145 value = value.copy(function=f)
2146 parameters[name] = value
2147 f.parameters = parameters
2148 return f
2149
Larry Hastings31826802013-10-19 00:09:25 -07002150
2151class Parameter:
2152 """
2153 Mutable duck type of inspect.Parameter.
2154 """
2155
2156 def __init__(self, name, kind, *, default=_empty,
2157 function, converter, annotation=_empty,
2158 docstring=None, group=0):
2159 self.name = name
2160 self.kind = kind
2161 self.default = default
2162 self.function = function
2163 self.converter = converter
2164 self.annotation = annotation
2165 self.docstring = docstring or ''
2166 self.group = group
2167
2168 def __repr__(self):
2169 return '<clinic.Parameter ' + self.name + '>'
2170
2171 def is_keyword_only(self):
2172 return self.kind == inspect.Parameter.KEYWORD_ONLY
2173
Larry Hastings2623c8c2014-02-08 22:15:29 -08002174 def is_positional_only(self):
2175 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2176
Larry Hastings7726ac92014-01-31 22:03:12 -08002177 def copy(self, **overrides):
2178 kwargs = {
2179 'name': self.name, 'kind': self.kind, 'default':self.default,
2180 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2181 'docstring': self.docstring, 'group': self.group,
2182 }
2183 kwargs.update(overrides)
2184 if 'converter' not in overrides:
2185 converter = copy.copy(self.converter)
2186 converter.function = kwargs['function']
2187 kwargs['converter'] = converter
2188 return Parameter(**kwargs)
2189
2190
2191
2192class LandMine:
2193 # try to access any
2194 def __init__(self, message):
2195 self.__message__ = message
2196
2197 def __repr__(self):
2198 return '<LandMine ' + repr(self.__message__) + ">"
2199
2200 def __getattribute__(self, name):
2201 if name in ('__repr__', '__message__'):
2202 return super().__getattribute__(name)
2203 # raise RuntimeError(repr(name))
2204 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002205
Larry Hastings31826802013-10-19 00:09:25 -07002206
2207def add_c_converter(f, name=None):
2208 if not name:
2209 name = f.__name__
2210 if not name.endswith('_converter'):
2211 return f
2212 name = name[:-len('_converter')]
2213 converters[name] = f
2214 return f
2215
2216def add_default_legacy_c_converter(cls):
2217 # automatically add converter for default format unit
2218 # (but without stomping on the existing one if it's already
2219 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002220 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002221 (cls.format_unit not in legacy_converters)):
2222 legacy_converters[cls.format_unit] = cls
2223 return cls
2224
2225def add_legacy_c_converter(format_unit, **kwargs):
2226 """
2227 Adds a legacy converter.
2228 """
2229 def closure(f):
2230 if not kwargs:
2231 added_f = f
2232 else:
2233 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002234 if format_unit:
2235 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002236 return f
2237 return closure
2238
2239class CConverterAutoRegister(type):
2240 def __init__(cls, name, bases, classdict):
2241 add_c_converter(cls)
2242 add_default_legacy_c_converter(cls)
2243
2244class CConverter(metaclass=CConverterAutoRegister):
2245 """
2246 For the init function, self, name, function, and default
2247 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002248 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002249 """
2250
Larry Hastings7726ac92014-01-31 22:03:12 -08002251 # The C name to use for this variable.
2252 name = None
2253
2254 # The Python name to use for this variable.
2255 py_name = None
2256
Larry Hastings78cf85c2014-01-04 12:44:57 -08002257 # The C type to use for this variable.
2258 # 'type' should be a Python string specifying the type, e.g. "int".
2259 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002260 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002261
2262 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002263 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002264 # Or the magic value "unknown" if this value is a cannot be evaluated
2265 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2266 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002267 default = unspecified
2268
Larry Hastings4a55fc52014-01-12 11:09:57 -08002269 # If not None, default must be isinstance() of this type.
2270 # (You can also specify a tuple of types.)
2271 default_type = None
2272
Larry Hastings31826802013-10-19 00:09:25 -07002273 # "default" converted into a C value, as a string.
2274 # Or None if there is no default.
2275 c_default = None
2276
Larry Hastings2a727912014-01-16 11:32:01 -08002277 # "default" converted into a Python value, as a string.
2278 # Or None if there is no default.
2279 py_default = None
2280
Larry Hastingsabc716b2013-11-20 09:13:52 -08002281 # The default value used to initialize the C variable when
2282 # there is no default, but not specifying a default may
2283 # result in an "uninitialized variable" warning. This can
2284 # easily happen when using option groups--although
2285 # properly-written code won't actually use the variable,
2286 # the variable does get passed in to the _impl. (Ah, if
2287 # only dataflow analysis could inline the static function!)
2288 #
2289 # This value is specified as a string.
2290 # Every non-abstract subclass should supply a valid value.
2291 c_ignored_default = 'NULL'
2292
Larry Hastings31826802013-10-19 00:09:25 -07002293 # The C converter *function* to be used, if any.
2294 # (If this is not None, format_unit must be 'O&'.)
2295 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002296
Larry Hastings78cf85c2014-01-04 12:44:57 -08002297 # Should Argument Clinic add a '&' before the name of
2298 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002299 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002300
2301 # Should Argument Clinic add a '&' before the name of
2302 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002303 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002304
2305 #############################################################
2306 #############################################################
2307 ## You shouldn't need to read anything below this point to ##
2308 ## write your own converter functions. ##
2309 #############################################################
2310 #############################################################
2311
2312 # The "format unit" to specify for this variable when
2313 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2314 # Custom converters should always use the default value of 'O&'.
2315 format_unit = 'O&'
2316
2317 # What encoding do we want for this variable? Only used
2318 # by format units starting with 'e'.
2319 encoding = None
2320
Larry Hastings77561cc2014-01-07 12:13:13 -08002321 # Should this object be required to be a subclass of a specific type?
2322 # If not None, should be a string representing a pointer to a
2323 # PyTypeObject (e.g. "&PyUnicode_Type").
2324 # Only used by the 'O!' format unit (and the "object" converter).
2325 subclass_of = None
2326
Larry Hastings78cf85c2014-01-04 12:44:57 -08002327 # Do we want an adjacent '_length' variable for this variable?
2328 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002329 length = False
2330
Larry Hastings5c661892014-01-24 06:17:25 -08002331 # Should we show this parameter in the generated
2332 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002333 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002334 show_in_signature = True
2335
2336 # Overrides the name used in a text signature.
2337 # The name used for a "self" parameter must be one of
2338 # self, type, or module; however users can set their own.
2339 # This lets the self_converter overrule the user-settable
2340 # name, *just* for the text signature.
2341 # Only set by self_converter.
2342 signature_name = None
2343
2344 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002345 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 -07002346 self.name = name
Larry Hastings7726ac92014-01-31 22:03:12 -08002347 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002348
2349 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002350 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002351 if isinstance(self.default_type, type):
2352 types_str = self.default_type.__name__
2353 else:
2354 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2355 fail("{}: default value {!r} for field {} is not of type {}".format(
2356 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002357 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002358
Larry Hastingsb4705752014-01-18 21:54:15 -08002359 if c_default:
2360 self.c_default = c_default
2361 if py_default:
2362 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002363
Larry Hastings31826802013-10-19 00:09:25 -07002364 if annotation != unspecified:
2365 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002366
2367 # this is deliberate, to prevent you from caching information
2368 # about the function in the init.
2369 # (that breaks if we get cloned.)
2370 # so after this change we will noisily fail.
2371 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002372 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002373 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002374
2375 def converter_init(self):
2376 pass
2377
2378 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002379 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002380
Larry Hastings5c661892014-01-24 06:17:25 -08002381 def _render_self(self, parameter, data):
2382 self.parameter = parameter
2383 original_name = self.name
2384 name = ensure_legal_c_identifier(original_name)
2385
2386 # impl_arguments
2387 s = ("&" if self.impl_by_reference else "") + name
2388 data.impl_arguments.append(s)
2389 if self.length:
2390 data.impl_arguments.append(self.length_name())
2391
2392 # impl_parameters
2393 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2394 if self.length:
2395 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2396
2397 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002398 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002399 original_name = self.name
2400 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002401
2402 # declarations
2403 d = self.declaration()
2404 data.declarations.append(d)
2405
2406 # initializers
2407 initializers = self.initialize()
2408 if initializers:
2409 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2410
Larry Hastingsc2047262014-01-25 20:43:29 -08002411 # modifications
2412 modifications = self.modify()
2413 if modifications:
2414 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2415
Larry Hastings31826802013-10-19 00:09:25 -07002416 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002417 if parameter.is_positional_only():
2418 data.keywords.append('')
2419 else:
2420 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002421
2422 # format_units
2423 if self.is_optional() and '|' not in data.format_units:
2424 data.format_units.append('|')
2425 if parameter.is_keyword_only() and '$' not in data.format_units:
2426 data.format_units.append('$')
2427 data.format_units.append(self.format_unit)
2428
2429 # parse_arguments
2430 self.parse_argument(data.parse_arguments)
2431
Larry Hastings31826802013-10-19 00:09:25 -07002432 # cleanup
2433 cleanup = self.cleanup()
2434 if cleanup:
2435 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2436
Larry Hastings5c661892014-01-24 06:17:25 -08002437 def render(self, parameter, data):
2438 """
2439 parameter is a clinic.Parameter instance.
2440 data is a CRenderData instance.
2441 """
2442 self._render_self(parameter, data)
2443 self._render_non_self(parameter, data)
2444
Larry Hastingsebdcb502013-11-23 14:54:00 -08002445 def length_name(self):
2446 """Computes the name of the associated "length" variable."""
2447 if not self.length:
2448 return None
2449 return ensure_legal_c_identifier(self.name) + "_length"
2450
Larry Hastings31826802013-10-19 00:09:25 -07002451 # Why is this one broken out separately?
2452 # For "positional-only" function parsing,
2453 # which generates a bunch of PyArg_ParseTuple calls.
2454 def parse_argument(self, list):
2455 assert not (self.converter and self.encoding)
2456 if self.format_unit == 'O&':
2457 assert self.converter
2458 list.append(self.converter)
2459
2460 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002461 list.append(c_repr(self.encoding))
2462 elif self.subclass_of:
2463 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002464
Larry Hastingsebdcb502013-11-23 14:54:00 -08002465 legal_name = ensure_legal_c_identifier(self.name)
2466 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002467 list.append(s)
2468
Larry Hastingsebdcb502013-11-23 14:54:00 -08002469 if self.length:
2470 list.append("&" + self.length_name())
2471
Larry Hastings31826802013-10-19 00:09:25 -07002472 #
2473 # All the functions after here are intended as extension points.
2474 #
2475
2476 def simple_declaration(self, by_reference=False):
2477 """
2478 Computes the basic declaration of the variable.
2479 Used in computing the prototype declaration and the
2480 variable declaration.
2481 """
2482 prototype = [self.type]
2483 if by_reference or not self.type.endswith('*'):
2484 prototype.append(" ")
2485 if by_reference:
2486 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002487 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002488 return "".join(prototype)
2489
2490 def declaration(self):
2491 """
2492 The C statement to declare this variable.
2493 """
2494 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002495 default = self.c_default
2496 if not default and self.parameter.group:
2497 default = self.c_ignored_default
2498 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002499 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002500 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002501 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002502 if self.length:
2503 declaration.append('\nPy_ssize_clean_t ')
2504 declaration.append(self.length_name())
2505 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002506 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002507
2508 def initialize(self):
2509 """
2510 The C statements required to set up this variable before parsing.
2511 Returns a string containing this code indented at column 0.
2512 If no initialization is necessary, returns an empty string.
2513 """
2514 return ""
2515
Larry Hastingsc2047262014-01-25 20:43:29 -08002516 def modify(self):
2517 """
2518 The C statements required to modify this variable after parsing.
2519 Returns a string containing this code indented at column 0.
2520 If no initialization is necessary, returns an empty string.
2521 """
2522 return ""
2523
Larry Hastings31826802013-10-19 00:09:25 -07002524 def cleanup(self):
2525 """
2526 The C statements required to clean up after this variable.
2527 Returns a string containing this code indented at column 0.
2528 If no cleanup is necessary, returns an empty string.
2529 """
2530 return ""
2531
Larry Hastings7726ac92014-01-31 22:03:12 -08002532 def pre_render(self):
2533 """
2534 A second initialization function, like converter_init,
2535 called just before rendering.
2536 You are permitted to examine self.function here.
2537 """
2538 pass
2539
Larry Hastings31826802013-10-19 00:09:25 -07002540
2541class bool_converter(CConverter):
2542 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002543 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002544 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002545 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002546
Serhiy Storchaka202fda52017-03-12 10:10:47 +02002547 def converter_init(self, *, accept={object}):
2548 if accept == {int}:
2549 self.format_unit = 'i'
2550 elif accept != {object}:
2551 fail("bool_converter: illegal 'accept' argument " + repr(accept))
Larry Hastings2a727912014-01-16 11:32:01 -08002552 if self.default is not unspecified:
2553 self.default = bool(self.default)
2554 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002555
2556class char_converter(CConverter):
2557 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002558 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002559 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002560 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002561
Larry Hastings4a55fc52014-01-12 11:09:57 -08002562 def converter_init(self):
Larry Hastings7f90cba2015-04-15 23:02:12 -04002563 if isinstance(self.default, self.default_type) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002564 fail("char_converter: illegal default value " + repr(self.default))
2565
2566
Larry Hastings31826802013-10-19 00:09:25 -07002567@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002568class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002569 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002570 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002571 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002572 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002573
2574 def converter_init(self, *, bitwise=False):
2575 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002576 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002577
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002578class byte_converter(unsigned_char_converter): pass
2579
Larry Hastings31826802013-10-19 00:09:25 -07002580class short_converter(CConverter):
2581 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002582 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002583 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002584 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002585
2586class unsigned_short_converter(CConverter):
2587 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002588 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002589 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002590 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002591
2592 def converter_init(self, *, bitwise=False):
2593 if not bitwise:
2594 fail("Unsigned shorts must be bitwise (for now).")
2595
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002596@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002597class int_converter(CConverter):
2598 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002599 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002600 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002601 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002602
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002603 def converter_init(self, *, accept={int}, type=None):
2604 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002605 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002606 elif accept != {int}:
2607 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002608 if type != None:
2609 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002610
2611class unsigned_int_converter(CConverter):
2612 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002613 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002614 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002615 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002616
2617 def converter_init(self, *, bitwise=False):
2618 if not bitwise:
2619 fail("Unsigned ints must be bitwise (for now).")
2620
2621class long_converter(CConverter):
2622 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002623 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002624 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002625 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002626
2627class unsigned_long_converter(CConverter):
2628 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002629 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002630 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002631 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002632
2633 def converter_init(self, *, bitwise=False):
2634 if not bitwise:
2635 fail("Unsigned longs must be bitwise (for now).")
2636
Benjamin Petersoncc854492016-09-08 09:29:11 -07002637class long_long_converter(CConverter):
2638 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002639 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002640 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002641 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002642
Benjamin Petersoncc854492016-09-08 09:29:11 -07002643class unsigned_long_long_converter(CConverter):
2644 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002645 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002646 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002647 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002648
2649 def converter_init(self, *, bitwise=False):
2650 if not bitwise:
Benjamin Petersoncc854492016-09-08 09:29:11 -07002651 fail("Unsigned long long must be bitwise (for now).")
Larry Hastings31826802013-10-19 00:09:25 -07002652
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002653
Larry Hastings31826802013-10-19 00:09:25 -07002654class Py_ssize_t_converter(CConverter):
2655 type = 'Py_ssize_t'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002656 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002657
Serhiy Storchaka762bf402017-03-30 09:15:31 +03002658 def converter_init(self, *, accept={int}):
2659 if accept == {int}:
2660 self.format_unit = 'n'
2661 self.default_type = int
2662 elif accept == {int, NoneType}:
2663 self.converter = '_Py_convert_optional_to_ssize_t'
2664 else:
2665 fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
2666
Larry Hastings31826802013-10-19 00:09:25 -07002667
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002668class slice_index_converter(CConverter):
2669 type = 'Py_ssize_t'
2670
2671 def converter_init(self, *, accept={int, NoneType}):
2672 if accept == {int}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002673 self.converter = '_PyEval_SliceIndexNotNone'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002674 elif accept == {int, NoneType}:
Serhiy Storchakad4edfc92017-03-30 18:29:23 +03002675 self.converter = '_PyEval_SliceIndex'
Serhiy Storchaka80ec8362017-03-19 19:37:40 +02002676 else:
2677 fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
2678
2679
Larry Hastings31826802013-10-19 00:09:25 -07002680class float_converter(CConverter):
2681 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002682 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002683 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002684 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002685
2686class double_converter(CConverter):
2687 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002688 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002689 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002690 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002691
2692
2693class Py_complex_converter(CConverter):
2694 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002695 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002696 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002697 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002698
2699
2700class object_converter(CConverter):
2701 type = 'PyObject *'
2702 format_unit = 'O'
2703
Larry Hastings4a55fc52014-01-12 11:09:57 -08002704 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2705 if converter:
2706 if subclass_of:
2707 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2708 self.format_unit = 'O&'
2709 self.converter = converter
2710 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002711 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002712 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002713
Larry Hastings77561cc2014-01-07 12:13:13 -08002714 if type is not None:
2715 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002716
2717
Larry Hastings7f90cba2015-04-15 23:02:12 -04002718#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002719# We define three conventions for buffer types in the 'accept' argument:
2720#
2721# buffer : any object supporting the buffer interface
2722# rwbuffer: any object supporting the buffer interface, but must be writeable
2723# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04002724#
2725
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002726class buffer: pass
2727class rwbuffer: pass
2728class robuffer: pass
2729
Larry Hastings38337d12015-05-07 23:30:09 -07002730def str_converter_key(types, encoding, zeroes):
2731 return (frozenset(types), bool(encoding), bool(zeroes))
2732
2733str_converter_argument_map = {}
2734
Larry Hastings31826802013-10-19 00:09:25 -07002735class str_converter(CConverter):
2736 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002737 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002738 format_unit = 's'
2739
Larry Hastings38337d12015-05-07 23:30:09 -07002740 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002741
Larry Hastings38337d12015-05-07 23:30:09 -07002742 key = str_converter_key(accept, encoding, zeroes)
2743 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002744 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07002745 fail("str_converter: illegal combination of arguments", key)
2746
Larry Hastingsebdcb502013-11-23 14:54:00 -08002747 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07002748 self.length = bool(zeroes)
2749 if encoding:
2750 if self.default not in (Null, None, unspecified):
2751 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
2752 self.encoding = encoding
2753 self.type = 'char *'
2754 # sorry, clinic can't support preallocated buffers
2755 # for es# and et#
2756 self.c_default = "NULL"
2757
2758 def cleanup(self):
2759 if self.encoding:
2760 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002761 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07002762
2763#
2764# This is the fourth or fifth rewrite of registering all the
2765# crazy string converter format units. Previous approaches hid
2766# bugs--generally mismatches between the semantics of the format
2767# unit and the arguments necessary to represent those semantics
2768# properly. Hopefully with this approach we'll get it 100% right.
2769#
2770# The r() function (short for "register") both registers the
2771# mapping from arguments to format unit *and* registers the
2772# legacy C converter for that format unit.
2773#
2774def r(format_unit, *, accept, encoding=False, zeroes=False):
2775 if not encoding and format_unit != 's':
2776 # add the legacy c converters here too.
2777 #
2778 # note: add_legacy_c_converter can't work for
2779 # es, es#, et, or et#
2780 # because of their extra encoding argument
2781 #
2782 # also don't add the converter for 's' because
2783 # the metaclass for CConverter adds it for us.
2784 kwargs = {}
2785 if accept != {str}:
2786 kwargs['accept'] = accept
2787 if zeroes:
2788 kwargs['zeroes'] = True
2789 added_f = functools.partial(str_converter, **kwargs)
2790 legacy_converters[format_unit] = added_f
2791
2792 d = str_converter_argument_map
2793 key = str_converter_key(accept, encoding, zeroes)
2794 if key in d:
2795 sys.exit("Duplicate keys specified for str_converter_argument_map!")
2796 d[key] = format_unit
2797
2798r('es', encoding=True, accept={str})
2799r('es#', encoding=True, zeroes=True, accept={str})
2800r('et', encoding=True, accept={bytes, bytearray, str})
2801r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
2802r('s', accept={str})
2803r('s#', zeroes=True, accept={robuffer, str})
2804r('y', accept={robuffer})
2805r('y#', zeroes=True, accept={robuffer})
2806r('z', accept={str, NoneType})
2807r('z#', zeroes=True, accept={robuffer, str, NoneType})
2808del r
Larry Hastings31826802013-10-19 00:09:25 -07002809
2810
2811class PyBytesObject_converter(CConverter):
2812 type = 'PyBytesObject *'
2813 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002814 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07002815
2816class PyByteArrayObject_converter(CConverter):
2817 type = 'PyByteArrayObject *'
2818 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002819 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07002820
2821class unicode_converter(CConverter):
2822 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002823 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002824 format_unit = 'U'
2825
Larry Hastings38337d12015-05-07 23:30:09 -07002826@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002827@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07002828@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07002829class Py_UNICODE_converter(CConverter):
2830 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002831 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002832 format_unit = 'u'
2833
Larry Hastings38337d12015-05-07 23:30:09 -07002834 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002835 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07002836 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002837 format_unit += '#'
2838 self.length = True
2839 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002840
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002841@add_legacy_c_converter('s*', accept={str, buffer})
2842@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
2843@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07002844class Py_buffer_converter(CConverter):
2845 type = 'Py_buffer'
2846 format_unit = 'y*'
2847 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002848 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002849
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002850 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002851 if self.default not in (unspecified, None):
2852 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002853
Larry Hastings3f144c22014-01-06 10:34:00 -08002854 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002855
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002856 if accept == {str, buffer, NoneType}:
2857 format_unit = 'z*'
2858 elif accept == {str, buffer}:
2859 format_unit = 's*'
2860 elif accept == {buffer}:
2861 format_unit = 'y*'
2862 elif accept == {rwbuffer}:
2863 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07002864 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002865 fail("Py_buffer_converter: illegal combination of arguments")
2866
2867 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002868
2869 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002870 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002871 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002872
2873
Larry Hastings5c661892014-01-24 06:17:25 -08002874def correct_name_for_self(f):
2875 if f.kind in (CALLABLE, METHOD_INIT):
2876 if f.cls:
2877 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03002878 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08002879 if f.kind == STATIC_METHOD:
2880 return "void *", "null"
2881 if f.kind in (CLASS_METHOD, METHOD_NEW):
2882 return "PyTypeObject *", "type"
2883 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
2884
Larry Hastingsc2047262014-01-25 20:43:29 -08002885def required_type_for_self_for_parser(f):
2886 type, _ = correct_name_for_self(f)
2887 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
2888 return type
2889 return None
2890
Larry Hastings5c661892014-01-24 06:17:25 -08002891
Larry Hastingsebdcb502013-11-23 14:54:00 -08002892class self_converter(CConverter):
2893 """
2894 A special-case converter:
2895 this is the default converter used for "self".
2896 """
Larry Hastings5c661892014-01-24 06:17:25 -08002897 type = None
2898 format_unit = ''
2899
Larry Hastings78cf85c2014-01-04 12:44:57 -08002900 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08002901 self.specified_type = type
2902
2903 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002904 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08002905 default_type, default_name = correct_name_for_self(f)
2906 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08002907 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002908
Larry Hastings5c661892014-01-24 06:17:25 -08002909 kind = self.function.kind
2910 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
2911
2912 if (kind == STATIC_METHOD) or new_or_init:
2913 self.show_in_signature = False
2914
2915 # tp_new (METHOD_NEW) functions are of type newfunc:
2916 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
2917 # PyTypeObject is a typedef for struct _typeobject.
2918 #
2919 # tp_init (METHOD_INIT) functions are of type initproc:
2920 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
2921 #
2922 # All other functions generated by Argument Clinic are stored in
2923 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
2924 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
2925 # However! We habitually cast these functions to PyCFunction,
2926 # since functions that accept keyword arguments don't fit this signature
2927 # but are stored there anyway. So strict type equality isn't important
2928 # for these functions.
2929 #
2930 # So:
2931 #
2932 # * The name of the first parameter to the impl and the parsing function will always
2933 # be self.name.
2934 #
2935 # * The type of the first parameter to the impl will always be of self.type.
2936 #
2937 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
2938 # * The type of the first parameter to the parsing function is also self.type.
2939 # This means that if you step into the parsing function, your "self" parameter
2940 # is of the correct type, which may make debugging more pleasant.
2941 #
2942 # * Else if the function is tp_new (METHOD_NEW):
2943 # * The type of the first parameter to the parsing function is "PyTypeObject *",
2944 # so the type signature of the function call is an exact match.
2945 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
2946 # in the impl call.
2947 #
2948 # * Else if the function is tp_init (METHOD_INIT):
2949 # * The type of the first parameter to the parsing function is "PyObject *",
2950 # so the type signature of the function call is an exact match.
2951 # * If self.type != "PyObject *", we cast the first parameter to self.type
2952 # in the impl call.
2953
2954 @property
2955 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08002956 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08002957
Larry Hastingsebdcb502013-11-23 14:54:00 -08002958 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08002959 """
2960 parameter is a clinic.Parameter instance.
2961 data is a CRenderData instance.
2962 """
2963 if self.function.kind == STATIC_METHOD:
2964 return
2965
2966 self._render_self(parameter, data)
2967
2968 if self.type != self.parser_type:
2969 # insert cast to impl_argument[0], aka self.
2970 # we know we're in the first slot in all the CRenderData lists,
2971 # because we render parameters in order, and self is always first.
2972 assert len(data.impl_arguments) == 1
2973 assert data.impl_arguments[0] == self.name
2974 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
2975
2976 def set_template_dict(self, template_dict):
2977 template_dict['self_name'] = self.name
2978 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08002979 kind = self.function.kind
2980 cls = self.function.cls
2981
2982 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
2983 if kind == METHOD_NEW:
2984 passed_in_type = self.name
2985 else:
2986 passed_in_type = 'Py_TYPE({})'.format(self.name)
2987
2988 line = '({passed_in_type} == {type_object}) &&\n '
2989 d = {
2990 'type_object': self.function.cls.type_object,
2991 'passed_in_type': passed_in_type
2992 }
2993 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002994
Larry Hastings31826802013-10-19 00:09:25 -07002995
2996
2997def add_c_return_converter(f, name=None):
2998 if not name:
2999 name = f.__name__
3000 if not name.endswith('_return_converter'):
3001 return f
3002 name = name[:-len('_return_converter')]
3003 return_converters[name] = f
3004 return f
3005
3006
3007class CReturnConverterAutoRegister(type):
3008 def __init__(cls, name, bases, classdict):
3009 add_c_return_converter(cls)
3010
3011class CReturnConverter(metaclass=CReturnConverterAutoRegister):
3012
Larry Hastings78cf85c2014-01-04 12:44:57 -08003013 # The C type to use for this variable.
3014 # 'type' should be a Python string specifying the type, e.g. "int".
3015 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07003016 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08003017
3018 # The Python default value for this parameter, as a Python value.
3019 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07003020 default = None
3021
Larry Hastings2a727912014-01-16 11:32:01 -08003022 def __init__(self, *, py_default=None, **kwargs):
3023 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003024 try:
3025 self.return_converter_init(**kwargs)
3026 except TypeError as e:
3027 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3028 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3029
3030 def return_converter_init(self):
3031 pass
3032
3033 def declare(self, data, name="_return_value"):
3034 line = []
3035 add = line.append
3036 add(self.type)
3037 if not self.type.endswith('*'):
3038 add(' ')
3039 add(name + ';')
3040 data.declarations.append(''.join(line))
3041 data.return_value = name
3042
3043 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003044 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003045
3046 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003047 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003048
3049 def render(self, function, data):
3050 """
3051 function is a clinic.Function instance.
3052 data is a CRenderData instance.
3053 """
3054 pass
3055
3056add_c_return_converter(CReturnConverter, 'object')
3057
Larry Hastings78cf85c2014-01-04 12:44:57 -08003058class NoneType_return_converter(CReturnConverter):
3059 def render(self, function, data):
3060 self.declare(data)
3061 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003062if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003063 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003064}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003065return_value = Py_None;
3066Py_INCREF(Py_None);
3067'''.strip())
3068
Larry Hastings4a55fc52014-01-12 11:09:57 -08003069class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003070 type = 'int'
3071
3072 def render(self, function, data):
3073 self.declare(data)
3074 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003075 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003076
3077class long_return_converter(CReturnConverter):
3078 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003079 conversion_fn = 'PyLong_FromLong'
3080 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003081 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003082
3083 def render(self, function, data):
3084 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003085 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003086 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003087 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003088
Larry Hastings4a55fc52014-01-12 11:09:57 -08003089class int_return_converter(long_return_converter):
3090 type = 'int'
3091 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003092
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003093class init_return_converter(long_return_converter):
3094 """
3095 Special return converter for __init__ functions.
3096 """
3097 type = 'int'
3098 cast = '(long)'
3099
3100 def render(self, function, data):
3101 pass
3102
Larry Hastings4a55fc52014-01-12 11:09:57 -08003103class unsigned_long_return_converter(long_return_converter):
3104 type = 'unsigned long'
3105 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003106 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003107
3108class unsigned_int_return_converter(unsigned_long_return_converter):
3109 type = 'unsigned int'
3110 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003111 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003112
3113class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003114 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003115 conversion_fn = 'PyLong_FromSsize_t'
3116
3117class size_t_return_converter(long_return_converter):
3118 type = 'size_t'
3119 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003120 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003121
3122
3123class double_return_converter(CReturnConverter):
3124 type = 'double'
3125 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003126
3127 def render(self, function, data):
3128 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003129 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003130 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003131 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3132
3133class float_return_converter(double_return_converter):
3134 type = 'float'
3135 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003136
3137
3138class DecodeFSDefault_return_converter(CReturnConverter):
3139 type = 'char *'
3140
3141 def render(self, function, data):
3142 self.declare(data)
3143 self.err_occurred_if_null_pointer("_return_value", data)
3144 data.return_conversion.append(
3145 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
3146
3147
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003148def eval_ast_expr(node, globals, *, filename='-'):
3149 """
3150 Takes an ast.Expr node. Compiles and evaluates it.
3151 Returns the result of the expression.
3152
3153 globals represents the globals dict the expression
3154 should see. (There's no equivalent for "locals" here.)
3155 """
3156
3157 if isinstance(node, ast.Expr):
3158 node = node.value
3159
3160 node = ast.Expression(node)
3161 co = compile(node, filename, 'eval')
3162 fn = types.FunctionType(co, globals)
3163 return fn()
3164
3165
Larry Hastings31826802013-10-19 00:09:25 -07003166class IndentStack:
3167 def __init__(self):
3168 self.indents = []
3169 self.margin = None
3170
3171 def _ensure(self):
3172 if not self.indents:
3173 fail('IndentStack expected indents, but none are defined.')
3174
3175 def measure(self, line):
3176 """
3177 Returns the length of the line's margin.
3178 """
3179 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003180 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003181 stripped = line.lstrip()
3182 if not len(stripped):
3183 # we can't tell anything from an empty line
3184 # so just pretend it's indented like our current indent
3185 self._ensure()
3186 return self.indents[-1]
3187 return len(line) - len(stripped)
3188
3189 def infer(self, line):
3190 """
3191 Infer what is now the current margin based on this line.
3192 Returns:
3193 1 if we have indented (or this is the first margin)
3194 0 if the margin has not changed
3195 -N if we have dedented N times
3196 """
3197 indent = self.measure(line)
3198 margin = ' ' * indent
3199 if not self.indents:
3200 self.indents.append(indent)
3201 self.margin = margin
3202 return 1
3203 current = self.indents[-1]
3204 if indent == current:
3205 return 0
3206 if indent > current:
3207 self.indents.append(indent)
3208 self.margin = margin
3209 return 1
3210 # indent < current
3211 if indent not in self.indents:
3212 fail("Illegal outdent.")
3213 outdent_count = 0
3214 while indent != current:
3215 self.indents.pop()
3216 current = self.indents[-1]
3217 outdent_count -= 1
3218 self.margin = margin
3219 return outdent_count
3220
3221 @property
3222 def depth(self):
3223 """
3224 Returns how many margins are currently defined.
3225 """
3226 return len(self.indents)
3227
3228 def indent(self, line):
3229 """
3230 Indents a line by the currently defined margin.
3231 """
3232 return self.margin + line
3233
3234 def dedent(self, line):
3235 """
3236 Dedents a line by the currently defined margin.
3237 (The inverse of 'indent'.)
3238 """
3239 margin = self.margin
3240 indent = self.indents[-1]
3241 if not line.startswith(margin):
3242 fail('Cannot dedent, line does not start with the previous margin:')
3243 return line[indent:]
3244
3245
3246class DSLParser:
3247 def __init__(self, clinic):
3248 self.clinic = clinic
3249
3250 self.directives = {}
3251 for name in dir(self):
3252 # functions that start with directive_ are added to directives
3253 _, s, key = name.partition("directive_")
3254 if s:
3255 self.directives[key] = getattr(self, name)
3256
3257 # functions that start with at_ are too, with an @ in front
3258 _, s, key = name.partition("at_")
3259 if s:
3260 self.directives['@' + key] = getattr(self, name)
3261
3262 self.reset()
3263
3264 def reset(self):
3265 self.function = None
3266 self.state = self.state_dsl_start
3267 self.parameter_indent = None
3268 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003269 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003270 self.group = 0
3271 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003272 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003273 self.indent = IndentStack()
3274 self.kind = CALLABLE
3275 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003276 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003277 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003278
Larry Hastingsebdcb502013-11-23 14:54:00 -08003279 def directive_version(self, required):
3280 global version
3281 if version_comparitor(version, required) < 0:
3282 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3283
Larry Hastings31826802013-10-19 00:09:25 -07003284 def directive_module(self, name):
3285 fields = name.split('.')
3286 new = fields.pop()
3287 module, cls = self.clinic._module_and_class(fields)
3288 if cls:
3289 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003290
3291 if name in module.classes:
3292 fail("Already defined module " + repr(name) + "!")
3293
Larry Hastings31826802013-10-19 00:09:25 -07003294 m = Module(name, module)
3295 module.modules[name] = m
3296 self.block.signatures.append(m)
3297
Larry Hastingsc2047262014-01-25 20:43:29 -08003298 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003299 fields = name.split('.')
3300 in_classes = False
3301 parent = self
3302 name = fields.pop()
3303 so_far = []
3304 module, cls = self.clinic._module_and_class(fields)
3305
Larry Hastingsc2047262014-01-25 20:43:29 -08003306 parent = cls or module
3307 if name in parent.classes:
3308 fail("Already defined class " + repr(name) + "!")
3309
3310 c = Class(name, module, cls, typedef, type_object)
3311 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003312 self.block.signatures.append(c)
3313
Larry Hastingsbebf7352014-01-17 17:47:17 -08003314 def directive_set(self, name, value):
3315 if name not in ("line_prefix", "line_suffix"):
3316 fail("unknown variable", repr(name))
3317
3318 value = value.format_map({
3319 'block comment start': '/*',
3320 'block comment end': '*/',
3321 })
3322
3323 self.clinic.__dict__[name] = value
3324
3325 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003326 if command == 'new':
3327 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003328 return
3329
Zachary Ware071baa62014-01-21 23:07:12 -06003330 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003331 self.clinic.get_destination(name).clear()
3332 fail("unknown destination command", repr(command))
3333
3334
Larry Hastings0759f842015-04-03 13:09:02 -07003335 def directive_output(self, command_or_name, destination=''):
3336 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003337
Larry Hastings0759f842015-04-03 13:09:02 -07003338 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003339 preset = self.clinic.presets.get(destination)
3340 if not preset:
3341 fail("Unknown preset " + repr(destination) + "!")
3342 fd.update(preset)
3343 return
3344
Larry Hastings0759f842015-04-03 13:09:02 -07003345 if command_or_name == "push":
3346 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003347 return
3348
Larry Hastings0759f842015-04-03 13:09:02 -07003349 if command_or_name == "pop":
3350 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003351 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003352 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003353 fd.update(previous_fd)
3354 return
3355
3356 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003357 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003358 self.block.output.append(pprint.pformat(fd))
3359 self.block.output.append('\n')
3360 return
3361
3362 d = self.clinic.get_destination(destination)
3363
Larry Hastings0759f842015-04-03 13:09:02 -07003364 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003365 for name in list(fd):
3366 fd[name] = d
3367 return
3368
Larry Hastings0759f842015-04-03 13:09:02 -07003369 if command_or_name not in fd:
3370 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3371 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003372
3373 def directive_dump(self, name):
3374 self.block.output.append(self.clinic.get_destination(name).dump())
3375
3376 def directive_print(self, *args):
3377 self.block.output.append(' '.join(args))
3378 self.block.output.append('\n')
3379
3380 def directive_preserve(self):
3381 if self.preserve_output:
3382 fail("Can't have preserve twice in one block!")
3383 self.preserve_output = True
3384
Larry Hastings31826802013-10-19 00:09:25 -07003385 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003386 if self.kind is not CALLABLE:
3387 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003388 self.kind = CLASS_METHOD
3389
3390 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003391 if self.kind is not CALLABLE:
3392 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003393 self.kind = STATIC_METHOD
3394
3395 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003396 if self.coexist:
3397 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003398 self.coexist = True
3399
3400 def parse(self, block):
3401 self.reset()
3402 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003403 self.saved_output = self.block.output
3404 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003405 block_start = self.clinic.block_parser.line_number
3406 lines = block.input.split('\n')
3407 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3408 if '\t' in line:
3409 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3410 self.state(line)
3411
3412 self.next(self.state_terminal)
3413 self.state(None)
3414
Larry Hastingsbebf7352014-01-17 17:47:17 -08003415 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3416
3417 if self.preserve_output:
3418 if block.output:
3419 fail("'preserve' only works for blocks that don't produce any output!")
3420 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003421
3422 @staticmethod
3423 def ignore_line(line):
3424 # ignore comment-only lines
3425 if line.lstrip().startswith('#'):
3426 return True
3427
3428 # Ignore empty lines too
3429 # (but not in docstring sections!)
3430 if not line.strip():
3431 return True
3432
3433 return False
3434
3435 @staticmethod
3436 def calculate_indent(line):
3437 return len(line) - len(line.strip())
3438
3439 def next(self, state, line=None):
3440 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3441 self.state = state
3442 if line is not None:
3443 self.state(line)
3444
3445 def state_dsl_start(self, line):
3446 # self.block = self.ClinicOutputBlock(self)
3447 if self.ignore_line(line):
3448 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003449
3450 # is it a directive?
3451 fields = shlex.split(line)
3452 directive_name = fields[0]
3453 directive = self.directives.get(directive_name, None)
3454 if directive:
3455 try:
3456 directive(*fields[1:])
3457 except TypeError as e:
3458 fail(str(e))
3459 return
3460
Larry Hastings31826802013-10-19 00:09:25 -07003461 self.next(self.state_modulename_name, line)
3462
3463 def state_modulename_name(self, line):
3464 # looking for declaration, which establishes the leftmost column
3465 # line should be
3466 # modulename.fnname [as c_basename] [-> return annotation]
3467 # square brackets denote optional syntax.
3468 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003469 # alternatively:
3470 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3471 # clones the parameters and return converter from that
3472 # function. you can't modify them. you must enter a
3473 # new docstring.
3474 #
Larry Hastings31826802013-10-19 00:09:25 -07003475 # (but we might find a directive first!)
3476 #
3477 # this line is permitted to start with whitespace.
3478 # we'll call this number of spaces F (for "function").
3479
3480 if not line.strip():
3481 return
3482
3483 self.indent.infer(line)
3484
Larry Hastings4a714d42014-01-14 22:22:41 -08003485 # are we cloning?
3486 before, equals, existing = line.rpartition('=')
3487 if equals:
3488 full_name, _, c_basename = before.partition(' as ')
3489 full_name = full_name.strip()
3490 c_basename = c_basename.strip()
3491 existing = existing.strip()
3492 if (is_legal_py_identifier(full_name) and
3493 (not c_basename or is_legal_c_identifier(c_basename)) and
3494 is_legal_py_identifier(existing)):
3495 # we're cloning!
3496 fields = [x.strip() for x in existing.split('.')]
3497 function_name = fields.pop()
3498 module, cls = self.clinic._module_and_class(fields)
3499
3500 for existing_function in (cls or module).functions:
3501 if existing_function.name == function_name:
3502 break
3503 else:
3504 existing_function = None
3505 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003506 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003507 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003508 fail("Couldn't find existing function " + repr(existing) + "!")
3509
3510 fields = [x.strip() for x in full_name.split('.')]
3511 function_name = fields.pop()
3512 module, cls = self.clinic._module_and_class(fields)
3513
3514 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3515 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003516 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 -08003517
3518 self.block.signatures.append(self.function)
3519 (cls or module).functions.append(self.function)
3520 self.next(self.state_function_docstring)
3521 return
3522
Larry Hastings31826802013-10-19 00:09:25 -07003523 line, _, returns = line.partition('->')
3524
3525 full_name, _, c_basename = line.partition(' as ')
3526 full_name = full_name.strip()
3527 c_basename = c_basename.strip() or None
3528
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003529 if not is_legal_py_identifier(full_name):
3530 fail("Illegal function name: {}".format(full_name))
3531 if c_basename and not is_legal_c_identifier(c_basename):
3532 fail("Illegal C basename: {}".format(c_basename))
3533
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003534 return_converter = None
3535 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003536 ast_input = "def x() -> {}: pass".format(returns)
3537 module = None
3538 try:
3539 module = ast.parse(ast_input)
3540 except SyntaxError:
3541 pass
3542 if not module:
3543 fail("Badly-formed annotation for " + full_name + ": " + returns)
3544 try:
3545 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003546 if legacy:
3547 fail("Legacy converter {!r} not allowed as a return converter"
3548 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003549 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003550 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003551 return_converter = return_converters[name](**kwargs)
3552 except ValueError:
3553 fail("Badly-formed annotation for " + full_name + ": " + returns)
3554
3555 fields = [x.strip() for x in full_name.split('.')]
3556 function_name = fields.pop()
3557 module, cls = self.clinic._module_and_class(fields)
3558
Larry Hastings8666e652014-01-12 14:12:59 -08003559 fields = full_name.split('.')
3560 if fields[-1] == '__new__':
3561 if (self.kind != CLASS_METHOD) or (not cls):
3562 fail("__new__ must be a class method!")
3563 self.kind = METHOD_NEW
3564 elif fields[-1] == '__init__':
3565 if (self.kind != CALLABLE) or (not cls):
3566 fail("__init__ must be a normal method, not a class or static method!")
3567 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003568 if not return_converter:
3569 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003570 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003571 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003572
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003573 if not return_converter:
3574 return_converter = CReturnConverter()
3575
Larry Hastings31826802013-10-19 00:09:25 -07003576 if not module:
3577 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3578 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3579 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3580 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08003581
3582 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08003583 type, name = correct_name_for_self(self.function)
3584 kwargs = {}
3585 if cls and type == "PyObject *":
3586 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08003587 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08003588 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
3589 self.function.parameters[sc.name] = p_self
3590
Larry Hastings4a714d42014-01-14 22:22:41 -08003591 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003592 self.next(self.state_parameters_start)
3593
3594 # Now entering the parameters section. The rules, formally stated:
3595 #
3596 # * All lines must be indented with spaces only.
3597 # * The first line must be a parameter declaration.
3598 # * The first line must be indented.
3599 # * This first line establishes the indent for parameters.
3600 # * We'll call this number of spaces P (for "parameter").
3601 # * Thenceforth:
3602 # * Lines indented with P spaces specify a parameter.
3603 # * Lines indented with > P spaces are docstrings for the previous
3604 # parameter.
3605 # * We'll call this number of spaces D (for "docstring").
3606 # * All subsequent lines indented with >= D spaces are stored as
3607 # part of the per-parameter docstring.
3608 # * All lines will have the first D spaces of the indent stripped
3609 # before they are stored.
3610 # * It's illegal to have a line starting with a number of spaces X
3611 # such that P < X < D.
3612 # * A line with < P spaces is the first line of the function
3613 # docstring, which ends processing for parameters and per-parameter
3614 # docstrings.
3615 # * The first line of the function docstring must be at the same
3616 # indent as the function declaration.
3617 # * It's illegal to have any line in the parameters section starting
3618 # with X spaces such that F < X < P. (As before, F is the indent
3619 # of the function declaration.)
3620 #
Larry Hastings31826802013-10-19 00:09:25 -07003621 # Also, currently Argument Clinic places the following restrictions on groups:
3622 # * Each group must contain at least one parameter.
3623 # * Each group may contain at most one group, which must be the furthest
3624 # thing in the group from the required parameters. (The nested group
3625 # must be the first in the group when it's before the required
3626 # parameters, and the last thing in the group when after the required
3627 # parameters.)
3628 # * There may be at most one (top-level) group to the left or right of
3629 # the required parameters.
3630 # * You must specify a slash, and it must be after all parameters.
3631 # (In other words: either all parameters are positional-only,
3632 # or none are.)
3633 #
3634 # Said another way:
3635 # * Each group must contain at least one parameter.
3636 # * All left square brackets before the required parameters must be
3637 # consecutive. (You can't have a left square bracket followed
3638 # by a parameter, then another left square bracket. You can't
3639 # have a left square bracket, a parameter, a right square bracket,
3640 # and then a left square bracket.)
3641 # * All right square brackets after the required parameters must be
3642 # consecutive.
3643 #
3644 # These rules are enforced with a single state variable:
3645 # "parameter_state". (Previously the code was a miasma of ifs and
3646 # separate boolean state variables.) The states are:
3647 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003648 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
3649 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07003650 #
3651 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3652 # 1: ps_left_square_before. left square brackets before required parameters.
3653 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08003654 # 3: ps_required. required parameters, positional-or-keyword or positional-only
3655 # (we don't know yet). (renumber left groups!)
3656 # 4: ps_optional. positional-or-keyword or positional-only parameters that
3657 # now must have default values.
3658 # 5: ps_group_after. in a group, after required parameters.
3659 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07003660 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003661 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07003662
3663 def state_parameters_start(self, line):
3664 if self.ignore_line(line):
3665 return
3666
3667 # if this line is not indented, we have no parameters
3668 if not self.indent.infer(line):
3669 return self.next(self.state_function_docstring, line)
3670
Larry Hastings2a727912014-01-16 11:32:01 -08003671 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003672 return self.next(self.state_parameter, line)
3673
3674
3675 def to_required(self):
3676 """
3677 Transition to the "required" parameter state.
3678 """
3679 if self.parameter_state != self.ps_required:
3680 self.parameter_state = self.ps_required
3681 for p in self.function.parameters.values():
3682 p.group = -p.group
3683
3684 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003685 if self.parameter_continuation:
3686 line = self.parameter_continuation + ' ' + line.lstrip()
3687 self.parameter_continuation = ''
3688
Larry Hastings31826802013-10-19 00:09:25 -07003689 if self.ignore_line(line):
3690 return
3691
3692 assert self.indent.depth == 2
3693 indent = self.indent.infer(line)
3694 if indent == -1:
3695 # we outdented, must be to definition column
3696 return self.next(self.state_function_docstring, line)
3697
3698 if indent == 1:
3699 # we indented, must be to new parameter docstring column
3700 return self.next(self.state_parameter_docstring_start, line)
3701
Larry Hastings2a727912014-01-16 11:32:01 -08003702 line = line.rstrip()
3703 if line.endswith('\\'):
3704 self.parameter_continuation = line[:-1]
3705 return
3706
Larry Hastings31826802013-10-19 00:09:25 -07003707 line = line.lstrip()
3708
3709 if line in ('*', '/', '[', ']'):
3710 self.parse_special_symbol(line)
3711 return
3712
3713 if self.parameter_state in (self.ps_start, self.ps_required):
3714 self.to_required()
3715 elif self.parameter_state == self.ps_left_square_before:
3716 self.parameter_state = self.ps_group_before
3717 elif self.parameter_state == self.ps_group_before:
3718 if not self.group:
3719 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08003720 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07003721 pass
3722 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003723 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07003724
Larry Hastings7726ac92014-01-31 22:03:12 -08003725 # handle "as" for parameters too
3726 c_name = None
3727 name, have_as_token, trailing = line.partition(' as ')
3728 if have_as_token:
3729 name = name.strip()
3730 if ' ' not in name:
3731 fields = trailing.strip().split(' ')
3732 if not fields:
3733 fail("Invalid 'as' clause!")
3734 c_name = fields[0]
3735 if c_name.endswith(':'):
3736 name += ':'
3737 c_name = c_name[:-1]
3738 fields[0] = name
3739 line = ' '.join(fields)
3740
Larry Hastings2a727912014-01-16 11:32:01 -08003741 base, equals, default = line.rpartition('=')
3742 if not equals:
3743 base = default
3744 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08003745
Larry Hastings31826802013-10-19 00:09:25 -07003746 module = None
3747 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003748 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003749 module = ast.parse(ast_input)
3750 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003751 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08003752 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003753 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08003754 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08003755 default = None
3756 ast_input = "def x({}): pass".format(line)
3757 module = ast.parse(ast_input)
3758 except SyntaxError:
3759 pass
Larry Hastings31826802013-10-19 00:09:25 -07003760 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003761 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003762
3763 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003764
3765 if len(function_args.args) > 1:
3766 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
3767 if function_args.defaults or function_args.kw_defaults:
3768 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
3769 if function_args.vararg or function_args.kwarg:
3770 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
3771
Larry Hastings31826802013-10-19 00:09:25 -07003772 parameter = function_args.args[0]
3773
Larry Hastings16c51912014-01-07 11:53:01 -08003774 parameter_name = parameter.arg
3775 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3776
Larry Hastings2a727912014-01-16 11:32:01 -08003777 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08003778 if self.parameter_state == self.ps_optional:
3779 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 -08003780 value = unspecified
3781 if 'py_default' in kwargs:
3782 fail("You can't specify py_default without specifying a default value!")
3783 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003784 if self.parameter_state == self.ps_required:
3785 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08003786 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06003787 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003788 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08003789 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003790 try:
3791 module = ast.parse(ast_input)
3792
Larry Hastings5c661892014-01-24 06:17:25 -08003793 if 'c_default' not in kwargs:
3794 # we can only represent very simple data values in C.
3795 # detect whether default is okay, via a blacklist
3796 # of disallowed ast nodes.
3797 class DetectBadNodes(ast.NodeVisitor):
3798 bad = False
3799 def bad_node(self, node):
3800 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08003801
Larry Hastings5c661892014-01-24 06:17:25 -08003802 # inline function call
3803 visit_Call = bad_node
3804 # inline if statement ("x = 3 if y else z")
3805 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003806
Larry Hastings5c661892014-01-24 06:17:25 -08003807 # comprehensions and generator expressions
3808 visit_ListComp = visit_SetComp = bad_node
3809 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003810
Larry Hastings5c661892014-01-24 06:17:25 -08003811 # literals for advanced types
3812 visit_Dict = visit_Set = bad_node
3813 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003814
Larry Hastings5c661892014-01-24 06:17:25 -08003815 # "starred": "a = [1, 2, 3]; *a"
3816 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003817
Larry Hastings5c661892014-01-24 06:17:25 -08003818 # allow ellipsis, for now
3819 # visit_Ellipsis = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003820
Larry Hastings5c661892014-01-24 06:17:25 -08003821 blacklist = DetectBadNodes()
3822 blacklist.visit(module)
3823 bad = blacklist.bad
3824 else:
3825 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06003826 # but at least make an attempt at ensuring it's a valid expression.
3827 try:
3828 value = eval(default)
3829 if value == unspecified:
3830 fail("'unspecified' is not a legal default value!")
3831 except NameError:
3832 pass # probably a named constant
3833 except Exception as e:
3834 fail("Malformed expression given as default value\n"
3835 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08003836 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08003837 fail("Unsupported expression as default value: " + repr(default))
3838
3839 expr = module.body[0].value
3840 # mild hack: explicitly support NULL as a default value
3841 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3842 value = NULL
3843 py_default = 'None'
3844 c_default = "NULL"
3845 elif (isinstance(expr, ast.BinOp) or
3846 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3847 c_default = kwargs.get("c_default")
3848 if not (isinstance(c_default, str) and c_default):
3849 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3850 py_default = default
3851 value = unknown
3852 elif isinstance(expr, ast.Attribute):
3853 a = []
3854 n = expr
3855 while isinstance(n, ast.Attribute):
3856 a.append(n.attr)
3857 n = n.value
3858 if not isinstance(n, ast.Name):
3859 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3860 a.append(n.id)
3861 py_default = ".".join(reversed(a))
3862
3863 c_default = kwargs.get("c_default")
3864 if not (isinstance(c_default, str) and c_default):
3865 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3866
3867 try:
3868 value = eval(py_default)
3869 except NameError:
3870 value = unknown
3871 else:
3872 value = ast.literal_eval(expr)
3873 py_default = repr(value)
3874 if isinstance(value, (bool, None.__class__)):
3875 c_default = "Py_" + py_default
3876 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003877 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003878 else:
3879 c_default = py_default
3880
3881 except SyntaxError as e:
3882 fail("Syntax error: " + repr(e.text))
3883 except (ValueError, AttributeError):
3884 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003885 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003886 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003887 if not (isinstance(c_default, str) and c_default):
3888 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3889
Larry Hastings2a727912014-01-16 11:32:01 -08003890 kwargs.setdefault('c_default', c_default)
3891 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003892
Larry Hastings31826802013-10-19 00:09:25 -07003893 dict = legacy_converters if legacy else converters
3894 legacy_str = "legacy " if legacy else ""
3895 if name not in dict:
3896 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08003897 # if you use a c_name for the parameter, we just give that name to the converter
3898 # but the parameter object gets the python name
3899 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07003900
3901 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08003902
3903 if isinstance(converter, self_converter):
3904 if len(self.function.parameters) == 1:
3905 if (self.parameter_state != self.ps_required):
3906 fail("A 'self' parameter cannot be marked optional.")
3907 if value is not unspecified:
3908 fail("A 'self' parameter cannot have a default value.")
3909 if self.group:
3910 fail("A 'self' parameter cannot be in an optional group.")
3911 kind = inspect.Parameter.POSITIONAL_ONLY
3912 self.parameter_state = self.ps_start
3913 self.function.parameters.clear()
3914 else:
3915 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
3916
Larry Hastings31826802013-10-19 00:09:25 -07003917 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003918
3919 if parameter_name in self.function.parameters:
3920 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003921 self.function.parameters[parameter_name] = p
3922
3923 def parse_converter(self, annotation):
3924 if isinstance(annotation, ast.Str):
3925 return annotation.s, True, {}
3926
3927 if isinstance(annotation, ast.Name):
3928 return annotation.id, False, {}
3929
Larry Hastings4a55fc52014-01-12 11:09:57 -08003930 if not isinstance(annotation, ast.Call):
3931 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003932
3933 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003934 symbols = globals()
3935
3936 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07003937 return name, False, kwargs
3938
3939 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07003940 if symbol == '*':
3941 if self.keyword_only:
3942 fail("Function " + self.function.name + " uses '*' more than once.")
3943 self.keyword_only = True
3944 elif symbol == '[':
3945 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3946 self.parameter_state = self.ps_left_square_before
3947 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3948 self.parameter_state = self.ps_group_after
3949 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003950 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07003951 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08003952 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07003953 elif symbol == ']':
3954 if not self.group:
3955 fail("Function " + self.function.name + " has a ] without a matching [.")
3956 if not any(p.group == self.group for p in self.function.parameters.values()):
3957 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3958 self.group -= 1
3959 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3960 self.parameter_state = self.ps_group_before
3961 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3962 self.parameter_state = self.ps_right_square_after
3963 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003964 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07003965 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003966 if self.positional_only:
3967 fail("Function " + self.function.name + " uses '/' more than once.")
3968 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08003969 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07003970 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08003971 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
3972 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07003973 if self.keyword_only:
3974 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03003975 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07003976 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08003977 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07003978 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3979 p.kind = inspect.Parameter.POSITIONAL_ONLY
3980
3981 def state_parameter_docstring_start(self, line):
3982 self.parameter_docstring_indent = len(self.indent.margin)
3983 assert self.indent.depth == 3
3984 return self.next(self.state_parameter_docstring, line)
3985
3986 # every line of the docstring must start with at least F spaces,
3987 # where F > P.
3988 # these F spaces will be stripped.
3989 def state_parameter_docstring(self, line):
3990 stripped = line.strip()
3991 if stripped.startswith('#'):
3992 return
3993
3994 indent = self.indent.measure(line)
3995 if indent < self.parameter_docstring_indent:
3996 self.indent.infer(line)
3997 assert self.indent.depth < 3
3998 if self.indent.depth == 2:
3999 # back to a parameter
4000 return self.next(self.state_parameter, line)
4001 assert self.indent.depth == 1
4002 return self.next(self.state_function_docstring, line)
4003
4004 assert self.function.parameters
4005 last_parameter = next(reversed(list(self.function.parameters.values())))
4006
4007 new_docstring = last_parameter.docstring
4008
4009 if new_docstring:
4010 new_docstring += '\n'
4011 if stripped:
4012 new_docstring += self.indent.dedent(line)
4013
4014 last_parameter.docstring = new_docstring
4015
4016 # the final stanza of the DSL is the docstring.
4017 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07004018 if self.group:
4019 fail("Function " + self.function.name + " has a ] without a matching [.")
4020
4021 stripped = line.strip()
4022 if stripped.startswith('#'):
4023 return
4024
4025 new_docstring = self.function.docstring
4026 if new_docstring:
4027 new_docstring += "\n"
4028 if stripped:
4029 line = self.indent.dedent(line).rstrip()
4030 else:
4031 line = ''
4032 new_docstring += line
4033 self.function.docstring = new_docstring
4034
4035 def format_docstring(self):
4036 f = self.function
4037
Larry Hastings5c661892014-01-24 06:17:25 -08004038 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4039 if new_or_init and not f.docstring:
4040 # don't render a docstring at all, no signature, nothing.
4041 return f.docstring
4042
Larry Hastings2623c8c2014-02-08 22:15:29 -08004043 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004044 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004045
4046 ##
4047 ## docstring first line
4048 ##
4049
Larry Hastings2623c8c2014-02-08 22:15:29 -08004050 if new_or_init:
4051 # classes get *just* the name of the class
4052 # not __new__, not __init__, and not module.classname
4053 assert f.cls
4054 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004055 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004056 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004057 add('(')
4058
4059 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004060 assert parameters, "We should always have a self parameter. " + repr(f)
4061 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004062 # self is always positional-only.
4063 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004064 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004065 positional_only = True
4066 for p in parameters[1:]:
4067 if not p.is_positional_only():
4068 positional_only = False
4069 else:
4070 assert positional_only
4071 if positional_only:
4072 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004073 else:
4074 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004075 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004076
4077 right_bracket_count = 0
4078
4079 def fix_right_bracket_count(desired):
4080 nonlocal right_bracket_count
4081 s = ''
4082 while right_bracket_count < desired:
4083 s += '['
4084 right_bracket_count += 1
4085 while right_bracket_count > desired:
4086 s += ']'
4087 right_bracket_count -= 1
4088 return s
4089
Larry Hastings2623c8c2014-02-08 22:15:29 -08004090 need_slash = False
4091 added_slash = False
4092 need_a_trailing_slash = False
4093
4094 # we only need a trailing slash:
4095 # * if this is not a "docstring_only" signature
4096 # * and if the last *shown* parameter is
4097 # positional only
4098 if not f.docstring_only:
4099 for p in reversed(parameters):
4100 if not p.converter.show_in_signature:
4101 continue
4102 if p.is_positional_only():
4103 need_a_trailing_slash = True
4104 break
4105
4106
Larry Hastings31826802013-10-19 00:09:25 -07004107 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004108
4109 first_parameter = True
4110 last_p = parameters[-1]
4111 line_length = len(''.join(text))
4112 indent = " " * line_length
4113 def add_parameter(text):
4114 nonlocal line_length
4115 nonlocal first_parameter
4116 if first_parameter:
4117 s = text
4118 first_parameter = False
4119 else:
4120 s = ' ' + text
4121 if line_length + len(s) >= 72:
4122 add('\n')
4123 add(indent)
4124 line_length = len(indent)
4125 s = text
4126 line_length += len(s)
4127 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004128
4129 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004130 if not p.converter.show_in_signature:
4131 continue
Larry Hastings31826802013-10-19 00:09:25 -07004132 assert p.name
4133
Larry Hastings2623c8c2014-02-08 22:15:29 -08004134 is_self = isinstance(p.converter, self_converter)
4135 if is_self and f.docstring_only:
4136 # this isn't a real machine-parsable signature,
4137 # so let's not print the "self" parameter
4138 continue
4139
4140 if p.is_positional_only():
4141 need_slash = not f.docstring_only
4142 elif need_slash and not (added_slash or p.is_positional_only()):
4143 added_slash = True
4144 add_parameter('/,')
4145
Larry Hastings31826802013-10-19 00:09:25 -07004146 if p.is_keyword_only() and not added_star:
4147 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004148 add_parameter('*,')
4149
4150 p_add, p_output = text_accumulator()
4151 p_add(fix_right_bracket_count(p.right_bracket_count))
4152
4153 if isinstance(p.converter, self_converter):
4154 # annotate first parameter as being a "self".
4155 #
4156 # if inspect.Signature gets this function,
4157 # and it's already bound, the self parameter
4158 # will be stripped off.
4159 #
4160 # if it's not bound, it should be marked
4161 # as positional-only.
4162 #
4163 # note: we don't print "self" for __init__,
4164 # because this isn't actually the signature
4165 # for __init__. (it can't be, __init__ doesn't
4166 # have a docstring.) if this is an __init__
4167 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004168 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004169 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004170
Larry Hastings5c661892014-01-24 06:17:25 -08004171 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004172 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004173
Larry Hastings31826802013-10-19 00:09:25 -07004174 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004175 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004176 value = p.converter.py_default
4177 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004178 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004179 p_add(value)
4180
4181 if (p != last_p) or need_a_trailing_slash:
4182 p_add(',')
4183
4184 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004185
4186 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004187 if need_a_trailing_slash:
4188 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004189 add(')')
4190
Larry Hastings2a727912014-01-16 11:32:01 -08004191 # PEP 8 says:
4192 #
4193 # The Python standard library will not use function annotations
4194 # as that would result in a premature commitment to a particular
4195 # annotation style. Instead, the annotations are left for users
4196 # to discover and experiment with useful annotation styles.
4197 #
4198 # therefore this is commented out:
4199 #
4200 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004201 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004202 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004203
Larry Hastings2623c8c2014-02-08 22:15:29 -08004204 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004205 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004206
Larry Hastings31826802013-10-19 00:09:25 -07004207 docstring_first_line = output()
4208
4209 # now fix up the places where the brackets look wrong
4210 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4211
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004212 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004213 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004214 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004215 for p in parameters:
4216 if not p.docstring.strip():
4217 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004218 if spacer_line:
4219 add('\n')
4220 else:
4221 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004222 add(" ")
4223 add(p.name)
4224 add('\n')
4225 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004226 parameters = output()
4227 if parameters:
4228 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004229
4230 ##
4231 ## docstring body
4232 ##
4233
4234 docstring = f.docstring.rstrip()
4235 lines = [line.rstrip() for line in docstring.split('\n')]
4236
4237 # Enforce the summary line!
4238 # The first line of a docstring should be a summary of the function.
4239 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4240 # by itself.
4241 #
4242 # Argument Clinic enforces the following rule:
4243 # * either the docstring is empty,
4244 # * or it must have a summary line.
4245 #
4246 # Guido said Clinic should enforce this:
4247 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4248
4249 if len(lines) >= 2:
4250 if lines[1]:
4251 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4252 "Every non-blank function docstring must start with\n" +
4253 "a single line summary followed by an empty line.")
4254 elif len(lines) == 1:
4255 # the docstring is only one line right now--the summary line.
4256 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004257 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004258 lines.append('')
4259
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004260 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4261 if parameters_marker_count > 1:
4262 fail('You may not specify {parameters} more than once in a docstring!')
4263
4264 if not parameters_marker_count:
4265 # insert after summary line
4266 lines.insert(2, '{parameters}')
4267
4268 # insert at front of docstring
4269 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004270
4271 docstring = "\n".join(lines)
4272
4273 add(docstring)
4274 docstring = output()
4275
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004276 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004277 docstring = docstring.rstrip()
4278
4279 return docstring
4280
4281 def state_terminal(self, line):
4282 """
4283 Called when processing the block is done.
4284 """
4285 assert not line
4286
4287 if not self.function:
4288 return
4289
4290 if self.keyword_only:
4291 values = self.function.parameters.values()
4292 if not values:
4293 no_parameter_after_star = True
4294 else:
4295 last_parameter = next(reversed(list(values)))
4296 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4297 if no_parameter_after_star:
4298 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4299
4300 # remove trailing whitespace from all parameter docstrings
4301 for name, value in self.function.parameters.items():
4302 if not value:
4303 continue
4304 value.docstring = value.docstring.rstrip()
4305
4306 self.function.docstring = self.format_docstring()
4307
4308
Larry Hastings5c661892014-01-24 06:17:25 -08004309
4310
Larry Hastings31826802013-10-19 00:09:25 -07004311# maps strings to callables.
4312# the callable should return an object
4313# that implements the clinic parser
4314# interface (__init__ and parse).
4315#
4316# example parsers:
4317# "clinic", handles the Clinic DSL
4318# "python", handles running Python code
4319#
4320parsers = {'clinic' : DSLParser, 'python': PythonParser}
4321
4322
4323clinic = None
4324
4325
4326def main(argv):
4327 import sys
4328
4329 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4330 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4331
4332 import argparse
4333 cmdline = argparse.ArgumentParser()
4334 cmdline.add_argument("-f", "--force", action='store_true')
4335 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004336 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004337 cmdline.add_argument("--converters", action='store_true')
Gregory P. Smith178418a2017-05-27 16:40:45 -07004338 cmdline.add_argument("--make", action='store_true',
4339 help="Walk --srcdir to run over all relevant files.")
4340 cmdline.add_argument("--srcdir", type=str, default=os.curdir,
4341 help="The directory tree to walk in --make mode.")
Larry Hastings31826802013-10-19 00:09:25 -07004342 cmdline.add_argument("filename", type=str, nargs="*")
4343 ns = cmdline.parse_args(argv)
4344
4345 if ns.converters:
4346 if ns.filename:
4347 print("Usage error: can't specify --converters and a filename at the same time.")
4348 print()
4349 cmdline.print_usage()
4350 sys.exit(-1)
4351 converters = []
4352 return_converters = []
4353 ignored = set("""
4354 add_c_converter
4355 add_c_return_converter
4356 add_default_legacy_c_converter
4357 add_legacy_c_converter
4358 """.strip().split())
4359 module = globals()
4360 for name in module:
4361 for suffix, ids in (
4362 ("_return_converter", return_converters),
4363 ("_converter", converters),
4364 ):
4365 if name in ignored:
4366 continue
4367 if name.endswith(suffix):
4368 ids.append((name, name[:-len(suffix)]))
4369 break
4370 print()
4371
4372 print("Legacy converters:")
4373 legacy = sorted(legacy_converters)
4374 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4375 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4376 print()
4377
4378 for title, attribute, ids in (
4379 ("Converters", 'converter_init', converters),
4380 ("Return converters", 'return_converter_init', return_converters),
4381 ):
4382 print(title + ":")
4383 longest = -1
4384 for name, short_name in ids:
4385 longest = max(longest, len(short_name))
4386 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4387 cls = module[name]
4388 callable = getattr(cls, attribute, None)
4389 if not callable:
4390 continue
4391 signature = inspect.signature(callable)
4392 parameters = []
4393 for parameter_name, parameter in signature.parameters.items():
4394 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4395 if parameter.default != inspect.Parameter.empty:
4396 s = '{}={!r}'.format(parameter_name, parameter.default)
4397 else:
4398 s = parameter_name
4399 parameters.append(s)
4400 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004401 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004402 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4403 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004404 sys.exit(0)
4405
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004406 if ns.make:
4407 if ns.output or ns.filename:
4408 print("Usage error: can't use -o or filenames with --make.")
4409 print()
4410 cmdline.print_usage()
4411 sys.exit(-1)
Gregory P. Smith178418a2017-05-27 16:40:45 -07004412 if not ns.srcdir:
4413 print("Usage error: --srcdir must not be empty with --make.")
4414 print()
4415 cmdline.print_usage()
4416 sys.exit(-1)
4417 for root, dirs, files in os.walk(ns.srcdir):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004418 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004419 if rcs_dir in dirs:
4420 dirs.remove(rcs_dir)
4421 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004422 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004423 continue
4424 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004425 if ns.verbose:
4426 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004427 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004428 return
4429
Larry Hastings31826802013-10-19 00:09:25 -07004430 if not ns.filename:
4431 cmdline.print_usage()
4432 sys.exit(-1)
4433
4434 if ns.output and len(ns.filename) > 1:
4435 print("Usage error: can't use -o with multiple filenames.")
4436 print()
4437 cmdline.print_usage()
4438 sys.exit(-1)
4439
4440 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004441 if ns.verbose:
4442 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004443 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004444
4445
4446if __name__ == "__main__":
4447 sys.exit(main(sys.argv[1:]))